[net.sources] Rog-O-Matic XIV

mlm@cmu-cs-cad.ARPA (Michael Mauldin) (02/01/85)

Rog-O-Matic XIV is the latest release of CMU's now famous automatic
Rogue playing program, and is now available for the first time on
net.sources without cost or obligation whatsoever.

Changes from version XIII include:

	o the genetic learning module described in our CSCSI-84
	  paper is now included.  Rog-O-Matic uses genetic learning
	  to determine eight parameters:

		srch:	Propensity for searching for traps
		door:	Propensity for searching for doors
		rest:	Propensity for resting
		arch:	Propensity for firing arrows at monsters
		exper:	Level on which to experiment with unknown items
		run:	Propensity for retreating
		wake:	Propensity for waking things up
		food:	Propensity for hoarding food

	o some of the modifications made at the University of Texas
	  (where Rog-O-Matic achieved its first total winner against
	  version 5.3 of Rogue) have been included.  Thanks to Dan
	  Reynolds at UTexas for his permission to include them.

	o numerous bugs have been fixed

	o numerous bugs have been added :-)

Rog-O-Matic will play the following versions of Rogue

	o Rogue 3.6 (Total winner, September 26, 1982 at CMU)

	o Rogue 5.2 (Total winner, October 10, 1983 at Waterloo)

	o Rogue 5.3 (Total winner, February 16, 1984 at Utexas)

Rog-O-Matic will not play Hack (that's about a month of enhancement
effort, and right now I've got this thesis proposal to write).  I will
be glad to help anyone who wants to modify Rogo to play Hack, just
getting it to play should be straightforward.

There are 10 shar format files (each less than 47,000) characters in
this distribution, for a total of 422,000 source characters and 14,000
lines of C code.  The 'unshar' command I recently posted will unpackage
them for you.

You will need Unix (or Rice Phoenix) on a Vax to run Rog-O-Matic, plus
your own copy of Rogue, and a friendly (or sleeping :-) ) sysad.

If you do snarf a copy from the net and get it running, I would very
much appreciate your sending me mail letting me know that you have a
running copy.  I would also appreciate mail concerning Rog-O-Matic's
performance against your version on Rogue, and I want to know if it
gets any more Total Winners (except in cheat mode against Rogue 3.6).

Michael Mauldin (Fuzzy)
Department of Computer Science
Carnegie-Mellon University
Pittsburgh, PA  15213
(412) 578-3065,  mauldin@cmu-cs-a.arpa

mlm@cmu-cs-cad.ARPA (Michael Mauldin) (02/01/85)

#!/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@cmu-cs-a.arpa
#
echo 'Start of Rog-O-Matic XIV, part 01 of 10:'
echo 'x - debug.c'
sed 's/^X//' > debug.c << '/'
X/*
X * debug.c: Rog-O-Matic XIV (CMU) Fri Dec 28 21:48:55 1984 - mlm
X * Copyright (C) 1985 by A. Appel, G. Jacobson, L. Hamey, and M. Mauldin
X *
X * This file contains the code for the debugger.  Rogomatic has one of
X * the tensest internal debuggers around, because in the early days it
X * had an incredible number of bugs, with no way to repeat an error
X * (because Rogue uses a different dungeon each time).
X */
X
X# include <curses.h>
X# include <setjmp.h>  
X# include "types.h"
X# include "globals.h"
X# include "install.h"
X
X/*
X * Debugging wait loop: Handle the usual Rogomatic command chars, and also
X * allows dumping the flags '^' command. Exits when a non-command char is
X * typed. To use, just put a "dwait (type, "message");" wherever you need 
X * debugging messages, and hit a space or a cr to continue
X */
X
Xdwait (msgtype, f, a1, a2, a3, a4, a5, a6, a7, a8)
Xchar *f;
Xint msgtype, a1, a2, a3, a4, a5, a6, a7, a8;
X{ char msg[128];
X  int r, c;
X
X  /* Build the actual message */
X  sprintf (msg, f, a1, a2, a3, a4, a5, a6, a7, a8);
X
X  /* Log the message if the error is severe enough */
X  if (!replaying && (msgtype & (D_FATAL | D_ERROR | D_WARNING)))
X  { char errfn[128]; FILE *errfil;
X
X    sprintf (errfn, "%s/error%s", RGMDIR, versionstr);
X    if ((errfil = wopen (errfn, "a")) != NULL)
X    { fprintf (errfil, "User %s, error type %d:  %s\n\n",
X               getname(), msgtype, msg);
X      if (msgtype & (D_FATAL | D_ERROR))
X      { printsnap (errfil);
X        summary (errfil, NEWLINE);
X        fprintf (errfil, "\f\n");
X      }
X      fclose (errfil);
X    }
X  }
X
X  if (msgtype & D_FATAL)
X  { extern jmp_buf commandtop;			/* From play */
X    saynow (msg);
X    playing = 0;
X    quitrogue ("fatal error trap", Gold, SAVED);
X    longjmp (commandtop);
X  }
X
X  if (! debug (msgtype | D_INFORM))		/* If debugoff */
X  { if (msgtype & D_SAY)			  /* Echo? */
X    { saynow (msg); return (1); }		  /* Yes => win */
X    return (0);					  /* No => lose */
X  }
X
X  if (*msg) { mvaddstr (0, 0, msg); clrtoeol (); }	/* Write msg */
X  if (noterm) return (1);				/* Exit if no user */
X
X  /* Debugging loop, accept debugging commands from user */  
X  while (1)
X  { refresh ();
X    switch (fgetc (stdin))
X    { case '?': 
X        say ("i=inv, d=debug !=stf, @=mon, #=wls, $=id, ^=flg, &=chr");
X        break;
X      case 'i': at (1,0); dumpinv (NULL); at (row, col); break;
X      case 'd': toggledebug (); 	break;
X      case 't': transparent = 1;        break;
X      case '!': dumpstuff ();           break;
X      case '@': dumpmonster ();         break;
X      case '#': dumpwalls ();           break;
X      case '^': promptforflags ();	break;
X      case '&':
X	if (getscrpos ("char", &r, &c))
X	  saynow ("Char at %d,%d '%c'", r, c, screen[r][c]);
X        break;
X      case '(': dumpdatabase (); at (row, col); break;
X      case ')': markcycles (DOPRINT); at (row, col); break;
X      case '~': saynow ("Version %d, quit at %d", version, quitat); break;
X      case '/': dosnapshot (); break;
X      default: at (row, col); return (1);
X    }
X  }
X}
X
X/* 
X * promptforflags: Prompt the user for a location and dump its flags.
X */
X
Xpromptforflags ()
X{ int r, c;
X
X  if (getscrpos ("flags", &r, &c))
X  { mvprintw (0, 0, "Flags for %d,%d ", r, c);
X    dumpflags (r, c);
X    clrtoeol ();
X    at (row, col);
X  }
X}
X
X/* 
X * dumpflags: Create a message line for the scrmap flags of a particular
X *            square.  Note that the fnames[] array must match the
X *            various flags defined in "types.h".
X */
X
Xchar *fnames[] = 
X{ "been",    "cango",    "door",     "hall",     "psd",     "room",
X  "safe",    "seen",     "deadend",  "stuff",    "trap",    "arrow",
X  "trapdor", "teltrap",  "gastrap",  "beartrap", "dartrap", "waterap",
X  "monster", "wall",     "useless",  "scarem",   "stairs",  "runok",
X  "boundry", "sleeper",  "everclr"
X};
X
Xdumpflags (r, c)
Xint   r, c;
X{ char **f; int b;
X
X    printw (":");
X    for (f=fnames, b=1;   b<=EVERCLR;   b = b * 2, f++)
X      if (scrmap[r][c] & b)
X        printw ("%s:", *f);
X}
X
X/* 
X * Timehistory: print a time analysis of the game.
X */
X
Xtimehistory (f, sep)
XFILE *f;
Xchar sep;
X{ register int i, j;
X  char s[2048];
X
X  timespent[0].timestamp = 0;
X
X  sprintf (s, "Time Analysis: %s%c%c",
X           "othr hand fght rest move expl rung grop srch door total",
X           sep, sep);
X
X  for (i=1; i<=MaxLevel; i++)
X  { sprintf (s, "%slevel %2d:     ", s, i);
X    for (j = T_OTHER; j < T_LISTLEN; j++)
X      sprintf (s, "%s%5d", s, timespent[i].activity[j]);
X    sprintf (s, "%s%6d%c",
X             s, timespent[i].timestamp - timespent[i-1].timestamp, sep);
X  }
X
X  if (f == NULL)
X    addstr (s);
X  else
X    fprintf (f, "%s", s);
X}
X
X/* 
X * toggledebug: Set the value of the debugging word.
X */
X
Xtoggledebug ()
X{ char debugstr[100];
X  int type = debugging & ~(D_FATAL | D_ERROR | D_WARNING);
X
X  if (debugging == D_ALL)         debugging = D_NORMAL;
X  else if (debugging == D_NORMAL) debugging = D_NORMAL | D_SEARCH;
X  else if (type == D_SEARCH)      debugging = D_NORMAL | D_BATTLE;
X  else if (type == D_BATTLE)      debugging = D_NORMAL | D_MESSAGE;
X  else if (type == D_MESSAGE)     debugging = D_NORMAL | D_PACK;
X  else if (type == D_PACK)        debugging = D_NORMAL | D_MONSTER;
X  else if (type == D_MONSTER)     debugging = D_NORMAL | D_CONTROL;
X  else if (type == D_CONTROL)     debugging = D_NORMAL | D_SCREEN;
X  else if (type == D_SCREEN)      debugging = D_NORMAL | D_WARNING;
X  else if (!debug (D_INFORM))     debugging = D_NORMAL | D_WARNING | D_INFORM;
X  else                            debugging = D_ALL;
X  
X  strcpy (debugstr, "Debugging :");
X
X  if (debug(D_FATAL))     strcat (debugstr, "fatal:");
X  if (debug(D_ERROR))     strcat (debugstr, "error:");
X  if (debug(D_WARNING))   strcat (debugstr, "warn:");
X  if (debug(D_INFORM))    strcat (debugstr, "info:");
X  if (debug(D_SEARCH))    strcat (debugstr, "search:");
X  if (debug(D_BATTLE))    strcat (debugstr, "battle:");
X  if (debug(D_MESSAGE))   strcat (debugstr, "msg:");
X  if (debug(D_PACK))      strcat (debugstr, "pack:");
X  if (debug(D_CONTROL))   strcat (debugstr, "ctrl:");
X  if (debug(D_SCREEN))    strcat (debugstr, "screen:");
X  if (debug(D_MONSTER))   strcat (debugstr, "monster:");
X  
X  saynow (debugstr);
X}
X
X/* 
X * getscrpos: Prompt the user for an x,y coordinate on the screen.
X */
X
Xgetscrpos (msg, r, c)
Xchar *msg;
Xint *r, *c;
X{ char buf[256];
X
X  saynow ("At %d,%d: enter 'row,col' for %s: ", atrow, atcol, msg);
X
X  if (fgets (buf, 256, stdin))
X  { sscanf (buf, "%d,%d", r, c);
X    if (*r>=1 && *r<23 && *c>=0 && *c<=79)
X      return (1);
X    else
X      say ("%d,%d is not on the screen!", *r, *c);
X  }
X
X  at (row, col);
X  return (0);
X}
/
echo 'x - strategy.c'
sed 's/^X//' > strategy.c << '/'
X/*
X * strategy.c: Rog-O-Matic XIV (CMU) Thu Jan 31 20:51:06 1985 - mlm
X * Copyright (C) 1985 by A. Appel, G. Jacobson, L. Hamey, and M. Mauldin
X *
X * This file contains all of the 'high level intelligence' of Rog-O-Matic. 
X */
X
X# include <stdio.h>
X# include <ctype.h>
X# include <curses.h>
X# include "types.h"
X# include "globals.h"
X# include "install.h"
X
X/*
X * foughtmonster records whether we engaged in battle recently.  This
X * information is used to tell whether we should sit still, waiting for a
X * confused monster to come back, or to go on about our business.
X * DIDFIGHT is the number of turns to sit still after a battle.
X */
X
X# define DIDFIGHT 3
X
Xextern int genericinit(), sleepvalue();	/* From explore.c */
X
X/*
X * strategize: Run through each rule until something fires. Return 1 if an
X * action was taken, otherwise return 0 (and then play will read a command
X * from the user).
X */
X
Xint   strategize ()
X{
X  dwait (D_CONTROL, "Strategizing...");
X
X  /* If replaying, instead of making an action, return the old one */
X  if (replaying) return (replaycommand ());
X
X  /* Clear any messages we printed last turn */
X  if (msgonscreen) { at (0,0); clrtoeol (); msgonscreen = 0; at (row,col); }
X
X
X  /* ----------------------- Production Rules --------------------------- */
X
X
X  if (fightmonster ())          /* We are under attack! */
X    return (1);
X
X  if (fightinvisible ())        /* Claude Raines! */
X    return (1);
X
X  if (tomonster ())             /* Go play with the pretty monster */
X    return (1);
X
X  if (shootindark ())           /* Shoot arrows in dark rooms */
X    return (1);
X
X  if (handleweapon ())		/* Play with the nice sword */
X  { dwait (D_BATTLE, "Switching to sword [1]"); return (1); }
X
X  if (light ())			/* Fiat lux! Especially if we lost */
X    return (1);			/* a monster from view.		   */
X
X  if (dinnertime ())            /* Soups on! */
X    return (1);
X
X  /* 
X   * These variables are short term memory.  Slowed and
X   * cancelled are fuses which are disabled after a small
X   * number of turns.
X   */
X
X  lyinginwait = 0;			/* No more monsters to wait for */
X  if (foughtmonster) foughtmonster--;	/* Turns since fought monster */
X  if (slowed) slowed--; 	        /* Turns since we slowed a monster */
X  if (cancelled) cancelled--;		/* Turns since we zapped 'cancel' */
X  if (beingheld) beingheld--;		/* Turns since held by a fungus */
X
X  /* ---- End of short term memory modification ---- */
X
X  if (dropjunk ())		/* Send it back */
X    return (1);
X 
X  if (readscroll ())		/* Get out the reading glasses */
X    return (1);			  /* Must come before handlearmor() */
X
X  if (handlearmor ())		/* Play dressup */
X    return (1);
X
X  if (quaffpotion ())		/* Glug glug glug ... */
X    return (1);			  /* Must come before handlering() */
X
X  if (handlering ())		/* We are engaged! */
X    return (1);
X
X  if (blinded && grope (100))	/* Who turned out the lights */
X  { display ("Blinded, groping..."); return (1); }
X
X  if (aftermelee ())		/* Wait for lingering monsters */
X    return (1);
X
X  if (tostuff ())		/* Pick up the play pretty */
X    return (1);
X
X  if (restup ())		/* Yawn! */
X    return (1);
X
X  if (goupstairs (NOTRUNNING))	/* Up we go! Make sure that we get */
X    return (1);			  /* a better rank on the board. */
X
X  if (trywand ())		/* Try to use a wand */
X    return (1);
X
X  if (gotowardsgoal ())		/* Keep on trucking */
X    return (1);
X
X  if (exploreroom ())		/* Search the room */
X    return (1);
X
X  if (archery ())		/* Try to position for fight */
X    return (1);
X
X  if (pickupafter ())		/* Look for stuff dropped by arched mon */
X    return (1);
X
X  if (plunge ())		/* Plunge mode */
X    return (1);
X
X  if (findarrow ())		/* Do we have an unitialized arrow? */
X    return (1);
X
X  if (findroom ())	/* Look for another room */
X    return (1);
X
X  /* 
X   * 'attempt' records the number of times we have completely searched
X   * this level for secret doors.  If attempt is greater than 0, then we
X   * have failed once to find the stairs and go down.  If this happens
X   * three times, there could be amonster sleeping on the stairs.  We set
X   * the SLEEPER bit for each square with a sleeping monster.  Go find
X   * such a monster and kill it to see whether (s)he was on the stairs).
X   */
X  
X  if (attempt > 4 && makemove (ATTACKSLEEP, genericinit, sleepvalue, REUSE))
X  { display ("No stairs, attacking sleeping monster...");
X    return (1);
X  }
X
X  if (Level>1 && larder>0 && doorexplore ())	/* Grub around */
X    return (1);
X
X  if (godownstairs (NOTRUNNING))		/* Down we go! */
X    return (1);
X
X  if ((Level<2 || larder<1) && doorexplore())   /* Grub around anyway */
X    return (1);
X
X  /* 
X   * If we think we are on the stairs, but arent, maybe they were moved
X   * (ie we were hallucinating when we saw them last time).
X   */
X  
X  if (on (STAIRS) && (atrow != stairrow || atcol != staircol))
X  { dwait (D_ERROR, "Stairs moved!"); findstairs (); return (1); }
X
X  /* 
X   * If we failed to find the stairs, explore each possible secret door
X   * another ten times.
X   */
X  
X  while (attempt++ < MAXATTEMPTS)
X  { timestosearch += max (3, k_door / 5);
X    foundnew ();
X    if (doorexplore ()) return (1);
X  }
X
X  /* 
X   * Don't give up, start all over!
X   */
X
X  newlevel ();
X  display ("I would give up, but I am too stubborn, starting over...");
X  return (grope (100));
X}
X
X/*
X * fightmonster: looks for adjacent monsters. If found, it calls
X * battlestations to prepare for battle otherwise hacks with the 
X * weapon already in hand.
X */
X
Xint   fightmonster ()
X{ register int i, rr, cc, mdir = NONE, mbad  = NONE, danger = 0;
X  int  melee = 0, adjacent = 0, alertmonster = 0;
X  int  wanddir = NONE, m = NONE, howmean;
X  char mon, monc = ':', *monster;
X
X  /* Check for adjacent monsters */
X  for (i = 0; i < mlistlen; i++)
X  { rr = mlist[i].mrow; cc = mlist[i].mcol;
X    if (max (abs (atrow-rr), abs (atcol-cc)) == 1)
X    { if (mlist[i].q != ASLEEP)
X      { if (mlist[i].q != HELD || Hp >= Hpmax || !havefood (1))
X	{ melee = 1;
X	  if (mlist[i].q == AWAKE) alertmonster = 1;
X	}
X      }
X    }
X  }
X  
X  if (!melee) return (0);               /* No one to fight */
X
X  /* Loop to find worst monster and tally danger & number adjacent */
X  for (i = 0; i < mlistlen; i++)
X  { rr = mlist[i].mrow; cc = mlist[i].mcol;	/* Monster position */
X
X    /* 
X     * If the monster is adjacent and is either awake or
X     * we dont know yet whether he is asleep, but we havent
X     * see any alert monsters yet.
X     */
X
X    if (max (abs (atrow-rr), abs (atcol-cc)) == 1 &&
X        (alertmonster ? mlist[i].q == AWAKE :
X                        mlist[i].q != ASLEEP)) /* DR Utexas 26 Jan 84 */
X    { mon = mlist[i].chr;		/* Record the monster type */
X      monster = monname (mon);		/* Record the monster name */
X      danger += maxhitchar(mon);	/* Add to the danger */
X
X      /* If he is adjacent, add to the adj count */
X      if (onrc (CANGO, rr, atcol) && onrc (CANGO, atrow, cc))
X      { adjacent++; howmean = isholder (monster) ? 10000 : avghit(i);
X            
X	/* If he is adjacent and the worst monster yet, save him */
X        if (howmean > mbad)
X        { wanddir = mdir = direc (rr-atrow, cc-atcol);
X          monc = mon; m = i; mbad = howmean;
X        }
X      }
X
X      /* If we havent yet a line of sight, check this guy out */
X      else if (wanddir == NONE)
X      { wanddir = direc (rr-atrow, cc-atcol); }
X
X      /* Debugging breakpoint */
X      dwait (D_BATTLE, "%c <%d,%d>, danger %d, worst %c(%d,%d), total %d",
X             screen[rr][cc], rr-atrow, cc-atcol,
X             danger, monc, mdir, mbad, adjacent);
X    }
X  }
X
X  /*
X   * The following variables have now been set:
X   *
X   * monc:      The letter of the worst monster we can hit
X   * mbad:      Relative scale 0 to 26, how bad is (s)he
X   * mdir:      Which direction to him/her
X   * danger:    How many hit points can (s)he/they do this round?
X   * wanddir:   Direction of worst monster, even if we cant move to it.
X   */
X
X  /*
X   * Check whether the battlestations expert has a suggested action.
X   */
X
X  monster = monname (monc);
X  if (battlestations (m, monster, mbad, danger, adjacent ? mdir : wanddir,
X                      adjacent ? 1 : 2, alertmonster, max (1, adjacent))) 
X  { foughtmonster = DIDFIGHT; return (1); }
X
X  /* 
X   * If we did not wait for him last turn, and he is not adjacent,
X   * let him move to us (otherwise, he gets to hits us first).
X   */
X  
X  if (!lyinginwait && !adjacent)
X  { command (T_FIGHTING, "s");
X    dwait (D_BATTLE, "Lying in wait...");
X    lyinginwait = 1;
X    foughtmonster = DIDFIGHT;
X    return (1);
X  }  
X
X  /* If we are here but have no direction, there was a bug somewhere */
X  if (mdir < 0)
X  { dwait (D_BATTLE, "Adjacent, but no direction known!");
X    return (0);
X  }
X
X  /* If we could die this round, tell the user about it */
X  if (danger >= Hp) display ("In trouble...");
X  
X  /* Well, nothing better than to hit the beast! Tell dwait about it */
X  dwait (D_BATTLE, "Attacking %s(%d) direction %d (total danger %d)...", 
X         monster, mbad, mdir, danger);
X
X  /* Record the monster type */
X  lastmonster = monc-'A'+1;
X
X  /* Move towards the monster (this causes us to hit him) */
X  rmove (1, mdir, T_FIGHTING);    
X  lyinginwait = 0;
X  foughtmonster = DIDFIGHT;
X  return (1);
X}
X
X/*
X * tomonster: if we can see a monster (and either it is awake or we
X * think we can beat it) then pick the worst one, call battlestations,
X * and then call gotowards to move toward the monster. If the monster
X * is an odd number of turns away, sit once to assure initiative before
X * charging after him. Special case for sitting on a door.
X */
X
Xint   tomonster ()
X{ register int i, dist, rr, cc, mdir = NONE, mbad = NONE;
X  int   closest, which, danger = 0, adj = 0;
X  char  monc = ':', monchar = ':', *monster;
X
X  /* If no monsters, fail */
X  if (mlistlen==0)
X    return (0);
X
X  /* 
X   * Loop through the monsters, 'which' and 'closest' record the index 
X   * and distance of the closest monster worth fighting.
X   */
X    
X  for (i = 0, which = NONE, closest = 999; i < mlistlen; i++)
X  { dist = max (abs (mlist[i].mrow - atrow), abs (mlist[i].mcol - atcol));
X    monchar = mlist[i].chr;
X
X    /* 
X     * IF   we are not using a magic arrow OR
X     *      we want to wake this monster up AND we can beat him OR
X     *      he is standing near something we want and we will have to 
X     *        fight him anywhay
X     * THEN consider fighting the monster.
X     *
X     * Don't pick fights with sleepers if cosmic.  DR UTexas 25 Jan 84 
X     */
X    
X    if (usingarrow || mlist[i].q == AWAKE || 
X        (!cosmic && wanttowake (monchar) &&
X	 (avghit (i) <= 50 || (maxhit (i) + 50 - k_wake) < Hp)) ||
X	(mlist[i].q == HELD && Hp >= Hpmax))
X    { danger += maxhit(i);		/* track total danger */
X      adj++;				/* count number of monsters */
X
X      /* If he is the closest monster, save his index and distance */
X      if (dist < closest)
X      { closest = dist; which = i; monc = mlist[i].chr; mbad = avghit(i); }
X
X      /* Or if he is meaner than another equally close monster, save him */
X      else if (dist == closest && avghit(i) > avghit(which))
X      { dwait (D_BATTLE, "Chasing %c(%d) rather than %c(%d) at distance %d.",
X               mlist[i].chr, avghit(i), mlist[which].chr,
X               avghit(which), dist);
X
X        closest = dist; which = i; monc = mlist[i].chr; mbad = avghit(i);
X      }
X    }
X  }
X
X  /* No monsters worth bothering, return failure */
X  if (which < 0) return (0); 
X
X  /* Save the monsters location in registers */
X  rr = mlist[which].mrow - atrow; cc = mlist[which].mcol - atcol;
X
X  /* If the monster is on an exact diagonal, record direction */
X  mdir = (rr==0 || cc==0 || abs(rr)==abs(cc)) ? direc (rr, cc) : -1;
X
X  /* Get a string which names the monster */
X  monster = monname (monc);
X
X  /* If 'battlestations' has an action, use that action */
X  if (battlestations (which, monster, mbad, danger, mdir, closest, 1, adj))
X    return (1);
X
X  /* If he is an odd number of squares away, lie in wait for him */
X  if (closest&1 == 0 && !lyinginwait)
X  { command (T_FIGHTING, "s");
X    dwait (D_BATTLE, "Waiting for monster an odd number of squares away...");
X    lyinginwait = 1;
X    return (1);
X  }
X
X  /* "We have him! Move toward him!" */
X  if (gotowards (mlist[which].mrow, mlist[which].mcol, 0))
X  { goalr = mlist[which].mrow; goalc = mlist[which].mcol;
X    lyinginwait = 0;
X    return (1);
X  }
X
X  /* Could not find a path to the monster, record failure */
X  return (0);
X}
X
X/*
X * wanttowake is true for monsters without special attacks, such that the
X * expected damage from hits is a reasonable estimate of their vorpalness.
X * Some monsters are included here because we want to shoot arrows at them.
X */
X
Xwanttowake(c) 
Xchar c;
X{ char *monster = monname (c);
X
X  if (missedstairs) 
X    return (1);
X
X  /*
X   * If monster sleeping but won't wake up when we move around him,
X   * return wanttowake as false.   DR UTexas 09 Jan 84
X   */
X
X  if (streq (monster, "centaur") ||
X      streq (monster, "dragon") ||
X      streq (monster, "floating eye") ||
X      streq (monster, "ice monster") ||
X      streq (monster, "leprechaun") ||
X      streq (monster, "nymph") ||
X      streq (monster, "wraith") ||
X      streq (monster, "purple worm") )
X    return (0);
X
X  return (1);
X}
X
X/*
X * aftermelee:	called when we have just fought a monster, assures
X *		that it wasn't just a confused monster that backed
X *		away and might get a hit on us if we move. Now only
X *		used when we lost a monster from view.
X *
X *		Also rest if we are critically weak and have some food.
X */
X
Xaftermelee ()
X{ 
X  if (foughtmonster > 0)
X  { lyinginwait = 1;  
X    command (T_RESTING, "s");
X    dwait (D_BATTLE, "Aftermelee: waiting for %d rounds.", foughtmonster);
X    return (1);
X  }
X
X  /* If critically weak, rest up so traps won't kill us.  DR Utexas */
X  if (Hp < 6 && larder > 0)
X  { command (T_RESTING, "s");
X    display ("Recovering from severe beating...");
X    return (1);
X  }
X
X  return (foughtmonster = 0);
X}
X
X/*
X * battlestations:
X *
X *      We are going into battle. Can we think of anything better to
X *      to than simply hacking at him with our weapon?
X */
X
X# define die_in(n)	(Hp/n < danger*50/(100-k_run))
X# define live_for(n)	(! die_in(n))
X
Xbattlestations (m, monster, mbad, danger, mdir, mdist, alert, adj)
Xint m;			/* Monster index */
Xchar *monster;          /* What is it? */
Xint mbad;               /* How bad is it? */
Xint danger;             /* How many points damage per round? */
Xint mdir;               /* Which direction (clear line of sight)? */
Xint mdist;              /* How many turns until battle? */
Xint alert;              /* Is he known to be awake? */
Xint adj;		/* How many attackers are there? */
X{ int obj, turns;
X  static int stepback = 0;
X
X  /* Ascertain whether we have a clear path to this monster */
X  if (mdir != NONE && !checkcango (mdir, mdist))
X    mdir = NONE;
X
X  /* Number of turns is one less than distance (modified if we are hasted) */
X  turns = hasted ? (mdist-1)*2 : (mdist-1);
X
X  /* No point in wasting resources when we are invulnerable */
X  if (on (SCAREM) && (turns > 0 || confused) && !streq(monster, "dragon"))
X  { command (T_RESTING, "s");
X    display ("Resting on scare monster");
X    dwait (D_BATTLE, "Battlestations: resting, on scaremonster.");
X    return (1);
X  }
X
X  /* 
X   * Take invisible stalkers into account into account,
X   * fightmonster() and tomonster() cant see stalkers.
X   */
X
X  if (beingstalked > 1000) { turns = 0; danger += 16; }
X
X  /* Debugging breakpoint */
X  dwait (D_BATTLE,
X        "Battlestations: %s(%d), total danger %d, dir %d, %d turns, %d adj.", 
X        monster, mbad, danger, mdir, turns, adj);
X
X
X  /* 
X   * Switch back to our mace or sword?
X   */
X
X  if (live_for (1) && turns < 2 && wielding (thrower) && handleweapon ())  
X  { dwait (D_BATTLE, "Switching to sword [2]"); return (1); }
X
X  /* 
X   * Dont waste magic when on a scare monster scroll
X   */
X  
X  if (on (SCAREM) && !streq (monster, "dragon"))
X  { dwait (D_BATTLE, "Battlestations: hitting from scaremonster.");
X    return (0);
X  }
X
X  /* 
X   * If we were busy resting on the stairs and we see a monster, go down
X   * Go on down if about to be attacked by a monster with an effective
X   * magic attack.  DR UTexas 25 Jan 84
X   */
X
X  if (on(STAIRS) && ((Level>18 && Level<26) || exploredlevel) && !floating &&
X      (die_in(5) ||
X       ((seeawakemonster ("rattlesnake") || seeawakemonster ("giant ant")) &&
X         (have (ring, "sustain strength") < 0)) ||
X       ((seeawakemonster ("aquator") || seeawakemonster ("rust monster")) &&
X        turns < 2 && willrust (currentarmor) &&
X	wearing ("maintain armor") == NONE) ||
X       seeawakemonster ("medusa") || seeawakemonster ("umber hulk")))
X  { if (goupstairs (RUNNING) || godownstairs (RUNNING))
X      return (1);
X  }
X
X  /* 
X   * Are healing potions worthwhile?
X   */
X   
X  if (die_in (1) && Hpmax-Hp > 10 && turns > 0 &&
X      ((obj = havenamed (potion, "extra healing")) != NONE ||
X       (obj = havenamed (potion, "healing")) != NONE))
X    return (quaff (obj));
X  
X  /* 
X   * Run away if we are sure of the direction and we are in trouble
X   * Dont try to run if a fungi has ahold of us. If we are confused,
X   * we will try other things, and we will decide to run later.
X   * If we are on a door, wait until the monster is on us (that way
X   * we can shoot arrows at him, if we want to).
X   * Don't run away from Dragons!!!  They'll just flame you.
X   */
X   
X  if (!confused && !beingheld && (!on(DOOR) || turns < 1) &&
X      (!streq (monster, "dragon") || cosmic) && Hp+Explev < Hpmax &&
X      ((die_in(1) || Hp <= danger + between (Level-10, 0, 10)) || chicken) &&
X      runaway ())
X  { display ("Run away! Run away!"); 
X    darkdir = NONE; darkturns = 0;
X    return(1); } 
X
X  /* 
X   * Be clever when facing multiple monsters?
X   */
X   
X  if (adj > 1 && !confused && !beingheld && !on (STAIRS | DOOR) &&
X      backtodoor (turns))
X    return (1);
X
X  /* 
X   * stepback to see if he is awake.
X   */
X   
X  if (!alert && !beingheld && !stepback && mdir != NONE &&
X      turns == 0 && !on (DOOR | STAIRS))
X  { int rdir = (mdir+4)%8;
X    if (onrc (CANGO | TRAP, atdrow(rdir), atdcol(rdir)) == CANGO)
X    { move1 (rdir); stepback = 7; return (1); }
X  }
X  
X  if (stepback) stepback--;     /* Decrement turns until step back again */
X  
X  /*
X   * Should we put on our ring of maintain armor?   DR UTexas 19 Jan 84
X   */
X
X  if (live_for (1) && currentarmor != NONE &&
X      (leftring == NONE || rightring == NONE) &&
X      (seemonster ("aquator") || seemonster ("rust monster")) &&
X      willrust (currentarmor) &&
X      wearing ("maintain armor") == NONE &&
X      (obj = havenamed (ring, "maintain armor")) != NONE &&
X      puton (obj))
X    return (1);
X
X  if (turns > 1 && live_for (2) && leftring != NONE && rightring != NONE &&
X      (seemonster ("aquator") || seemonster ("rust monster")) &&
X      wearing ("maintain armor") < 0 &&
X      findring ("maintain armor"))
X    return (1);
X
X  /*
X   * Should we put on our ring of sustain strength?  DR UTexas 19 Jan 84
X   */
X
X  if ((live_for (1) || turns > 0) &&
X      (leftring == NONE || rightring == NONE) &&
X      (seemonster ("giant ant") || seemonster ("rattlesnake")) &&
X      wearing ("sustain strength") < 0 &&
X      (obj = havenamed (ring, "sustain strength")) != NONE &&
X      puton (obj))
X    return (1);
X
X  if ((live_for (2) || turns > 1) &&
X      leftring != NONE && rightring != NONE &&
X      (seemonster ("giant ant") || seemonster ("rattlesnake")) &&
X      wearing ("sustain strength") < 0 &&
X      findring ("sustain strength"))
X    return (1);
X
X  /* 
X   * Should we put on our ring of regeneration? Make sure we wont kill
X   * ourselves trying to do it, by checking how many turns it will take to
X   * get it on compared to the number of hits we can take.
X   */
X  
X  /* Have a ring and a free hand, one turn */
X  if (die_in (4) && (live_for (1) || turns > 0) &&
X      (leftring == NONE || rightring == NONE) &&
X      !(turns == 0 && (streq (monster, "rattlesnake") ||
X                       streq (monster, "giant ant"))) &&
X      wearing ("regeneration") < 0 &&
X      (obj = havenamed (ring, "regeneration")) != NONE &&
X      puton (obj))
X    return (1);
X
X  /* Have a ring and both hands are full, takes two turns */
X  if (die_in (4) && (live_for (2) || turns > 1) &&
X      leftring != NONE && rightring != NONE &&
X      wearing ("regeneration") < 0 &&
X      findring ("regeneration"))
X    return (1);
X
X  /* 
X   * Haste ourselves?
X   */
X   
X  if (!hasted && version > RV36B && (turns > 0 || live_for (1)) &&
X      die_in (2) && (obj = havenamed (potion, "haste self")) != NONE &&
X      quaff (obj))
X    return (1);
X
X  /* 
X   * Confuse the poor beast?
X   */
X   
X  if (die_in (2) && turns > 0 && !redhands &&
X      ((obj = havenamed (scroll, "monster confusion")) != NONE))
X    return (reads (obj));
X  
X  /* 
X   * Put them all to sleep? This does us little good, since we cant
X   * currently infer that we have a scroll of Hold Monster. But we
X   * will read scrolls of identify on the second one.  Bug, this
X   * does not put them to sleep, it just holds them in place.
X   * We have a lot more programming to do here!!!!   Fuzzy
X   */
X   
X  if (die_in (1) && (obj = havenamed (scroll, "hold monster")) != NONE &&
X      reads (obj))
X  { holdmonsters ();
X    return (1);
X  }
X   
X  /* 
X   * Drop a scare monster?
X   */
X   
X  if (die_in (1) && !streq(monster, "dragon") &&
X      (obj = havenamed (scroll, "scare monster")) != NONE &&
X      drop (obj))
X  { set (SCAREM);
X    droppedscare++;
X    return (1);
X  }
X  
X  /* 
X   * Buy buy birdy!
X   */
X   
X  if (die_in (1) && mdir != NONE && turns == 0 &&
X      (obj = havewand ("teleport away")) != NONE &&
X      point (obj, mdir))
X  { if (streq (monster, "violet fungi")) beingheld = 0;
X    if (streq (monster, "venus flytrap")) beingheld = 0;
X    return (1);
X  }
X
X  /* 
X   * Eat dust, turkey!
X   */
X   
X  if (die_in (1) && turns == 0 &&
X      (obj = havenamed (scroll, "teleportation")) != NONE)
X  { beingheld = 0;
X    return (reads (obj));
X  }
X
X  /* 
X   * The better part of valor...
X   */
X   
X  if ((die_in (1) && turns == 0 || fainting ()) && quitforhonors ())
X    return (1);
X
X  /*
X   * If we trust our magic arrow, give it a whirl
X   */
X
X  if (!confused && cheat && usingarrow && goodarrow > 10 && turns == 0)
X    return (0);
X
X  /* 
X   * Try to protect our armor from Rusties.
X   */
X
X  if (!cursedarmor && currentarmor != NONE &&
X      (seeawakemonster ("rust monster") || seeawakemonster ("aquator")) &&
X      live_for (1) &&
X      !(cosmic && Level < 8) &&               /* DR UTexas 25 Jan 84 */
X      willrust (currentarmor) &&
X      wearing ("maintain armor") == NONE &&
X      takeoff ())
X  { return (1); }
X
X  /* 
X   * Any life saving wands?
X   */
X   
X  if (die_in (2) && Hp > 40 && turns < 3 &&
X      !(streq (monster, "purple worm") || streq (monster, "jabberwock")) &&
X      (obj = havewand ("drain life")) != NONE)
X    return (point (obj, 0));
X
X  if (mdir != NONE && die_in (2) &&
X      (!cosmic || Level > 18) &&          /* DR UTexas 31 Jan 84 */
X      (streq (monster, "dragon")     || streq (monster, "purple worm")   || 
X       streq (monster, "jabberwock") || streq (monster, "medusa")        ||
X       streq (monster, "xorn")       || streq (monster, "violet fungi")  || 
X       streq (monster, "griffin")    || streq (monster, "venus flytrap") ||
X       streq (monster, "umber hulk") || streq (monster, "black unicorn")) &&
X      (obj = havewand ("polymorph")) != NONE)
X    return (point (obj, mdir));
X  
X  /* 
X   * Any life prolonging wands?
X   */
X   
X  if ((die_in (1) || (turns == 0 && streq (monster, "floating eye")) ||
X      (turns == 0 && streq (monster, "ice monster"))) &&
X      mdir != NONE && mdist < 6 && !on(DOOR) &&
X      ((obj = havewand ("fire")) != NONE &&  !streq(monster, "dragon") ||
X       (obj = havewand ("cold")) != NONE ||
X       (obj = havewand ("lightning")) != NONE))
X    return (point (obj, mdir));
X
X  if (die_in (2) && mdir != NONE && !slowed && (turns>0 || live_for (2)) && 
X      (obj = havewand ("slow monster")) != NONE &&
X      (slowed = 5))
X    return (point (obj, mdir));
X
X  if (mdir != NONE && !cancelled && turns == 0 &&
X      (streq (monster, "wraith") ||
X       streq (monster, "vampire") ||
X       streq (monster, "floating eye") ||
X       streq (monster, "ice monster") ||
X       streq (monster, "leprechaun") ||
X       streq (monster, "violet fungi") ||
X       streq (monster, "venus flytrap")) &&      
X      (obj = havewand ("cancellation")) != NONE &&
X      (cancelled = 10))
X  { if (streq (monster, "violet fungi") || streq (monster, "venus flytrap"))
X      beingheld = 0;
X    return (point (obj, mdir));
X  }
X
X  if (((die_in (3) && live_for (1)) ||
X       (turns == 0 && streq (monster, "floating eye")) ||
X       (turns == 0 && streq (monster, "ice monster"))) &&
X      mdir != NONE &&
X      (((obj = havewand ("magic missile")) != NONE && turns > 0) ||
X       ((obj = havewand ("striking")) != NONE && turns == 0)))
X    return (point (obj, mdir));
X
X  /* 
X   * Since we have no directional things, we will try to run even though
X   * we are confused. Again, wait at door until the monster is on us.
X   * Don't run away from dragons, they'll just flame you!!
X   */
X   
X  if (confused && !beingheld && (!on(DOOR) || turns < 1) &&
X      ! streq (monster, "dragon") &&
X      ((die_in (1) && Hp+Explev/2+3 < Hpmax) || chicken) && 
X      runaway ())
X  { display ("Run away! Run away!"); return(1); }
X  
X  /* 
X   * We can live for a while, try to get to a position where we can run
X   * away if we really get into trouble.  Dont run away from dragons,
X   * they'll just flame you!!!
X   */
X
X  if (!confused && !beingheld && ! streq (monster, "dragon") &&
X      (mdir < 0 || turns < 5) &&
X      (((adj > 1 || live_for (1)) && die_in (4) && !canrun ())) &&
X      unpin ())
X  { display ("Unpinning!!!"); return(1); }
X
X  /* 
X   * Light up the room if we are in combat.
X   */
X   
X  if (turns > 0 && die_in (3) && lightroom ())
X    return (1);
X
X  /* 
X   * We arent yet in danger and can shoot at the old monster.
X   */
X   
X  if ((live_for (5) || turns > 1) && shootindark ())
X    return (1);
X
X  /* 
X   * Try out an unknown wand?  Try shooting unknown wands at 
X   * rattlesnakes since they are such a pain.   DR UTexas  19 Jan 84
X   */
X   
X  if (live_for (2) && (Level > 8 || streq (monster, "rattlesnake") ||
X                                    streq (monster, "giant ant")) &&
X      mdir != NONE && on(ROOM) && mdist < 6 &&
X      ((obj = unknown (wand)) != NONE) && point (obj, mdir))
X  { usesynch = 0;
X    /* zappedunknown = TRUE; */		/* DR UTexas  19 Jan 84 */
X    return (1);
X  }
X
X  /* 
X   * Wait to see if he is really awake.
X   */
X   
X  if (!alert && !lyinginwait && turns > 0)
X  { command (T_FIGHTING, "s");
X    dwait (D_BATTLE, "Waiting to see if he is awake...");
X    lyinginwait = 1;
X    return (1);
X  }
X
X  /* 
X   * Archery: try to move into a better position, and after that, try to
X   * shoot an arrow at the beast. Conserve arrows below SAVEARROWS.
X   */
X
X  if ((streq (monster, "leprechaun") ||
X       streq (monster, "nymph") ||
X       streq (monster, "floating eye") ||
X       streq (monster, "ice monster") ||
X       streq (monster, "giant ant") ||
X       streq (monster, "rattlesnake") ||
X       streq (monster, "wraith") ||
X       streq (monster, "vampire") ||
X       streq (monster, "centaur") ||   /* DR UTexas 21 Jan 84 */
X       die_in (1+k_arch/20) || ammo > SAVEARROWS+5-k_arch/10) &&
X      (obj = havemissile ()) != NONE)
X  {
X    /* Move into position */  
X    if ((!alert || mdir < 0) && turns > 0 && archmonster (m, 1))
X      return (1);
X
X    /* If in position */
X    if (!on (HALL) && mdir != NONE && turns > 0)
X    { int bow;
X
X      /* Wield the bow if we have time */
X      if (!cursedweapon && !wielding (thrower) && turns > 4 &&
X          (bow = havebow (1, NOPRINT)) != NONE && wield (bow))
X        return (1);
X
X      /* And shoot! */
X      throw (obj, mdir);
X      return (1);
X    }
X  }
X
X  /* 
X   * Switch back to our mace or sword?
X   */
X
X  if (!cursedweapon && wielding (thrower) && handleweapon ())  
X  { dwait (D_BATTLE, "Switching to sword [3]"); return (1); }
X
X  /* 
X   * No bright ideas. Return and let the caller figure out what to do.
X   */
X   
X  return (0);
X}
X
X/*
X * tostuff: if we see something to pick up, go to it. If our pack is full, 
X * try to drop our least useful item. If pack is still full, fail.
X */
X
Xint tostuff ()
X{ register int i, closest, dist, w, worst, worstval;
X  int   which, wrow, wcol;
X  stuff what;
X
X  /* If we don't see anything (or dont care), return failure */
X  if (slistlen == 0 || Level == 1 && have (amulet) != NONE) return (0);  
X
X  /* 
X   * Now find the closest thing to pick up.  Dont consider things we have
X   * already dropped (those squares have the USELESS bit set), unless we
X   * have dropped a scroll of SCARE MONSTER, in which case we want our
X   * pack to be full.  Dont be fooled by stairs when hallucinating.
X   *
X   * NOTE: Dont pick up the scaremonster scroll!!!    MLM
X   */
X
X  for (i = 0, which = NONE, closest = 999; i < slistlen; i++)
X  { if (!onrc (USELESS, slist[i].srow, slist[i].scol) ||
X        (droppedscare && objcount < maxobj &&
X         !onrc (SCAREM, slist[i].srow, slist[i].scol)))
X    { dist = max (abs (slist[i].srow - atrow), abs (slist[i].scol - atcol));
X
X      /* Make junk look farther away, but not farther than infinity */
X      if (onrc (USELESS, slist[i].srow, slist[i].scol)) dist += 500;
X
X      /* If this is the closest item, save its distance and index */
X      if (dist < closest)
X      { closest = dist; which = i; }
X    }
X  }
X
X  /* Could not find anything worth picking up, return failure */
X  if (which < 0) return (0);
X
X  /* Found something, save its location and type in registers */
X  what= slist[which].what; wrow= slist[which].srow; wcol= slist[which].scol;
X
X  /* We can always pick up more gold */
X  if (what == gold) return (gotowards (wrow, wcol, 0));
X
X  /* Have space in our pack, go get it */
X  if (objcount < maxobj) return (gotowards (wrow, wcol, 0));
X
X  /* No space in pack and we cannot drop something here, fail */
X  if (on (STUFF | DOOR | TRAP | STAIRS)) return (0);
X
X  /* Must drop something, pick least valuable item to drop */
X  for (worst = NONE, worstval = 9999, i = 0;   i < invcount;   i++)
X  { if (inven[i].count && !itemis (i, INUSE) && (w = worth (i)) < worstval)
X    { worst = i; worstval = w; }
X
X    /* Once we have found a toally useless item, stop looking */
X    if (worstval == 0) break; 
X  }
X
X  /* Found an item, drop it */
X  if (worst != NONE) return (drop (worst));
X
X  /* Pack is full and we cant find something to drop, fail */
X  return (0);
X}
X
X/*
X * fightinvisible: being hounded by unseen beasties, try something clever.
X */
X
X# define INVDAM		(16)
X# define INVPRES	(INVHIT-100)
X# define INVLURK	(INVPRES-200)
X
Xfightinvisible ()
X{ char cmd[20]; register int dir, liberties = 0, lastdir, obj;
X
X  /* Count down the time since we were last hit by a stalker */
X  if (--beingstalked < 0)
X  { return (beingstalked=0); }
X
X  /* If we are in real trouble, we might want to quit */
X  if (beingstalked > INVPRES && Hp < INVDAM && quitforhonors ())
X  { return (1); }
X
X  /* Can we teleport out of here? */  
X  if (Hp < INVDAM && beingstalked > INVPRES &&
X      (obj = havenamed (scroll, "teleport")) != NONE && reads (obj))
X  { beingstalked = INVPRES-1;
X    return (1); }  
X
X  /* Can we quaff a potion of see invisible? */
X  if ((obj = havenamed (potion, "see invisible")) != NONE && quaff (obj))
X  { beingstalked = 0; return (1); }
X
X  /* If we have some time, try putting on a ring of see invisible */
X  if (Hp > (INVDAM * 3/2) && beingstalked > INVLURK &&
X      findring ("see invisible"))
X  { return (1); }
X
X  /* If we can bail out to the next level, do so */
X  if (((beingstalked < INVPRES  && Hp < (INVDAM * 2)) ||
X       (beingstalked >= INVPRES && Hp < (INVDAM * 3))) &&
X      godownstairs (RUNNING))
X  { display ("Running like hell from an invisible stalker...");
X    return (1); }
X
X  /* Nothing worth doing, but he is around somewhere */
X  if (beingstalked <= INVPRES)
X    return (0);
X
X  /* Must fight him 'mano a mano', tell the user (who cant see him either) */
X  display ("Fighting invisible stalker...");
X  *cmd = '\0';
X
X  /* Record the monster type (for didhit and didmiss, see mess.c) */
X  if (version < RV53A)
X    lastmonster = ('I'-'A'+1);
X  else
X    lastmonster = ('P'-'A'+1);
X
X  /* Count how many orthogonal moves we can make */
X  for (dir=0; dir<8; dir++)
X    if (atdrow(dir) > 0 && atdrow(dir) < 23 &&
X        onrc(CANGO, atdrow(dir), atdcol(dir)) &&
X        onrc(CANGO, atdrow(dir), atcol) &&
X        onrc(CANGO, atrow, atdcol(dir))) 
X    { liberties++; lastdir = dir; }
X
X  /* If can only go two ways, then go back and forth (will hit) */
X  if (liberties == 1 || liberties == 2)
X    sprintf (cmd, "%c%c", keydir[lastdir], keydir[(lastdir+4)&7]);
X
X  /* Try to get away, usually gets to a square with only 2 liberties */
X  else if (runaway ()) return (1);
X
X  /* Else run two and then double back on him. If that will */
X  /* not work, run in a circle (will hit one out of 4)      */
X  else
X  { for (dir=0; dir<8; dir += 2)
X      if ((onrc(CANGO, atdrow(dir), atdcol(dir))) &&
X          (onrc(CANGO, atrow+2*deltr[dir], atcol+2*deltc[dir])))
X        break;
X
X    if (dir > 7)	command (T_FIGHTING, "hjlk");
X    else		command (T_FIGHTING, "%c%c%c", keydir[dir],
X			         keydir[dir], keydir[(dir+4)&7]);
X  }
X
X  return (1);
X}
X
X/*
X * archery: Try to arch sleeping monsters.  The 'mtokill' attr keeps track
X * of how many arrows we want to be able to pump into a monster before we
X * decide to wake him up.  That means we must be that far away AND have
X * that many missiles in our pack.  This number can be modified by our hit
X * and damage bonuses.
X *
X * Note: some monsters are to wimpy archery, and some too mean.     MLM
X */
X
Xarchery ()
X{ register int m, mtk;
X  char *monster;
X
X  for (m=0; m < mlistlen; m++)		/* Find a sleeping monster */
X  { monster = monname (mlist[m].chr);
X
X    /* 
X     * If he is not awake and either
X     *   we are much stronger than he is or
X     *   he is a known target for archery and
X     * we have enough arrows to wipe this dude out and
X     * we have food or he is a leprechaun and we arent hungry yet
X     *
X     * Then try calling archmonster to move to the right place.
X     */
X     
X    if (mlist[m].q != AWAKE && gplushit != NONE &&
X	!(mlist[m].q == HELD && Hp < Hpmax)  &&	/* DR UTexas 26 Jan 84 */
X        (maxhit(m) > Hp/3 ||
X         streq (monster, "leprechaun")	  ||
X         streq (monster, "nymph")	  ||
X	 streq (monster, "floating eye")  ||
X	 streq (monster, "giant ant")	  ||
X	 streq (monster, "rattlesnake")	  ||
X	 streq (monster, "centaur")	  ||
X	 streq (monster, "ice monster"))  &&
X        ammo >= (mtk = monatt[mlist[m].chr-'A'].mtokill - gplushit) &&
X        larder > 0 ||
X        ((streq (monster, "leprechaun") && !hungry ()) ||
X          streq (monster, "nympyh")))
X    { dwait (D_BATTLE, "Arching at %c at (%d,%d)",
X	     mlist[m].chr, mlist[m].mrow, mlist[m].mcol);
X      if (archmonster (m, mtk)) return (1);
X      dwait (D_BATTLE, "Archmonster failed in archery.");
X    }
X  }
X  
X  return (0);
X}
X
X/*
X * pickupafter: Go stand on square where the monster used to be.
X *              If (s)he left something behind (evens just arrows
X *		that missed) we will find it and pick it up.
X *
X * Bug:		Sometimes goes the long way around and doesnt see things.
X */
X
Xpickupafter ()
X{ /* If no goal */
X  if (agoalr < 0 || agoalc < 0)
X    return (0);
X
X  /* If on goal */  
X  if (atrow == agoalr && atcol == agoalc)
X  { agoalr = agoalc = NONE;
X    return (0);
X  }
X  
X  /* Else go for it */  
X  return (gotowards (agoalr, agoalc, 0));
X}
X
X/*
X * dropjunk: This doesnt just drop something.  It destroys it.
X *           When an object is thrown diagonally into a corner,
X *           Rogue cant find a place to put it, and the object is
X *           removed from the game.  Used to get rid of empty wands
X *           and staves.  This way, we dont pick them up later,
X *           and mistake them for fresh wands.
X */
X
Xdropjunk ()
X{ int obj;
X
X  if ((obj = haveuseless ()) != NONE && (gotocorner () || throw (obj, 7)))
X    return (1);
X
X  return (0);
X}
X
X/*
X * quitforhonors: We are in mortal danger.  Do we want to quit?
X *
X * Strategy:	'quitat' is the score to beat (set in setup);
X *		If we will beat it anyway, dont quit.  If we
X *		wont beat it anyway, dont quit.  If we will just
X *		beat the score by quiting, then do so.
X *
X * Assumes a 10 percent death tax.
X */
X
Xquitforhonors ()
X{
X  if (Gold > quitat && (Gold-Gold/10) <= quitat)
X  { quitrogue ("quit (scoreboard)", Gold, 0);
X    return (1);
X  }
X
X  return (0);
X}
/
echo 'Part 01 of Rog-O-Matic XIV complete.'
exit

mlm@cmu-cs-cad.ARPA (Michael Mauldin) (02/01/85)

#!/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@cmu-cs-a.arpa
#
echo 'Start of Rog-O-Matic XIV, part 03 of 10:'
echo 'x - mess.c'
sed 's/^X//' > mess.c << '/'
X/*
X * mess.c: Rog-O-Matic XIV (CMU) Thu Jan 31 15:33:12 1985 - mlm
X * Copyright (C) 1985 by A. Appel, G. Jacobson, L. Hamey, and M. Mauldin
X *
X * mess.c: This file contains all of the functions which parse the 
X * message line.
X */
X
X# include <curses.h>
X# include <ctype.h>
X# include "types.h"
X# include "globals.h"
X
X/* Matching macros */
X# define MATCH(p) smatch(mess,p,result)
X
X/* Local data recording statistics */
Xstatic int monkilled[] = {
X    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
X    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
Xstatic int totalkilled=0, timeshit=0, timesmissed=0, hits=0, misses=0;
Xstatic int sumgold=0, sumsqgold=0, numgold=0;
X
Xstatic mhit=0, mmiss=0, mtarget= NONE;
X
X/* Other local data */
Xidentifying = 0;		/* Next message is from identify scroll */
Xstatic int justreadid = 0;	/* True if just read identify scroll */
Xstatic int gushed = 0;		/* True ==> water on the head msg recently */
Xstatic int echoit;		/* True ==> echo this message to the user */
X
X/* Results from star matcher */
Xstatic char res1[NAMSIZ], res2[NAMSIZ], res3[NAMSIZ], res4[NAMSIZ];
Xstatic char *result[] = { res1, res2, res3, res4 };
X
X/*
X * terpmes: called when a message from Rogue is on the top line, 
X * this function parses the message and notes the information.
X * Note that the messages are all lower cased, to help with 
X * compatability bewtween 3.6 and 5.2, since 5.2 capitalizes more
X * messages than does 3.6.  Trailing punctuation is also ignored.
X * 
X * As of Rogue 5.3, multiple messages are broken into single
X * messages before being passed to parsemsg.  Periods separate
X * multiple messages.
X */
X
Xterpmes ()
X{ char mess[128];
X  register char *m, *mend, *s = screen[0], *t;
X
X  /* Set 't' to the tail of the message, skip backward over blank & dot */  
X  for (t=s+79; *t==' ' || *t=='.'; t--) ;	/* Find last non-blank */
X  t++;						/* t -> beyond string */
X  
X  /* 
X   * Loop through each message, finding the beginning and end, and 
X   * copying it to mess, lower-casing it as we go. Then call parsemsg.
X   */
X 
X  while (s<t)				      /* While more chars in msg */
X  { while (*s==' ' && s<t) s++;			/* Skip leading blanks */
X    for (m = mess;				/* Copy text */
X	 s<t && (version < RV53A || *s != '.');
X	 s++)	
X      *m++ = isupper (*s) ? tolower (*s) : *s;	  /* Lower case the char */
X    s++;					/* Skip the period, if any */
X    *(mend = m) = '\0';				/* Add trailing null */
X    if (mess != mend) parsemsg (mess, mend);	/* Parse it */
X  }
X}
X
X/* 
X * parsemsg: Parse a single message, and if necessary set variables
X * or call functions.
X */
X
Xparsemsg (mess, mend)
Xregister char *mess, *mend;
X{ int unknown = 0;
X
X  echoit = 1;
X
X  /*----------------Take action based on type of message-------------*/
X
X  if (MATCH("was wearing *")) ;
X
X  /* Message indicates we picked up a new item */
X  else if (mend[-1]==')' && mend[-3]=='(')
X  { inventory (mess, mend); identifying = justreadid = 0; }
X
X  /* Message describes an old item already in our pack */
X  else if (mess[1]==')')
X  { echoit = identifying; identifying = justreadid = 0; inventory(mess,mend); }
X
X  /* A random message, switch of first char to save some time... */
X  else switch (mess[0])
X  { case 'a':
X      if (MATCH("as you read the scroll, it vanishes")) echoit=0;
X      else if (MATCH("a cloak of darkness falls around you"))
X      { infer ("blindness"); blinded=1; }
X      else if (MATCH("a teleport trap")) nametrap (TELTRAP,NEAR);
X      else if (MATCH("a trapdoor")) nametrap (TRAPDOR,NEAR);
X      else if (MATCH("an arrow shoots *"))
X      { arrowshot=1; nametrap(ARROW,HERE); }
X      else if (MATCH("an arrow trap")) nametrap (ARROW,NEAR);
X      else if (MATCH("a beartrap")) nametrap (BEARTRP,NEAR);
X      else if (MATCH("a strange white mist *")) nametrap (GASTRAP,HERE);
X      else if (MATCH("a sleeping gas trap")) nametrap (GASTRAP,NEAR);
X      else if (MATCH("a small dart *")) nametrap (DARTRAP,HERE);
X      else if (MATCH("a dart trap")) nametrap (DARTRAP,NEAR);
X      else if (MATCH("a poison dart trap")) nametrap (DARTRAP,NEAR);
X      else if (MATCH("a rust trap")) nametrap (WATERAP,NEAR);
X      else if (MATCH("a gush of water hits you on the head")) gushed++;
X      else if (MATCH("a sting has weakened you")) ;
X      else if (MATCH("a bite has weakened you")) ;
X      else if (MATCH("a ring *")) ;
X      else if (MATCH("a wand *")) ;
X      else if (MATCH("a staff *")) ;
X      else if (MATCH("a scroll *")) ;
X      else if (MATCH("a potion *")) ;
X      else if (MATCH("a +*")) ;
X      else if (MATCH("a -*")) ;
X      else unknown++;
X      break;
X
X    case 'b':
X      if (MATCH("bolt bounces")) infer ("lightning");
X      else if (MATCH("bolt hits")) infer ("lightning");
X      else if (MATCH("bolt misses")) infer ("lightning");
X      else if (MATCH("bummer, this food tastes awful")) ;
X      else if (MATCH("bummer!  you've hit the ground")) floating=0;
X      else if (MATCH("bite has no effect")) ;
X      else unknown++;
X      break;
X
X    case 'c': 
X      if (MATCH("call it*")) echoit=0;   /* Handled in getrogue() */
X      else unknown++;
X      break;
X
X    case 'd':
X      if (MATCH("defeated the *")) { echoit=0; killed(res1); }
X      else if (MATCH("defeated it")) { echoit=0; killed("it"); }
X      else if (MATCH("defeated *")) { echoit=0; killed(res1); }
X      else if (MATCH("drop what*")) echoit=0;
X      else if (MATCH("dropped *")) ;
X      else unknown++;
X      break;
X
X    case 'e':
X      if (MATCH("eat what*")) echoit=0;
X      else if (MATCH("everything looks so boring now")) cosmic=0;
X      else unknown++;
X      break;
X
X    case 'f': 
X      if (MATCH("flame *")) ;
X      else if (MATCH("far out!  everything is all cosmic again")) blinded=0;
X      else unknown++;
X      break;
X
X    case 'g':
X      if (MATCH("getting hungry")) echoit=0;
X      else if (MATCH("getting the munchies")) echoit=0;
X      else unknown++;
X      break;
X
X    case 'h':
X      if (MATCH("hey, this tastes great*")) infer ("restore strength");
X      else if (MATCH("huh? what? who?")) ;
X      else if (MATCH("heavy!  that's a nasty critter!")) ;
X      else unknown++;
X      break;
X
X    case 'i':
X      if (MATCH("it hit")) { washit ("it"); echoit=0; }
X      else if (MATCH("it misses"))  { wasmissed ("it"); echoit=0; }
X      else if (MATCH("it appears confused")) ;
X      else if (MATCH("ice *")) ;
X      else if (MATCH("identify what*")) echoit=0;
X      else if (MATCH("illegal command*")) echoit=0;
X      else if (MATCH("i see no way*")) {unset(STAIRS); findstairs();}
X      else if (MATCH("it appears to be cursed")) curseditem ();
X      else if (MATCH("it make*")) ;
X      else unknown++;
X      break;
X
X    case 'j':
X    case 'k':
X      unknown++;
X      break;
X
X    case 'l':
X      if (MATCH("left or*")) echoit=0;
X      else unknown++;
X      break;
X
X    case 'm':
X      if (MATCH("missile vanishes")) infer ("magic missile");
X      else if (MATCH("missle vanishes")) infer ("magic missile");
X      else if (MATCH("my, that was a yummy *")) ;
X      else if (MATCH("moved onto *")) set (STUFF);
X      else unknown++;
X      break;
X
X    case 'n':
X      if (MATCH("nothing happens")) inven[lastwand].charges = 0;
X      else if (MATCH("no more *")) ;
X      else if (MATCH("nothing appropriate")) ;
X      else if (MATCH("no room")) ;
X      else unknown++;
X      break;
X
X    case 'o':
X      if (MATCH("oh no! an arrow shot *"))
X      { arrowshot=1; nametrap(ARROW,HERE); }
X      else if (MATCH("oh, now this scroll has a map *"))
X      { infer ("magic mapping"); didreadmap = Level; }
X      else if (MATCH("oh, bummer!  everything is dark!  help!"))
X      { infer ("blindness"); blinded=1; }
X      else if (MATCH("oh, wow!  everything seems so cosmic!"))
X      { infer ("hallucination"); cosmic=1; }
X      else if (MATCH("oh, wow!  you're floating in the air!"))
X      { infer ("levitation"); floating=1; }
X      else if (MATCH("oh, wow, that tasted good")) ;
X      else unknown++;
X      break;
X
X    case 'p':
X      if (MATCH("please spec*")) echoit=0;
X      else if (MATCH("put on what*")) echoit=0;
X      else unknown++;
X      break;
X
X    case 'q':
X      if (MATCH("quaff what*")) echoit=0;
X      else unknown++;
X      break;
X
X    case 'r':
X      if (MATCH("range is 'a' to '*'")) 
X      { echoit=0;
X        if (*res1-'a'+1 != invcount)
X        { dwait (D_INFORM, "Range check failed..."); usesynch = 0; }
X      }
X      else if (MATCH("read what*")) echoit=0;
X      else unknown++;
X      break;
X
X    case 's':
X      if (MATCH("she stole *")) usesynch = 0;
X      else if (MATCH("sting has no effect")) ;
X      else unknown++;
X      break;
X
X    case 't':
X      if (MATCH("throw what*")) echoit=0;
X      else if (MATCH("the * bounces")) ;
X      else if (MATCH("the bolt *")) ;
X      else if (MATCH("the flame *")) ;
X      else if (MATCH("the ice hits")) ;
X      else if (MATCH("the ice misses")) ;
X      else if (MATCH("the ice whizzes by you")) wasmissed ("ice monster");
X      else if (MATCH("the * hits it")) {echoit=0; mshit ("it");}
X      else if (MATCH("the * misses it")) {echoit=0; msmiss ("it");}
X      else if (MATCH("the * hits the *")) {echoit=0; mshit (res2);}
X      else if (MATCH("the * misses the *")) {echoit=0; msmiss (res2);}
X      else if (MATCH("the * hit")) { washit (res1); gushed=0; echoit=0; }
X      else if (MATCH("the * misses")) { wasmissed (res1); echoit=0; }
X      else if (MATCH("the * appears confused")) ;
X      else if (MATCH("the rust vanishes instantly"))
X      { if (gushed) { gushed = 0; nametrap (WATERAP, HERE); } }
X      else if (MATCH("the room is lit")) { setnewgoal (); infer ("light"); }
X      else if (MATCH("the * has confused you")) confused = 1;
X      else if (MATCH("this scroll is an * scroll"))
X      { if (stlmatch (res1, "identify")) readident (res1); }
X      else if (MATCH("that's not a valid item"))
X      { echoit = justreadid < 1; if (justreadid-- == 0) sendnow (" *");
X        if (justreadid < -50) dwait (D_FATAL, "Caught in invalid item loop"); }
X      else if (MATCH("the veil of darkness lifts")) blinded=0;
X      else if (MATCH("the scroll turns to dust*")) 
X      { deletestuff (atrow, atcol); unset(SCAREM | STUFF); droppedscare--; }
X      else if (MATCH("this potion tastes * dull")) infer ("thirst quenching");
X      else if (MATCH("this potion tastes pretty")) infer ("thirst quenching");
X      else if (MATCH("this potion tastes like apricot juice"))
X      { infer ("see invisible"); if (version == RV36A) sendnow ("%c", ESC); }
X      else if (MATCH("this scroll seems to be blank")) infer ("blank paper");
X      else if (MATCH("the * bounces")) ;
X      else if (MATCH("the * vanishes as it hits the ground"))
X      { darkturns = 0; darkdir = NONE; targetmonster = 0; echoit=0; }
X      else if (MATCH("there is something here*")) { usesynch=0; set(STUFF); }
X      else if (MATCH("the munchies are interfering*")) ;
X      else if (MATCH("the monsters around you freeze")) holdmonsters ();
X      else if (MATCH("the monster freezes")) holdmonsters ();
X      else if (MATCH("that's inedible")) usesynch = 0; 
X      else unknown++;
X      break;
X
X    case 'u':
X    case 'v':
X      unknown++;
X      break;
X
X    case 'w':
X      if (MATCH("what do you want*")) echoit=0;
X      else if (MATCH("wield what*")) echoit=0;
X      else if (MATCH("wielding a*")) echoit=0;
X      else if (MATCH("wear what*")) echoit=0;
X      else if (MATCH("what monster*")) echoit=0;
X      else if (MATCH("wait, what's going*")) {infer("confusion"); confused=1;}
X      else if (MATCH("wait!  that's a *")) ;
X      else if (MATCH("what a*feeling*")) { infer("confusion"); confused=1; }
X      else if (MATCH("what a*piece of paper")) infer ("blank paper");
X      else if (MATCH("welcome to level *")) ;
X      else if (MATCH("was wearing*")) ;
X      else if (MATCH("what bulging muscles*")) ;
X      else if (MATCH("wearing *")) ;
X      else unknown++;
X      break;
X
X    case 'x':
X      unknown++;
X      break;
X
X    case 'y':
X      if (MATCH("you hit*")) { echoit=0; didhit (); }
X      else if (MATCH("you miss*")) { echoit=0; didmiss (); }
X      else if (MATCH("you are starting to feel weak")) echoit=0;
X      else if (MATCH("you are weak from hunger")) {echoit=0; eat();}
X      else if (MATCH("you are being held")) beingheld=30;
X      else if (MATCH("you can move again")) echoit=0;
X      else if (MATCH("you are still stuck *")) nametrap (BEARTRP,HERE);
X      else if (MATCH("you can't move")) echoit=0;
X      else if (MATCH("you can't carry anything else"))
X      { echoit=0; set (STUFF); maxobj=objcount; }
X      else if (MATCH("you can't *")) {echoit=0; curseditem ();}
X      else if (MATCH("you can't")) echoit=0;
X      else if (MATCH("you begin to feel better")) infer ("healing");
X      else if (MATCH("you begin to feel much better")) infer("extra healing");
X      else if (MATCH("you begin to sense the presence of monsters"))
X      { infer("monster detection"); }
X      else if (MATCH("you feel a strange sense of loss")) ;
X      else if (MATCH("you feel stronger, now*")) infer ("gain strength");
X      else if (MATCH("you feel very sick now")) infer ("poison");
X      else if (MATCH("you feel momentarily sick")) infer ("poison");
X      else if (MATCH("you suddenly feel much more skillful"))
X      { infer("raise level"); }
X      else if (MATCH("your nose tingles")) infer ("food detection");
X      else if (MATCH("you start to float in the air"))
X      { infer ("levitation"); floating=1; }
X      else if (MATCH("you're floating off the ground!")) floating=1;
X      else if (MATCH("you float gently to the ground")) floating=0;
X      else if (MATCH("you feel yourself moving much faster"))
X      { infer ("haste self"); hasted = 1; }
X      else if (MATCH("you feel yourself slowing down")) 
X      { hasted = 0; doublehasted = 0; }
X      else if (MATCH("you faint from exhaustion"))
X      { if (version < RV52A) doublehasted = 1; else hasted = 0; }
X      else if (MATCH("you feel less confused now")) confused = 0;
X      else if (MATCH("you feel less trip*")) confused = 0;
X      else if (MATCH("your * vanishes as it hits the ground"))
X      { darkturns = 0; darkdir = NONE; echoit=0; }
X      else if (MATCH("your hands begin to glow *"))
X      { infer ("monster confusion"); redhands = 1; }
X      else if (MATCH("your hands stop glowing *")) redhands = 0;
X      else if (MATCH("you feel as if somebody is watching over you") ||
X               MATCH("you feel in touch with the universal onenes")) 
X      { infer ("remove curse"); cursedarmor = cursedweapon = 0; 
X        newarmor = newweapon = 1;}
X      else if (MATCH("your armor weakens"))
X      { inven[currentarmor].phit--; 
X        if (gushed) { gushed=0; nametrap (WATERAP,HERE); } }
X      else if (MATCH("your armor is covered by a shimmering * shield"))
X      { infer ("protect armor"); protected++;
X	remember (currentarmor, PROTECTED); }
X      else if (MATCH("your armor glows * for a moment"))
X      { infer ("enchant armor"); inven[currentarmor].phit++;
X        cursedarmor = 0; newarmor = 1; }
X      else if (MATCH("your * glows * for a moment"))
X      { infer ("enchant weapon"); plusweapon (); newweapon = 1; }
X      else if (MATCH("you hear a high pitched humming noise")) 
X      { infer ("aggravate monsters"); wakemonster (9); aggravated = 1; }
X      else if (MATCH("you hear maniacal laughter*")) infer ("scare monster");
X      else if (MATCH("you hear a faint cry*")) infer ("create monster");
X      else if (MATCH("you fall asleep")) infer ("sleep");
X      else if (MATCH("you have been granted the boon of genocide"))
X      { infer ("genocide"); echoit=0; rampage (); }
X      else if (MATCH("you have a tingling feeling")) infer ("drain life");
X      else if (MATCH("you are too weak to use it")) infer ("drain life");
X      else if (MATCH("you begin to feel greedy")) infer ("gold detection");
X      else if (MATCH("you feel a pull downward")) infer ("gold detection");
X      else if (MATCH("you begin to feel a pull downward"))
X      { infer ("gold detection"); }
X      else if (MATCH("you are caught *")) nametrap (BEARTRP,HERE);
X      else if (MATCH("your purse feels lighter")) ;
X      else if (MATCH("you suddenly feel weaker")) ;
X      else if (MATCH("you must identify something")) ;
X      else if (MATCH("you have a * feeling for a moment, then it passes")) ;
X      else if (MATCH("you are transfixed")) ;
X      else if (MATCH("you are frozen")) washit ("ice monster");
X      else if (MATCH("you faint")) {echoit=0; if (version<RV36B) eat();}
X      else if (MATCH("you freak out")) echoit = 0;
X      else if (MATCH("you fell into a trap!")) ;
X      else if (MATCH("yum*")) echoit=0;
X      else if (MATCH("yuk*")) echoit=0;
X      else if (MATCH("you sense the presence of magic*")) echoit=0;
X      else unknown++;
X      break;
X
X    case 'z':
X      if (MATCH("zap with what*")) echoit=0;
X      else unknown++;
X      break;
X
X    default:
X      if (MATCH( "* gold pieces")) { echoit=0; countgold (res1); }
X      else if (MATCH("'*'*: *")) { echoit=0; mapcharacter (*res1, res3); }
X      else if (*mess == '+' || *mess == '-' || ISDIGIT (*mess)) ;
X      else unknown++;      
X      break;
X  }
X
X  /* Log unknown or troublesome messages */
X  if (morecount > 50)	dwait (D_WARNING, "More loop msg '%s'", mess);
X  else if (unknown)	dwait (D_WARNING, "Unknown message '%s'", mess);
X
X  /* Send it to dwait; if dwait doesnt print it (and echo is on) echo it */
X  if (echoit & !dwait (D_MESSAGE, mess))
X    saynow (mess);
X}
X
X/* 
X * smatch: Given a data string and a pattern containing one or
X * more embedded stars (*) (which match any number of characters)
X * return true if the match succeeds, and set res[i] to the
X * characters matched by the 'i'th *.
X */
X
Xsmatch (dat, pat, res)
Xregister char *dat, *pat, **res;
X{ register char *star = 0, *starend, *resp;
X  int nres = 0;
X
X  while (1)
X  { if (*pat == '*')
X    { star = ++pat; 			     /* Pattern after * */
X      starend = dat; 			     /* Data after * match */
X      resp = res[nres++]; 		     /* Result string */
X      *resp = '\0'; 			     /* Initially null */
X    }
X    else if (*dat == *pat) 		     /* Characters match */
X    { if (*pat == '\0') 		     /* Pattern matches */
X	return (1);
X      pat++; 				     /* Try next position */
X      dat++;
X    }
X    else
X    { if (*dat == '\0') 		     /* Pattern fails - no more */
X	return (0); 			     /* data */
X      if (star == 0) 			     /* Pattern fails - no * to */
X	return (0); 			     /* adjust */
X      pat = star; 			     /* Restart pattern after * */
X      *resp++ = *starend; 		     /* Copy character to result */
X      *resp = '\0'; 			     /* null terminate */
X      dat = ++starend; 			     /* Rescan after copied char */
X    }
X  }
X}
X
X/*
X * readident: read an identify scroll.
X */
X
Xreadident (name)
Xchar *name;
X{ int obj; char id = '*';	/* Default is "* for list" */
X
X  if (!replaying && version <= RV53A &&
X      (nextid < LETTER (0) || nextid > LETTER (invcount))) 
X  { dwait (D_FATAL, "Readident: nextid %d, afterid %d, invcount %d.",
X           nextid, afterid, invcount); }
X
X  infer (name);		/* Record what kind of scroll this is */
X
X  if (version < RV53A)		/* Rogue 3.6, Rogue 5.2 */
X  { deleteinv (OBJECT (afterid));	/* Assume object gone */
X    sendnow (" %c", nextid);		/* Identify it */
X    send ("I%c", afterid);		/* Generate a message about it */
X    knowident = identifying = 1;	/* Set variables */
X  }
X  else				/* Rogue 5.3 */
X  { if (streq (name, "identify scroll"))
X    { if ((obj = unknown (scroll)) != NONE || (obj = have (scroll)) != NONE)
X        id = LETTER (obj);
X    }
X    else if (streq (name, "identify potion"))
X    { if ((obj = unknown (potion)) != NONE || (obj = have (potion)) != NONE)
X        id = LETTER (obj);
X    }
X    else if (streq (name, "identify armor"))
X    { if ((obj = unknown (armor)) != NONE || (obj = have (armor)) != NONE)
X        id = LETTER (obj);
X    }
X    else if (streq (name, "identify weapon"))
X    { if ((obj = unknown (hitter)) != NONE ||
X	  (obj = unknown (thrower)) != NONE || 
X          (obj = unknown (missile)) != NONE ||
X	  (obj = have (hitter)) != NONE ||
X          (obj = have (thrower)) != NONE ||
X	  (obj = have (missile)) != NONE)
X        id = LETTER (obj);
X    }
X    else if (streq (name, "identify ring, wand or staff"))
X    { if ((obj = unknown (ring)) != NONE || (obj = unknown (wand)) != NONE ||
X          (obj = have (ring)) != NONE    || (obj = have (wand)) != NONE)
X        id = LETTER (obj);
X    }
X    else dwait (D_FATAL, "Unknown identify scroll '%s'", name);
X
X    waitfor ("not a valid item"); waitfor ("--More--");
X    sendnow (" %c;", id);		/* Pick an object to identify */
X    usesynch = 0; justreadid=1;		/* Must resest inventory */
X  }
X
X  newring = newweapon = 1; afterid = nextid = '\0';
X}
X
X/*
X * rampage: read a scroll of genocide.
X */
X 
Xrampage ()
X{ char monc;
X
X  /* Check the next monster in the list, we may not fear him */ 
X  while (monc = *genocide)
X  { /* Do not waste genocide on stalkers if we have the right ring */
X    if ((streq (monname (monc), "invisible stalker") ||
X         streq (monname (monc), "phantom")) &&
X        havenamed (ring, "see invisible") != NONE)
X    { genocide++; }
X
X    /* Do not waste genocide on rusties if we have the right ring */
X    else if ((streq (monname (monc), "rust monster") || 
X              streq (monname (monc), "aquator")) &&
X             havenamed (ring, "maintain armor") != NONE)
X    { genocide++; }
X    
X    /* No fancy magic for this monster, use the genocide scroll */
X    else break;
X  }
X
X  /* If we found a monster, send his character, else send ESC */
X  if (monc)
X  { saynow ("About to rampage against %s", monname (monc));
X    sendnow (" %c;", monc);	/* Send the monster */
X
X    /* Add to the list of 'gone' monsters */
X    sprintf (genocided, "%s%c", genocided, monc);
X    genocide++;
X  }
X  else
X  { dwait (D_ERROR, "Out of monsters to genocide!");
X    sendnow (" %c;", ESC);	/* Cancel the command */
X  }
X}
X
X/*
X * curseditem: the last object we tried to drop (unwield, etc.)  was cursed.
X *
X * Note that cursed rings are not a problem since we only put on
X * Good rings we have identified, so dont bother marking rings.
X */
X
Xcurseditem ()
X{ usesynch = 0;    /* Force a reset inventory */
X
X  /* lastdrop is index of last item we tried to use which could be cursed */
X  if (lastdrop != NONE && lastdrop < invcount)
X  { remember (lastdrop, CURSED);
X
X    /* Is our armor cursed? */
X    if (inven[lastdrop].type == armor)
X    { currentarmor = lastdrop; cursedarmor = 1; return; }
X    
X    /* Is it our weapon (may be wielding a hitter or a bogus magic arrow)? */
X    else if (inven[lastdrop].type==hitter || inven[lastdrop].type==missile)
X    { currentweapon = lastdrop; cursedweapon = 1; return; }
X  }
X
X  /* Dont know what was cursed, so assume the worst */
X  cursedarmor=1;
X  cursedweapon=1; 
X}
X
X/* 
X * First copy the title of the last scroll into the appropriate slot,  
X * then find the real name of the object by looking through the data
X * base, and then zap that name into all of the same objects 
X */
X
Xinfer (roguename)
Xchar *roguename;
X{ register int i;
X
X  if (*lastname && *roguename && !stlmatch (roguename, lastname))
X  { infername (lastname, roguename);
X  
X    for (i=0; i<MAXINV; i++)
X      if (stlmatch (inven[i].str, lastname))
X      { strcpy (inven[i].str, roguename);
X        remember (i, KNOWN);
X      }
X  }  
X}
X
X/*
X * Killed: called whenever we defeat a monster.
X */
X
Xkilled (monster)
Xregister char *monster;
X{ register int m = 0, mh = 0;
X
X  /* Find out what we really killed */
X  if (!cosmic && !blinded && targetmonster>0 && streq (monster, "it"))
X  { monster = monname (targetmonster); }
X  if ((mh = getmonhist (monster, 0)) != NONE)
X  { monster = monhist[mh].m_name; m = monsternum (monster); }
X
X  /* Tell the user what we killed */
X  dwait (D_BATTLE | D_MONSTER, "Killed '%s'", monster);
X
X  /* If cheating against Rogue 3.6, check out our arrow */
X  if (version < RV52A && cheat)
X  { if (usingarrow && hitstokill > 1 && !beingstalked && goodarrow < 20)
X    { saynow ("Oops, bad arrow...");
X      newweapon = badarrow = 1; remember (currentweapon, WORTHLESS); }
X    else if (usingarrow) goodarrow++;
X  }
X
X  /* Echo the number arrows we pumped into him */
X  if (mh >=0 && mhit+mmiss > 0 && mtarget == mh)
X    dwait (D_BATTLE | D_MONSTER, "%d out of %d missiles hit the %s", 
X           mhit, mhit+mmiss, monster);
X
X  /* If we killed it by hacking, add the result to long term memory */
X  if (hitstokill > 0 && mh != NONE)
X    addstat (&monhist[mh].htokill, hitstokill); 
X
X  /* If we killed it with arrows, add that fact to long term memory */
X  if (mhit > 0 && mh != NONE)
X    addstat (&monhist[mh].atokill, mhit);
X
X  /* Stop shooting arrows if we killed the right monster */
X  if (targetmonster == (m+'A'-1))
X  { darkturns = 0; darkdir = NONE; targetmonster = 0; }
X
X  goalr = goalc = NONE;			/* Clear old movement goal */
X  killmonster (m+'A'-1);		/* Notify lost monster functions */
X  monkilled[m]++; totalkilled++;	/* Bump kill count */
X  hitstokill = mhit = mmiss = 0;	/* Clear indiviual monster stats */
X  mtarget = NONE;				/* Clear target */
X  beingheld = cancelled = 0;		/* Clear flags */
X
X  /* If we killed an invisible, assume no more invisible around */
X  if (!cosmic && !blinded &&
X      (streq (monster, "invisible stalker") || streq (monster, "phantom")))
X    beingstalked = 0;
X}
X
X/*
X * washit: Record being hit by a monster.
X */
X
Xwashit (monster)
Xchar *monster;
X{ register int mh = 0, m = 0;
X
X  /* Find out what really hit us */
X  if ((mh = getmonhist (monster, 1)) != NONE)
X  { monster = monhist[mh].m_name; m = monsternum (monster); }
X
X  dwait (D_MONSTER, "was hit by a '%s'", monster);
X
X  timeshit++;			/* Bump global count */
X  if (m>0) wakemonster(-m);	/* Wake him up */
X  terpbot ();			/* Hit points changed, read bottom */
X
X  /* Add data about the event to long term memory */
X  if (mh != NONE)
X  { addprob (&monhist[mh].theyhit, SUCCESS);
X    addstat (&monhist[mh].damage, lastdamage);
X    analyzeltm ();
X  }
X}
X
X/*
X * wasmissed: Record being missed by a monster.
X */
X
Xwasmissed (monster)
Xchar *monster;
X{ register int mh = 0, m = 0;
X
X  /* Find out what really missed us */
X  if ((mh = getmonhist (monster, 1)) != NONE)
X  { monster = monhist[mh].m_name; m = monsternum (monster); }
X
X  dwait (D_MONSTER, "was missed by a '%s'", monster);
X
X  timesmissed++;		/* Bump global count */
X  if (m>0) wakemonster(-m);	/* Wake him up */
X
X  /* Add data to long term memory */
X  if (mh != NONE)
X  { addprob (&monhist[mh].theyhit, FAILURE);
X    analyzeltm ();
X  }
X}
X
X/*
X * didhit: Record hitting a monster.
X */
X
Xdidhit ()
X{ register int m = 0;
X
X  /* Record our hit */
X  if (!cosmic) m = lastmonster;
X
X  hits++; hitstokill++;
X  addprob (&monhist[monindex[m]].wehit, SUCCESS);
X
X  if (wielding (wand))
X  { inven[currentweapon].charges--; newweapon++; }
X}
X
X/*
X * didmiss: Record missing a monster.
X */
X
Xdidmiss ()
X{ register int m = 0;
X
X  /* Record our miss */
X  if (!cosmic) m = lastmonster;
X
X  misses++;
X  addprob (&monhist[monindex[m]].wehit, FAILURE);
X
X  if (usingarrow && goodarrow < 20)
X  { newweapon = badarrow = 1; remember (currentweapon, WORTHLESS); }
X}
X
X/*
X * mshit: Record hitting a monster with a missile.
X */
X
Xmshit (monster)
Xchar *monster;
X{ register int mh;
X
X  /* Arching in a dark room? */
X  if (!cosmic && !blinded && targetmonster > 0 && streq (monster, "it"))
X    monster = monname (targetmonster);
X
X  /* Add data about the event to long term memory */
X  if ((mh = getmonhist (monster, 0)) < 0) return;
X  { addprob (&monhist[monindex[mh]].arrowhit, SUCCESS);
X    if (mh == mtarget) { mhit++; }
X    else { mhit=1; mmiss = 0; mtarget=mh; }
X  }
X}
X
X/*
X * msmiss: Record missing a monster with a missile.
X */
X
Xmsmiss (monster)
Xchar *monster;
X{ register int mh;
X
X  /* Arching in a dark room? */
X  if (!cosmic && !blinded && targetmonster > 0 && streq (monster, "it"))
X    monster = monname (targetmonster);
X
X  /* Add data about the event to long term memory */
X  if ((mh = getmonhist (monster, 0)) < 0) return;
X  { addprob (&monhist[monindex[mh]].arrowhit, FAILURE);
X    if (mh == mtarget) { mmiss++; }
X    else { mmiss=1; mhit=0; mtarget=mh; }
X  }
X}
X
X/*
X * Countgold: called whenever msg contains a message about the number
X *            of gold pieces we just picked up. This routine keeps
X *            statistics about the amount of gold picked up.
X */
X
Xcountgold (amount)
Xregister char *amount;
X{ int pot;
X
X  if ((pot = atoi (amount)) > 0)
X  { sumgold += pot; sumsqgold += pot*pot; numgold ++; }
X}
X
X/* 
X * Summary: print a summary of the game.
X */
X
Xsummary (f, sep)
XFILE *f;
Xchar sep;
X{ register int m;
X  char s[1024], *monname ();
X
X  sprintf (s, "Monsters killed:%c%c", sep, sep);
X
X  for (m=0; m<=26; m++)
X    if (monkilled[m] > 0)
X    { sprintf (s, "%s\t%d %s%s%c", s, monkilled[m],  monname (m+'A'-1),
X               plural (monkilled[m]), sep);
X    }
X
X  sprintf (s, "%s%cTotal: %d%c%c", s, sep, totalkilled, sep, sep);
X  
X  sprintf (s, "%sHit %d out of %d times, was hit %d out of %d times.%c", s,
X           hits, misses+hits,
X           timeshit, timesmissed+timeshit, sep);
X
X  if (numgold > 0)
X    sprintf (s, "%sGold %d total, %d pots, %d average.%c",  s,
X             sumgold, numgold, (sumgold*10+5) / (numgold*10), sep);
X
X  if (f == NULL)
X    addstr (s);
X  else
X    fprintf (f, "%s", s);
X}
X
X/*
X * versiondep: Set version dependent variables.
X */
X
Xversiondep ()
X{
X  if (version >= RV53A)		genocide = "DMJGU";
X  else if (version >= RV52A)	genocide = "UDVPX";
X  else				genocide = "UXDPW";  
X
X  analyzeltm ();
X}
X
X/* 
X * getmonhist: Retrieve the index in the history array of a monster,
X * taking our status into account.  This code is responsible for determining
X * when we are being stalked by an invisible monster.
X */
X
Xgetmonhist (monster, hitormiss)
Xchar *monster;
Xint hitormiss;
X{ if (cosmic || blinded)
X  { return (findmonster ("it")); }
X  else
X  { if (streq (monster, "it") && hitormiss)
X    { if (version < RV53A)
X      { if (! seemonster ("invisible stalker")) beingstalked=INVHIT;
X        return (findmonster ("invisible stalker"));
X      }
X      else
X      { if (! seemonster ("phantom")) beingstalked=INVHIT;
X	return (findmonster ("phantom"));
X      }
X    }
X    else
X    { if (version < RV52B && streq (monster, "invisible stalker") &&
X          ! seemonster (monster))
X	beingstalked = INVHIT;
X      return (findmonster (monster));
X    }
X  }
X}
/
echo 'x - search.c'
sed 's/^X//' > search.c << '/'
X/*
X * search.c: Rog-O-Matic XIV (CMU) Mon Jan 28 18:28:07 1985 - mlm
X * Copyright (C) 1985 by A. Appel, G. Jacobson, L. Hamey, and M. Mauldin
X *
X * This file contains the very basic search mechanisms for exploration etc.
X */
X
X# include <stdio.h>
X# include <curses.h>
X# include "types.h"
X# include "globals.h"
X
X# define QSIZE (4000)
X
X# define QUEUEBREAK  (111)
X# define FROM         (20)
X# define UNREACHABLE  (12)
X# define NOTTRIED     (11)
X# define TARGET       (10)
X
Xstatic int moveavd[24][80], moveval[24][80], movecont[24][80],
X	movedepth[24][80];
Xstatic char mvdir[24][80];
Xstatic int mvtype=0;
Xstatic int didinit=0;
X
X/* 
X * makemove: repeat move from here towards some sort of target.
X * Modified to use findmove.			5/13	MLM
X */
X
Xmakemove (movetype, evalinit, evaluate, reevaluate)
Xint movetype, (*evalinit)(), (*evaluate)(), reevaluate;
X{ 
X  if (findmove (movetype, evalinit, evaluate, reevaluate))
X    return (followmap (movetype));
X
X  return (0);
X}
X
X/* 
X * findmove: search for a move of type movetype.  The move map is left in
X *           the correct state for validatemap or followmap to work.	MLM
X */
X
Xfindmove (movetype, evalinit, evaluate, reevaluate)
Xint movetype, (*evalinit)(), (*evaluate)(), reevaluate;
X{ int result;
X
X  didinit = ontarget = 0;
X
X  if (!reevaluate)		/* First try to reuse the movement map */
X  { result = validatemap (movetype, evalinit, evaluate);
X    if (result == 1) return (1);	/* Success */
X    if (result == 2) return (0);	/* Evalinit failed, no move */
X  }
X
X  /* Must rebuild the movement map */
X  mvtype = 0;	/* Will become 'if (mvtype==movetype) movetype=0;' */
X
X  dwait (D_SEARCH, "Findmove: computing new search path.");
X
X  /* currentrectangle(); */     /* always done after each move of the rogue */
X
X  searchstartr = atrow; searchstartc = atcol;
X
X  if (!(*evalinit)())    /* Compute evalinit from current location */
X  { dwait (D_SEARCH, "Findmove: evalinit failed."); return (0); }
X
X  if (!searchfrom (atrow, atcol, evaluate, mvdir, &targetrow, &targetcol))
X  { return (0); }	/* move failed */
X
X  if (targetrow == atrow && targetcol == atcol)
X  { ontarget = 1; return (0); }
X
X  /* <<copy the newly created map to save*[][]>> */
X  mvtype = movetype;	/* mvtype will be the type of saved map */
X
X  return (1);
X}
X
X/* 
X * followmap: Assuming that the mvdir map is correct, send a movement
X *            command following the map (possibly searching first).
X *
X *	<<Must be changed to use the saved map, when that code is added>>
X *
X * May 13, MLM
X */
X
Xfollowmap (movetype)
Xregister int movetype;
X{ register int dir, dr, dc, r, c;
X  int timemode, searchit, count=1;
X
X  dir=mvdir[atrow][atcol]-FROM; dr=deltr[dir]; dc=deltc[dir];
X
X  if (dir > 7 || dir < 0)
X  { dwait (D_ERROR, "Followmap: direction invalid!");
X    return (0);			      /* Something Broke */
X  }
X
X  r=atrow+dr; c=atcol+dc;		/* Save next square in registers */
X
X  /* If exploring and are moving to a new hall square, use fmove */
X  if (movetype == EXPLORE &&
X      onrc (HALL|BEEN, targetrow, targetcol) != HALL|BEEN &&
X      onrc (HALL,r,c))
X  { fmove (dir); return (1); }
X
X  /* Timemode tells why we are moving this way, T_RUNNING ==> no search */
X  timemode = (movetype == GOTOMOVE)    ? T_MOVING :
X             (movetype == EXPLORE)     ? T_EXPLORING :
X             (movetype == EXPLOREROOM) ? T_EXPLORING :
X             (movetype == FINDROOM)    ? T_EXPLORING :
X             (movetype == EXPLORERUN)  ? T_RUNNING :
X             (movetype == RUNTODOOR)   ? T_RUNNING :
X             (movetype == RUNAWAY)     ? T_RUNNING :
X             (movetype == UNPIN)       ? T_RUNNING :
X             (movetype == UNPINEXP)    ? T_RUNNING :
X             (movetype == RUNAWAY)     ? T_RUNNING :
X             (movetype == RUNDOWN)     ? T_RUNNING :
X             (movetype == ATTACKSLEEP) ? T_FIGHTING :  T_MOVING;
X
X  /* How many times do we wish to search each square before moving? */
X  /* Search up to k times if 2 or more foods and deeper than level 6 */
X  searchit = max (0, min (k_srch/20, min (larder - 1, Level - 6)));
X
X  /* Can we move more than one square at a time? */
X  if (compression)
X  { while (mvdir[r][c]-FROM==dir && (onrc (SAFE, r+=dr, c+=dc) || !searchit))
X      count++;
X  }
X
X  /* Maybe search unsafe square before moving onto it */
X  if (timemode != T_RUNNING && !onrc (SAFE, atrow+dr, atcol+dc) &&
X      timessearched[atrow+dr][atcol+dc] < searchit)
X  { command (T_SEARCHING, "s"); return (1); }
X
X  /* Maybe take armor off before stepping on rust trap */
X  if (timemode != T_RUNNING && onrc (WATERAP, atrow+dr, atcol+dc) &&
X      currentarmor != NONE && willrust () && takeoff ())
X  { rmove (1, dir, timemode); return (1); }
X  
X  /* If we are about to step onto a scare monster scroll, use the 'm' cmd */
X  if (version >= RV53A && onrc (SCAREM, atrow+dr, atcol+dc))
X  { mmove (dir, timemode); return (1); }
X
X  /* Send the movement command and return success */
X  rmove (count, dir, timemode); return (1);
X}
X
X/*
X * validatemap: If we have a stored move, make it and return true.
X *
X *	<<Must be changed to use the saved map, when that code is added>>
X *
X * Called only by findmove.	MLM
X */
X
Xvalidatemap (movetype, evalinit, evaluate)
Xint movetype, (*evalinit)(), (*evaluate)();
X{ register int thedir, dir, r, c;
X  int val, avd, cont;
X
X  dwait (D_CONTROL | D_SEARCH, "Validatemap: type %d", movetype);
X
X  if (mvtype != movetype)
X  { dwait (D_SEARCH, "Validatemap: move type mismatch, map invalid.");
X    return (0);
X  }
X
X  thedir = mvdir[atrow][atcol] - FROM;
X  if (thedir > 7 || thedir < 0)
X  { dwait (D_SEARCH, "Validatemap: direction in map invalid.");
X    return (0);  /* Something Broke */
X  }
X
X  /*
X   * Check that the planned path is still valid.  This is done by
X   * proceeding along it and checking that the value and avoidance
X   * returned from the evaluation function are the same as
X   * when the search was first performed.  The initialisation function
X   * is re-performed and then the evaluation function done.
X   */
X
X  if (!didinit && !(*evalinit)())
X  { dwait (D_SEARCH, "Validatemap: evalinit failed.");
X    return (2);  /* evalinit failed */
X  }
X  didinit=1;
X
X  r=atrow; c=atcol;
X  while (1)
X  { val = avd = cont = 0;
X    if (!(*evaluate)(r, c, movedepth[r][c], &val, &avd, &cont))
X    { dwait (D_SEARCH, "Validatemap: evaluate failed.");
X      return (0);
X    }
X    if (!onrc (CANGO, r, c) ||
X        avd!=moveavd[r][c] || val!=moveval[r][c] || cont!=movecont[r][c])
X    { dwait (D_SEARCH, "Validatemap: map invalidated.");
X      return (0);
X    }
X    if ((dir=mvdir[r][c]-FROM) == TARGET)
X    { dwait (D_SEARCH, "Validatemap: existing map validated.");
X      break;
X    }
X    if (dir < 0 || dir > 7)
X    { dwait (D_SEARCH, "Validatemap: direction in map invalid.");
X      return (0);
X    }
X    r += deltr[dir];  c += deltc[dir];
X  }
X  return (1);
X}
X
X/*
X * cancelmove: Invalidate all stored moves of a particular type.
X */
X
Xcancelmove (movetype)
Xint movetype;
X{ if (movetype == mvtype) mvtype = 0;
X}
X
X/*
X * setnewgoal: Invalidate all stored moves.
X */
X
Xsetnewgoal ()
X{ mvtype = 0;
X  goalr = goalc = NONE;
X}
X
X/* 
X * searchfrom: By means of breadth first search, find a path
X * from the given row and column to a target.  This is done by using
X * searchto and then reversing the path to the row, col from the selected
X * target.  Note that this means that the resultant direction map can
X * only be re-used if the new row, col is on the existing path.  The
X * reversed path consists of directions offset by FROM.
X * arguments and results otherwise the same as searchto.	LGCH
X */
X
Xsearchfrom (row, col, evaluate, dir, trow, tcol)
Xint row, col, *trow, *tcol;
Xint (*evaluate)();
Xchar dir[24][80];
X{ register int r, c, sdir, tempdir;
X  if (!searchto (row, col, evaluate, dir, trow, tcol))
X  { return (0);
X  }
X
X  for (r = *trow, c = *tcol, sdir = FROM+TARGET; ; )
X  { tempdir = dir[r][c];
X    dir[r][c] = sdir;
X    if (debug (D_SCREEN | D_INFORM | D_SEARCH))
X    { at (r, c);  printw ("%c", ">/^\\</v\\  ~"[sdir-FROM]);}
X    sdir = (tempdir + 4) % 8 + FROM;  /* reverse direction and offset */
X    if (tempdir == TARGET) break;
X    r += deltr[tempdir];  c += deltc[tempdir];
X  }
X  dwait (D_SEARCH, "Searchfrom wins.");
X  return (1);
X}
X
X/*
X * searchto: By means of a breadth first search, find a path to the
X * given row and column from a target.  A target is defined as a
X * location which has +ve value returned by the evaluation function and
X * for which the avoidance value has been decremented to zero. The most
X * valuable target found in the first successful iteration of the
X * search, is selected. (i.e. the most valuable square at the lowest
X * level of the search).  Returns dir the direction map of paths to
X * row,col from target Also returns trow, tcol the position of the
X * selected target (NOTE: To use this search directly, e.g. to find
X * paths to a single actual target such as the staircase, the
X * evaluation function should give zero value to everything except the
X * current Rog-O-Matic location To re-use the results of a search,
X * ensure that dir[row][col] is still set to TARGET and check that a
X * valid direction exists at the target position.)
X *
X * The search prefers horizontal movements to vertical movements, and
X * prefers moves onto SAFE squares to moves onto other squares.	       LGCH
X */
X
X/* 
X * Since this code is the single most time consuming subroutine, I am
X * attempting to hack it into a faster form. 			11/6/82 MLM
X */
X
Xsearchto (row, col, evaluate, dir, trow, tcol)
Xint row, col, *trow, *tcol;
Xint (*evaluate)();
Xchar dir[24][80];
X{ int searchcontinue = 10000000, type, havetarget=0, depth=0;
X  register int r, c, nr, nc;
X  register int k;
X  char begin[QSIZE], *end, *head, *tail;
X  int saveavd[24][80], val, avd, cont;
X  int any;
X  static int sdirect[8] = {4, 6, 0, 2, 5, 7, 1, 3},
X	     sdeltr[8]  = {0,-1, 0, 1,-1,-1, 1, 1},
X	     sdeltc[8]  = {1, 0,-1, 0, 1,-1,-1, 1};
X
X  head = tail = begin;
X  end = begin + QSIZE;
X
X  for (c = 23*80; c--; ) dir[0][c] = NOTTRIED;		/* MLM */
X  for (c = 80; c--; ) dir[0][c] = 0;			/* MLM */
X
X  *(tail++) = row;  *(tail++) = col; 
X  *(tail++) = QUEUEBREAK;  *(tail++) = QUEUEBREAK;
X  dir[row][col] = TARGET;  moveval[row][col] = NONE;
X  any = 1;
X
X  while (1)
X  { /* Process the next queued square. */
X    r = *(head++);  c = *(head++);
X    if (head == end) head = begin;  /* wrap-around queue */
X
X    if (r==QUEUEBREAK)
X    { /* If we have completed an evaluation loop */
X      if (searchcontinue <= 0 || !any)
X      { if (havetarget) dwait (D_SEARCH, "Searchto wins.");
X	else dwait (D_SEARCH, "Searchto fails.");
X	
X        return (havetarget);  /* have found somewhere to go */
X      }
X
X      searchcontinue--;   depth++;
X
X      /* ----------------------------------------------------------------
X      if (debug (D_SCREEN))
X        dwait (D_SEARCH, "Searchto: at queue break, cont=%d, havetarget=%d",
X	       searchcontinue, havetarget);
X      ---------------------------------------------------------------- */
X
X      any = 0;    /* None found in queue this time round */
X
X      *(tail++) = QUEUEBREAK;  *(tail++) = QUEUEBREAK;
X      if (tail == end) tail = begin;
X      continue;
X    }
X
X    any = 1;   /* Something in queue */
X
X    if (moveval[r][c] == NONE)
X    { /* unevaluated: evaluate it */
X      val = avd = cont = 0;
X      if ((*evaluate)(r,c,depth,&val,&avd,&cont)) /* Evaluate it. */
X      { movedepth[r][c] = depth;
X        moveavd[r][c] = avd;
X        moveval[r][c] = val;
X	movecont[r][c] = cont;
X
X        if (avd >= INFINITY)
X        { /* Infinite avoidance */
X	  dir[r][c]=UNREACHABLE;  /* we cant get here */
X	  continue;	/* discard the square from consideration. */
X        }
X        else
X        { saveavd[r][c]=avd;
X        }
X      }
X      else 		/* If evaluate fails, forget it for now. */
X      { dwait (D_SEARCH, "Searchto: evaluate failed.");
X	continue;
X      }
X    }
X
X    if (saveavd[r][c])
X    { /* If to be avoided, leave in queue for a while */
X      *(tail++) = r;  *(tail++) = c;   --(saveavd[r][c]);  /* Dec avoidance */
X      if (tail == end) tail = begin;
X      continue;
X    }
X
X    if (moveval[r][c] > havetarget)
X    { /* It becomes the target if it has value bigger than the best found
X      so far, and if it has a non-zero value.
X       */
X
X      if (debug (D_SCREEN | D_SEARCH | D_INFORM))
X      { mvprintw (r, c, "=");
X	dwait (D_SEARCH, "Searchto: target value %d.", moveval[r][c]);
X      }
X      searchcontinue = movecont[r][c];
X      *trow = r;  *tcol = c;  havetarget = moveval[r][c];
X    }
X
X    type = SAFE;
X    while (1)
X    { for (k=0; k<8; k++)
X      { register int S;
X
X	/* examine adjacent squares. */
X	nr = r + sdeltr[k];
X	nc = c + sdeltc[k];
X	S = scrmap[nr][nc];
X
X	/* IF we have not considered stepping on the square yet */
X	/* and if it is accessible    THEN: Put it on the queue */
X        if (dir[nr][nc] == NOTTRIED && (CANGO&S) && (type&S) == type &&
X	    (k<4 || onrc (CANGO,r,nc) && onrc (CANGO,nr,c)))
X        { moveval[nr][nc] = NONE;  /* flag unevaluated */
X
X	  *(tail++) = nr;  *(tail++) = nc; if (tail == end) tail = begin;
X
X	  dir[nr][nc] = sdirect[k];  /* direction we used to get here */
X
X	  if (debug (D_SCREEN | D_SEARCH | D_INFORM))
X	  { at (nr, nc); printw ("%c", ">/^\\</v\\  ~"[dir[nr][nc]]);}
X        }
X      }
X      if (type == 0) break;
X      type = 0;
X    }
X  }
X}
/
echo 'Part 03 of Rog-O-Matic XIV complete.'
exit

mlm@cmu-cs-cad.ARPA (Michael Mauldin) (02/01/85)

#!/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@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

mlm@cmu-cs-cad.ARPA (Michael Mauldin) (02/01/85)

#!/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@cmu-cs-a.arpa
#
echo 'Start of Rog-O-Matic XIV, part 06 of 10:'
echo 'x - rogomatic.6'
sed 's/^X//' > rogomatic.6 << '/'
X.TH ROGOMATIC 6 02/01/85
X.UC 4
X.SH NAME
Xrogomatic \- Automatically Exploring The Dungeons of Doom
X.SH SYNOPSIS
X.I rogomatic
X[
X.I -cefprstuw
Xor
X.I save_file
X]
X.SH DESCRIPTION
X.PP
X.I Rog-O-Matic
Xis a computer fantasy game with a newer twist.  It is crt oriented and the
Xobject of the game is to automatically survive the attacks of various
Xmonsters and get a lot of gold, rather than having to actually type the
Xrequired commands yourself.
X.PP
XOnce you have entered the world of 
X.I Rog-O-Matic
Xyou will stay there, passively watching the game unfold before you much
Xlike a catatonic teenager watching television.
XShould you wish to intervene, type the 
X.B t
Xcommand and 
X.I Rog-O-Matic
Xwill enter transparent mode. Here you can type several commands, the
Xmost useful of which is the
X.B ?
Xcommand, which prints out the next help line. Press the 
X.B ?
Xkey repeatedly to see all of the help. 
XSome useful commands are:
X.B h
X.B j
X.B k
X.B l
X.B H
X.B J
X.B K
X.B L
X.B b
X.B n
X.B y
X.B u
X.B f
X.B s
X.B >
X.B <
X.B S
X.B Q.
XThese have the same meaning as in normal Rogue. To return to 
X.I Rog-O-Matic
Xmode, type the 
X.B t
Xcommand again.
X.PP
XSome useful commands are:
X.TP
X.B t
X.I Toggle,
Xtoggles the setting of the
X.I transparent
Xmode flag. In transparent mode, 
X.I Rog-O-Matic
Xwill not automatically attack monsters, pick up treasure, or explore
Xaround.  Unfortunately, there is no way to enter complicated commands
Xlike 
X.I quaff
Xor
X.I read
Xin transparent mode.  Typing any 
X.I Rogue
Xcommand, or single-step command also enables transparent mode.
X.TP
X.B Q
X.I Quit,
Xtells 
X.I Rog-O-Matic 
Xto quit the game. The score is logged in the score file, and possibly the
X.I Rogue
Xtop ten, and the game is terminated.
X.TP
X.B S
X.I Save,
Xthe game is saved to the default save file, set by the
X.I <file>
Xargument to 
X.I rogomatic
Xor the 
X.I ROGUEOPTS
Xenvironment variable. The game may be restarted later.
X.TP
X.B c
X.I Cheat,
Xtells 
X.I Rog-O-Matic
Xto take advantage of idiosyncracies in the
X.I Rogue
Xgame to get a higher score. This is unfortunately necessary to allow fair
Xcompetition with other human top ten players who take advantage of the same
Xbugs. Note that this option should only be used on the Unix version
Xof Rogue, since the VMS version does not exhibit the same bugs.
XNote too that when playing against 
X.I Rogue 5.2
Xand
X.I Rogue 5.3
Xno cheating is done, since the bugs are not widely known and used by
Xhuman competition.
X.TP
X.B d
X.I Debugging,
Xtoggles the debugging flag, which is useless to non-wizard
Xplayers (although it is entertaining if your terminal has reverse video).
X.TP
X.B e
X.I Echoing,
Xcauses a copy of the game to be written to file 
X.I roguelog
Xin the current directory. Typing 
X.B e
Xa second time closes the log file.  When the game is ended, the roguelog
Xfile is renamed to <killer>.<level>.<score> so if a troll killed poor
X.I Rog-O-Matic
Xon level 14 leaving him with a score of 3088, the file would be named
X.I trol.14.3088.
XNote that only the first four characters of the killer are used.
XThe
X.B -p
Xoption will replay a saved game.  Additionally, a stop action command
X(carriage return gives a single step) has been added.  Pigs didn't fly
Xfirst!
X.TP
X.B i
X.I Inventory,
Xdumps the current inventory on the screen.
X.TP
X.B m
X.I Monster list,
Xshows the current long term memory evaluation of the monsters.
X.I Rog-O-Matic
Xnows keeps a long term memory file (for each version of Rogue) in the
Xscore directory, and records the meanness of each monster it finds.
XThis command prints out the letter, name, and strength of each monster.
XStrength is listed as three numbers: expected damage (scaled by 10) and
Xmaximum damage (unscaled) are shown in parentheses, and the mean number
Xof arrows required to kill a monster is shown in square brackets.
X.TP
X.B CR
X.I Single step,
Xa carriage return enables
X.I transparent
Xmode, and causes
X.I Rog-O-Matic
Xto single-step. The command sent is printed at the
Xbottom right hand of the screen.
X.TP
X.B /
X.I Snapshot,
Xa timestamp, the current screen, and the current inventory are appended
Xto file
X.I rgm.snapshot
Xin the current directory.
X.TP
X.B $
X.I Weaponrank,
Xdumps 
X.I Rog-O-Matic's 
Xcurrent estimate of his weapons rankings.
X.TP
X.B %
X.I Armorrank,
Xdumps 
X.I Rog-O-Matic's 
Xcurrent estimate of his armor rankings.
X.TP
X.B =
X.I Ringrank,
Xdumps 
X.I Rog-O-Matic's 
Xcurrent estimate of his ring rankings.
X.TP
X.B -
X.I Status,
Xprints out a status line indicating various things like whether 
X.I Rog-O-Matic
Xis confused, has red hands, is wearing cursed armor or wielding a cursed
Xweapon, and which monsters have been genocided.
XIt also prints the number of turns elapsed in the game.
X.TP
X.B `
X.I Summary,
Xa backquote prints a short summary of the game.
X.TP
X.B ~
X.I Version,
Xprints the version of
X.I Rogue
Xand
X.I Rog-O-Matic
Xbeing used. It also prints the current goal score.
X.TP
X.B G
X.I Genotype,
Xdisplays the settings of the genetically learned parameters of the
Xgenotype playing now.
X.TP
X.B R
X.I Replay position,
Xallows you to skip around in a log file when replaying an old game.
XThis key must be followed by either
X.B f, p, c, n,
Xor
X.B l.
XThese indicate you wish to see the
X.I first, previous, current, next,
Xor
X.B last
Xlevels of the game.  The first time you enter the
X.B R
Xcommand, there will be a pause of several seconds while the whole log
Xfile is digested.  After this initialization, there should be no delay
Xwhen skipping around in the log file.  After you have skipped once, the
Xprogram won't terminate at the end of the file until you enter the
X.B Q
X.I (quit)
Xcommand.  This way you can replay the last level over (and over...).
X.IR
X.PP
XWhen the game ends, either by your death, when you quit, or when 
X.I Rog-O-Matic
Xdies horribly of some bug, you will not get a list of the top-ten scorers.
XThe scoring is based entirely upon useless criteria anyway.
X.I Rog-O-Matic
Xdoes keep a list of its games. To see the best 
X.I Rog-O-Matic
Xgames, use "rogomatic -s" which dumps the current scores in reverse order.
X.PP
XFor more detailed directions, read the source.
X.SH OPTIONS
X.TP
X.B -c
XTurns on cheat mode. See also the
X.B c
Xcommand in transparent mode.
X.TP
X.B -e
XTurns on logging. See also the
X.B e
Xcommand in transparent mode.
X.TP
X.B -f
XFile command. The next argument is the file name of the 
X.I Rogue
Xexecutable to use.
X.I Rog-O-Matic
Xwill play versions 3.6, 5.2, and 5.3;
X.I rogomatic -f /usr/games/rogue
XWould run 
X.I Rog-O-Matic
Xagainst the standard system 
X.I Rogue
Xgame.  You can run Rog-O-Matic on modified rogues using this option,
Xbut be warned that the interface must be completely compatible with
Xone of the standard versions of Rogue listed, and the version number
Xprinted must be either "3.6," "5.2," or "5.3."
X.TP
X.B -p
XReplay option. Typing 
X.I rogomatic -p
Xwill replay log file 
X.I roguelog.
XOr use
X.I rogomatic -p <file>
Xto replay a specific file.
X.TP
X.B -r
XRestore option. Plays the game saved in the default 
X.I Rogue
Xsave file.
X.TP
X.B -s
XScores. Lists the 
X.I Rog-O-Matic 
Xscoreboard.
X.TP
X.B -t
XTerse mode. In terse mode,
X.I Rog-O-Matic 
Xwill only print a summary after each level explored.
X.TP
X.B -u
XUser mode. Tells 
X.I Rog-O-Matic 
Xto start up in transparent mode, so the user can type commands before
X.I Rog-O-Matic
Xstarts exploring level 1.
X.SH FILES
XThere are two executable files: rogomatic and player.  Rogomatic
Xis a small program which forks and execs the Rogue process and then execs the
Xplayer process.  Thus you must have access to all of these files.  These are
Xavailable as
X.PP
X	/usr/mlm/bin/rogomatic on the GP-Vax
X.br
X	/usr/mlm/bin/player on the GP-Vax
X.PP
XIf you are moving these files to another machine, you must either edit the 
Xrogomatic module to change the name of the player process, or run rogomatic 
Xfrom a directory containing the player module.
X.PP
XThe score file is kept in /usr/mlm/games/rlog/rgmscore<version>.
XIf this file does not exist, it is created.
X.SH SEE ALSO
Xrogue(6)
X.SH BUGS
XOccasionally 
X.I Rog-O-Matic
Xwill dead-lock waiting for input from 
X.I Rogue.
XWhen this happens, type an interrupt and enter the
X.I t
Xcommand again. This usually wakes it up enough to re-start the game.
XIn completely unusual cases, try interrupting and then entering the
X.I S
Xcommand to save the game, and then re-start with "rogomatic -r". Sometimes
Xyou will have to use transparent mode to get it down to the next level
Xbefore turning it loose again.
X.SH HISTORY
X.TP
X01-Feb-85  Michael Mauldin (mlm) at CMU
XAdded genetic learning, UTexas mods, new titlepage, new version XIV.
X.TP
X01-Nov-83  Michael Mauldin (mlm) at CMU
XModified to include long term memory, and to play Rogue 5.3.
X.TP
X31-Aug-83  Michael Mauldin (mlm) at CMU
XModified the replay command to allow skipping around and replaying
Xindividual levels over and over.
X.TP
X16-Jun-83  Michael Mauldin (mlm) at CMU
XAdded error logging, single-step mode, fixed several small bug fixes,
Xmodified title animation to display correct version number.
X.TP
X23-Apr-83  Hamey and Mauldin at CMU
XVersion XII, replaced
X.I replay
Xcommand with an option which causes input to come from a log file, and
Xnot from the Rogue process.  This removes the necessity of a standalone
Xreplay command.
X.TP
X16-Apr-83  Leonard Hamey (lgh) at CMU
XAdded ability to infer unseen halls and use them in searchto without
Xhaving trodden on them first.  Modified exploration algorithm.
X.TP
X07-Nov-82  Michael Mauldin (mlm) at CMU
XAdded archery, homogenous ring handling, removed the keyact kluge.
X.TP
X27-Oct-82  Appel, Hamey, Jacobson, and Mauldin at CMU
XAdded support for Rogue 5.2, and various other improvements and fixes.
X.TP
X30-Sep-82  Michael Mauldin (mlm) at CMU
XAdded improved Invisible Stalker code, modified strength management,
XAmulet handling, improved cheating. Was a total winner on Level 26 with a
Xscore of 14,655.
X.TP
X18-May-82  Appel, Jacobson, and Mauldin at CMU
XAdded running away, level searching, wand and staff usage.
X.TP
X26-Apr-82  Michael Mauldin (mlm) at CMU 
XAdded replay ability.
X.TP
X22-Apr-82  Michael Mauldin (mlm) at CMU 
XAdded cheating mode and enhanced magic handling abilities.
X.TP
X11-Apr-82  Michael Mauldin (mlm) at CMU 
XAdded searching for secret doors.
XModified breadth first search to avoid traps and prefer known safe squares.
XAdded detection of potions of blindness.
X.TP
X21-Mar-82  Michael Mauldin (mlm) at CMU 
XAdded termcap support.
X.TP
X12-Jan-82  Andrew Appel (awa) and Guy Jacobson (guy) at CMU
XAdded breadth first search.
X.TP
X14-Oct-81  Andrew Appel (awa) and Guy Jacobson (guy) at CMU
XCreated.
/
echo 'x - rooms.c'
sed 's/^X//' > rooms.c << '/'
X/*
X * rooms.c: Rog-O-Matic XIV (CMU) Thu Jan 31 20:22:14 1985 - mlm
X * Copyright (C) 1985 by A. Appel, G. Jacobson, L. Hamey, and M. Mauldin
X *
X * Contains functions which deal with the geometry of
X * the dungeon levels, rooms, and passages.
X */
X
X# include <curses.h>
X# include <ctype.h>
X# include "types.h"
X# include "globals.h"
X
X# define sign(x) ((x)?(x)>0?1:-1:0)
X# define EXPLORED 01
X# define HASROOM  02
X
Xint levelmap[9];
X
X/*
X * newlevel: Clear old data structures and set up for a new level.
X */
X
Xnewlevel ()
X{ int   i, j;
X
X  initstufflist ();			/* Delete the list of items */
X  droppedscare = 0;			/* Old stuff gone */
X  maxobj = 22;				/* Reset maximum # of objs */
X  newmonsterlevel ();			/* Do new monster stuff */
X  exploredlevel = 0;			/* New level */
X  aggravated = 0;			/* Old monsters gone */
X  beingstalked = 0;			/* Old monsters gone */
X  darkdir = NONE; darkturns = 0;	/* Not arching old monster */
X  stairrow = NONE; staircol = 0;	/* Get rid of old stairs */
X  missedstairs = 0;
X  newdoors = doorlist;			/* Clear door list */
X  goalr = goalc = NONE;			/* Old goal invalid */
X  trapr = trapc = NONE;			/* Old traps are gone */
X  foundarrowtrap = foundtrapdoor = 0;   /* Old traps are gone */
X  teleported = 0;			/* Not teleported yet */
X  attempt = 0;				/* Haven't search for doors yet */
X  usesynch = 0;				/* Force a new inventory */
X  compression = Level < 13;		/* Set move compression */
X  newarmor = newweapon = newring = 1;	/* Reevaluate our items */
X  foundnew ();				/* Reactivate all rules */
X
X  /*
X   * Clear the highlevel map
X   */
X
X  for (i = 0; i < 9; i++) levelmap[i] = 0;
X  for (i = 0; i < 9; i ++) for (j = 0; j < 9; j ++) zonemap[i][j] = (i == j);
X  zone = NONE;
X
X  /*
X   * Clear the lowlevel map
X   */
X
X  for (i = 1; i < 23; i++)
X    for (j = 0; j < 80; j++)    /* Forall screen positions */
X    { scrmap[i][j] = 0;
X      timessearched[i][j] = 0;
X      updatepos (screen[i][j], i, j);
X    }
X
X  atrow0 = atrow;
X  atcol0 = atcol;
X  set (ROOM);
X  setnewgoal ();
X  timestosearch = k_door / 5;
X}
X
X/* routine to find the rooms:
X * room[i] =     0 -- nothing in sector
X *            ROOM -- room found already
X *	     CANGO -- halls, but no room in sector
X */
X
Xstatic struct {int top,bot,left,right;} bounds[9]=
X
X       /* top bot left right */
X/*0*/	{{ 1,  6,   0,  25},
X/*1*/	 { 1,  6,  27,  51},
X/*2*/	 { 1,  6,  53,  79},
X/*3*/	 { 8, 14,   0,  25},
X/*4*/	 { 8, 14,  27,  51},
X/*5*/	 { 8, 14,  53,  79},
X/*6*/	 {16, 22,   0,  25},
X/*7*/	 {16, 22,  27,  51},
X/*8*/	 {16, 22,  53,  79}};
X
Xmarkmissingrooms ()
X{ register rm,i,j;
X  for (rm=0; rm<9; ++rm)
X  { room[rm]=0;
X    for (i=bounds[rm].top; i<=bounds[rm].bot; ++i)
X      for (j=bounds[rm].left; j<=bounds[rm].right; ++j)
X	if (onrc(ROOM,i,j)) { room[rm]=ROOM; goto nextroom; }
X	else if (onrc(BEEN,i,j)) { room[rm]=BEEN; goto nextroom; }
X    nextroom: ;
X  }
X}
X
X/*
X * whichroom: Return the zone number of a square (0..8) or -1, as follows:
X *
X *		room 0 | room 1 | room 2
X *              -------+--------+-------
X *		room 3 | room 4 | room 5
X *              -------+--------+-------
X *		room 6 | room 7 | room 8
X */
X
Xint whichroom (r,c)
Xregister int r,c;
X{ register int rm;
X
X  for (rm=0; rm<9; ++rm)
X    if (r >= bounds[rm].top  && r <= bounds[rm].bot &&
X        c >= bounds[rm].left && c <= bounds[rm].right)
X      return(rm);
X
X    return (-1);
X}
X
X/*
X * nametrap: look around for a trap and set its type.
X */
X
Xnametrap (ttype, standingonit)
Xint ttype, standingonit;
X{ register int i, r, c, tdir = NONE, monsteradj = 0;
X
X  if (standingonit)
X  { r=atrow; c=atcol; }
X
X  else if (blinded)		/* Cant see, dont bother */
X    return;
X
X  else
X  { /* Look all around and see what there is next to us */
X    for (i = 0; i < 8; i++)
X    { r = atdrow(i); c = atdcol(i);
X
X      if (seerc ('^', r, c))		/* Aha, a trap! */
X      { if (tdir != NONE) return;        /* Second trap, ambigous case */
X        else tdir = i;                    /* First trap,  record direction */
X      }
X      else if (isupper(screen[r][c]))   /* Trap could be under monster */
X        monsteradj++;
X    }
X
X    /* See one trap, set (r,c) to the trap location */
X    if (tdir != NONE)
X    { r = atdrow(tdir); c =  atdcol(tdir); }
X
X    /* See no traps, if there is a monster adjacent, he could be on it */
X    else if (monsteradj)
X      return;
X
X    /* Cant ever sit on a trap door or a teleport trap */
X    else if (ttype == TRAPDOR || ttype == TELTRAP)
X      return;
X
X    /* Cant see trap anywhere else, we must be sitting on it */
X    else
X    { r = atrow; c = atcol; }
X  }
X
X  /* Record last arror trap found (for cheating against 3.6) */
X  if (ttype == ARROW) { foundarrowtrap = 1; trapr = r; trapc = c; }
X  else if (ttype == TRAPDOR) { foundtrapdoor = 1; }
X
X  /* If a trapdor, reactivate rules */
X  if (ttype == TRAPDOR) foundnew ();
X
X  /* Set the trap type */
X  unsetrc (TELTRAP|TRAPDOR|BEARTRP|GASTRAP|ARROW|DARTRAP, r, c);
X  setrc (TRAP | ttype, r, c);
X}
X
X/*
X * findstairs: Look for STAIRS somewhere and set the stairs to that square.
X */
X
Xfindstairs (notr, notc)
Xint notr, notc;
X{ register int r, c;
X
X  stairrow = staircol = NONE;
X
X  for (r = 2; r < 22; r++)
X    for (c = 1; c < 79; c++)
X      if ((seerc ('%', r, c) || onrc (STAIRS, r, c)) &&
X	  r != notr && c != notc)
X      { setrc (STAIRS, r, c); stairrow = r; staircol = c; }
X}
X
X/*
X * downright: Find a square from which we cannot go down or right.
X */
X
Xdownright (drow, dcol)
Xint *drow, *dcol;
X{ register int i=atrow, j=atcol;
X
X  while (i < 23 && j < 79)
X  { if (onrc (CANGO, i, j+1)) j++;
X    else if (onrc (CANGO, i+1, j)) i++;
X    else { *drow = i; *dcol = j; return (1); }
X  }
X
X  return (0);
X}
X
X/*
X * Try to light up the situation
X */
X
Xlightroom ()
X{ int obj;
X
X  /* not in a room nor on door or room lit?? */
X  if (blinded || !darkroom ())
X    return (0);
X
X  if ((obj = havenamed (scroll, "light")) >=0 && reads (obj))
X    return (1);
X
X  if ((obj = havewand ("light")) >=0 && point (obj, 0))
X    return (1);
X
X  return (0);
X}
X
X/*
X * darkroom: Are we in a dark room?
X */
X
Xdarkroom ()
X{ register int dir, dir2, drow, dcol;
X
X  if (!on (DOOR | ROOM))
X    return (0);
X
X  for (dir=0; dir<8; dir++)
X    if (seerc ('.', (drow = atdrow(dir)), (dcol = atdcol(dir))))
X      for (dir2=0; dir2<8; dir2++)
X	if (seerc (' ', drow+deltr[dir2], dcol+deltc[dir2]))
X	  return (1);
X
X  return (0);
X}
X
X/*
X * currentrectangle: infer room extent based on clues from walls
X * NOTE: When a door appears on the screen, currentrectangle
X * should be re-initialised.				LGCH
X */
X
X# define fT 1
X# define fB 2
X# define fL 4
X# define fR 8
X
Xstatic int curt, curb, curl, curr;
X
Xcurrentrectangle ()
X{ int   flags = fT + fB + fL + fR, r, c, any = 1;
X
X  /*
X   * DEFINITION: curt is the current top of the room.  This is the
X   * topmost row which is known to be a room square.  The wall location
X   * is therefore curt-1.  curb: bottom.  curl: left. curr: right
X   * Since we discover new info when we step on a square on the
X   * extremity of the known room area, the following statement was
X   * modified by LGCH to use >=, <= instead of >, <
X   */
X
X  if ((atrow >= curb || atrow <= curt || atcol <= curl || atcol >= curr)
X      && on (ROOM))
X  { curt = curb = atrow;
X    curl = curr = atcol;
X    while (any)
X    { any = 0;
X
X      if (flags & fT)
X        for (r = curt - 1, c = curl - 1; c <= curr + 1; c++)
X          if (onrc (ROOM, r, c))      { curt--; any = 1; break; }
X          else if (seerc ('-', r, c)) { flags &= ~fT; break; }
X
X      if (flags & fB)
X        for (r = curb + 1, c = curl - 1; c <= curr + 1; c++)
X          if (onrc (ROOM, r, c))      { curb++; any = 1; break; }
X          else if (seerc ('-', r, c)) { flags &= ~fB; break; }
X
X      if (flags & fL)
X        for (r = curt, c = curl - 1; r <= curb; r++)
X          if (onrc (ROOM, r, c))      { curl--; any = 1; break; }
X          else if (seerc ('|', r, c)) { flags &= ~fL; break; }
X
X      if (flags & fR)
X        for (r = curt, c = curr + 1; r <= curb; r++)
X          if (onrc (ROOM, r, c))      { curr++; any = 1; break; }
X          else if (seerc ('|', r, c)) { flags &= ~fR; break; }
X
X    }
X    for (r = curt; r <= curb; r++)
X      for (c = curl; c <= curr; c++)
X      { setrc (ROOM + CANGO, r, c);
X        unsetrc	 (HALL, r, c);
X      }
X
X# define ckdoor(FLAG, NODOOR, STATIC, INC, S1, S2, I1, I2) \
X    if (0 == (flags & FLAG)) \
X    { any = 0; \
X      if (NODOOR) any = 1; \
X      else \
X	for (STATIC = S2, INC = I1; INC <= I2; INC++) \
X	  if (onrc (DOOR, r, c)) { any = 1; break; } \
X      if (any) \
X      { for (STATIC = S2, INC = I1; INC <= I2; INC++) \
X	  setrc (SEEN+WALL, r, c); \
X	for (STATIC = S1, INC = I1; INC <= I2; INC++) \
X	  setrc (BOUNDARY, r, c);   /* Room boundary   LGCH */ \
X      } \
X      else \
X      { for (STATIC = S2, INC = I1; INC <= I2; INC++) \
X	  setrc (BOUNDARY, r, c);  /* Unseen wall or door LGCH */ \
X      } \
X    }
X
X    if (curt <= 2) flags &= ~fT;    /* Wall must be on screen edge */
X    if (curb >= 21) flags &= ~fB;
X    if (curl <= 1) flags &= ~fL;
X    if (curr >= 78) flags &= ~fR;
X
X    ckdoor (fT, curt<6,  r, c, curt, curt-1, curl-1, curr+1)
X    ckdoor (fB, curb>17, r, c, curb, curb+1, curl-1, curr+1)
X    ckdoor (fL, curl<24, c, r, curl, curl-1, curt-1, curb+1)
X    ckdoor (fR, curr>56, c, r, curr, curr+1, curt-1, curb+1)
X
X    /* Fill in the corners of the room without seeing them */
X    /* Prevents looking at corners to find missing doors */
X    if ((flags & fT+fR) == 0)  setrc (SEEN + WALL, curt-1, curr+1);
X    if ((flags & fT+fL) == 0)  setrc (SEEN + WALL, curt-1, curl-1);
X    if ((flags & fB+fR) == 0)  setrc (SEEN + WALL, curb+1, curr+1);
X    if ((flags & fB+fL) == 0)  setrc (SEEN + WALL, curb+1, curl-1);
X  }
X}
X
Xclearcurrect()
X{ curl = curr = curt = curb = 0;
X}
X
X/*
X * updateat: We have moved, record results of our passge...
X *
X * Bug if monster is chasing us:  +######A@
X * Bug if teleported horiz or vert. Infers cango
X */
X
Xupdateat ()
X{ register int dr = atrow - atrow0, dc = atcol - atcol0;
X  register int i, r, c;
X  int   dist, newzone, sum;
X
X  /*
X   * Record passage from one zone to the next
X   */
X
X  newzone = whichroom (atrow, atcol);
X
X  if (newzone != NONE && zone != NONE && newzone != zone)
X  { new_arch = 1;
X    zonemap[zone][newzone] = zonemap[newzone][zone] = 1;
X    if ((levelmap[zone] & (EXPLORED | HASROOM)) == 0)
X    { for (i = 0, sum = 0; i < 9; i++) sum += zonemap[zone][i];
X      if (sum >= 3) markexplored (atrow0, atcol0);
X    }
X  }
X
X  if (newzone != NONE)
X    zone = newzone;
X
X
X  /*
X   * Check for teleport, else if we moved multiple squares, mark them as BEEN
X   */
X
X  if (direc (dr, dc) != movedir || dr && dc && abs(dr) != abs(dc))
X    teleport ();
X  else
X  { dist = (abs(dr)>abs(dc)) ? abs(dr) : abs(dc);
X    dr = (dr > 0) ? 1 : (dr < 0) ? -1 : 0;
X    dc = (dc > 0) ? 1 : (dc < 0) ? -1 : 0;
X    for (r = atrow0, c = atcol0;
X         dist >= 0 && (onrc(DOOR,r,c) || !onrc(WALL,r,c));
X         r += dr, c += dc, dist--)
X    { setrc (BEEN | SEEN | CANGO, r, c);
X      if (!onrc (TRAP, r, c)) setrc (SAFE, r, c);
X    }
X  }
X
X  /* Mark surrounding area according to what we see */
X
X  if (!on (HALL | DOOR | ROOM) && !blinded)
X  { int i, rr, cc;
X    int halls = 0, rooms = 0, rm;
X    char *terrain = "nothing";
X
X    for (i=0; i<8; i += 2)
X    { rr = atdrow(i); cc = atdcol(i);
X      if (onrc (HALL, rr, cc))
X        halls++;
X      else if (onrc (ROOM, rr, cc))
X        rooms++;
X    }
X
X    if (seerc ('|', atrow-1, atcol) && seerc ('|', atrow+1, atcol) ||
X        seerc ('-', atrow, atcol-1) && seerc ('-', atrow, atcol+1))
X    { set (DOOR | SAFE); unset (HALL | ROOM); terrain = "door";
X      if ((rm = whichroom (atrow, atcol)) != NONE) levelmap[rm] |= HASROOM;
X    }
X    else if (halls > 0)
X    { set (HALL | SAFE); unset (DOOR | ROOM); terrain = "hall"; }
X    else if (rooms > 0)
X    { set (ROOM); unset (HALL | DOOR); terrain = "room"; }
X    else
X      return;
X
X    dwait (D_INFORM, "Inferring %s at %d,%d.", terrain, atrow, atcol);
X  }
X  else if (on (DOOR | ROOM) && !isexplored (atrow, atcol) && !darkroom ())
X  { markexplored (atrow, atcol);
X  }
X}
X
X/*
X * updatepos: Something changed on the screen, update the screen map
X */
X
Xupdatepos (ch, row, col)
Xregister char  ch;
Xregister int row, col;
X{ char  oldch = screen[row][col], *monster, functionchar();
X  int   seenbefore = onrc (EVERCLR, row, col);
X  int   couldgo = onrc (CANGO, row, col);
X  int   unseen = !onrc (SEEN, row, col);
X  int   rm = whichroom (row, col);
X
X  if (mlistlen && ch != oldch) deletemonster (row, col);
X  if (unseen) { foundnew (); }
X
X  switch (ch)
X  { case '@':
X      setrc (SEEN | CANGO | BEEN | EVERCLR, row, col);
X      unsetrc (MONSTER | SLEEPER, row, col);
X      atrow = row;
X      atcol = col;
X      break;
X
X    case '#':
X      if (!onrc (HALL, row, col))
X      { foundnew ();
X        timestosearch = k_door / 5;
X      }
X      if (onrc (STUFF, row, col)) deletestuff (row, col);
X      setrc (SEEN | CANGO | SAFE | HALL | EVERCLR, row, col);
X      unsetrc (DOOR | ROOM | TRAP | ARROW | TRAPDOR | TELTRAP | GASTRAP |
X	       BEARTRP | DARTRAP | MONSTER | SCAREM | WALL | SLEEPER | STAIRS,
X	       row, col);
X      break;
X
X    case '+':
X      if (!onrc (DOOR, row, col))
X      { foundnew ();
X        timestosearch = k_door / 5;
X	teleported = 0; /* Dont give up on this level yet */
X	*newdoors++ = row;  *newdoors++ = col;
X      }
X      if (onrc (STUFF, row, col)) deletestuff (row, col);
X      setrc (SEEN | CANGO | SAFE | DOOR | WALL | EVERCLR, row, col);
X      unsetrc (ROOM | TRAP | ARROW | TRAPDOR | TELTRAP | GASTRAP | BEARTRP |
X               DARTRAP | MONSTER | SCAREM | SLEEPER, row, col);
X      clearcurrect();  /* LGCH: redo currentrectangle */
X      break;
X
X    /*
X     * Room floor:  there are many cases of what a room floor means,
X     * depending on the version of Rogue, whether the room is lit, whether
X     * we are in the room or not, and whether or not we were shooting
X     * missiles last turn.
X     */
X
X    case '.':
X      /* The square cant be any of these */
X      unsetrc (HALL | DOOR | MONSTER | SCAREM | WALL | TRAP | ARROW |
X               TRAPDOR | TELTRAP | GASTRAP | BEARTRP | DARTRAP, row, col);
X
X      if (!onrc (ROOM, row, col))		/* New room? */
X        unmarkexplored (row, col);
X      if (rm != NONE) levelmap[rm] |= HASROOM;	/* Room here */
X
X      /* If older Rogue, or our last position or a moving missile or */
X      /* in the same room, then a floor '.' means no stuff there     */
X      if ((version < RV52A ||
X           oldch == '@' ||
X           oldch == ')' && functionchar (lastcmd) == 't' ||
X           (on (ROOM) && whichroom (row, col) == whichroom (atrow, atcol))) &&
X          onrc (STUFF, row, col))
X      { deletestuff (row, col); }
X
X      /* If the stairs moved, look for them */
X      if (oldch == '@' && onrc (STAIRS, row, col)) findstairs (row, col);
X
X      /* Record whether this square has been clear of monsters */
X      if (!isupper (oldch)) setrc (EVERCLR, row, col);
X
X      /* Safe if we have been there, but not if the stuff was an arrow */
X      if (onrc (BEEN, row, col)) setrc (SAFE, row, col);
X      else if (oldch == ')' && functionchar (lastcmd) == 't')
X        unsetrc (SAFE, row, col);
X
X      setrc (SEEN | CANGO | ROOM, row, col);	/* Square must be these */
X      break;
X
X    case '-':
X    case '|':
X      setrc (SEEN | WALL | EVERCLR, row, col);
X      unsetrc (CANGO | HALL | DOOR | ROOM | SLEEPER, row, col);
X      break;
X
X    case ':':
X    case '?':
X    case '!':
X    case ')':
X    case ']':
X    case '/':
X    case '=':
X    case ',':           /* HAH! *//* HAH HAH! *//* HAH HAH HAH! */
X    case '*':
X      setrc (SEEN | CANGO | SAFE | EVERCLR, row, col);
X      unsetrc (DOOR | TRAP | ARROW | TRAPDOR | TELTRAP | GASTRAP | BEARTRP |
X               DARTRAP | MONSTER | WALL | SLEEPER, row, col);
X      if (ch != '?') unsetrc (SCAREM, row, col);
X      if (!onrc (BEEN, row, col) || !onrc(STAIRS, row, col) || !cosmic)
X      { addstuff (ch, row, col); unsetrc (STAIRS, row, col); }
X      setnewgoal ();
X      break;
X
X    case '%':
X      if (!onrc (STAIRS, row, col)) foundnew ();
X      if ((!cosmic || onrc (BEEN, row, col)) && onrc (STUFF, row, col))
X        deletestuff (row, col);
X      setrc (SEEN | CANGO | SAFE | ROOM | STAIRS | EVERCLR, row, col);
X      unsetrc (DOOR | HALL | TRAP | ARROW | TRAPDOR | TELTRAP | GASTRAP | 
X	       BEARTRP | DARTRAP | MONSTER | SCAREM | SLEEPER,
X               row, col);
X      stairrow = row;
X      staircol = col;
X      setnewgoal ();
X      break;
X
X    case '^':
X      setrc (SEEN | CANGO | ROOM | TRAP | EVERCLR, row, col);
X      if (onrc (STUFF, row, col)) deletestuff (row, col);
X      unsetrc (SAFE | HALL | DOOR | MONSTER | SCAREM | WALL | SLEEPER,
X               row, col);
X      break;
X
X    case ' ':
X      unsetrc (MONSTER | WALL, row, col);
X      break;
X
X    default:
X      if (isupper (ch))
X      { monster = monname (ch);
X        setrc (SEEN | CANGO | MONSTER, row, col);
X        unsetrc (SCAREM, row, col);
X	if (onrc (WALL, row, col))	/* Infer DOOR here */
X	{ if (!onrc (DOOR, row, col))
X          { foundnew ();
X            timestosearch = k_door / 5;
X            setrc (DOOR, row, col); /* MLM */
X            unsetrc (WALL, row, col); /* MLM */
X          }
X        }
X        if (!revvideo && ch != oldch) /* R5.2 MLM */
X        { blinded = 0;
X          if (seenbefore)
X            addmonster (ch, row, col, AWAKE);
X          else if (!onrc (HALL | DOOR, row, col) && !aggravated &&
X                   (streq (monster, "floating eye") ||
X                    streq (monster, "ice monster") ||
X                    streq (monster, "leprechaun") ||
X                    streq (monster, "nymph") ||
X                    (version < RV52A && (ch == 'T' || ch == 'P'))))
X          { addmonster (ch, row, col, ASLEEP);
X            setrc (SLEEPER, row, col);
X          }
X          else if (onrc (HALL | DOOR, row, col) || aggravated)
X          { addmonster (ch, row, col, AWAKE);
X	    setrc (EVERCLR, row, col);
X	  }
X          else
X            addmonster (ch, row, col, 0);
X        }
X      }
X      break;
X  }
X
X  /* If the stairs moved, look for the real stairs */
X  if ((!onrc (STAIRS, row, col) && (row==stairrow && col==staircol)) ||
X      (stairrow != NONE && !onrc (STAIRS, stairrow, staircol)))
X    findstairs (row, col);
X
X  if (!couldgo && onrc (CANGO, row, col))
X    setnewgoal ();
X}
X
X/*
X * teleport: We have just been teleported. Reset whatever is necessary to
X * avoid doing silly things.
X */
X
Xteleport ()
X{ register int r = atrow0, c = atcol0;
X
X  goalr = goalc = NONE; setnewgoal ();
X
X  hitstokill = 0; darkdir = NONE; darkturns = 0;
X
X  if (movedir >= 0 && movedir < 8 && !confused)
X  { teleported++;
X
X    while (r > 1 && r < 23 && c > 0 && c < 79)
X    { if (onrc (WALL | DOOR | HALL, r, c)) break;
X      if (onrc (TRAP, r, c))
X      { if (!onrc (ARROW|DARTRAP|GASTRAP|BEARTRP|TRAPDOR|TELTRAP, r, c))
X          saynow ("Assuming teleport trap at %d, %d", r, c);
X	break;
X      }
X      r += deltr[movedir]; c += deltc[movedir];
X    }
X  }
X}
X
X/*
X * mapinfer: Rewritten by Michael Mauldin.  August 19, 1983.
X * Infer bit settings after reading a scroll of magic mapping.
X * Because the mapping scroll gives extra information (in particular
X * we now know all the room squares so we can plan run-away paths
X * properly) it is best to process the entire map making extra
X * inferences.
X */
X
Xmapinfer()
X{ register r, c, inroom;
X
X  dwait (D_CONTROL, "Map read: inferring rooms.");
X  for (r=1; r<23; r++)
X  { inroom = 0;
X    for (c=0; c<80; c++)
X    { if (seerc ('|', r, c) || (seerc ('+', r, c) && !seerc('-', r, c-1)))
X      { inroom = !inroom; }
X      else if (inroom)
X      { setrc (ROOM | CANGO, r, c); }
X      else
X      { setrc (SEEN, r, c); }
X    }
X  }
X}
X
X/*
X * markexplored: If we are in a room, mark the location as explored.
X */
X
Xmarkexplored (row, col)
Xint row, col;
X{ register int rm = whichroom (row, col);
X
X  if (rm != NONE && !(levelmap[rm] & EXPLORED))
X  { levelmap[rm] |= EXPLORED;
X    if (!(levelmap[rm] & HASROOM))
X      saynow ("Assuming room %d is gone.", zone);
X  }
X}
X
X/*
X * unmarkexplored: If we are in a room, unmark the location as explored.
X */
X
Xunmarkexplored (row, col)
Xint row, col;
X{ register int rm = whichroom (row, col);
X
X  if (rm != NONE) levelmap[rm] &= ~EXPLORED;
X}
X
X/*
X * isexplored: If we are in a room, return true if it has been explored.
X */
X
Xisexplored (row, col)
Xint row, col;
X{ register int rm = whichroom (row, col);
X
X  return (rm != NONE ? levelmap[rm] & EXPLORED : 0);
X}
X
X/*
X * haveexplored: Have we explored n rooms?
X */
X
Xhaveexplored (n)
Xint n;
X{ register int rm, count = 0;
X
X  for (rm = 0; rm < 9; rm++)
X    if (levelmap[rm] & EXPLORED)
X      count++;
X
X  return (count >= n);
X}
X
X/*
X * printexplored: List the explored rooms
X */
X
Xprintexplored ()
X{ register int rm;
X
X  at (0,0);
X  printw ("Rooms explored: ");
X  for (rm = 0; rm < 9; rm++)
X  { if (levelmap[rm] & EXPLORED)
X    { printw (" %d", rm);
X    }
X  }
X  clrtoeol ();
X  at (row, col);
X  refresh ();
X}
X
X/*
X * inferhall: When a door appears on the screen where no door was before,
X * check whether we can infer a hall between it an a neighbouring room.
X * The technique is simple: We first determine whether the hall is already
X * known, and if it is not, we scan away from the room looking for another
X * wall. If we find one, then we look for a door and if we find THAT then
X * we infer a hall between the matching doors. Of course, this means that
X * we must set CANGO bits so that exploration can use the guessed hall. So
X * we set CANGO for the complete rectangle joining the two doors and then
X * rely on the CANGO bits being unset again where we actually see blank
X * space.
X */
X
Xinferhall (r, c)
Xregister int r, c;
X{ register int i, j, k;
X
X  int inc, rm, end1, end2, end, dropout = 0, dir= NONE;
X  for (k = 0; k < 8; k += 2)
X  { if (onrc (HALL, r + deltr[k], c + deltc[k]))      /* Hall has been seen */
X      return;
X    else if (onrc (ROOM, r + deltr[k], c + deltc[k])) /* Room is over here */
X      dir = k;
X  }
X
X  dwait (D_SEARCH, "Room direction %d", dir);
X
X  if (dir < 0) return;
X
X  if (dir % 4 == 0) 			     /* If horizontal dir */
X  { inc = -deltc[dir]; rm = whichroom (r, c);
X    end1 = bounds[rm].top; end2 = bounds[rm].bot;
X    if (inc < 0) end = bounds[rm-1].left;
X    else         end = bounds[rm+1].right;
X    end = end * inc;
X
X    for (j = c+inc; j*inc < end; j += inc)
X    { for (i = end1; i <= end2; i++)
X      { if (debug (D_SCREEN | D_SEARCH | D_INFORM)) mvaddch (i, j, 'h');
X	if (onrc (DOOR | WALL | ROOM | HALL, i, j))
X	{ /* Modified only to find doors on vertical walls */
X          if (onrc (DOOR,i,j) && (onrc (WALL,i-1,j) || onrc (WALL,i+1,j)))
X	    connectdoors (r, c+inc, i, j-inc);
X	  dropout = 1;
X	}
X      }
X      if (dropout)
X	break;
X    }
X  }
X
X  else
X  { inc = -deltr[dir]; rm = whichroom (r, c);
X    end1 = bounds[rm].left; end2 = bounds[rm].right;
X    if (inc < 0) end = bounds[rm-3].top;
X    else         end = bounds[rm+3].bot;
X    end = end * inc;
X
X    for (i = r+inc; i*inc < end; i += inc)
X    { for (j = end1; j <= end2; j++)
X      { if (debug (D_SCREEN | D_SEARCH | D_INFORM)) mvaddch (i, j, 'v');
X	if (onrc (DOOR | WALL | ROOM | HALL, i, j))
X	{ /* Modified only to find doors on horizontal walls */
X          if (onrc (DOOR,i,j) && (onrc (WALL,i,j-1) || onrc (WALL,i,j+1)))
X	    connectdoors (r+inc, c, i-inc, j);
X	  dropout = 1;
X	}
X      }
X      if (dropout) break;
X    }
X  }
X
X  /* NOTE: If we set SEEN here on the three squares beyond the door, then
X   * we can prevent Rogomatic's persistence in searching out every
X   * corridor that leads to a secret door at the other end. Or, we could set
X   * a bit on the door to make it a preferred exploration target so that
X   * Rogomatic would ALWAYS search out every corridor leading to a secret
X   * door at the other end. The latter alternative is probably better
X   * unless we implement the inferred corridors so that we can infer a
X   * corridor which has a secret door and therefore we can traverse it
X   * more easily one way than the other. NOTE that we must have a flag to
X   * indicate why the search for a corridor failed: if it found a wall
X   * then we know there is a secret door; if it stopped for another reason
X   * then we don't know what we may find - maybe a room, maybe a path to a
X   * corridor.
X   */
X
X  dwait (D_SEARCH | D_CONTROL, "Hall search done.");
X}
X
Xconnectdoors (r1, c1, r2, c2)
Xregister int r1, c1, r2, c2;
X{ register int r, c;
X  int endr = max (r1, r2), endc = max (c1, c2);
X
X  dwait (D_INFORM, "Inferring hall (%d,%d) to (%d,%d)", r1, c1, r2, c2);
X
X  for (r = min (r1, r2); r <= endr; r++)
X    for (c = min (c1, c2); c <= endc; c++)
X      setrc (CANGO|SAFE, r, c);              /* Can go (somewhere) here */
X
X  for (r = min (r1, r2) - 1; r <= endr + 1; r++)
X    for (c = min (c1, c2) - 1; c <= endc + 1; c++)
X      setrc (SEEN, r, c); 		     /* Nothing to see here */
X}
X
X/*
X * canbedoor: Called from setpsd() to check that a dead end could in fact
X * lead to a room.  Only checks that there is enough empty space next to a
X * square.  Does NOT check that this square is in fact a dead end.
X *
X * September 25, 1983	Michael L. Mauldin
X */
X
Xcanbedoor (deadr, deadc)
Xint deadr, deadc;
X{ register int r, c, dr, dc, k, count;
X
X  /* Check all orthogonal directions around the square */
X  for (k=0; k < 8; k+=2)
X  { dr = deltr[k]; dc = deltc[k];
X    r = deadr+dr; c = deadc+dc;
X
X    /* If there are four blank squares, then it could be a door */
X    for (count=0; count < 4 && seerc (' ',r,c); count++)
X    { r+=dr; c+=dc; }
X
X    if (count >= 4) return (1);
X  }
X
X  /* Not enough room in any direction */
X  return (0);
X}
X
X/*
X * mazedoor: Return true if this could be a door to a maze
X */
X
Xmazedoor (row, col)
Xint row, col;
X{ register int r=row, c=col, dr, dc, k=0, dir = NONE;
X
X  if (onrc (HALL,r,c+1)) {dir=0; k++; dr=0;   dc=1;}
X  if (onrc (HALL,r-1,c)) {dir=2; k++; dr= -1; dc=0;}
X  if (onrc (HALL,r+1,c)) {dir=6; k++; dr=1;   dc=0;}
X  if (onrc (HALL,r,c-1)) {dir=4; k++; dr=0,   dc= -1;}
X  if (k != 1) return (0);
X
X  /* Fail if no adjacent hall, or not double corridor */
X  if ((onrc (HALL, r+dr+dr, c+dc+dc) == 0))
X    return (0);
X
X  /* Must have two sets of double corridor */
X  if (! (((onrc (HALL, r+dr+deltr[(dir+1)&7], c+dc+deltc[(dir+1)&7])) &&
X          (onrc (HALL, r+dr+deltr[(dir+2)&7], c+dc+deltc[(dir+2)&7]))) ||
X         ((onrc (HALL, r+dr+deltr[(dir-1)&7], c+dc+deltc[(dir-1)&7])) &&
X          (onrc (HALL, r+dr+deltr[(dir-2)&7], c+dc+deltc[(dir-2)&7])))))
X    return (0);
X
X  /* If there are four blank squares, then it could be a door */
X  for (r = row-dr, c = col-dc, k=0;  k < 4 && seerc (' ',r,c);  k++)
X  { r-=dr; c-=dc; }
X
X  if (k >= 4) return (1);
X
X  /* Not enough room for room */
X  return (0);
X}
X
X/*
X * nextto:  Is there a square type orthogonally adjacent?
X */
X
Xnextto (type,r,c)
Xregister int type, r, c;
X{ register int result;
X  if (result = onrc (type, r-1, c)) return (result);
X  if (result = onrc (type, r+1, c)) return (result);
X  if (result = onrc (type, r, c-1)) return (result);
X  if (result = onrc (type, r, c+1)) return (result);
X  return (0);
X}
X
X/*
X * nexttowall:  Is there a wall adjacent wall?
X *			|
X *  e.g.	########|   <----   there should be a door here.
X *			|
X * Fuzzy:	Replaces knowisdoor (), October 17, 1983.
X */
X
Xnexttowall (r,c)
Xregister int r, c;
X{ return (onrc (DOOR | WALL, r-1, c) == WALL ||
X          onrc (DOOR | WALL, r+1, c) == WALL ||
X          onrc (DOOR | WALL, r, c-1) == WALL ||
X          onrc (DOOR | WALL, r, c+1) == WALL);
X}
X
X/*
X * dumpmazedoor: Show all squares for which mazedoor(r,c) is true.
X */
X
Xdumpmazedoor ()
X{ register int r, c;
X
X  for (r=2; r<22; r++)
X  { for (c=1; c<79; c++)
X    { if (((scrmap[r][c] & (BEEN|DOOR|HALL|ROOM|WALL|STAIRS)) == 0) &&
X          mazedoor (r, c))
X        mvaddch (r, c, 'M');
X    }
X  }
X
X  at (row, col);
X}
X
X/* 
X * foundnew: Reactivate rules which new new squares to work
X */
X
Xfoundnew ()
X{ new_mark = new_findroom = new_search = new_stairs = 1;
X  reusepsd = teleported = 0;
X  cancelmove (SECRETDOOR);
X  unrest ();
X}
/
echo 'x - setup.c'
sed 's/^X//' > setup.c << '/'
X/*
X * setup.c: Rog-O-Matic XIV (CMU) Wed Jan 30 17:38:07 1985 - mlm
X * Copyright (C) 1985 by A. Appel, G. Jacobson, L. Hamey, and M. Mauldin
X *
X * This is the program which forks and execs the Rogue & the Player
X */
X
X# include <stdio.h>
X# include <signal.h>
X# include "install.h"
X
X# define READ    0
X# define WRITE   1
X
X/* Define the Rog-O-Matic pseudo-terminal (Concept Based) */
X
X# define ROGUETERM "rg|rterm:am:bs:ce=^[^S:cl=^L:cm=^[a%+ %+ :co#80:li#24:so=^[D:se=^[d:pt:ta=^I:up=^[;:db:xn:"
X
Xint   frogue, trogue;
X
Xmain (argc, argv)
Xint   argc;
Xchar *argv[];
X
X{ int   ptc[2], ctp[2];
X  int   child, score = 0, oldgame = 0;
X  int   cheat = 0, noterm = 1, echo = 0, nohalf = 0, replay = 0;
X  int   emacs = 0, rf = 0, terse = 0, user = 0, quitat = 2147483647;
X  char  *rfile = "", *rfilearg = "", options[32];
X  char  ropts[128], roguename[128];
X
X  while (--argc > 0 && (*++argv)[0] == '-')
X  { while (*++(*argv))
X    { switch (**argv)
X      { case 'c': cheat++;        break; /* Will use trap arrows! */
X        case 'e': echo++;         break; /* Echo file to roguelog */
X        case 'f': rf++;           break; /* Next arg is the rogue file */
X        case 'h': nohalf++;       break; /* No halftime show */
X        case 'p': replay++;       break; /* Play back roguelog */
X        case 'r': oldgame++;      break; /* Use saved game */
X        case 's': score++;        break; /* Give scores only */
X        case 't': terse++;        break; /* Give status lines only */
X        case 'u': user++;         break; /* Start up in user mode */
X        case 'w': noterm = 0;     break; /* Watched mode */
X        case 'E': emacs++;        break; /* Emacs mode */
X        default:  printf 
X                  ("Usage: rogomatic [-cefhprstuwE] or rogomatic [file]\n");
X                  exit (1);
X      }
X    }
X
X    if (rf) 
X    { if (--argc) rfilearg = *++argv;
X      rf = 0;
X    }
X  }
X
X  if (argc > 1)
X  { printf ("Usage: rogomatic [-cefhprstuwE] or rogomatic <file>\n");
X    exit (1);
X  }
X
X  /* Find which rogue to use */
X  if (*rfilearg)
X  { if (access (rfilearg, 1) == 0)	rfile = rfilearg;
X    else				{ perror (rfilearg); exit (1); }
X  }
X  else if (access ("rogue", 1) == 0)	rfile = "rogue";
X# ifdef NEWROGUE
X  else if (access (NEWROGUE, 1) == 0)	rfile = NEWROGUE;
X# endif
X# ifdef ROGUE
X  else if (access (ROGUE, 1) == 0)	rfile = ROGUE;
X# endif
X  else
X  { perror ("rogue");
X    exit (1);
X  }
X
X  if (!replay && !score) quitat = findscore (rfile, "Rog-O-Matic");
X
X  sprintf (options, "%d,%d,%d,%d,%d,%d,%d,%d",
X           cheat, noterm, echo, nohalf, emacs, terse, user,quitat);
X  sprintf (roguename, "Rog-O-Matic %s for %s", RGMVER, getname ());
X  sprintf (ropts, "name=%s,%s,%s,%s,%s,%s,%s,%s,%s,%s",
X           roguename, "fruit=apricot", "terse", "noflush", "noask",
X           "jump", "step", "nopassgo", "inven=slow", "seefloor");
X
X  if (score)  { dumpscore (argc==1 ? argv[0] : DEFVER); exit (0); }
X  if (replay) { replaylog (argc==1 ? argv[0] : ROGUELOG, options); exit (0); }
X
X  if ((pipe (ptc) < 0) || (pipe (ctp) < 0))
X  { fprintf (stderr, "Cannot get pipes!\n");
X    exit (1);
X  }
X
X  trogue = ptc[WRITE];
X  frogue = ctp[READ];
X
X  if ((child = fork ()) == 0)
X  { close (0);
X    dup (ptc[READ]);
X    close (1);
X    dup (ctp[WRITE]);
X
X    putenv ("TERMCAP", ROGUETERM);
X    putenv ("ROGUEOPTS", ropts);
X
X    if (oldgame)  execl (rfile, rfile, "-r", 0);
X    if (argc)     execl (rfile, rfile, argv[0], 0);
X    execl (rfile, rfile, 0);
X    _exit (1);
X  }
X
X  else
X  { /* Encode the open files into a two character string */
X
X    char *ft = "aa", rp[32]; ft[0] += frogue; ft[1] += trogue;
X
X    /* Pass the process ID of the Rogue process as an ASCII string */
X    sprintf (rp, "%d", child);
X
X    if (!author ()) nice (4);
X
X    execl ("player", "player", ft, rp, options, roguename, 0);
X# ifdef PLAYER
X    execl (PLAYER, "player", ft, rp, options, roguename, 0);
X# endif
X    printf ("Rogomatic not available, 'player' binary missing.\n");
X    kill (child, SIGKILL);
X  }
X}
X
X/* 
X * replaylog: Given a log file name and an options string, exec the player
X * process to replay the game.  No Rogue process is needed (since we are
X * replaying an old game), so the frogue and trogue file descrptiors are
X * given the fake value 'Z'.
X */
X
Xreplaylog (fname, options)
Xchar *fname, *options;
X{ execl ("player", "player", "ZZ", "0", options, fname, 0);
X# ifdef PLAYER
X  execl (PLAYER, "player", "ZZ", "0", options, fname, 0);
X# endif
X  printf ("Replay not available, 'player' binary missing.\n");
X  exit (1);
X}
X
X/*
X * author:
X *	See if a user is an author of the program
X */
X
Xauthor()
X{
X  switch (getuid())
X  { case 1337:	/* Fuzzy */
X    case 1313:	/* Guy */
X    case 1241:	/* Andrew */
X    case 345:	/* Leonard */
X    case 342:	/* Gordon */
X		return 1;
X    default:	return 0;
X  }
X}
/
echo 'Part 06 of Rog-O-Matic XIV complete.'
exit

mlm@cmu-cs-cad.ARPA (Michael Mauldin) (02/01/85)

#!/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@cmu-cs-a.arpa
#
echo 'Start of Rog-O-Matic XIV, part 07 of 10:'
echo 'x - Bugreport'
sed 's/^X//' > Bugreport << '/'
X/*
X * Bugreport: Rog-O-Matic XIV (CMU) Tue Jan 29 14:59:59 1985 - mlm
X * Copyright (C) 1985 by A. Appel, G. Jacobson, L. Hamey, and M. Mauldin
X */
X
XNo known bugs (yet).
/
echo 'x - datesub.l'
sed 's/^X//' > datesub.l << '/'
X%{
X/*
X * datesub.l: Rog-O-Matic XIV (CMU) Fri Feb  1 10:23:56 1985 - mlm
X * Copyright (C) 1985 by A. Appel, G. Jacobson, L. Hamey, and M. Mauldin
X */
X
X# define yywrap() 1
X%}
X%%
X"Jan"				printf ("1"); 
X"Feb"				printf ("2"); 
X"Mar"				printf ("3"); 
X"Apr"				printf ("4"); 
X"May"				printf ("5"); 
X"Jun"				printf ("6"); 
X"Jul"				printf ("7"); 
X"Aug"				printf ("8"); 
X"Sep"				printf ("9"); 
X"Oct"				printf ("10"); 
X"Nov"				printf ("11"); 
X"Dec"				printf ("12"); 
X%%
X
Xmain ()
X{ while (yylex ())
X    ; 
X}
/
echo 'x - learn.c'
sed 's/^X//' > learn.c << '/'
X/*
X * learn.c: Rog-O-Matic XIV (CMU) Thu Jan 31 20:30:10 1985 - mlm
X * Copyright (C) 1985 by A. Appel, G. Jacobson, L. Hamey, and M. Mauldin
X *
X * Genetic learning component.
X */
X
X# include <stdio.h>
X# include "types.h"
X
X# define TRIALS(g)		((g)->score.count)
X# define NONE		(-1)
X# define MAXM		100
X# define ALLELE		100
X# define ZEROSTAT	{0, 0, 0, 0, 0}
X
Xtypedef struct
X{ int   id, creation, father, mother, dna[MAXKNOB];
X        statistic score, level;
X}               genotype;
X
Xextern int knob[];
Xextern double mean(), stdev(), sqrt();
Xextern FILE *wopen();
X
Xstatic int inittime=0, trialno=0, lastid=0;
Xstatic int crosses=0, shifts=0, mutations=0;
Xstatic statistic g_score = ZEROSTAT;
Xstatic statistic g_level = ZEROSTAT;
Xstatic genotype *genes[MAXM];
Xstatic int length = 0;
Xstatic int mindiff = 10, pmutate = 4, pshift = 2, mintrials = 1;
Xstatic double step = 0.33; /* standard deviations from the mean */
Xstatic FILE *glog=NULL;
X
Xstatic int compgene();
X
X/*
X * Start a new gene pool
X */
X
Xinitpool (k, m)
X{ inittime = time (0);
X
X  if (glog) fprintf (glog, "Gene pool initalized, k %d, m %d, %s",
X                     k, m, ctime (&inittime));
X
X  randompool (m);
X}
X
X/*
X * Summarize the current gene pool
X */
X
Xanalyzepool (full)
Xint full;
X{ register int g;
X
X  qsort (genes, length, sizeof (*genes), compgene);
X
X  printf ("Gene pool size %d, started %s", length, ctime (&inittime));
X  printf ("Trials %d, births %d (crosses %d, mutations %d, shifts %d)\n",
X          trialno, lastid, crosses, mutations, shifts);
X  printf ("Mean score %1.0lf+%1.0lf, Mean level %3.1lf+%3.1lf\n\n",
X	  mean (&g_score), stdev (&g_score),
X	  mean (&g_level), stdev (&g_level));
X
X  for (g=0; g<length; g++)
X  { printf ("Living: "); summgene (stdout, genes[g]);
X    if (full)
X    { if (genes[g]->mother)
X        printf ("  Parents: %3d,%-3d", genes[g]->father, genes[g]->mother);
X      else
X        printf ("  Parent:  %3d,   ", genes[g]->father);
X      printf ("  best %4.0lf/%-2.0lf",
X		genes[g]->score.high, genes[g]->level.high);
X      printf ("    DNA  "); printdna (stdout, genes[g]); printf ("\n\n");
X    }
X  }
X}
X
X/*
X * setknobs: Read gene pool, pick genotype, and set knobs accordingly.
X */
X
Xsetknobs (newid, knob, best, avg)
Xint *newid, *knob, *best, *avg;
X{ register int i, g;
X  
X  ++trialno;
X
X  g = pickgenotype ();	/* Pick one genotype */
X  *newid = genes[g]->id;
X
X  for (i=0; i<MAXKNOB; i++)	/* Set the knobs for that genotype */
X    knob[i] = genes[g]->dna[i];
X
X  *best = genes[g]->score.high;
X  *avg = (int) mean (&(genes[g]->score));
X}
X
X/*
X * evalknobs: Add a data point to the gene pool
X */
X
Xevalknobs (gid, score, level)
Xint gid, score, level;
X{ register int g;
X
X  /* Find out which gene has the correct id */
X  for (g=0; g<length; g++)
X    if (gid == genes[g]->id) break;
X
X  /* If he got deleted by someone else, blow it off */  
X  if (g >= length) return;
X
X  /* Add information about performance */
X  addstat (&(genes[g]->score), score);
X  addstat (&g_score, score);
X  addstat (&(genes[g]->level), level);
X  addstat (&g_level, level);
X
X  if (glog)
X  { fprintf (glog, "Trial %4d, Id %3d -> %4d/%-2d  ",
X      trialno, genes[g]->id, score, level);
X
X    fprintf (glog, "age %2d, %4.0lf+%-4.0lf  %4.1lf+%3.1lf\n",
X	     TRIALS(genes[g]),
X	     mean (&(genes[g]->score)), stdev (&(genes[g]->score)),
X	     mean (&(genes[g]->level)), stdev (&(genes[g]->level)));
X  }
X}
X
X/*
X * openlog: Open the gene log file
X */
X
XFILE *openlog (genelog)
Xregister char *genelog;
X{ glog = wopen (genelog, "a");    
X  return (glog);
X}
X
X/*
X * closelog: Close the log file
X */
X
Xcloselog ()
X{ if (glog) fclose (glog);
X}
X
X/*
X * pickgenotype: Run one trial, record performance, and do some learning
X */
X
Xpickgenotype ()
X{ register int youth, father, mother, new;
X  
X  /* Find genotype with fewer trials than needed to measure its performance */
X  youth = untested ();
X  if (youth >= 0) return (youth);
X
X  /* 
X   * Have a good measure of all genotypes, pick a father, a mother, and
X   * a loser and create a new genotype using genetic operators.
X   */
X
X  father = selectgene (NONE, NONE);
X  mother = selectgene (father, NONE);
X  new = badgene (father, mother);
X
X  /* If no losers yet, return the youngest */
X  if (new < 0) return (youngest ());
X 
X  /* Shift a single genotype with probability pshift */
X  if (randint (100) < pshift)
X  { if (glog)
X    { fprintf (glog, "Select: "); summgene (glog, genes[father]);
X      fprintf (glog, "Death:  "); summgene (glog, genes[new]);
X    }
X 
X    shift (father, new);
X  }
X
X  /* Mutate a single genotype with probability pmutate */
X  else if (randint (100-pshift) < pmutate)
X  { if (glog)
X    { fprintf (glog, "Select: "); summgene (glog, genes[father]);
X      fprintf (glog, "Death:  "); summgene (glog, genes[new]);
X    }
X 
X    mutate (father, new);
X  }
X
X  /* Cross two genotypes with probability 1-pshift-pmutate */
X  else
X  { if (glog)
X    { fprintf (glog, "Select: "); summgene (glog, genes[father]);
X      fprintf (glog, "Select: "); summgene (glog, genes[mother]);
X      fprintf (glog, "Death:  "); summgene (glog, genes[new]);
X    }
X 
X    cross (father, mother, new);
X  }
X
X  /* Log the birth */
X  if (glog) birth (glog, genes[new]);
X
X  return (new);  		/* Evaluate the new genotype */
X}
X
X/*
X * readgenes: Open the genepool for reading, and fill the current gene pool.
X * Returns true if the file was was, and 0 if there was no fail.  Exits
X * if the file exists and cannot be read.
X */
X
Xreadgenes (genepool)
Xregister char *genepool;
X{ char buf[BUFSIZ];
X  register char *b;
X  register int g=0;
X  FILE *gfil;
X
X  if ((gfil = fopen (genepool, "r")) == NULL)
X  { if (fexists (genepool))
X      quit (1, "Cannot open file '%s'\n", genepool);
X    else
X      return (0);
X  }
X
X  /* Read the header line */
X  b = buf;
X  fgets (b, BUFSIZ, gfil);
X  sscanf (b, "%d %d %d %d %d %d",
X	&inittime, &trialno, &lastid, &crosses, &shifts, &mutations);
X  SKIPTO ('|', b);
X  parsestat (b, &g_score);
X  SKIPTO ('|', b);
X  parsestat (b, &g_level);
X
X  /* Now read in each genotype */
X  while (fgets (buf, BUFSIZ, gfil) && length < MAXM-1)
X  { if (g >= length)
X    { genes[g] = (genotype *) malloc (sizeof (**genes));
X      length++;
X    }
X    initgene (genes[g]);
X    parsegene (buf, genes[g++]);
X  }
X
X  fclose (gfil);
X  return (1);
X}
X
X/*
X * parsegene: Given a string representing a genotype and a genotype
X * structure, fill the structure according to the string.
X */
X
Xstatic parsegene (buf, gene)
Xregister char *buf;
Xregister genotype *gene;
X{ register int i;
X
X  /* Get genotype specific info */
X  sscanf (buf, "%d %d %d %d", &gene->id, &gene->creation,
X	  &gene->father, &gene->mother);
X
X  /* Read each DNA gene */
X  SKIPTO ('|', buf);
X  SKIPCHAR (' ', buf);
X  for (i=0; ISDIGIT (*buf); i++)
X  { if (i < MAXKNOB) gene->dna[i] = atoi (buf);
X    SKIPDIG (buf);
X    SKIPCHAR (' ', buf);
X  }
X
X  /* Read the score and level performance stats */
X  SKIPTO ('|', buf);
X  parsestat (buf, &(gene->score));
X  SKIPTO ('|', buf);
X  parsestat (buf, &(gene->level));
X}
X
X/*
X * writegenes: Write the gene pool 'genes' out to file 'genepool'
X */
X
Xwritegenes (genepool)
Xregister char *genepool;
X{ register FILE *gfil;
X  register int g;
X
X  /* Open the gene file */
X  if ((gfil = wopen (genepool, "w")) == NULL)
X    quit (1, "Cannot open file '%s'\n", genepool);
X
X  /* Write the header line */
X  fprintf (gfil, "%d %d %d %d %d %d",
X	   inittime, trialno, lastid, crosses, shifts, mutations);
X  fprintf (gfil, "|");
X  writestat (gfil, &g_score);
X  fprintf (gfil, "|");
X  writestat (gfil, &g_level);
X  fprintf (gfil, "|\n");
X
X  /* Loop through each genotype */
X  for (g=0; g<length; g++)
X    writegene (gfil, genes[g]);
X  
X  fclose (gfil);
X}
X
X/*
X * Write out one line representing the gene.
X */
X
Xstatic writegene (gfil, g)
Xregister FILE *gfil;
Xregister genotype *g;
X{ register int i;
X
X  /* Print genotype specific info */
X  fprintf (gfil, "%3d %4d %3d %3d|", g->id, g->creation,
X	  g->father, g->mother);
X
X  /* Write out dna */
X  for (i=0; i<MAXKNOB; i++) 
X  { fprintf (gfil, "%2d", g->dna[i]);
X    if (i < MAXKNOB-1) fprintf (gfil, " ");
X  }
X  fprintf (gfil, "|");
X
X  /* Write out statistics */
X  writestat (gfil, &(g->score));
X  fprintf (gfil, "|");
X  writestat (gfil, &(g->level));
X  fprintf (gfil, "|\n");
X}
X
X/*
X * initgene: Allocate a new genotype structure, set everything to 0.
X */
X
Xstatic initgene (gene)
Xregister genotype *gene;
X{ register int i;
X
X  /* Clear genoptye specific info */
X  gene->id = gene->creation = gene->father = gene->mother = 0;
X
X  /* Clear the dna */
X  for (i = 0; i < MAXKNOB; i++) gene->dna[i] = 0;
X
X  /* Clear the statictics */
X  clearstat (&(gene->score));
X  clearstat (&(gene->level));
X}
X
X/*
X * compgene: Compare two genotypes in terms of score.
X */
X
Xstatic int compgene (a, b)
Xgenotype **a, **b;
X{ register int result;
X
X  result = (int) mean (&((*b)->score)) - 
X           (int) mean (&((*a)->score));
X
X  if (result) return (result);
X  else return ((*a)->id - (*b)->id);
X}
X
X/*
X * summgene: Summarize a single genotype
X */
X
Xstatic summgene (f, gene)
Xregister FILE *f;
Xregister genotype *gene;
X{ fprintf (f, "%3d age %2d, created %4d, ",
X	   gene->id, TRIALS(gene), gene->creation);
X  fprintf (f, "score %5.0lf+%-4.0lf level %4.1lf+%-3.1lf\n",
X           mean (&(gene->score)), stdev (&(gene->score)),
X           mean (&(gene->level)), stdev (&(gene->level)));
X}
X
X/*
X * Birth: Summarize Record the birth of a genotype.
X */
X
Xstatic birth (f, gene)
Xregister FILE *f;
Xregister genotype *gene;
X{
X  if (!glog) return;
X
X  fprintf (f, "Birth:  %d ", gene->id);
X
X  if (gene->mother)
X    fprintf (f, "(%d,%d)", gene->father, gene->mother);
X  else
X      fprintf (f, "(%d)", gene->father);
X
X  fprintf (f, " created %d, DNA ", gene->creation);
X  printdna (f, gene);
X  fprintf (f, "\n");
X}
X
X/*
X * printdna: Print the genotype of a gene
X */
X
Xstatic printdna (f, gene)
XFILE *f;
Xregister genotype *gene;
X{ register int i;
X
X  fprintf (f, "(");
X  for (i=0; i < MAXKNOB; i++)
X  { fprintf (f, "%02d", gene->dna[i]);
X    if (i < MAXKNOB-1) fprintf (f, " ");
X  }
X  fprintf (f, ")");
X}
X
X/*
X * cross: Cross two genotypes producing a new genotype
X */
X
Xstatic cross (father, mother, new)
Xregister int father, mother, new;
X{ register int cpoint, i;
X
X  /* Set the new genotypes info */
X  genes[new]->id = ++lastid;
X  genes[new]->creation = trialno;
X  genes[new]->father = genes[father]->id;
X  genes[new]->mother = genes[mother]->id;
X  clearstat (&(genes[new]->score));
X  clearstat (&(genes[new]->level));
X  
X  /* Pick a crossover point and dominant parent */
X  cpoint = randint (MAXKNOB-1) + 1;
X
X  /* Fifty/fifty chance we swap father and mother */
X  if (randint (100) < 50)
X  { father ^= mother; mother ^= father; father ^= mother; }
X
X  /* Copy the dna over */
X  for (i=0; i<MAXKNOB; i++)
X    genes[new]->dna[i] = (i<cpoint) ?
X      genes[father]->dna[i] : genes[mother]->dna[i];
X
X  makeunique (new);
X
X  /* Log the crossover */  
X  if (glog)
X  { fprintf (glog, "Crossing %d and %d produces %d\n",
X		genes[father]->id,  genes[mother]->id, genes[new]->id);
X  }
X  
X  crosses++;
X}
X
X/*
X * mutate: mutate a genes producing a new gene
X */
X
Xstatic mutate (father, new)
Xregister int father, new;
X{ register int i;
X
X  /* Set the new genotypes info */
X  genes[new]->id = ++lastid;
X  genes[new]->creation = trialno;
X  genes[new]->father = genes[father]->id;
X  genes[new]->mother = 0;
X  clearstat (&(genes[new]->score));
X  clearstat (&(genes[new]->level));
X
X  /* Copy the dna over */  
X  for (i=0; i<MAXKNOB; i++)
X    genes[new]->dna[i] = genes[father]->dna[i];
X
X  /* Randomly change genes until the new genotype is unique */
X  do
X  { i=randint (MAXKNOB);
X    genes[new]->dna[i] = (genes[new]->dna[i] +
X			  triangle (20) + ALLELE) % ALLELE;
X  } while (!unique (new));
X
X  /* Log the mutation */
X  if (glog)
X  { fprintf (glog, "Mutating %d produces %d\n",
X		genes[father]->id, genes[new]->id);
X  }
X
X  mutations++;
X}
X
X/*
X * shift: shift a gene producing a new gene
X */
X
Xstatic shift (father, new)
Xregister int father, new;
X{ register int i, offset;
X  
X  /* Set the new genotypes info */
X  genes[new]->id = ++lastid;
X  genes[new]->creation = trialno;
X  genes[new]->father = genes[father]->id;
X  genes[new]->mother = 0;
X  clearstat (&(genes[new]->score));
X  clearstat (&(genes[new]->level));
X
X  /* Pick an offset, triangularly distributed around 0, until unique */
X  offset = triangle (20);
X  for (i=0; i<MAXKNOB; i++)
X    genes[new]->dna[i] = (genes[father]->dna[i] + 
X			  offset + ALLELE) % ALLELE;
X
X  makeunique (new);
X
X  /* Now log the shift */
X  if (glog)
X  { fprintf (glog, "Shifting %d by %d produces %d\n",
X		genes[father]->id, offset, genes[new]->id);
X  }
X
X  shifts++;
X}
X
X/*
X * randompool: Initialize the pool to a random starting point
X */
X
Xstatic randompool (m)
Xregister int m;
X{ register int i, g;
X
X  for (g=0; g<m; g++)
X  { if (g >= length)
X    { genes[g] = (genotype *) malloc (sizeof (**genes));
X      length++;
X    }
X    initgene (genes[g]);
X    genes[g]->id = ++lastid;
X    for (i=0; i<MAXKNOB; i++) genes[g]->dna[i] = randint (ALLELE);
X    birth (glog, genes[g]);
X  }
X  
X  length = m;
X}
X
X/*
X * selectgene: Select a random gene, weighted by mean score.
X */
X
Xstatic selectgene (e1, e2)
Xregister int e1, e2;
X{ register int total=0;
X  register int g;
X
X  /* Find the total worth */
X  for (g=0; g<length; g++)
X  { if (g==e1 || g==e2) continue;
X    /* total += (int) mean (&(genes[g]->score)); */
X    total += genes[g]->score.high;
X  }
X  
X  /* Pick a random number and find the corresponding gene */
X  if (total > 0)
X  { for (g=0, total=randint (total); g<length; g++)
X    { if (g==e1 || g==e2) continue;
X      /* total -= (int) mean (&(genes[g]->score)); */
X      total -= genes[g]->score.high;
X      if (total < 0) return (g);
X    }
X  }
X
X  /* Total worth zero, pick any gene at random */
X  while ((g = randint (length))==e1 || g==e2) ;
X  return (g);
X}
X
X/*
X * unique: Return false if gene is an exact copy of another gene.
X */
X
Xstatic unique (new)
Xregister int new;
X{ register int g, i, delta, sumsquares;
X
X  for (g=0; g<length; g++)
X  { if (g != new)
X    { sumsquares = 0;
X      for (i=0; i<MAXKNOB; i++)
X      { delta = genes[g]->dna[i] - genes[new]->dna[i];
X	sumsquares += delta * delta;
X      }
X      if (sumsquares < mindiff) return (0);
X    }
X  }
X  
X  return (1);
X}
X
X/*
X * untested: Return the index of the youngest genotype with too few
X * trials to have an accurate measure.  The number of trials is
X * greater for older genotypes.
X */
X
Xstatic untested ()
X{ register int g, y= -1, trials=1e9, newtrials, count=length;
X  
X  for (g = randint (length); count-- > 0; g = (g+1) % length)
X  { if (TRIALS (genes[g]) >= trials) continue;
X
X    newtrials = trialno - genes[g]->creation;	/* Turns since creation */
X
X    if (TRIALS (genes[g]) < newtrials / (4 * length) + mintrials)
X    { y = g; trials = TRIALS (genes[g]); }
X  }
X
X  return (y);
X}
X
X/*
X * youngest: Return the index of the youngest genotype
X */
X
Xstatic youngest ()
X{ register int g, y=0, trials=1e9, newtrials, count=length;
X  
X  for (g = randint (length); count-- > 0; g = (g+1) % length)
X  { newtrials = TRIALS (genes[g]);
X    if (newtrials < trials) { y=g; trials=newtrials; }
X  }
X
X  return (y);
X}
X
X/*
X * makeunique: Mutate a genotype until it is unique
X */
X
Xstatic makeunique (new)
Xregister int new;
X{ register int i;
X
X  while (!unique (new))
X  { i=randint (MAXKNOB);
X    genes[new]->dna[i] = (genes[new]->dna[i] +
X		          triangle (20) + ALLELE) % ALLELE;
X  }
X}
X
X/*
X * triangle: Return a non-zero triangularly distributed number from -n to n.
X */
X
Xstatic triangle (n)
Xregister int n;
X{ register int val;
X
X  do
X  { val = randint (n) - randint (n);
X  } while (val==0);
X  
X  return (val);
X}
X
X/*
X * badgene: Find the worst performer so far (with the lowest id).
X * only consider genotypes dominated by other genotypes.
X */
X
Xstatic badgene (e1, e2)
Xregister int e1, e2;
X{ register int g, worst, trials;
X  double worstval, bestval, avg, dev, value;
X
X  worst = -1; worstval = 1.0e9;
X  bestval = -1.0e9;
X    
X  for (g=0; g<length; g++)
X  { if ((trials = TRIALS (genes[g])) < mintrials) continue;
X    avg = mean (&(genes[g]->score));    
X    dev = stdev (&(genes[g]->score)) / sqrt ((double) trials);
X    value = avg - step * dev;
X    if (value > bestval) { bestval=value; }
X    if (g==e1 || g==e2) continue;
X    value = avg + step * dev;
X    if (value < worstval) { worst=g; worstval=value; }
X  }
X
X  if (worstval < bestval)	return (worst);
X  else				return (-1);
X}
/
echo 'x - tactics.c'
sed 's/^X//' > tactics.c << '/'
X/*
X * tactics.c: Rog-O-Matic XIV (CMU) Thu Jan 31 20:31:22 1985 - mlm
X * Copyright (C) 1985 by A. Appel, G. Jacobson, L. Hamey, and M. Mauldin
X *
X * This file contains all of the 'medium level intelligence' of Rog-O-Matic. 
X */
X
X# include <stdio.h>
X# include <ctype.h>
X# include <curses.h>
X# include "types.h"
X# include "globals.h"
X# include "install.h"
X
X/*
X * handlearmor: This routine is called to determine whether we should 
X * take off or put on armor.
X *
X * Current strategy:   Wear best armor on levels 1..7 or 19 on or
X *                     if protected or have maintain armor.
X *                     Wear 2nd best armor between levels 13..18.
X *                     Wear best leather armor between levels 8..12   
X *                     or 2nd best if no leather armor.   DR UTexas 12/15/83
X *
X * Note that leather armor does not rust.
X */
X
Xhandlearmor ()
X{ int obj;
X
X  /* Only check when armor status is different */
X  if (!newarmor || cursedarmor) return (0);
X
X  /* 
X   * Pick the armor we want to wear. If we are worried about rust monster
X   * we wear the second best armor, but if we wont see any rust monsters,
X   * if our armor is too good for a rust monster to hit it, or we have a
X   * ring of maintain armor, then we should wear our best armor.  On
X   * levels 13-18 we wear our second best no matter what.
X   */
X   
X  obj = havearmor (1, NOPRINT, ANY);		/* Get best armor */
X
X  if (Level > 7 && Level < 19 && 
X      wearing ("maintain armor") == NONE &&
X      willrust (obj) &&
X      itemis (obj, KNOWN))
X  { if (Level < 13)
X      obj = havearmor (1, NOPRINT, RUSTPROOF);
X    if (Level >= 13 || obj == NONE)
X      obj = havearmor (2, NOPRINT, ANY);
X  }
X    
X  /* If  the new armor is really bad, then don't bother wearing any */
X  if (obj != NONE &&
X      (armorclass (obj) > 9) ||
X      (itemis (obj, CURSED) &&
X       (havenamed(scroll, "remove curse") == NONE) &&
X       (armorclass (obj) > 6))) 
X  { obj = NONE; }
X
X  /* If we are wearing the right armor, then dont bother */
X  if (obj == currentarmor)
X  { newarmor = 0; return (0); }
X
X  /* Debugging */
X  dwait (D_PACK, "handlearmor: obj %d, currentarmor %d", obj, currentarmor);
X
X  /* Take off the wrong armor */
X  if (currentarmor != NONE && takeoff ())
X  { return (1); }
X
X  /* Put on the right armor, avoid wearing cursed armor */
X  if (obj != NONE)
X  { return (wear (obj)); }
X
X  /* If we have no armor, then forget it */
X  newarmor = 0;
X  return (0);
X}
X
X/* 
X * handleweapon: wield our best weapon. Calls haveweapon.
X *
X *  The current strategy is to wield the best weapon from haveweapon.
X */
X
Xhandleweapon ()
X{ int obj; 
X
X  if ((!newweapon || cursedweapon) && !wielding (thrower)) return (0);
X
X  /* haveweapon (1) returns the index of the best weapon in the pack */
X  if ((obj = haveweapon (1, NOPRINT)) < 0) return (0);
X  
X  /* If we are not wielding our best weapon, do so */
X  if (obj == currentweapon) { newweapon = 0; return (0); }
X  else if (obj != NONE)        { return (wield (obj)); }
X  else                      { newweapon = 0; return (0); }
X}
X
X/*
X * quaffpotion: check whether we should quaff a potion, and call
X * quaff if so.  We quaff add strength, restore strength, healing, 
X * extra healing, and raise level here.  Potions of seeinvisible
X * are handled in 'fightinvisible'.
X *
X * If we are at or below the exp. level, then experiment with unknown potions.
X */
X
X# define MAXSTR (version < RV52A ? 1900 : 3100)
X
Xquaffpotion ()
X{ int obj = NONE, obj2 = NONE;
X
X  /* Take advantage of double haste bug -- assures permanent haste */
X  if (!doublehasted && version < RV52A &&
X      ((hasted && (obj = havenamed (potion, "haste self")) != NONE) ||
X       ((obj = havemult (potion, "haste self", 2)) != NONE)) &&
X      quaff (obj))
X    return (1);
X
X  /* 
X   * Can we use a gain strength to our advantage? Or a restore?
X   * If we have a Gain Strength, or our strength is very bad,
X   * then we quaff a Regain Strength.
X   */
X   
X  if (Str == Strmax && (obj = havenamed (potion, "gain strength")) != NONE &&
X      quaff (obj))
X    return (1);
X
X  if ((Str < 700 ||
X       (Str != Strmax && (havenamed (potion, "gain strength") != NONE))) &&
X      (obj = havenamed (potion, "restore strength")) != NONE &&
X      quaff (obj))
X    return (1);
X
X  if ((Str < 1600 || Level > 12) &&
X      (obj = havemult (potion, "restore strength", 2)) != NONE &&
X      quaff (obj))
X    return (1);
X
X  /* Try to get unblinded by quaffing a potion */
X  if (blinded && 
X      ((obj = havenamed (potion, "healing")) != NONE ||
X       (obj = havenamed (potion, "extra healing")) != NONE ||
X       (obj = havenamed (potion, "see invisible")) != NONE) &&
X      quaff (obj))
X    return (1);
X
X  /* Try to get uncosmic by quaffing a potion */
X  if (cosmic &&
X      (obj = havenamed(potion, "extra healing")) != NONE &&
X      quaff (obj))
X    return (1);
X
X  if (cosmic && Str != Strmax &&
X      (obj = havenamed (potion, "poison")) != NONE)
X  { if (wearing ("sustain strength") != NONE && quaff (obj) ||
X        findring ("sustain strength"))
X      return (1);
X  }
X
X  /* 
X   * Quaff healing to raise our MaxHp
X   * Wait for cosmic known to quaff extra healing. DR,TG  UTexas
X   */
X
X  if (Hp == Hpmax &&
X      ((obj = havemult (potion, "healing", 2)) != NONE ||
X       (obj = havemult (potion, "extra healing", 2)) != NONE ||
X       know ("blindness") && (obj = havenamed (potion, "healing")) != NONE ||
X       know ("blindness") && (know ("hallucination") || version < RV53A)  &&
X        Level < 15 && (obj = havenamed (potion, "extra healing")) != NONE) &&
X      quaff (obj))
X    return (1);
X
X  /*
X   * Quaff a raise level potion?
X   */
X  
X  if ((Explev > 8 || Level > 13) &&
X      (obj = havenamed (potion, "raise level")) != NONE && 
X      quaff (obj))
X    return (1);
X
X  /* Quaff an unknown potion? */
X  if ((Level >= (k_exper/10) || objcount >= maxobj || Str<1000 || blinded) &&
X      (obj = unknown (potion)) != NONE)
X  { if ((obj2 = wearing ("add strength")) != NONE && removering (obj2))
X      return (1);
X    else if (wearing ("sustain strength") < 0 &&
X             (obj2 = havenamed (ring, "sustain strength")) != NONE &&
X             puton (obj2))
X      return (1);
X    else if (quaff (obj))
X      return (1);
X  }
X
X  return (0);
X}
X
X/*
X * readscroll: check whether we should read a scroll, and call reads
X * to actually read it.
X *
X * Scrolls of identify, remove curse, genocide, enchant weapon, 
X * enchant armor, magic mapping are defined.  Scrolls of scare
X * monster and confuse monster are handled in 'battlestations'.
X * 
X * If we are at or below (k_exper/10), experiment with unknown scrolls.
X * Make certain that we are wearing our best armor when reading
X * enchant armor or an unknown scroll (which could be enchant
X * armor).
X */
X
Xreadscroll ()
X{ register int obj, obj2;
X
X  /* Check the item specific identify scrolls first */
X  if (((obj = havenamed (scroll, "identify armor")) != NONE &&
X       (obj2 = unknown (armor)) != NONE) ||
X      ((obj = havenamed (scroll, "identify weapon")) != NONE &&
X       (obj2 = unknown (hitter)) != NONE) ||
X      ((obj = havenamed (scroll, "identify potion")) != NONE &&
X       (obj2 = unknown (potion)) != NONE) ||
X      ((obj = havenamed (scroll, "identify scroll")) != NONE &&
X       (obj2 = unknown (scroll)) != NONE) ||
X      ((obj = havenamed (scroll, "identify ring, wand or staff")) != NONE &&
X       ((obj2 = unknown (ring)) != NONE || (obj2 = unknown (wand)) != NONE)))
X  { prepareident (obj2, obj);
X    return (reads (obj)); }
X
X  /* In older version, have multiple uses for generic identify scrolls */
X  if ((obj = havenamed (scroll, "identify")) != NONE &&
X      (currentweapon != NONE) &&
X      (!itemis (currentweapon, KNOWN) && 
X        (!usingarrow || goodarrow > 20)))
X  { prepareident (currentweapon, obj);
X    return (reads (obj)); }
X
X  if ((obj = havenamed (scroll, "identify")) != NONE &&
X      ((obj2 = unknown (ring)) != NONE ||
X       (obj2 = unidentified (wand)) != NONE ||
X       (obj2 = unidentified (scroll)) != NONE ||
X       Level > 10 && (obj2 = unknown (wand)) != NONE ||
X       ((cheat || version == RV36A) &&
X        ((obj2 = unknown (potion)) != NONE ||
X         (obj2 = haveother (scroll)) != NONE))))
X  { prepareident (obj2, obj);
X    return (reads (obj)); }
X
X  if ((cursedarmor || cursedweapon) &&
X      (obj = havenamed (scroll, "remove curse")) != NONE)
X    return (reads (obj));
X
X  if ((obj = havenamed (scroll, "genocide")) != NONE)
X    return (reads (obj));
X
X  if (currentweapon != NONE && 
X      (goodweapon || usingarrow || MaxLevel > 12) &&
X      (obj = havenamed (scroll, "enchant weapon")) != NONE)
X    return (reads (obj));
X
X  if (Level != didreadmap && Level > 12 &&
X       (obj = havenamed (scroll, "magic mapping")) != NONE)
X    return (reads (obj));
X
X  /* About to read an unknown scroll. We will assure that we have */
X  /* a weapon in hand, and put on our best armor for the occasion */
X  /* We must also prepare to identify something, just in case.    */
X
X  if ((obj = havenamed (scroll, "enchant armor")) != NONE ||
X      (obj = havenamed (scroll, "protect armor")) != NONE ||
X      ((currentweapon != NONE) &&
X       (Level >= (k_exper/10) || objcount >= maxobj ||
X        cursedarmor || cursedweapon) &&
X       (exploredlevel || know ("aggravate monster")) &&
X       (obj = unknown (scroll)) != NONE))
X  { prepareident (pickident (), obj);
X
X    /* Go to a corner to read the scroll */
X    if (version <= RV36B && know ("create monster") == '\0' && gotocorner ())
X      return (1);
X
X    /* Must put on our good armor first */
X    if (!cursedarmor && 
X        (!know("enchant armor") || stlmatch(inven[obj].str, "enchant armor") ||
X         !know("protect armor") || stlmatch(inven[obj].str, "protect armor")))
X    { int obj2 = havearmor (1, NOPRINT, ANY); /* Pick our best armor */
X
X      if (obj2 == currentarmor);
X
X      /* Take off the bad stuff */
X      else if (currentarmor != NONE && takeoff ()) return (1);
X
X      /* Put on the good stuff */
X      else if (obj2 != NONE && wear (obj2)) return (1);
X    }
X
X    /* No armor handling, so read the scroll */    
X    return (reads (obj));
X  }
X
X  return (0);
X}
X
X/*
X * handlering: check whether we should put on a ring, and call
X * puton to wear it.  Calls 'havering' to find the two best rings
X * and wears them if their evaluations are greater than 1000.
X *
X * 'havering' understands about when different rings are good, and how
X * much food we need to use each ring.
X */
X
Xhandlering ()
X{ int ring1, ring2;
X
X  if (!newring && !beingstalked) return (0);
X
X  ring1 = havering (1, NOPRINT);
X  ring2 = havering (2, NOPRINT);
X
X  dwait (D_PACK, "Handlering: ring1 %d, ring2 %d, left %d, right %d", 
X	 ring1, ring2, leftring, rightring);
X
X  if ((leftring == ring1 && rightring == ring2) ||
X      (rightring == ring1 && leftring == ring2))
X  { newring = 0; return (0);
X  }
X
X  if (leftring != NONE && leftring != ring1 && leftring != ring2 &&
X      removering (leftring))
X  { return (1);
X  }
X
X  if (rightring != NONE && rightring != ring1 && rightring != ring2 &&
X      removering (rightring))
X  { return (1);
X  }
X
X  if (ring1 != leftring && ring1 != rightring && puton (ring1))
X  { return (1);
X  }
X
X  if (ring2 != leftring && ring2 != rightring && puton (ring2))
X  { return (1);
X  }
X  
X  return (0);
X}
X
X/*
X * findring: called with the named of a ring, attempts to locate such
X * a ring in the pack and wear it. It will remove rings (other than
X * maintain armor) to accomplish this task if it we are wearing two
X * rings.
X *
X * Could be extended to have an ordering of rings to wear.
X */
X
Xfindring (name)
Xchar *name;
X{ int obj;
X
X  if ((obj = havenamed (ring, name)) < 0 ||
X      wearing (name) != NONE)
X    return (0);
X
X  if (leftring != NONE && rightring != NONE)
X  { if (stlmatch (inven[leftring].str, "maintain armor"))
X      return (removering (rightring));
X    else
X      return (removering (leftring));
X  }
X
X  return (puton (obj));
X}
X
X/*
X * grope: get to a safe square and sit and vibrate (move back and forth)
X * and then sleep for 'turns' turns.
X *
X * Problem: We need to know which side of us the monster is on. Then
X * we could zap him with wands or staves.  This requires some kind of
X * memory and the ability to detect when the motion command (ie 'hit'
X * fails to move us).		MLM
X */
X
Xgrope (turns)
Xregister int turns;
X{ register int k, moves;
X
X  if (atrow < 2 || atcol < 1)
X  { command (T_GROPING, "%ds", (turns > 0) ? turns : 1);  
X    return (1);
X  }
X
X  /* Count adjacent CANGO squares */  
X  for (k=0, moves=0; k<8; k++)
X    if (onrc(CANGO, atdrow(k), atdcol(k))) moves++;
X
X  if (moves > 2 && findsafe ()) /* find a spot with 2 or fewer moves */
X    return (1);
X
X  /* blindir is direction of adjacent CANGO square which is not a trap */
X  for (k=0; k<4; k++, blindir = (blindir+2) % 8)
X    if ((onrc(CANGO|TRAP, atdrow(blindir), atdcol(blindir)) == CANGO)) 
X      break;
X
X  if (turns) command (T_GROPING, "%c%c%ds", keydir[blindir],
X                      keydir[(blindir+4)&7], turns);
X  else       command (T_GROPING, "%c%c", keydir[blindir],
X                      keydir[(blindir+4)&7]);
X
X  blindir = (blindir+2) % 8;
X  return (1);
X}
X
X/*
X * findarrow: This function tries to run over an arrow trap to get a 
X *            magic arrow. Make certain we have some food.
X */
X
Xfindarrow ()
X{
X  /* If wrong version, not cheating or must go find food, then forget it */
X  if (version > RV36B || !cheat || hungry())  
X    return (0);
X
X  else if (!usingarrow && foundarrowtrap && !on (ARROW) &&
X           gotowards (trapr, trapc, 0))
X  { display ("Trying for arrow..."); return (1); }
X  
X  return (0);
X}
X
X/* 
X * checkcango: verify that a missile fired in direction 'dir' will
X *             travel 'turns' turns.
X *
X * Modified by mlm, 5/31/83: Return false if a monster is in the way.
X * only return true if the missile will travel EXACTLY the distance
X * specified.  Also changed it to not check the current square (since
X * we can fire from a door, even if we cant shoot through one).
X */
X
Xcheckcango (dir, turns)
Xregister int dir, turns;
X{ register int r, c, dr, dc;
X
X  for (dr = deltr[dir], dc = deltc[dir], r=atrow+dr, c=atcol+dc;
X       turns > 0 && onrc (CANGO | DOOR, r, c) == CANGO;
X       r+=dr, c+=dc, turns--)
X    ;
X
X  return (turns==0);
X}
X
X/*
X * godownstairs: issues a down command and check for the halftimeshow.
X */
X
Xgodownstairs (running)
Xregister int running; /* True ==> dont do anything fancy */
X{ register int p;
X  int genericinit(), downvalue();
X
X  /* We dont want to go down if we have just gotten an arrow, since */
X  /* It is probably bad, and we will want to go back to the trap;   */
X  /* Dont go down until we have killed five monsters in one blow.   */
X  /* While waiting, run back and forth to look for monsters.        */
X
X  if (cheat && version <= RV36B && !running &&
X      foundarrowtrap && usingarrow && 
X      have (food) != NONE && goodarrow < 5 && waitaround ())
X  { saynow ("Checking out arrow...");
X    return (1);
X  }
X
X  /* Check for applicability of this rule */
X  if (! new_stairs) return (0);
X
X  /* If we are on the stairs, perhaps we should rest up some */
X  p = between ((Explev+larder)*10, 60, 100);
X             
X  if (atrow == stairrow && atcol == staircol && 
X      !running && larder > 0 && Hp < max (10, percent (Hpmax, p)))
X  { command (T_RESTING, "s");
X    display ("Resting on stairs before next level");
X    return (1);
X  }
X
X  /* Allow other rules a chance to notice that we are done with the level */
X  if (on (STAIRS) && !exploredlevel)
X  { exploredlevel = 1; return (1); }
X
X  /* If we are floating, we cant go down, either rest or fail */
X  if (floating && running)
X  { saynow ("Cannot escape, floating in mid-air!"); return (0); }
X  else if (floating)
X  { saynow ("Floating above stairs...");
X    command (T_RESTING, "s"); return (1); }
X
X  /* If we are on the stairs, go down */
X  if (on (STAIRS))
X  { halftimeshow (Level);
X
X    /* Start logging at Level GOODGAME, if we arent already */
X    if (Level > (GOODGAME-2) && !replaying && !logging) toggleecho ();
X
X    /* Send the DOWN command and return */
X    command (T_MOVING, ">");
X    return (1);
X  }
X
X  /* If we are running and can run to the next level, do that */
X  if (running && makemove (RUNDOWN, genericinit, downvalue, REEVAL))
X  { return (1);
X  }
X
X  /* If we see the stairs or a trap door, go there */
X  if (!running && makemove (DOWNMOVE, genericinit, downvalue, REUSE))
X  { goalr = targetrow; goalc = targetcol;   /* Set a goal (CPU time hack) */
X    return (1);
X  }
X   
X new_stairs = 0;
X return (0);
X}
X
X/* 
X * plunge: Should we head down immediately?
X *
X * If we are being teleported too much or
X *    we are on a bad level (19 to 25) or
X *    we want to get past Rust Monsters (level 18) or
X *    we have aggravated all of the monsters then
X *
X * we head down immediately.
X */
X 
Xplunge ()
X{
X  /* Check for applicability of this rule */
X  if (stairrow < 0 && !foundtrapdoor) return (0);
X
X  if (teleported > (larder+1)*5 && godownstairs (NOTRUNNING))
X  { if (!on (STAIRS)) saynow ("Giving up on level, too much teleporting");
X    return (1);
X  }
X
X  if (Level > 17 && Level < 26 && godownstairs (NOTRUNNING))
X  { if (!on (STAIRS)) saynow ("Plunge mode!!!");
X    return (1);
X  }
X
X  if (aggravated && godownstairs (NOTRUNNING))
X  { if (!on (STAIRS)) saynow ("Running from aggravated monsters");
X    return (1);
X  }
X
X  if (haveexplored (9) && godownstairs (NOTRUNNING))
X  { if (!on (STAIRS)) saynow ("Level explored");
X    return (1);
X  }
X
X  return (0);
X}
X
X/*
X * waitaround: Hang around here waiting for monsters.
X */
X
Xstatic struct { int vertstart, 
X		    vertend, 
X		    vertdelt, 
X		    horstart, 
X		    horend, 
X		    hordelt; } cb [4] = 
X	{ {  3, 21,  1,  1, 78,  1},	/* Top left corner */
X	  {  3, 21,  1, 78,  1, -1},	/* Top right corner */
X	  { 21,  3, -1, 78,  1, -1},	/* Bottom right corner */
X	  { 21,  3, -1,  1, 78,  1} };  /* Bottom left corner */
X
Xstatic gc = 0; /* Goal corner from 0..3 */
X
X/* 
X * waitaround: For some reason we want to stay on this level for a while.
X * Try running to each corner of the level.
X */
X
Xwaitaround ()
X{ register int i, j;
X
X  if (gotowardsgoal ()) return (1);
X
X  gc = ++gc % 4;
X
X  for (i = cb[gc].vertstart; i != cb[gc].vertend; i += cb[gc].vertdelt)
X    for (j = cb[gc].horstart; j != cb[gc].horend; j += cb[gc].hordelt)
X      if (onrc (BEEN | CANGO | ROOM, i, j) &&
X          !onrc (TRAP, i, j) && gotowards (i, j, 0))
X      { goalr = i; goalc = j; return (1); }
X
X  return (0);
X}
X
X/*
X * goupstairs:
X *
X *      If we have the amulet, and our score is good enough, then
X *      go up stairs. This function also checks for the end of the
X *      game, and issues the proper calls to get the score written.
X */
X
Xgoupstairs (running)
Xint running;
X{ int obj;
X
X  /* Check for applicability of this rule */
X  if (stairrow < 0 || have(amulet) < 0 ||
X      (!running && quitat < BOGUS && Gold <= quitat))
X    return (0);
X      
X  /* If we are on the stairs, then check for win, else go up */
X  if (atrow == stairrow && atcol == staircol)
X  { 
X    /* If we are about to win, dump any magic arrows or minus things */
X    if (Level == 1 && 
X        ((obj = havearrow ()) != NONE || (obj = haveminus ()) != NONE))
X    { throw (obj, 0); return (1); }
X
X    /* No magic arrows, time to leave */
X    else if (Level == 1)
X    { 
X      /* Send an up command and a space to clear the 'You Made It' */
X      sendnow ("< ");
X
X      /* Now read chars until we have the end of the inventory. */
X      /* Note misspelling in Rogue 'Peices', so dont assume anything */
X      waitfor ("Gold P");
X
X      /* Note that quitrogue sends a '\n' to get the score */
X      quitrogue ("total winner", Gold, 0);
X      return (1);
X    }
X
X    /* Not at the top yet, keep on trucking */
X    else
X    { command (T_MOVING, "<"); return (1); }
X  }
X
X  /* If we know where the stairs are, go there */
X  else if ((goalr = stairrow) > 0 && (goalc = staircol) > 0 &&
X           gotowards (goalr, goalc, running)) 
X    return (1);
X
X  return (0);
X}
X
X/*
X * restup: If we are low on hit points, sit for a while. Since handlering 
X * was called first, we will be wearing a ring of regeneration if need be.
X * 
X * First we find a good place to rest (we will move into a room, but not
X * out of one).  In lit rooms, stand far from doors so we can shoot
X * arrows at things coming in.  In dark rooms, stand diagonally away
X * from doors (so we get a one turn warning of monsters coming in that
X * door).  In either case, stand on stairs or next to trap doors and
X * teleport traps).
X *  
X * Then rest by searching 's'.  If one blow would not kill us, and we
X * dont plan to shoot arrows, then rest up so as to heal one hit point.
X * If we are critically low, rest up one turn at a time.
X * 
X * Other considerations:	Dont move if confused or cosmic.
X *				Drink healing potions if really low.
X *				Dont rest when hungry (and no food)
X */
X
Xrestup ()
X{ register int obj, turns;
X
X  /* If we are confused, sit still so we dont bump into anything bad */
X  if (confused) { command (T_RESTING, "s"); return (1); }
X
X  /* If cosmic and plenty of hit points and food, rest for long periods */
X  if (cosmic && (Hp >= percent (Hpmax, 80)) && larder > 2)
X  { display ("Oh wow man, I'm contemplating my navel!");
X    command (T_RESTING, "100s"); return (1); }  
X
X  /* If we are well, return */
X  if (Hp >= max (8, percent (Hpmax, between (Explev*10+k_rest-50, 40, 80))))
X  { unrest ();  return (0); }
X
X  /*
X   * If we are really ill then try a healing potion (save a healing
X   * potion for blindness, extra healing for hallucination).
X   */
X
X  if (Hp < Level+10 && Hp < Hpmax/3 &&
X      ((obj = havemult (potion, "extra healing", 2)) != NONE ||
X       (obj = havemult (potion, "healing", 2)) != NONE ||
X       (know ("hallucination") &&
X        (obj = havenamed (potion, "extra healing")) != NONE) ||
X       (know ("blindness") &&
X        (obj = havenamed (potion, "healing")) != NONE)) &&
X      quaff (obj))
X  { return (1); }
X
X  /* Dont rest when we havent enough to eat */
X  if (hungry ()) return (0);
X
X  display ("Resting up...");
X
X  /*
X   * Look for a good place to rest
X   */
X
X  if (movetorest ()) return (1);
X
X  /* 
X   * If we are very ill, or we are very deep, or we are in a lit room
X   * and can shoot at things as they come ate us, rest only one turn so
X   * monsters dont get the first shot. Otherwise rest enough turns 
X   * to heal one step.
X   */
X  
X  turns = (Level < 8) ? (20-Explev*2) : 3;
X  if ((!darkroom () && ammo) || Hp < Level*2+8 || Level > 15) turns = 1;
X
X  command (T_RESTING, "%ds", turns);
X  return (1);
X}
X
X/*
X * If goalr and goalc are set (not -1,-1) then attempt to move towards
X * that square. Calls gotowards which calls bfsearch.
X */
X
Xgotowardsgoal ()
X{ if (goalr > 0 && goalc > 0)   /* Keep on trucking */
X  { if (goalr == atrow && goalc == atcol) { goalr = NONE; goalc = NONE; }
X    else if (gotowards (goalr, goalc, 0)) { return (1); }
X    else                                  { goalr = NONE; goalc = NONE; }
X  }
X  
X  return (0);
X}
X
X/*
X * gotocorner:	Find a corner using downright and try to go there.
X *		This is done so we can destroy old wands by throwing
X *		them into the corner (which destroys them).
X */
X
Xgotocorner ()
X{ int r, c;
X  if (!downright (&r, &c)) return (0);
X  if (debug (D_SCREEN))
X  { saynow ("Gotocorner called:"); mvaddch (r, c, 'T'); at (row, col); }
X  if (gotowards (r, c, 0)) { goalr=r; goalc=c; return (1); }
X  return (0);
X}
X
X/*
X * lightroom: Try to light up the room if we are below level 17.
X */
X
Xlight ()
X{ if (Level < 17) return (0);
X  return (lightroom ());
X}
X
X/*
X * shootindark: If we are arching at an old monster, fire another arrow.
X */
X
Xshootindark ()
X{ register int obj, bow;
X
X  /* If no longer arching in the dark, fail */
X  if (darkturns < 1 || darkdir == NONE || !darkroom ()) return (0);
X  
X  darkturns--;			/* Count off turns till he reaches us */
X
X  /* If he is one turn away, switch back to our sword */
X  if (!cursedweapon && wielding (thrower) && darkturns==0 && handleweapon ())
X  { dwait (D_BATTLE, "Switching to sword [4]"); return (1); }
X
X  /* If we have room, switch to our bow */
X  if (!cursedweapon && !wielding (thrower) && darkturns > 3 && 
X      (bow = havebow (1, NOPRINT)) != NONE && wield (bow))
X    return (1);
X
X  /* Fail if we have run out of arrows */
X  if ((obj = havemissile ()) < 0) return (0);
X
X  /* Throw the arrow in the arching direction */
X  return (throw (obj, darkdir));
X}
X
X/* 
X * dinnertime: Eat if we are hungry or if we have a surplus of food.
X */
X 
Xdinnertime ()
X{
X  if ((havefood (5) && objcount == maxobj && ! droppedscare) ||
X      (larder > 0 && hungry ()))
X  { return (eat ()); }
X  
X  return (0);
X}
X
X/* 
X * trywand: Zap a blank wall with an unknown and unused wand in an attempt
X * to generate a message which identifies the wand.
X */
X
Xtrywand ()
X{ register int obj, dir, r, c, count;
X
X  /* If we arent in a room, if there are monsters around,  */
X  /* or we are in the dark, then we cant try this strategy */
X  if (!on (ROOM) || mlistlen || darkroom ()) return (0);
X
X  /* Have we a wand to identify? */
X  if ((obj = unknown (wand)) < 0)
X    return (0);
X
X  /* Look for a wall either 3 or 4 away */
X  for (dir = 0; dir < 8; dir += 2)
X  { for (count = 0, r=atrow, c=atcol;
X         onrc (CANGO | DOOR, r, c) == CANGO;
X         r += deltr[dir], c += deltc[dir])
X      count++;
X
X    if (count == 4 || count == 5) break;	/* Found a likely wall */
X  }
X
X  /* If we couldnt find room, then fail */
X  if (dir > 7) return (0);
X
X  /* Set to do a reset inventory (usesynch) and point the wand */
X  usesynch = 0;  
X  return (point (obj, dir));
X}
X
X/*
X * eat: If we have food, eat it.
X */
X
Xeat ()
X{ int obj;
X
X  if ((obj = have (food)) != NONE)
X  { command (T_HANDLING, "e%c", LETTER (obj));
X    return (1);
X  }
X
X  return (0);
X}
/
echo 'Part 07 of Rog-O-Matic XIV complete.'
exit

mlm@cmu-cs-cad.ARPA (Michael Mauldin) (02/01/85)

#!/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@cmu-cs-a.arpa
#
echo 'Start of Rog-O-Matic XIV, part 08 of 10:'
echo 'x - arms.c'
sed 's/^X//' > arms.c << '/'
X/*
X * arms.c: Rog-O-Matic XIV (CMU) Thu Jan 31 15:46:02 1985 - mlm
X * Copyright (C) 1985 by A. Appel, G. Jacobson, L. Hamey, and M. Mauldin
X * 
X * This file contains all utility functions which exist for armor, 
X * weapons and rings.
X */
X
X# include <curses.h>
X# include "types.h"
X# include "globals.h"
X
X/*
X * havearmor: Return Kth best armor. K should be in the range 1 to invcount.
X *            If K is greater than the number of pieces of armor we have,
X *            then NONE is returned.  Will not return cursed armor or
X *	      armor worse than wearing nothing.
X */
X
X# define swap(x,y) {t=(x); (x)=(y); (y)=t;}
X
Xint havearmor (k, print, rustproof)
X{ register int i, j, w, t, n=0;
X  int armind[MAXINV], armval[MAXINV];
X
X  /* Sort armor by armor class (best first) */
X  for (i=0; i<invcount; ++i)
X  { if (inven[i].count && inven[i].type == armor &&
X        ! (rustproof && willrust (i)))
X    { n++;
X      w = armorclass (i);
X      for (j = n-1; j > 0 && w <= armval[j-1]; j--)
X      { swap (armind[j], armind[j-1]);
X        swap (armval[j], armval[j-1]);
X      }
X      armind[j] = i;
X      armval[j] = w;
X    }
X  }
X
X  /* Put protected sets of armor with equal ACs first.  DR UTexas 19 Jan 84 */
X  for (j = n-1; j > 0; j--)
X  { if (armval[j] == armval[j-1])
X    { i = armind[j];
X      w = armind[j-1];
X      if (!itemis (w, PROTECTED) && itemis (i, PROTECTED))
X        swap (armind[j], armind[j-1]);
X    }
X  }
X
X  if (print)
X  { mvaddstr (1, 0, "Current Armor Rankings");
X    for (i = 0; i<n; i++)
X      mvprintw (i+3, 8, "%2d: %3d %s", i+1, armval[i], itemstr (armind[i]));
X  }
X
X  /* Any uncursed, useful armor at or beyond position k? */
X  for (i=k; i <= n; i++)
X    if (!itemis ((j = armind[i-1]), CURSED) && armval[j] < 10) return (j);
X  
X  /* Return the kth best, even though it is cursed or useless */
X  return ((k <= n) ? armind[k-1] : NONE);
X}
X
X/*
X * armorclass: Given the index of a piece of armor, return the armor
X * class. Assume modifiers of +2 for unknown armor when we have scrolls
X * of remove curse and -2 for when we don't have a remove curse.
X */
X
Xarmorclass (i)
Xint i;
X{ int class;
X
X  if (inven[i].type != armor)
X    return (1000);
X    
X  if (stlmatch (inven[i].str, "leather"))        class = 8;
X  else if (stlmatch (inven[i].str, "ring"))      class = 7;
X  else if (stlmatch (inven[i].str, "studded"))   class = 7;
X  else if (stlmatch (inven[i].str, "scale"))     class = 6;
X  else if (stlmatch (inven[i].str, "chain"))     class = 5;
X  else if (stlmatch (inven[i].str, "splint"))    class = 4;
X  else if (stlmatch (inven[i].str, "banded"))    class = 4;
X  else if (stlmatch (inven[i].str, "plate"))     class = 3;
X  else                                           class = 1000;
X
X  /* Know the modifier exactly */
X  if (inven[i].phit != UNKNOWN)
X    class -= inven[i].phit;
X
X  /* Can remove curse, so assume it is +2 armor */
X  else if (havenamed (scroll, "remove curse") != NONE)
X    class -= 2;
X
X  /* Can't remove curse, assume it is -2 armor */
X  else
X    class += 2;
X
X  return (class);
X}
X
X/*
X * haveweapon: Return Kth best weapon. K should be in the range 1 to invcount.
X *             If K is greater than the number of weapons we have,
X *             then NONE is returned.
X */
X
Xint haveweapon (k, print)
X{ register int i, j, w, t, n=0;
X  int weapind[MAXINV], weapval[MAXINV];
X  for (i=0; i<invcount; ++i)
X    if (inven[i].count && (w = weaponclass (i)) > 0)
X    { n++;
X      for (j = n-1; j > 0 && w >= weapval[j-1]; j--)
X      { swap (weapind[j], weapind[j-1]);
X        swap (weapval[j], weapval[j-1]);
X      }
X      weapind[j] = i;
X      weapval[j] = w;
X    }
X
X    /*
X     * Put enchanted weapons above unenchanted ones if the weapon
X     * ratings are equal.  DR UTexas 25 Jan 84 
X     */
X
X    for (j = n-1; j > 0; j--)
X    { if (weapval[j] == weapval[j-1])
X      { i = weapind[j];
X        w = weapind[j-1];
X        if (!itemis (w, ENCHANTED) && itemis (i, ENCHANTED) &&
X            !itemis (w, KNOWN) && !itemis (i, KNOWN))
X        { swap (weapind[j], weapind[j-1]); }
X      }
X    }
X
X  if (print)
X  { mvaddstr (1, 0, "Current Weapon Rankings");
X    for (i = 0; i<n; i++)
X      mvprintw (i+3, 8, "%2d: %5d %s", i+1, weapval[i], itemstr (weapind[i]));
X  }
X
X  return ((k <= n) ? weapind[k-1] : NONE);
X}
X
X/*
X * weaponclass: Given the index of a weapon, return the weapon class. 
X *              This is the average damage done + 3/2 the plus to
X *              hit, multiplied by 10. Magic arrows are given very
X *              high numbers.
X */
X
Xweaponclass (i)
Xint i;
X{ int class, hitplus = 0, damplus = 0;
X
X  /* Swords and maces are always valid weapons */   
X  if (inven[i].type == hitter)
X    ;
X  /* Under special circumstances, arrows are valid weapons (Hee hee) */
X  else if (cheat && inven[i].type == missile &&
X           stlmatch (inven[i].str, "arrow"))
X    ;
X  /* Not a valid weapon */
X  else
X    return (0);
X
X  /* 
X   * Set the basic expected damage done by the weapon. 
X   */
X    
X  if (stlmatch (inven[i].str, "mace"))
X    class =  50;
X  else if (stlmatch (inven[i].str, "two handed sword"))
X    class = (version < RV52A) ? 105 : 100;
X  else if (stlmatch (inven[i].str, "long sword"))
X    class =  (version < RV52A) ? 55 : 75;
X  else if (stlmatch (inven[i].str, "arrow"))
X    class =  10;
X  else
X    class =   0;
X
X  /* Know the modifier exactly */
X  if (inven[i].phit != UNKNOWN)
X  { hitplus += inven[i].phit;
X
X    if (inven[i].pdam != UNKNOWN)
X      damplus = inven[i].pdam; 
X  }
X
X  /* 
X   * Strategy for "Magic Arrows". These are single arrows when
X   * we are cheating. Since arrows normally come in clumps, and
X   * since we have never (in cheat mode) thrown any, then a
X   * single arrow must have come from a trap, and until it fails
X   * to kill something, we assume it is a valuable arrow.
X   */
X
X  else if (cheat && version <= RV36B && usingarrow && goodarrow > 20 &&
X           i == currentweapon)
X    return (1800);
X
X  else if (cheat && version <= RV36B && stlmatch (inven[i].str, "arrow") &&
X           inven[i].count == 1 && !itemis (i, WORTHLESS) && 
X           (!badarrow || i != currentweapon))
X  { hitplus = 50;  damplus = 50; }
X
X  hitplus = (hitplus < 100) ? hitplus : 100;
X  damplus = (damplus < 200) ? damplus : 200;
X
X  return (class + 12*hitplus + 10*damplus);
X}
X
X/*
X * havering: Return Kth best ring. K should be in the range 1 to invcount.
X *           If K is greater than the number of rings we have,
X *           then NONE is returned.
X */
X
Xint havering (k, print)
X{ register int i, j, r, t, n=0;
X  int ringind[MAXINV], ringval[MAXINV];
X  for (i=0; i<invcount; ++i)
X    if (inven[i].count && (r = ringclass (i)) > 0)
X    { n++;
X      for (j = n-1; j > 0 && r >= ringval[j-1]; j--)
X      { swap (ringind[j], ringind[j-1]);
X        swap (ringval[j], ringval[j-1]);
X      }
X      ringind[j] = i;
X      ringval[j] = r;
X    }
X
X  if (print)
X  { mvaddstr (1, 0, "Current Ring Rankings");
X    for (i = 0; i<n; i++)
X      mvprintw (i+3, 8, "%2d: %5d  %s", i+1, ringval[i], itemstr (ringind[i]));
X  }
X
X  /* 
X   * Since rings are class [1-1000] if we don't want to wear them,
X   * return the ring index only if its value is greater than 1000.
X   */
X
X  return ((k <= n && ringval[k-1] > 1000) ? ringind[k-1] : NONE);
X}
X
X/*
X * ringclass: Given the index of a ring, return the ring class. 
X *            This is a subjective measure of how much good it
X *            would do us to wear this ring. Values of [1-1000] indicates
X *            that we should not wear this ring at all. A value of 0
X *            indicates a worthless ring. This routine uses the amount
X *            of food available to decide how valuable rings are.
X *            Worth evaluates the value of a ring by subtracting 1000 if
X *            the ringclass is over 1000 to decide how valuable the ring
X *            is, so we add 1000 to indicate that the ring should be worn
X *            and try to assign values from 0 to 999 to determine the
X *            value of the ring.
X */
X
Xringclass (i)
Xint i;
X{ int class = 0, magicplus = 0;
X
X  if (inven[i].type != ring)
X    return (0);
X
X  /* Get the magic plus */
X  if (inven[i].phit != UNKNOWN)
X  { magicplus = inven[i].phit;
X  }
X
X  /* A ring of protection */
X  if (stlmatch (inven[i].str, "protection"))
X  { if (magicplus > 0) class = (havefood (1) ? 1000 : 0) + 450; }
X
X  /* A ring of add strength */
X  else if (stlmatch (inven[i].str, "add strength"))
X  { if (itemis (i, INUSE) && magicplus > 0)
X    { if (hitbonus (Str) == hitbonus (Str - magicplus * 100) &&
X          damagebonus (Str) == damagebonus (Str - magicplus * 100))
X        class = 400;
X      else
X        class = (havefood (1) ? 1000 : 0) + 400;
X    }
X    else if (magicplus > 0)
X    { if (hitbonus (Str) == hitbonus (Str + magicplus * 100) &&
X          damagebonus (Str) == damagebonus (Str + magicplus * 100))
X        class = 400;
X      else
X        class = (havefood (1) ? 1000 : 0) + 400;
X    }
X  }
X
X  /* A ring of sustain strength */
X  else if (stlmatch (inven[i].str, "sustain strength"))
X  { 
X    /* A second ring of sustain strength is useless */
X    if (!itemis (i, INUSE) && wearing ("sustain strength") != NONE)
X      class = 0;
X
X    else
X      class = (havefood (3) ? 1000 : 0) + 
X              (Level > 12 ? 150 : 
X               Str > 2000 ? 700 :
X               Str > 1600 ? Str - 1200 :
X                            100);
X  }
X
X  /* A ring of searching */
X  else if (stlmatch (inven[i].str, "searching"))
X  { class = (havefood (0) ? 1000 : 0) + 250; }
X
X  /* A ring of see invisible */
X  else if (stlmatch (inven[i].str, "see invisible"))
X  { 
X    /* A second ring of see invisible is useless */
X    if (!itemis (i, INUSE) && wearing ("see invisible") != NONE)
X      class = 0;
X
X    /* 
X     * If we are beingstalked and we are wearing this ring, then
X     * we should take it off and put it on to set the Rogue CANSEE
X     * bit, which can be unset by a second ring of see invisible or
X     * by a see invisible potion wearing off.				MLM
X     */
X
X    else if (itemis (i, INUSE) && beingstalked)
X      class = 800;
X
X    /*
X     * When we put the ring on, keep its importance high for 20
X     * turns, just in case the beast comes back to haunt us.		MLM
X     */
X
X    else
X      class = (beingstalked || turns - putonseeinv < 20) ? 1999 :
X              ((havefood (0) && Level > 15 && Level < 26) ? 1000 : 0) + 300;  }
X
X  /* A ring of adornment */
X  else if (stlmatch (inven[i].str, "adornment"))
X  { class = 0; }
X
X  /* A ring of aggravate monster */
X  else if (stlmatch (inven[i].str, "aggravate monster"))
X  { class = 0; }
X
X  /* A ring of dexterity */
X  else if (stlmatch (inven[i].str, "dexterity"))
X  { if (magicplus > 0) class = (havefood (0) ? 1000 : 0) + 475; }
X
X  /* A ring of increase damage */
X  else if (stlmatch (inven[i].str, "increase damage"))
X  { if (magicplus > 0) class = (havefood (0) ? 1000 : 0) + 500; }
X
X  /* A ring of regeneration */
X  else if (stlmatch (inven[i].str, "regeneration"))
X  {
X    /* Analysis indicates that rings of regenerate DO NOT hold back   */
X    /* the character after any level. They each add one hit point per */
X    /* turn of rest regardless of your level!			MLM   */
X
X    class = 50*(Hpmax-Hp-Explev) + 500; }
X
X  /* A ring of slow digestion */
X  else if (stlmatch (inven[i].str, "slow digestion"))
X  { 
X    /* A second ring of slow digestion is not too useful */
X    if (havefood (0) && !itemis (i, INUSE) &&
X	wearing ("slow digestion") != NONE)
X      class = 1001;
X
X    else
X    { class =	havefood (3) ?	1100 :
X		havefood (2) ?	1300 :
X		havefood (1) ?	1500 :
X		havefood (0) ?	1900 :
X				1999 ;
X    }
X  }
X
X  /* A ring of teleportation */
X  else if (stlmatch (inven[i].str, "telportation") || 
X           stlmatch (inven[i].str, "teleportation"))
X  { class = 0; }
X
X  /* A ring of stealth */
X  else if (stlmatch (inven[i].str, "stealth"))
X  {
X    /* A second ring of stealth is useless */
X    if (!itemis (i, INUSE) && wearing ("stealth") != NONE)
X      class = 0;
X
X    else
X    { class = (havefood (1) ? 1000 : 0) + 
X             (Level > 17 ? 850 : Level > 12 ? 700 : 300);
X    }
X  }
X
X  /* A ring of maintain armor */
X  else if (stlmatch (inven[i].str, "maintain armor"))
X  { int bestarm, nextarm, armdiff;
X
X    /* No rust monsters yet or cursed armor */
X    if (Level < 9 || cursedarmor) return (900);
X    
X    /* Past the rust monsters */
X    else if (Level > 18) return (300);
X
X    /* A second ring of maintain armor is useless */
X    else if (!itemis (i, INUSE) && wearing ("maintain armor") != NONE)
X      class = 0;
X
X    else
X    { bestarm = havearmor (1, NOPRINT, ANY);
X      nextarm = havearmor (1, NOPRINT, RUSTPROOF);
X
X      if (bestarm < 0)                       /* No armor to protect */
X        return (700);
X
X      else if (!willrust (bestarm))	     /* Armor wont rust anyway */
X        return (0);
X
X      else if (nextarm < 0)	             /* Naked is AC 10 */
X        armdiff = 10 - armorclass (bestarm);
X
X      else			             /* Get difference in classes */
X        armdiff = armorclass (nextarm) -
X		  armorclass (bestarm);
X
X      class = (havefood (1) ? 1000 : 0) +
X              200 * armdiff;
X    }
X  }
X
X  /* Not a known ring, forget it */
X  else
X    return (0);
X
X  /* A magical plus is worth 100 */
X  return (class + 100*magicplus);
X}
X
X/*
X * havebow: Return Kth best thrower. K should be in the range 1 to invcount.
X *          If K is greater than the number of weapons we have,
X *          then NONE is returned.
X */
X
Xint havebow (k, print)
X{ register int i, j, w, t, n=0;
X  int bowind[MAXINV], bowval[MAXINV];
X  for (i=0; i<invcount; ++i)
X    if (inven[i].count && (w = bowclass (i)) > 0)
X    { n++;
X      for (j = n-1; j > 0 && w >= bowval[j-1]; j--)
X      { swap (bowind[j], bowind[j-1]);
X        swap (bowval[j], bowval[j-1]);
X      }
X      bowind[j] = i;
X      bowval[j] = w;
X    }
X
X  if (print)
X  { mvaddstr (1, 0, "Current Bow Rankings");
X    for (i = 0; i<n; i++)
X      mvprintw (i+3, 8, "%2d: %5d %s", i+1, bowval[i], itemstr (bowind[i]));
X  }
X
X  return ((k <= n) ? bowind[k-1] : NONE);
X}
X
X/*
X * bowclass: Given the index of a bow, return the bow class. 
X *           This is the average damage done + 6/5 the plus to
X *           hit, multiplied by 10.
X */
X
Xbowclass (i)
Xint i;
X{ int class, hitplus = 0, damplus = 0;
X
X  if (inven[i].type == thrower &&
X      stlmatch (inven[i].str, "short bow") &&
X      havemult (missile, "arrow", 5) != NONE)
X    class =  35;
X  else
X    return (0);
X
X  /* Find the modifiers */
X  if (inven[i].phit != UNKNOWN)
X  { hitplus += inven[i].phit;
X
X    if (inven[i].pdam != UNKNOWN)
X      damplus = inven[i].pdam; 
X  }
X
X  return (class + 12*hitplus + 10*damplus);
X}
X
X/*
X * havemissile: Return best missile. Dont consider arrows if we
X * are cheating.  Consider arrows first if we are wielding our bow.
X */
X
Xint havemissile ()
X{ register int i, fewest = 9999, obj = NONE;
X
X  if (wielding (thrower))	/* Wielding bow, use arrows */
X  { for (i=0; i<invcount; ++i)
X      if (inven[i].count > 0 && inven[i].count < fewest &&
X          inven[i].type == missile && stlmatch(inven[i].str,"arrow"))
X      { obj = i; fewest = inven[i].count; }
X  }
X
X  if (obj < 0)			/* Not wielding bow or no arrows */
X  { for (i=0; i<invcount; ++i)
X      if (inven[i].count > 0 &&
X	  inven[i].count < fewest &&
X	  !itemis (i, INUSE) &&
X          (inven[i].type == missile ||
X           stlmatch(inven[i].str,"spear") || 
X           stlmatch(inven[i].str,"dagger") || 
X           stlmatch(inven[i].str,"mace") && inven[i].phit <= 0 || 
X           stlmatch(inven[i].str,"long sword") && inven[i].phit < 0))
X      { obj = i; fewest = inven[i].count; }
X  }
X
X  if (obj != NONE)
X    dwait (D_BATTLE, "Havemissile returns (%s", itemstr (obj));
X  else
X    dwait (D_BATTLE, "Havemissile fails");
X
X  return (obj);
X}
X
X/*
X * havearrow: return the index of any arrow which has count 1.
X */
X
Xhavearrow ()
X{ int arr;
X
X  for (arr = 0; arr<invcount; arr++)
X    if (inven[arr].type == missile &&
X        inven[arr].count == 1 &&
X        stlmatch(inven[arr].str,"arrow"))
X      return (arr);
X
X  return (NONE);
X}
X
X/*
X * plusweapon: we just enchanted our current weapon.
X *             Do a picky identify to try to find its plusses.
X */
X
Xplusweapon ()
X{
X  cursedweapon = 0;
X  newweapon = 1;
X  forget (currentweapon, CURSED);
X  usesynch = 0;
X}
X
X/* 
X * hitbonus: Return the bonus to hit.
X */
X
Xhitbonus (strength)
Xint strength;
X{ int bonus = 0;
X  
X  if (strength < 700) bonus = strength/100 - 7;
X
X  else if (version > RV36B)
X  { if (strength < 1700) bonus = 0;
X    else if (strength < 2100) bonus = 1;
X    else if (strength < 3100) bonus = 2;
X    else bonus = 3;    
X  }
X
X  else 
X  { if (strength < 1700) bonus = 0;
X    else if (strength < 1851) bonus = 1;
X    else if (strength < 1900) bonus = 2;
X    else bonus = 3;    
X  }
X
X  return (bonus);
X}
X
X/* 
X * damagebonus: bonus = the damage bonus.
X */
X
Xdamagebonus (strength)
Xint strength;
X{ int bonus = 0;
X
X  if (strength < 700) bonus = strength/100 - 7;
X
X  else  if (version > RV36B)
X  { if (strength < 1600) bonus = 0;
X    else if (strength < 1800) bonus = 1;
X    else if (strength < 1900) bonus = 2;
X    else if (strength < 2100) bonus = 3;
X    else if (strength < 2200) bonus = 4;
X    else if (strength < 1600) bonus = 5;
X    else bonus = 6;
X  }
X
X  else 
X  { if (strength < 1600) bonus = 0;
X    else if (strength < 1800) bonus = 1;
X    else if (strength < 1801) bonus = 2;
X    else if (strength < 1876) bonus = 3;
X    else if (strength < 1891) bonus = 4;
X    else if (strength < 1900) bonus = 5;
X    else bonus = 6;    
X  }
X
X  return (bonus);
X}
X
X/* 
X * setbonuses: Set global hit and damage pluses.
X */
X
Xsetbonuses ()
X{
X  /* Set global Hit bonus */
X  gplushit = hitbonus (Str);
X
X  if (leftring != NONE && stlmatch (inven[leftring].str, "dexterity") &&
X      inven[leftring].phit != UNKNOWN)
X   gplushit += inven[leftring].phit;
X
X  if (rightring != NONE && stlmatch (inven[rightring].str, "dexterity") &&
X      inven[rightring].phit != UNKNOWN)
X   gplushit += inven[rightring].phit;
X
X  /* Set global Damage Bonus */
X  gplusdam = damagebonus (Str);
X
X  if (leftring != NONE && stlmatch (inven[leftring].str, "add damage") &&
X      inven[leftring].pdam != UNKNOWN)
X   gplusdam += inven[leftring].pdam;
X
X  if (rightring != NONE && stlmatch (inven[rightring].str, "add damage") &&
X      inven[rightring].pdam != UNKNOWN)
X   gplusdam += inven[rightring].pdam;
X
X  /* Set bonuses for weapons */
X  wplushit = gplushit;
X  wplusdam = gplusdam;
X
X  if (currentweapon != NONE)
X  { if (inven[currentweapon].phit != UNKNOWN)
X      wplushit += inven[currentweapon].phit;
X
X    if (inven[currentweapon].pdam != UNKNOWN)
X      wplusdam += inven[currentweapon].pdam;
X  }
X}
/
echo 'x - globals.h'
sed 's/^X//' > globals.h << '/'
X/*
X * globals.h: Rog-O-Matic XIV (CMU) Thu Jan 31 18:12:50 1985 - mlm
X * Copyright (C) 1985 by A. Appel, G. Jacobson, L. Hamey, and M. Mauldin
X *
X * Global variables
X */
X
X/* global files */
Xextern FILE *frogue,*trogue;	/* From Rogue, To Rogue */
Xextern FILE *fecho;		/* Rogomatic score file */
Xextern FILE *logfile;		/* Rogomatic score file */
Xextern FILE *realstdout;	/* Real stdout when in terse or emacs mode */
Xextern FILE *snapshot;		/* File for snapshot command */
XFILE *wopen();			/* Open a file for world access */
X
X/* global characters and strings */
Xextern char afterid;		/* Index of object after identify */
Xextern char *genocide;		/* List of monsters to genocide */
Xextern char genocided[];	/* List of monsters genocided */
Xextern char lastcmd[];		/* Copy of last command sent to Rogue */
Xextern char lastname[];		/* Name of last potion/scroll/wand */
Xextern char nextid;		/* Next object to identify */
Xextern char ourkiller[];	/* What was listed on the tombstone */
Xextern char *parmstr;		/* Pointer to argument space */
Xextern char queue[];		/* stuff to be sent to Rogue */
Xextern char *roguename;		/* Name we are playing under */
Xextern char screen[24][80];	/* characters drawn by Rogue */
Xextern char sumline[];		/* Summation line */
Xextern char *termination;	/* Latin verb for how we died */
Xextern char versionstr[];	/* Version of Rogue we are playing */
X
X/* character and string functions */
Xextern char getlogtoken(), *getname(), *itemstr();
Xextern char logchar(), *monname(), *realname();
X
X/* double precision floating point functions */
Xdouble prob(), mean(), stdev();	/* For stats.c */
X
X/* global integers */
Xextern int aggravated;		/* True if we aggravated this level */
Xextern int agoalr,agoalc;	/* where we killed a monster */
Xextern int ammo;		/* Number of missiles in pack */
Xextern int arglen;		/* Length of argument space */
Xextern int arrowshot;		/* True if trap fired at us this round */
Xextern int atrow,atcol;		/* where is the '@'? (us) */
Xextern int atrow0,atcol0;	/* where was the '@' last time */
Xextern int attempt;		/* # times have we explored this level */
Xextern int badarrow;		/* True if we missed with this arrow */
Xextern int beingheld;		/* True if being held by a fungus */
Xextern int beingstalked;	/* True if an Invisible Stalker is around */
Xextern int blinded;		/* True if blinded */
Xextern int blindir;		/* Last direction we moved when blind */
Xextern int cancelled;		/* Turns till use cancellation again */
Xextern int cecho;		/* Last message type to logfile */
Xextern int cheat;		/* True ==> cheat to win */
Xextern int checkrange;		/* True ==> check range */
Xextern int chicken;		/* True ==> test run away code */
Xextern int compression;		/* True ==> move multiple squares */
Xextern int confused;		/* True if confused */
Xextern int cosmic;		/* True if hallucinating */
Xextern int currentarmor;	/* Index of our armor */
Xextern int currentweapon;	/* Index of our weapon */
Xextern int cursedarmor;		/* True if armor is cursed */
Xextern int cursedweapon;	/* True if weapon if cursed */
Xextern int darkdir;		/* Direction of arrow in dark room */
Xextern int darkturns;		/* # arrows left to fire in dark room */
Xextern int debugging;		/* Debugging options in effect */
Xextern int didreadmap;		/* Last magically mapped level */
Xextern int doorlist[], *newdoors; /* Holds r,c of new doors found */
Xextern int doublehasted;	/* True if double hasted (3.6 only) */
Xextern int droppedscare;	/* Number of scare mon. on this level */
Xextern int emacs;		/* True if in emacs mode */
Xextern int exploredlevel;	/* We completely explored this level */
Xextern int floating;		/* True if we are levitating */
Xextern int foughtmonster;	/* True if we recently fought a monster */
Xextern int foundarrowtrap;	/* Well, did we? */
Xextern int foundtrapdoor;	/* Well, did we? */
Xextern int goalr,goalc;		/* where are we trying to go */
Xextern int goodarrow;		/* Number of times we killed in one blow */
Xextern int goodweapon;		/* Used for two-handed sword */
Xextern int gplusdam;		/* Global damage bonus */
Xextern int gplushit;		/* Global hit bonus */
Xextern int hasted;		/* True if hasted */
Xextern int head,tail;		/* endpoints of circular queue */
Xextern int hitstokill;		/* Number of hits to kill last monster */
Xextern int interrupted;		/* True if at commandtop from onintr() */
Xextern int knowident;		/* Found an identify scroll? */
Xextern int larder;		/* Number of foods left */
Xextern int lastate;		/* Time we last ate */
Xextern int lastdamage;		/* Amount of last hit by a monster */
Xextern int lastdrop;		/* What did we last try to drop */
Xextern int lastfoodlevel;	/* Last food found */
Xextern int lastmonster;		/* Last monster we tried to hit */
Xextern int lastobj;		/* What did we last try to use */
Xextern int lastwand;		/* Index of last wand */
Xextern int leftring;		/* Index of our left ring */
Xextern int logdigested;		/* True if game log has been read by replay */
Xextern int logging;		/* True if logging game */
Xextern int lyinginwait;		/* Did we lie in wait last turn? */
Xextern int maxobj;		/* How much can we carry */
Xextern int missedstairs;	/* True if we missed the stairs */
Xextern int morecount;		/* Number of messages since last command */
Xextern int msgonscreen;		/* There is a rogomatic msg on the screen */
Xextern int newarmor;		/* True if our armor status has changed */
Xextern int newring;		/* True if our ring status has changed */
Xextern int newweapon;		/* True if our weapon status has changed */
Xextern int nohalf;		/* True if no halftime show */
Xextern int noterm;		/* True if no human watching */
Xextern int objcount;		/* Number of objects */
Xextern int ourscore;		/* Our score when we died/quit */
Xextern int playing;		/* True if still playing the game */
Xextern int poorarrow;		/* # Times we failed to kill in one blow */
Xextern int protected;		/* True if we protected our armor */
Xextern int putonseeinv;		/* Time when last put on see invisible ring */
Xextern int quitat;		/* Score we are trying to beat */
Xextern int redhands;		/* True if our hands are red */
Xextern int replaying;		/* True if replaying old game */
Xextern int revvideo;		/* True if in rev. video mode */
Xextern int rightring;		/* Index of our right ring */
Xextern int rogpid;		/* Process id of Rogue process */
Xextern int room[];		/* Flags for each room */
Xextern int row,col;		/* where is the cursor? */
Xextern int scrmap[24][80];	/* attribute flags for squares */
Xextern int slowed;		/* True if we recently slowed a monster */
Xextern int stairrow,staircol;	/* Where is the staircase */
Xextern int teleported;		/* times teleported on this level */
Xextern int terse;		/* True if in terse mode */
Xextern int transparent;		/* True ==> user mode */
Xextern int trapc;		/* Col of last trap */
Xextern int trapr;		/* Row of last trap */
Xextern int urocnt;		/* Un-identified Rogue Object count */
Xextern int usesynch;		/* Have we finished using something? */
Xextern int usingarrow;		/* True if wielding an arrow from a trap */
Xextern int version;		/* From types.h, set by getrougeversion */
Xextern int wplusdam;		/* Weapon damage bonus */
Xextern int wplushit;		/* Weapon hit bonus */
Xextern int zone;		/* Current zone (0 to 8) */
Xextern int zonemap[9][9];	/* Connectivity map */
X
X/* Status line variables */
Xextern int Level,MaxLevel,Gold,Hp,Hpmax,Str,Strmax,Ac,Exp,Explev;
Xextern char Ms[];		/* Msg 'X', 'Hungry', 'Weak', 'Fainting' */
Xextern int turns;		/* Est time in Rogue turns since start */
X
X/* Geometry data */
Xextern int deltc[], deltr[];	/* Displacements for directions */
Xextern int deltrc[];		/* ditto */
Xextern char keydir[];		/* Directions for motion keys */
Xextern int movedir;		/* Which direction did we last move */
Xextern stuff translate[];	/* what Rogue characters represent */
X
X/* Time history */
Xextern timerec timespent[];
X
X/* Objects in pack */
Xextern invrec inven[];	extern int invcount;
X
X/* Stuff on this level */
Xextern stuffrec slist[]; extern int slistlen;
X
X/* Monster on this level */
Xextern monrec mlist[];	extern int mlistlen;
X
Xextern char	killedmonster, targetmonster;
X
X/* Door search variables */
Xextern int	new_mark, new_findroom, new_search, new_stairs, new_arch;
Xextern char	timessearched[24][80], timestosearch;
Xextern int	searchstartr, searchstartc;
Xextern int	reusepsd;
X
X/* Results of last makemove */
Xextern int	ontarget, targetrow, targetcol;
X
X/* Monster attribute and Long term memory arrays */
Xextern attrec monatt[];		/* Monster attributes */
Xextern lrnrec ltm;		/* Long term memory -- general */
Xextern ltmrec monhist[]; 	/* Long term memory -- creatures */
Xextern ltmrec delhist[]; 	/* Long term memory -- changes this game */
Xextern int nextmon;		/* Length of LTM */
Xextern int monindex[];		/* Index into monhist array */
X
X/* Genetic learning arrays */
Xextern int knob[];		/* Knobs */
Xextern int k_srch;		/* Propensity for searching squares */
Xextern int k_door;		/* Propensity for searching doors */
Xextern int k_rest;		/* Propensity for resting */
Xextern int k_arch;		/* Propensity for firing arrows */
Xextern int k_exper;		/* Level on which to experiment with items */
Xextern int k_run;		/* Propensity for retreating */
Xextern int k_wake;		/* Propensity for waking things up */
Xextern int k_food;		/* Propensity for hoarding food (rings) */
/
echo 'x - survival.c'
sed 's/^X//' > survival.c << '/'
X/*
X * survival.c: Rog-O-Matic XIV (CMU) Mon Jan  7 15:22:23 1985 - mlm
X * Copyright (C) 1985 by A. Appel, G. Jacobson, L. Hamey, and M. Mauldin
X *
X * This file contains all of the "Run Away" code.
X * Well, almost all of the run away code.
X * At least I think it has something to do with running away.
X */
X
X# include <stdio.h>
X# include <ctype.h>
X# include <curses.h>
X# include "types.h"
X# include "globals.h"
X
X# define SO	  1
X# define SE	  0
X
X# define highlight(rowcol,stand)		\
X  if (print || debug (D_SCREEN))		\
X  { at((rowcol)/80,(rowcol)%80);		\
X    if (stand) standout ();			\
X    printw("%c",screen[0][rowcol]);		\
X    if (stand) standend ();			\
X    refresh (); }
X
X/*
X * markcycles: evokes fond memories of an earlier time, when Andrew
X * was a hacker who just patched things together until they worked,
X * and used the SHIFT-STOP key to compile things, rather than thinking.
X *
X * markcycles does a depth-first-search of the squares to find loops in
X * the rooms.  All doors on loops are marked RUNOK, and are used by the
X * runaway code.
X */
X
Xmarkcycles (print)
X{ short mark[1920];
X  struct {short where,door,dirs;} st[1000];
X  register int sp,newsquare; int *Scr; int whichdir; int D;
X
X  if (!new_mark) return (0);
X
X  Scr=scrmap[0];
X
X  { register int count=1920; register short *m=mark; while(count--) *m++=0;}
X  sp=1; st[1].where=atrow*80+atcol; st[1].dirs=1; st[1].door=0;
X
X  for (D = 0; D < 8; D += 2)
X  { if ((Scr[newsquare = (st[1].where+deltrc[D^4])]) & CANGO)
X    { if (mark[newsquare])
X      { int stop, i;
X        if (mark[newsquare] < sp)
X          for (stop = st[mark[newsquare]].door,
X                 i = (Scr[st[sp].where] & DOOR) ? sp : st[sp].door;
X               i !=  stop;
X               i =st[i].door)
X          { Scr[st[i].where] |= RUNOK; 
X            highlight (st[i].where, SO) 
X          }
X       }
X       else
X       { sp++; mark[newsquare] = sp;
X         highlight (newsquare, SO)
X         st[sp].where=newsquare;
X         st[sp].dirs=1; st[1].dirs= -1;
X         st[sp].door = (Scr[st[sp-1].where]&DOOR) ? sp-1 : st[sp-1].door;
X       }
X     }
X
X     while (sp > 1)
X     { if ((whichdir=(st[sp].dirs++)<<1)<8)
X       { /* whichdir is 6,2, or 4. */
X         if ((Scr[newsquare= (st[sp].where+deltrc[(whichdir+D)&7])])&CANGO)
X         { if (mark[newsquare])
X           { register int stop,i;
X             if (mark[newsquare]<sp)
X                 for (stop=st[mark[newsquare]].door,
X                 i=(Scr[st[sp].where]&DOOR)?sp:st[sp].door;
X                 i!=stop;
X                 i=st[i].door)
X             { Scr[st[i].where] |= RUNOK;
X               highlight (st[i].where, SO)
X             }
X           }
X           else
X           { sp++; mark[newsquare]=sp;
X             highlight (newsquare, SO)
X             st[sp].where=newsquare;
X             st[sp].dirs=1; D += whichdir+4;
X             st[sp].door = (Scr[st[sp-1].where]&DOOR) ? sp-1 : st[sp-1].door;
X           }
X         }
X       }
X       else
X       { if (! (Scr[st[sp].where] & RUNOK)) highlight (st[sp].where, SE) 
X         sp--;
X         D -= 4+((st[sp].dirs-1)<<1);
X       }
X     }
X  }
X  highlight (st[1].where, SE)
X
X  new_mark = 0;
X  return (1);
X}
X
X/* 
X * Runaway: Panic!
X */
X
Xint runaway ()
X{
X  if (on (SCAREM)) 
X  { dwait (D_BATTLE, "Not running, on scare monster scroll!");
X    return (0);
X  }
X
X  dwait (D_BATTLE | D_SEARCH, "Run away!!!!");
X
X  if (on (STAIRS) && !floating)		/* Go up or down */
X  { if (!goupstairs (RUNNING)) godownstairs (RUNNING); 
X    return (1);
X  }
X
X  if (canrun ())		/* If canrun finds a move, use it */
X    return (followmap (RUNAWAY));
X
X  return (0);			/* Cant run away */  
X}
X
X/*
X * Canrun: set up a move which will get us away from danger.
X */
X
Xint canrun ()
X{ int result, oldcomp = compression;
X  int runinit(), runvalue(), expruninit(), exprunvalue();
X  
X  if (on (STAIRS)) return (1);		/* Can run down stairs */
X
X  compression = 0;			/* Be tense when fleeing */
X  result = (findmove (RUNAWAY, runinit, runvalue, REEVAL) ||
X            findmove (EXPLORERUN, expruninit, exprunvalue, REEVAL));
X
X  compression = oldcomp;
X  return (result);
X}
X
X/*
X * unpin:
X *
X *	"When you're stuck and wriggling on a pin,
X *	 When you're pinned and wriggling on a wall..."
X *
X *		"The Love Song of J. Alfred Prufrock", T.S. Eliot
X */
X
Xint unpin ()
X{ int result, oldcomp = compression;
X  int unpininit (), runvalue (), expunpininit (),
X      exprunvalue (), expunpinvalue ();
X
X  if (on (SCAREM)) 
X  { dwait (D_BATTLE, "Not unpinning, on scare monster scroll!");
X    return (0);
X  }
X
X  if (on (STAIRS) && !floating)
X  { if (!goupstairs (RUNNING)) godownstairs (RUNNING); 
X    return (1);
X  }
X
X  dwait (D_BATTLE, "Pinned!!!!");
X
X  /* currentrectangle ();   // always done after each move of the rogue // */
X
X  compression = 0;	/* Be tense when fleeing */
X  result = (makemove (UNPIN, unpininit, runvalue, REEVAL) ||
X            makemove (UNPINEXP, expunpininit, expunpinvalue, REEVAL));
X
X  compression = oldcomp;
X  return (result);
X}
X
X/*
X * backtodoor: Useful when being ganged up on. Back into the nearest
X *             door.
X */
X
Xint backtodoor (dist)
Xint dist;
X{ int rundoorinit(), rundoorvalue();
X  static int lastcall= -10, stillcount=0, notmoving=0, closest=99;
X  
X  /* 
X   * Keep track of the opponents distance.  If they stop advancing on us,
X   * disable the rule for 10 turns.
X   */
X
X  if (turns-lastcall > 20)
X  { notmoving=0; closest=99; stillcount=0; }
X  else if (dist < closest)
X  { closest=dist; stillcount=0; }
X  else if (++stillcount > 5)
X  { notmoving++; }
X
X  lastcall = turns;
X
X  /* 
X   * Now check whether we try to move back to the door
X   */
X
X  if (notmoving)
X    dwait (D_BATTLE, "backtodoor: monsters not moving");
X  
X  else if (on (SCAREM)) 
X    dwait (D_BATTLE, "Not backing up, on scare monster scroll!");
X
X  else if (dist > 0 && (on (DOOR) || nextto (DOOR, atrow, atcol)))
X    dwait (D_BATTLE, "backtodoor: next to door, have time");
X
X  else if (makemove (RUNTODOOR, rundoorinit, rundoorvalue, REEVAL))
X  { dwait (D_BATTLE, "Back to the door..."); return (1); }
X
X  return (0);
X}
/
echo 'x - types.h'
sed 's/^X//' > types.h << '/'
X/*
X * types.h: Rog-O-Matic XIV (CMU) Wed Jan 30 14:57:17 1985 - mlm
X * Copyright (C) 1985 by A. Appel, G. Jacobson, L. Hamey, and M. Mauldin
X *
X * Miscellaneous Macros and Constants 
X */
X
X/* The unctrl macro for systems where curses doesn't define it */
X
X# ifndef unctrl
Xextern char	*_unctrl[];
X
X# define	unctrl(ch)	(_unctrl[ch & 0177])
X# endif
X
X/* Global Preprocessor constants */
X
X# define ill		";'"
X# define status		"Str:"
X# define MAXATTEMPTS	(10)
X# define ROGQUIT	(-2)
X# define DIED		(1)
X# define FINISHED	(0)
X# define SAVED		(2)
X# define MAXINV		(26)
X# define NONE		(-1)
X# define MAXSTUFF	(30)
X# define MAXMONST	(40)
X# define SAVEARROWS	(30)
X# define NAMSIZ		(64)
X# define MAXLEV		(30)
X# define MAXMON		(128)
X# define SUCCESS	(1)
X# define FAILURE	(0)
X
X# define ISPRT(c)	((c) >= ' ' && (c) <= '~')
X# define GETROGUECHAR	fgetc(frogue)
X# define GETLOGCHAR	fgetc(logfile)
X
X/*
X * Magic numbers for Invisible stalker strategies
X */
X
X# define INVHIT		(1000)
X
X/*
X * Attribute bits for the screen map: If you change this list, be sure
X * to change the flag names at the end of debug.c.   MLM
X */
X
X# define BEEN		(0000000001)
X# define CANGO		(0000000002)
X# define DOOR		(0000000004)
X# define HALL		(0000000010)
X# define PSD		(0000000020)
X# define ROOM		(0000000040)
X# define SAFE		(0000000100)
X# define SEEN		(0000000200)
X# define SEENPOS	(7)
X# define DEADEND	(0000000400)
X# define STUFF		(0000001000)
X# define TRAP		(0000002000)
X# define ARROW		(0000004000)
X# define TRAPDOR	(0000010000)
X# define TELTRAP	(0000020000)
X# define GASTRAP	(0000040000)
X# define BEARTRP	(0000100000)
X# define DARTRAP	(0000200000)
X# define WATERAP	(0000400000)
X# define MONSTER	(0001000000)
X# define WALL		(0002000000)
X# define USELESS	(0004000000)
X# define SCAREM		(0010000000)
X# define STAIRS		(0020000000)
X# define RUNOK		(0040000000)
X# define BOUNDARY	(0100000000)
X# define SLEEPER	(0200000000)
X# define EVERCLR	(0400000000)
X
X# define TOPW		(0)
X# define BOTW		(1)
X# define LEFTW		(2)
X# define RIGHTW		(3)
X# define NOTW		(-1)
X# define DOORW		(-2)
X# define CORNERW	(-3)
X
X# define INFINITY	(10000)
X
X# define NOTAMOVE	(-1)
X
X# define FORCE		(1)
X# define OPTIONAL	(0)
X
X# define NEAR		(0)
X# define HERE		(1)
X
X# define NOPRINT	(0)
X# define DOPRINT	(1)
X
X# define NOTRUNNING	(0)
X# define RUNNING	(1)
X
X# define ANY		(0)
X# define RUSTPROOF	(1)
X
X/* Types of moves planned by makemove */
X# define REUSE		(0)
X# define REEVAL		(1)
X
X# define EXPLORE	(1)
X# define EXPLORERUN	(2)
X# define RUNTODOOR	(3)
X# define RUNAWAY	(4)
X# define SECRETDOOR	(5)
X# define FINDSAFE	(6)
X# define GOTOMOVE	(7)
X# define ATTACKSLEEP	(8)
X# define ARCHERYMOVE	(9)
X# define UNPIN		(10)
X# define UNPINEXP	(11)
X# define EXPLOREROOM	(12)
X# define FINDROOM	(13)
X# define RESTMOVE	(14)
X# define DOWNMOVE	(15)
X# define RUNDOWN	(16)
X# define NUMMOVES	(17)
X
X/* Version numbers */
X# define RV36A		(361)	/* OLDROG: Rogue 3.6 w/o wands */
X# define RV36B		(362)	/* CURROG: Rogue 3.6 with wands */
X# define RV52A		(521)	/* NEWROG: Rogue 5.2 */
X# define RV52B		(522)	/* Rogue 5.2 with maze rooms */
X# define RV53A		(531)	/* Rogue 5.3 new monsters */
X
X/* Ways to spend time */
X
X# define T_OTHER	(0)
X# define T_HANDLING	(1)
X# define T_FIGHTING	(2)
X# define T_RESTING	(3)
X# define T_MOVING	(4)
X# define T_EXPLORING	(5)
X# define T_RUNNING	(6)
X# define T_GROPING	(7)
X# define T_SEARCHING	(8)
X# define T_DOORSRCH	(9)
X# define T_LISTLEN	(10)
X
X/* Bit value for debugging types (for debugging function dwait) */
X
X# define D_FATAL	(00001)
X# define D_ERROR	(00002)
X# define D_WARNING	(00004)
X# define D_INFORM	(00010)
X# define D_SEARCH	(00020)
X# define D_BATTLE	(00040)
X# define D_MESSAGE	(00100)
X# define D_PACK		(00200)
X# define D_CONTROL	(00400)
X# define D_SCREEN	(01000)
X# define D_MONSTER	(02000)
X# define D_SAY		(04000)
X# define D_ALL		(01777)
X# define D_NORMAL	(D_FATAL | D_ERROR)
X
X# define debugon(mask)	(debugging|=(mask))
X# define debugoff(mask)	(debugging&=(~(mask)))
X# define debug(mask)	(debugging&(mask))
X
X/* Parameters for genetic learning, knobs */
X# define K_SRCH		(0)
X# define K_DOOR		(1)
X# define K_REST		(2)
X# define K_ARCH		(3)
X# define K_EXPER	(4)
X# define K_RUN		(5)
X# define K_WAKE		(6)
X# define K_FOOD		(7)
X# define MAXKNOB	(8)
X
X/* Monster attributes */
X# define AWAKE		(1)
X# define ASLEEP		(2)
X# define ALL		(9)
X# define HELD		(10)
X
X/* Constants for handling inventory */
X# define UNKNOWN	-99999
X# define INVMAX		25
X
X/* Pack item attributes  DR UTexas 25 Jan 84 */
X# define KNOWN                 (0000000001)
X# define CURSED                (0000000002)
X# define ENCHANTED             (0000000004)
X# define PROTECTED             (0000000010)
X# define UNCURSED              (0000000020)
X# define INUSE                 (0000000040)
X# define WORTHLESS             (0000000100)
X
X/* Miscellaneous macros */
X
X# define LETTER(i)	((char)((i)+'a'))
X# define DIGIT(c)	((int)((c)-'a'))
X# define OBJECT(c)	DIGIT(c)
X# define ISDIGIT(c)	((c) >= '0' && (c) <= '9')
X# define plural(n)	((n)==1 ? "" : "s")
X# define ordinal(n)	((((n)/10)%10==1) ? "th": \
X			      ((n)%10==1) ? "st": \
X			      ((n)%10==2) ? "nd": \
X			      ((n)%10==3) ? "rd":"th")
X# define ctrl(c)	((c)&037)
X# define ESC		ctrl('[')
X# define NEWLINE	ctrl('J')
X# define abs(a)		((a) >= 0 ? (a) : -(a))
X# define max(a,b)	(((a) > (b)) ? (a) : (b))
X# define min(a,b)	(((a) < (b)) ? (a) : (b))
X# define between(v,a,b)	((v) < (a) ? (a) : (v) > (b) ? (b) : (v))
X# define percent(v,p)	(((v)*(p))/100)
X# define SKIPARG	while (*++(*argv)); --(*argv)
X# define when	        break; case
X# define orwhen	        case
X# define otherwise      break; default
X# define SKIPDIG(s)	while (ISDIGIT(*(s))) (s)++
X# define SKIPCHAR(c,s)	while (*(s)==(c)) (s)++
X# define SKIPTO(c,s)	\
X	{ while (*(s) && *(s)!=(c)) (s)++; if (*(s)==(c)) (s)++; }
X
X/* Utility Macros */
X
X/* onrc - tell if row and col have the proper attributes */
X# define onrc(type,r,c) ((type)&scrmap[r][c])
X
X/* on - tell if current position has correct attributes */
X# define on(type) onrc(type,atrow,atcol)
X
X/* seerc - is this character at row,col */
X# define seerc(ch,r,c) ((ch)==screen[r][c])
X
X/* see - is this character at current position */
X# define see(ch) seerc(atrow,atcol)
X
X/* setrc - set attribute at <r,c> */
X# define setrc(type,r,c) scrmap[r][c]|=(type)
X
X/* set - set attribute at current position */
X# define set(type) setrc(type,atrow,atcol)
X
X/* unsetrc - unset attribute at <r,c> */
X# define unsetrc(type,r,c) scrmap[r][c]&= ~(type)
X
X/* unset - unset attribute at current position */
X# define unset(type) unsetrc(type,atrow,atcol)
X
X/* Direc - give the vector from an xy difference */
X# define direc(r,c) (r>0?(c>0?7:(c<0?5:6)):(r<0?(c>0?1:(c<0?3:2)):(c>0?0:4)))
X
X/* atdrow - gives row of adjacent square given direction */
X# define atdrow(dir) (atrow+deltr[(dir)])
X
X/* atdcol - gives col of adjacent square given direction */
X# define atdcol(dir) (atcol+deltc[(dir)])
X
X/* Define a more mnemonic string comparison */
X# define streq(s1,s2) (strcmp ((s1),(s2)) == 0)
X
X/* Monster value macros */
X# define maxhitchar(m) (cosmic ? Level*3/2+6 : monatt[(m)-'A'].maxdam)
X# define avghitchar(m) (cosmic ? Level*2/3+4 : monatt[(m)-'A'].expdam)
X# define maxhit(m) maxhitchar(mlist[m].chr)
X# define avghit(m) avghitchar(mlist[m].chr)     /* times 10 */
X
X/* Item knowledge macros   DR UTexas 25 Jan 84 */
X
X/* itemis - test pack item for traits */
X# define itemis(obj,trait) ((obj>=0) ? ((trait)&inven[obj].traits) : 0)
X
X/* remember - set traits for pack item */
X# define remember(obj,trait) ((obj>=0) ? (inven[obj].traits|=(trait)) : 0)
X
X/* forget - clear traits for pack item */
X# define forget(obj,trait) ((obj>=0) ? (inven[obj].traits&= ~(trait)) : 0)
X
X/* The types of objects */
Xtypedef enum { strange, food, potion, scroll, wand, ring, hitter,
X               thrower, missile, armor, amulet, gold, none} stuff;
X
Xtypedef struct { int   fail, win; } probability;
X
Xtypedef struct { int   count;
X		 double sum, sumsq, low, high; } statistic;
X
Xtypedef struct { int   scol, srow;
X                 stuff what; } stuffrec;
X
Xtypedef struct { int   mcol, mrow;
X                 char  chr;
X                 int   q; } monrec;
X
Xtypedef struct { int   expdam, maxdam, mtokill; } attrec;
X
Xtypedef struct { int gamecnt, gamesum, inittime, timeswritten; } lrnrec;
X
Xtypedef struct { char m_name[NAMSIZ];
X		 probability wehit, theyhit, arrowhit;
X		 statistic htokill, damage, atokill; } ltmrec;
X
Xtypedef struct { stuff type; 
X                 int   count, phit, pdam, charges, traits;
X		 char  *str;  } invrec;
X
Xtypedef struct { int activity[T_LISTLEN];
X		 int timestamp; } timerec;
/
echo 'Part 08 of Rog-O-Matic XIV complete.'
exit

mlm@cmu-cs-cad.ARPA (Michael Mauldin) (02/01/85)

#!/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@cmu-cs-a.arpa
#
echo 'Start of Rog-O-Matic XIV, part 09 of 10:'
echo 'x - README'
sed 's/^X//' > README << '/'
X************************************************************************
X* README: Rog-O-Matic XIV (CMU) Tue Jan 29 15:02:02 1985 - mlm
X* Copyright (C) 1985 by A. Appel, G. Jacobson, L. Hamey, and M. Mauldin
X************************************************************************
X
X* Here is Rog-O-Matic XIV, the automatic Rogue player for the eighties! *
X
X1.0 UNPACKING:
X
XRog-O-Matic is shipped as a collection of shell archives.  Run the
Xdistribution files through the shell (e.g. "sh rgm14.01"), and the
Xindividual source files will be created.  Rog-O-Matic is stored on the
XGeneral Purpose Vax at Carnegie-Mellon University, and may be retrieved via
XFTP using the following file name:
X
X		mlm/rgm/rgm14.xx @ CMU-CS-G		(xx = 01,02,...)
X
XThe file
X
X		mlm/rgm/Instructions @ CMU-CS-G
X
Xcontains instructions and pointers to files for this public directory.
XFor FTP access, the username is 'ftpguest' and the password is 'cmunix'.
X
X2.0 INSTRUCTIONS FOR USE:
X
XTear along the dotted line and put all files into a directory. You should
Xhave the following files:
X
X	Bugreport     findscore.c   main.c        rogomatic.6   survival.c
X	README        gene.c        makefile      rooms.c       tactics.c
X	arms.c        globals.h     mess.c        rplot         termtokens.h
X	command.c     histplot.c    monsters.c    scorefile.c   things.c
X	database.c    install.h     pack.c        search.c      titlepage.c
X	datesub.l     io.c          rand.c        setup.c       types.h
X	debug.c       learn.c       replay.c      stats.c       utility.c
X	explore.c     ltm.c         rgmplot.c     strategy.c    worth.c
X
XBugreport contains descriptions of any known bugs and patches to fix them.
XMain.c is the main file of Rog-O-Matic, and contains descriptions of all
Xother files.  Install.h contains the installation dependent preprocessor
Xvariables. 
X
XEdit "install.h" to set up various log files and directories, and then
Xcreate the RGMDIR directory, making certain that it is publicly readable
Xand writable.  After that, the 'make' command will build your own
Xpersonalized automatic Rogue playing system!
X
XThe preprocessor variables defined are:
X
XBEST:           The compile time copy of the best current score. 
X		Now 43,402 (against 3.6) and 7935 (against 5.2),
X		and 11,316, total winner (against Rogue 5.3).
XBOGUS:          The highest score to be considered "reasonable" by
X                Rog-O-Matic. Rog-O-Matic will only try to beat non-bogus
X                scores. Currently set at 50,000.
XERRORLOG:	A fully qualified filename to which snapshots of game
X		positions are appended when severe or fatal bugs/
X                inconsistencies are found.
XLOCKFILE:	A file name in in the /tmp directory used to serialize
X		accesses to the score file.
XMAXLOCK:	A number of seconds after which to ignore the lock file.
X		Usually 3 minutes (120 seconds).
XNEWROGUE:	On systems where the default Rogue is 3.6, this is the
X		name of the Rogue 5.2 or Rogue 5.3 file.
XPLAYER:         This is the file name of the player program, which is
X                execl'ed by the rogomatic program. It should be fully
X                qualified.
XRGMDIR:		The name of the directory where the Rog-O-Matic gene pool,
X		long term memory, and score files are kept.  It must be 
X		publicly readable and writeable.  This directory must
X		be created by hand.
XROGUE:          This is the file name of the Rogue game. Usually this is
X                /usr/games/rogue.
XROGUELOG:       When the game logging (or "echoing") is enabled, a
X		complete transcript of the game is written to this
X		file.  If the program finishes normally, this file
X		will be renamed to <killer>.<level>.<score>, and can 
X		either be examined by "cat"ing it or replayed using the
X		"-p" option of rogomatic. This should be an unqualified
X		file name.
XSNAPSHOT:	An unqualified file name where game snapshots are put.
X		The 'snapshot' command appends game photos to this file
X		in the user's directory.
X
XAfter "make"ing, you should have the following programs:
X
X        rogomatic  player  datesub  rgmplot  histplot gene
X
Xand the shell script:
X
X        rplot
X
X
XThese should be put into the games directory, in such a way that the player
Xprogram has the same name as that specified by the PLAYER variable in
Xinstall. Otherwise, you will have to "cd" to the directory containing
XRogomatic to play.
X
X3.0 DESCRIPTIONS OF THE PROGRAMS AND COMMANDS.
X
X3.1 ROGOMATIC
X
X    The files "rogomatic" and "player" contain the basic Rog-O-Matic.
X    Rogomatic parses the arguments and forks and execs Rogue and Player.
X    For more information about the "rogomatic" command, see rogomatic.6.
X
X3.2 RPLOT
X
X    "rplot" prints a scatter plot of the rogomatic score file. Options
X    allow for inclusion of scores obtained by cheating and addition of
X    a rolling average to the plot.  "rplot" uses the rgmplot program.
X
X3.3 HISTPLOT
X
X    "histplot" reads the scorefile and produces a histogram of either
X    final score or level reached, depending on the option set.  The
X    histogram plots the killing monster for each game.
X
X3.4 GENE
X
X    "gene" summarizes the current gene pool.
X
X4.0 MORE ABOUT FILES
X
X   For those perusing the source, the following files are in the
Xsource.  The notes indicate how important an understanding of that file
Xis to understanding the strategy Rogomatic uses, and whether that file
Xcontains system code, strategy code, or utility code.
X
X	Importance:	0..9  (9 must read, 0 never look at it)
X
X	Classes:	(strat) = strategy,
X			(tact)  = tactics,
X			(mech)  = mechanics,
X			(util)  = utility
X
X       Importance	File		
X       Class:	  	Name:		Description:
X
X 	9 (mech)	install.h:	Must edit to run Rogomatic
X	9 (mech)	main.c:		Main file, references everything else
X	9 (strat)	strategy.c:	Top level strategy
X	8 (strat,tact)	tactics.c:	More insteresting production rules
X	7 (mech)	globals.h:	Description of globals
X	7 (mech)	types.h:	More description of globals
X	7 (mech)	setup.c:	Main program, forks & execs Rogue, Rgm
X	7 (tact)	arms.c:		Rules: worth of armor, weapons, rings
X	7 (tact)	worth.c:	Rules about worth of objects
X	6 (mech)	mess.c:		Handles message from Rogue
X	6 (strat,mech)	explore.c:	Defines exploration strategy
X	5 (mech)	rooms.c:	Builds terrain map
X	4 (mech)	io.c:		Handles communications from Rogue
X	4 (mech)	search.c:	Does path planning
X	4 (mech)	things.c:	Handles objects in pack
X	3 (mech)	command.c:	Sends commands to Rogue
X	3 (tact,mech)	survival.c:	Code for running away from monsters
X	2 (mech)	scorefile.c:	Handles Rogomatic scoreboard
X	2 (util)	database.c:	Remembers objects and their names
X	2 (util)	findscore.c:	Reads Rogue scoreboard
X	1 (mech)	monsters.c:	Keeps track of monsters on level
X	1 (util)	debug.c:	Debugging handler (error logger)
X	0 (mech)	replay.c:	Finds levels in log files
X	0 (mech)	termtokens.h:	Contains definitions for terminal
X	0 (mech)	titlepage.c:	Prints animated copyright notice
X	0 (util)	histplot.c:	Plots histograms of Rgm performance
X	0 (mech)	rgmplot.c:	Plots Rgm performance over time
X	0 (util)	utility.c:	Contains CMU specific system functions
X
X5.0 NET ADDRESS
X
XQuestions, comments, gripes, and ephemera to
X
X        Michael.Mauldin@CMU-CS-A.ARPA
X
X	Michael Mauldin (Fuzzy)		(412) 578-3065
X	Department of Computer Science
X	Carnegie-Mellon University
X	Pittsburgh, PA  15213
X
X6.0 MORE INFORMATION
X
X    Copies of CMU Technical Report CMU-CS-83-144, "ROG-O-MATIC:
X    A Belligerent Expert System" may be obtained by sending mail
X    to Michael Mauldin at the above addresses.  Since these will
X    be sent by US Post, you must include your US Mail address.
X
X    ROG-O-MATIC: A Belligerent Expert System    (CMU-CS-83-144)   ABSTRACT
X
X   "Rog-O-Matic  is  an  unusual combination of algorithmic and production
X    systems programming techniques which cooperate to  explore  a  hostile
X    environment. This environment is the computer game Rogue, which offers
X    several  advantages  for  studying  exploration  tasks.    This  paper
X    presents the major features of the Rog-O-Matic system,  the  types  of
X    knowledge  sources  and  rules  used  to  control the exploration, and
X    compares the performance of the system with human Rogue players."
X
X    An  abbreviated  but more recent version of this paper appeared in the
X    conference proceedings of CSCSI in May of 1984.
X    
X    A short reference to  Rog-O-Matic  also appeared in the  February 1985
X    Computer Recreations column of Scientific American, page 18-21.
X
X---end of Rog-O-Matic XIV description---
/
echo 'x - command.c'
sed 's/^X//' > command.c << '/'
X/*
X * command.c: Rog-O-Matic XIV (CMU) Thu Jan 31 20:13:11 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 send commands to
X * Rogue, this file and 'things.c' make up the effector interface.
X */
X
X# include <curses.h>
X# include <ctype.h>
X# include "types.h"
X# include "globals.h"
X
X# define EQUAL 0
X
Xstatic int cmdonscreen = 0, comcount = 0;
X
X/* Move one square in direction 'd' */
Xmove1 (d)
Xint   d;
X{ command (T_MOVING, "%c", keydir[d]);
X}
X
X/* Move in direction 'd' until we find something */
Xfmove (d)
Xint   d;
X{ if (version < RV53A)	command (T_MOVING, "f%c", keydir[d]);
X  else			command (T_MOVING, "%c", ctrl (keydir[d]));
X}
X
X/* Move 'count' squares in direction 'd', with time use mode 'mode' */
Xrmove (count, d, mode)
Xint   count, d, mode;
X{ command (mode, "%d%c", count, keydir[d]);
X}
X
X/* Move one square in direction 'd' without picking anything up */
Xmmove (d, mode)
Xint   d, mode;
X{ command (mode, "m%c", keydir[d]);
X}
X
X/*
X * command: Send a command which takes Rogue time to execute. These
X * include movement commands, sitting, and physical actions. Actions which
X * gather information are sent to Rogue using the 'send' function.
X */
X
Xcommand (tmode, f, a1, a2, a3, a4)
Xchar *f;
Xint tmode, a1, a2, a3, a4;
X{ int times;
X  char cmd[128], functionchar (); 
X  static char lastcom[32] = "";
X
X  /* Build the command */
X  sprintf (cmd, f, a1, a2, a3, a4);
X
X  /* Echo the command if in transparent mode */
X  if (transparent)		showcommand (cmd);
X  else if (cmdonscreen)		clearcommand ();
X
X  /* Figure out whether and in which direction we are moving */
X  switch ((functionchar (cmd) & 037) | 0100)
X  { case 'L': movedir = 0; wakemonster (movedir); break;
X    case 'U': movedir = 1; wakemonster (movedir); break;
X    case 'K': movedir = 2; wakemonster (movedir); break;
X    case 'Y': movedir = 3; wakemonster (movedir); break;
X    case 'H': movedir = 4; wakemonster (movedir); break;
X    case 'B': movedir = 5; wakemonster (movedir); break;
X    case 'J': movedir = 6; wakemonster (movedir); break;
X    case 'N': movedir = 7; wakemonster (movedir); break;
X    default:  movedir = NOTAMOVE;
X  }
X  
X  /* If in a real game (not replaying), then check for looping */
X  if (!replaying)
X  { if (streq (lastcom, cmd))
X    { comcount++;
X      if (streq (cmd, "i") && comcount > 3)
X        dwait (D_FATAL, "command: cannot synchronize inventory, invcount %d.",
X               invcount);
X    }
X    else
X    { strcpy (lastcom, cmd);
X      comcount = 1;
X    }
X  }
X
X  /* If command takes time to execute, mark monsters as sleeping */
X  /* If they move, wakemonsters will mark them as awake */
X  if (tmode != T_OTHER)
X    sleepmonster ();
X
X  /* Do time accounting */
X  times = commandcount (cmd);
X  if (tmode < T_OTHER || tmode >= T_LISTLEN) tmode = T_OTHER;
X  turns += times;
X  timespent[Level].timestamp = turns;
X  timespent[Level].activity[tmode] += times > 1 ? times : 1;
X
X  /* Do the inventory stuff */
X  if (movedir == NOTAMOVE)
X    adjustpack (cmd);
X
X  /* If we have a ring of searching, take that into account */
X  if (wearing ("searching") != NONE)
X    bumpsearchcount ();
X
X  send (cmd);
X}
X
X/* 
X * commandcount: Return the number of a times a command is to happen.
X */
X
Xcommandcount (cmd)
Xchar *cmd;
X{ register int times = atoi (cmd);
X
X  return (max (times, 1));
X}
X
X/* 
X * functionchar: return the function character of a command.
X */
X
Xchar
Xfunctionchar (cmd)
Xchar *cmd;
X{ register char *s = cmd;
X
X  while (ISDIGIT (*s) || *s == 'f') s++;
X  return (*s);
X}
X
X/* 
X * commandarg: return the nth argument of a command.
X */
X
Xchar
Xcommandarg (cmd, n)
Xchar *cmd;
X{ register char *s = cmd;
X
X  while (ISDIGIT (*s) || *s == 'f') s++;
X  return (s[n]);
X}
X
X/* 
X * adjustpack: adjust pack in accordance with command.
X */
X
Xadjustpack (cmd)
Xchar *cmd;
X{ char is1[128], is2[128], functionchar(), commandarg();
X  int newweapon, obj;
X
X  switch (functionchar (cmd))
X  { case 'd':	setrc (STUFF | USELESS, atrow, atcol);
X		deleteinv (OBJECT (commandarg (cmd, 1)));
X		break;
X
X    case 'e':   removeinv (OBJECT (commandarg (cmd, 1)));
X                Ms[0] = 'X'; newring = 1;
X		lastate = turns;
X                break;
X
X    case 'i':	doresetinv ();
X		break;
X
X    case 'q':	lastobj = OBJECT (commandarg (cmd, 1));
X		usemsg ("Quaffing", lastobj);
X		strcpy (lastname, inven[lastobj].str);
X		useobj (inven[lastobj].str);
X		removeinv (lastobj);
X		break;
X
X    case 'r':	lastobj = OBJECT (commandarg (cmd, 1));
X		usemsg ("Reading", lastobj);
X		strcpy (lastname, inven[lastobj].str);
X		useobj (inven[lastobj].str);
X		removeinv (lastobj);
X		break;
X
X    case 't':	removeinv (OBJECT (commandarg (cmd, 2)));
X		hitstokill -= 1; /* Dont blame weapon if arrow misses */
X		break;
X
X    case 'w':	if (currentweapon != NONE)
X		  forget (currentweapon, INUSE);
X
X		newweapon = OBJECT (commandarg (cmd, 1));
X		usemsg ("About to wield", newweapon);
X
X		if (commandarg (cmd, 2) == 'w')
X		{ lastdrop = currentweapon = newweapon; }
X		else
X		{ lastdrop = currentweapon; currentweapon = newweapon; }
X
X		remember (currentweapon, INUSE);
X		
X		usingarrow = (inven[currentweapon].type == missile);
X		goodweapon = (weaponclass (currentweapon) >= 100);
X		
X		badarrow = goodarrow = poorarrow = hitstokill = 0;
X		newweapon = 1;
X		setbonuses ();
X		break;
X
X    case 'p': case 'z':
X		lastwand = OBJECT (commandarg (cmd, 2));
X		usemsg ("Pointing", lastwand);
X		strcpy (lastname, inven[lastwand].str);
X		useobj (inven[lastwand].str);
X
X		/* Update number of charges */
X		if (inven[lastwand].charges > 0) 
X		{ if (version >= RV52A &&
X		      stlmatch (inven[lastwand].str, "striking"))
X		  inven[lastwand].charges -= 2;
X		else
X		  inven[lastwand].charges--;
X		}
X  
X		hitstokill -= 1; /* Dont blame weapon if wand misses */
X		break;
X
X    case 's':   bumpsearchcount ();
X		break;
X
X    case 'P':	obj = OBJECT (commandarg (cmd, 1));
X		usemsg ("Putting on", obj);
X
X		if (commandarg (cmd, 2) == 'l')		leftring = obj;
X		else if (commandarg (cmd, 2) == 'r')	rightring = obj;
X		else if (leftring == NONE)		leftring = obj;
X		else					rightring = obj;
X
X		/* Check for putting on see invisible */
X		if (streq (inven[obj].str, "see invisible"))
X		{ beingstalked = 0; putonseeinv = turns; }
X
X		remember (obj, INUSE);
X		setbonuses ();
X		newarmor = 1;
X
X		break;
X
X    case 'R':	if (commandarg (cmd, 1) == 'l')
X		{ lastdrop = leftring; leftring = NONE; }
X		else if (commandarg (cmd, 1) == 'r')
X		{ lastdrop = rightring; rightring = NONE; }
X		else if (leftring != NONE)
X		{ lastdrop = leftring; leftring = NONE; }
X		else
X		{ lastdrop = rightring; rightring = NONE; }
X
X		usemsg ("Taking off", lastdrop);
X
X  		forget (lastdrop, INUSE);
X		setbonuses ();
X		newarmor = 1;
X
X		break;
X
X    case 'T':   lastdrop = currentarmor;
X		usemsg ("About to take off", currentarmor);
X                forget (currentarmor, INUSE);
X                currentarmor = NONE;
X                newarmor = 1;
X		break;
X
X    case 'W':	currentarmor = OBJECT (commandarg (cmd, 1));
X		usemsg ("About to wear", currentarmor);
X		remember (currentarmor, INUSE);
X                newarmor = 1;
X		break;
X  }
X}
X
X/* 
X * bumpsearchcount: Note that we just searched this square.
X */
X
Xbumpsearchcount ()
X{ register int dr, dc;
X  for (dr = -1; dr <= 1; dr++)
X    for (dc = -1; dc <= 1; dc++)
X      timessearched[atrow+dr][atcol+dc]++;
X}
X
X/* 
X * replaycommand: Find the old command in the log file and send it.
X */
X
Xreplaycommand ()
X{ char oldcmd[128];
X
X  getoldcommand (oldcmd);
X  command (T_OTHER, oldcmd); 
X  return (1); 
X}
X
X/* 
X * showcommand:		Echo a string in the lower right hand corner.
X * clearcommand:	Remove the command we showed.
X */
X
Xshowcommand (cmd)
Xchar *cmd;
X{ register char *s;
X  at (23,72); standout (); printw (" ");
X  for (s=cmd; *s; s++) printw ("%s", unctrl (*s));
X  printw (" "); standend (); clrtoeol (); at (row, col); refresh ();
X  cmdonscreen = 1;
X}
X
Xclearcommand ()
X{ at (23,72); clrtoeol (); at (row, col);
X  cmdonscreen = 0;
X}
X/*
X * usemsg: About to use an item, tell the user.
X */
X
Xusemsg (str, obj)
Xchar *str;
Xint obj;
X{ if (! dwait (D_INFORM, "%s (%s", str, itemstr (obj)))
X    saynow ("%s (%s", str, itemstr (obj));
X}
X
/
echo 'x - histplot.c'
sed 's/^X//' > histplot.c << '/'
X/*
X * histplot.c: Rog-O-Matic XIV (CMU) Fri Dec 28 22:13:21 1984 - mlm
X * Copyright (C) 1985 by A. Appel, G. Jacobson, L. Hamey, and M. Mauldin
X *
X * This program takes a Rog-O-Matic log file and produces a histogram
X * of the scores.
X */
X
X# include <stdio.h>
X# define SKIPARG	while (*++(*argv)); --(*argv)
X
X# define BWIDTH 200
X# define NUMBUK 51
X# define BUCKET(n) (((n)+BWIDTH/2)/BWIDTH)
X# define isdigit(c) ((c) >= '0' && (c) <= '9')
X# define NOMON 29
X
Xint cheat = 0;
X
Xmain (argc, argv)
Xint argc;
Xchar *argv[];
X{ int score = 0, maxfreq = 0, lowscore = 0, min = 200, killnum = 0;
X  int bucket[NUMBUK], killed[NUMBUK][NOMON], level = 0, dolev = 0;
X  int total[NOMON];
X  register int i, j, h, f;
X  char killer[100], plot[128];  
X
X  /* Zero the buckets */
X  for (i = NUMBUK; i--; )
X  { bucket[i] = 0;
X    for (j = NOMON; j--; )
X      killed[i][j] = 0;
X  }
X  for (j = NOMON; j--;)
X    total[j] = 0;
X
X  /* Get the options */
X  while (--argc > 0 && (*++argv)[0] == '-')
X    while (*++(*argv))
X    { switch (**argv)
X      { case 'c': cheat++; break; /* List cheat games */
X        case 'l': dolev++; break; /* Plot level instead of score */
X	case 'a': min = atoi (*argv+1); SKIPARG; break;
X        default:  printf ("Usage: histplot [-c]\n");
X                  exit (1);
X      }
X    }
X
X  /*  Print out the header */
X  printf ("         %s  Histogram of Rog-O-Matic %s\n\n",
X          dolev ? "" : "            ", dolev ? "Levels" : "Scores");
X  printf ("\n");
X  if (dolev)
X    printf ("Games     1   5   10   15   20   25   30\n");
X  else
X    printf ("Games    0      2000      4000      6000      8000     10000\n");
X
X  /* While more scores do action for each score */
X  while (getscore (&score, killer, &level) != EOF)
X  {
X    if (score < min) { lowscore++; continue; }
X
X    if (dolev) { h = level; }
X    else       { if ((h = BUCKET(score)) >= NUMBUK) h = NUMBUK-1; }
X
X    bucket[h]++;
X    
X    if (stlmatch (killer, "arrow"))			killnum = 1;
X    else if (stlmatch (killer, "black unicorn"))	killnum = 'u'-'a'+2;
X    else if (stlmatch (killer, "bolt"))			killnum = 1;
X    else if (stlmatch (killer, "dart"))			killnum = 1;
X    else if (stlmatch (killer, "fatal error trap"))	killnum = 0;
X    else if (stlmatch (killer, "floating eye"))		killnum = 'e'-'a'+2;
X    else if (stlmatch (killer, "gave"))			killnum = 0;
X    else if (stlmatch (killer, "giant ant"))		killnum = 'a'-'a'+2;
X    else if (stlmatch (killer, "hypothermia"))		killnum = 'i'-'a'+2;
X    else if (stlmatch (killer, "quit"))			killnum = 28;
X    else if (stlmatch (killer, "starvation"))		killnum = 'e'-'a'+2;
X    else if (stlmatch (killer, "user"))			killnum = 0;
X    else if (stlmatch (killer, "venus flytrap"))	killnum = 'f'-'a'+2;
X    else if (stlmatch (killer, "violet fungi"))		killnum = 'f'-'a'+2;
X    else killnum = *killer - 'a' + 2;
X
X    killed[h][killnum]++;
X        
X    if (bucket[h] > maxfreq) maxfreq = bucket[h];
X  }
X
X  for (f = ((maxfreq+9)/10)*10; f; f--)
X  { if (dolev)
X    { if (f%10 == 0)
X        sprintf (plot, "|----+----|----+----|----+----|");
X      else if (f%5 == 0)
X        sprintf (plot, "|    +    |    +    |    +    |");
X      else
X        sprintf (plot, "|         |         |         |");
X    }
X    else
X    { if (f%10 == 0)
X        sprintf (plot, "|----+----|----+----|----+----|----+----|----+----|");
X      else if (f%5 == 0)
X        sprintf (plot, "|    +    |    +    |    +    |    +    |    +    |");
X      else
X        sprintf (plot, "|         |         |         |         |         |");
X    }
X    
X    for (i = 0; i < NUMBUK; i++)
X      if (bucket[i] >= f)
X      { plot[i] = '#';
X        for (j = NOMON; j--;)
X        { if (killed[i][j] > 0)
X	  { killed[i][j]--;
X	    plot[i] = "$@ABCDEFGHIJKLMNOPQRSTUVWXYZ#"[j];
X	    total[j]++;
X	    break;
X	  }
X	}
X      }
X    
X    if (f%5 == 0)
X      printf ("     %3d %s\n", f, plot);
X    else
X      printf ("         %s\n", plot);
X  }
X
X  if (dolev)
X  {
X    printf ("         |----+----|----+----|----+----|\n");
X    printf ("          1   5   10   15   20   25   30\n");
X  }
X  else
X  {
X    printf ("         |----+----|----+----|----+----|----+----|----+----|\n");
X    printf ("         0      2000      4000      6000      8000     10000\n");
X  }
X
X
X  printf ("\n\n");
X  if (total[28])
X    printf ("             # Quit\n");
X  printf ("           A-Z Monster which killed Rog-O-Matic\n");
X  if (total[1])
X    printf ("             @ Killed by an arrow, bolt, or dart\n");
X  if (total[0])
X    printf ("             $ Killed by user or error\n");
X  if (lowscore)
X    printf ("      %8d scores below %d not printed.\n", lowscore, min);
X}
X
X# define LEVELPOS 47
X
Xgetscore (score, killer, level)
Xint *score, *level;
Xchar *killer;
X{ int dd, yy;
X  char line[128], mmstr[8], player[16], cheated=' ';
X  while (fgets (line, 128, stdin))
X  { dd = yy = *score = 0;
X    sscanf (line, "%s %d, %d %10s%d%c%17s",
X            mmstr, &dd, &yy, player, score, cheated, killer);
X    if (strlen (line) > LEVELPOS) *level = atoi (line+LEVELPOS);
X    if (yy > 0 &&
X        (cheated != '*' || cheat) &&
X        !stlmatch (killer, "saved") &&
X        (*score > 2000 || !stlmatch (killer, "user")))
X      return (1);
X  }
X  return (EOF);
X}
/
echo 'x - ltm.c'
sed 's/^X//' > ltm.c << '/'
X/*
X * ltm.c: Rog-O-Matic XIV (CMU) Fri Dec 28 20:37:04 1984 - mlm
X * Copyright (C) 1985 by A. Appel, G. Jacobson, L. Hamey, and M. Mauldin
X *
X * This file contains functions for maintaining a database or "long
X * term memory"
X */
X
X# include <curses.h>
X# include <math.h>
X# include "types.h"
X# include "globals.h"
X# include "install.h"
X
Xstatic int nosave = 0;		/* True ==> dont write ltm back out */
Xstatic char ltmnam[100];	/* Long term memory file name */
X
X/* 
X * mapcharacter: Read a character help message
X */
X
Xmapcharacter (ch, str)
Xchar ch, *str;
X{
X  dwait (D_CONTROL, "mapcharacter called: '%c' ==> '%s'", ch, str);  
X
X  /* Ancient versions of Rogue had no wands or staves */
X  if (ch == '/' && stlmatch (str, "unknown"))
X    version = RV36A;
X
X  /* Dont map any unknown character */
X  else if (stlmatch (str, "unknown"))
X    ;
X
X  /* If it is a monster, set its array index */
X  else if (ch >= 'a' && ch <= 'z')
X  { monindex[ch-'a'+ 1] = addmonhist (str); }
X}
X
X/* 
X * addmonhist:  Return the monster index of a given monster name in the
X * history array.  Create an entry if none exists.
X */
X
Xint addmonhist (monster)
Xchar *monster;
X{ register int m;
X
X  /* Search for the monsters entry in the table */
X  for (m=0; m<nextmon; m++)
X    if (streq (monster, monhist[m].m_name))
X      return (m);
X
X  if (nextmon >= MAXMON)			/* Check for overflow */
X    dwait (D_FATAL, "Overflowed monster array");
X
X  strcpy (monhist[nextmon].m_name, monster);	/* Copy in the name */
X  return (nextmon++);				/* Return the index */
X}
X
X/* 
X * findmonster:  Return the monster index of a given monster name in the
X * history array.  Return -1 if the monster is not in the table.
X */
X
Xint findmonster (monster)
Xchar *monster;
X{ register int m;
X
X  /* Search for the monsters entry in the table */
X  for (m=0; m<nextmon; m++)
X    if (streq (monster, monhist[m].m_name))
X      return (m);
X
X  return (-1);
X}
X
X/* 
X * saveltm: Write the new monster information out to the long term memory
X * file for this version of Rogue.  Be careful about serializing
X * access to the output file.
X */
X
Xsaveltm (score)
Xint score;
X{ register int m;
X  register FILE *ltmfil;
X  
X  if (nextmon < 1 || nosave) return;
X
X  dwait (D_CONTROL, "Saveltm called, writing file '%s'", ltmnam);
X
X  /* Disable interrupts and open the file for writing */
X  critical ();
X
X  /* Only write out the new results if we can get write access */
X  if (lock_file (LOCKFILE, MAXLOCK))
X  { if ((ltmfil = wopen (ltmnam, "w")) == NULL)
X    { dwait (D_WARNING, "Can't write long term memory file '%s'...", ltmnam); }
X    else
X    { /* Write the ltm file header */
X      fprintf (ltmfil, "Count %d, sum %d, start %d, saved %d\n",
X	       ltm.gamecnt+1, ltm.gamesum+score,
X               ltm.inittime, ltm.timeswritten+1);
X
X      /* Now write a line for each monster */
X      for (m = 0; m < nextmon; m++)
X      { fprintf (ltmfil, "%s|", monhist[m].m_name);
X        writeprob (ltmfil, &monhist[m].wehit);    fprintf (ltmfil, "|");
X        writeprob (ltmfil, &monhist[m].theyhit);  fprintf (ltmfil, "|");
X        writeprob (ltmfil, &monhist[m].arrowhit); fprintf (ltmfil, "|");
X        writestat (ltmfil, &monhist[m].htokill);   fprintf (ltmfil, "|");
X        writestat (ltmfil, &monhist[m].damage);   fprintf (ltmfil, "|");
X        writestat (ltmfil, &monhist[m].atokill);  fprintf (ltmfil, "|\n");
X      }
X
X      /* Close the file and unlock it */  
X      fclose (ltmfil);
X    }
X    unlock_file (LOCKFILE);
X  }
X  
X  /* Re-enable interrupts */
X  uncritical ();
X}
X
X/* 
X * restoreltm: Read the long term memory file.
X */
X
Xrestoreltm ()
X{
X  sprintf (ltmnam, "%s/ltm%d", RGMDIR, version);
X  dwait (D_CONTROL, "Restoreltm called, reading file '%s'", ltmnam);
X
X  clearltm (monhist);			/* Clear the original sums */
X  nextmon = 0;				/* Zero the list of monsters */
X  monindex[0] = addmonhist ("it");	/* Monster 0 is "it" */
X
X  /* Disable interrupts and open the file for reading */
X  critical ();
X
X  /* Only read the long term memory if we can get access */
X  if (lock_file (LOCKFILE, MAXLOCK))
X  { if (fexists (ltmnam))
X      readltm ();
X    else 
X    { dwait (D_CONTROL | D_SAY,
X             "Starting long term memory file '%s'...", ltmnam);
X      ltm.gamecnt = ltm.gamesum = ltm.timeswritten = 0;
X      ltm.inittime = time (0);
X    }
X
X    unlock_file (LOCKFILE);
X  }
X  else
X  { saynow ("Warning: could not lock long term memory file!");    
X    nosave = 1;
X  }
X  
X  uncritical ();
X}
X
X/* 
X * readltm: Read in the long term memory file for this version of Rogue
X * into storage.  Be careful about serializing access to the file.
X */
X
Xreadltm ()
X{ char buf[BUFSIZ];
X  register FILE *ltmfil;
X  
X  if ((ltmfil = fopen (ltmnam, "r")) == NULL)
X  { nosave = 1;
X    dwait (D_WARNING | D_SAY,
X           "Could not read long term memory file '%s'...", ltmnam);
X  }
X  else
X  { /* Read the ltm file header */
X    if (fgets (buf, BUFSIZ, ltmfil))
X      sscanf (buf, "Count %d, sum %d, start %d, saved %d",
X	      &ltm.gamecnt, &ltm.gamesum, 
X	      &ltm.inittime, &ltm.timeswritten);
X
X    /* Read each monster line */
X    while (fgets (buf, BUFSIZ, ltmfil))
X      parsemonster (buf);
X
X    fclose (ltmfil);
X  }
X}
X
X/* 
X * parsemonster: parse one line from the ltm file.
X */
X
Xparsemonster (monster)
Xchar *monster;
X{ register char *attrs;
X  char *index();
X  register int m;
X
X  /* Separate the monster name from the attributes */
X  if ((attrs = index (monster, '|')) == NULL) return;
X  *attrs++ = '\0';
X
X  /* Find the monsters entry in long term memory */
X  m = addmonhist (monster);
X
X  /* Now parse the probabilities and statistics */
X  parseprob (attrs, &monhist[m].wehit);		SKIPTO ('|', attrs);
X  parseprob (attrs, &monhist[m].theyhit);	SKIPTO ('|', attrs);
X  parseprob (attrs, &monhist[m].arrowhit);	SKIPTO ('|', attrs);
X  parsestat (attrs, &monhist[m].htokill);	SKIPTO ('|', attrs);
X  parsestat (attrs, &monhist[m].damage);	SKIPTO ('|', attrs);
X  parsestat (attrs, &monhist[m].atokill);	SKIPTO ('|', attrs);
X}
X
X/* 
X * clearltm: Clear a whole long term memory array.
X */
X
Xclearltm (ltm)
Xregister ltmrec *ltm;
X{ register int i;
X
X  for (i=0; i<MAXMON; i++)
X  { ltm[i].m_name[0] = '\0';
X    clearprob (&ltm[i].wehit);
X    clearprob (&ltm[i].theyhit);
X    clearprob (&ltm[i].arrowhit);
X    clearstat (&ltm[i].htokill);
X    clearstat (&ltm[i].damage);
X    clearstat (&ltm[i].atokill);
X  }
X}
X
X/* 
X * dumpmonstertable: Format and print the monster table on the screen
X */
X
Xdumpmonstertable ()
X{ register int m;
X  char monc;
X
X  clear (); mvprintw (0,0,"Monster table:");
X  analyzeltm ();
X
X  for (m=0, monc='A';  m<26;  m++, monc++)
X  { if (m < 13) at (m+2, 0);
X    else        at (m-11, 40);
X
X    printw ("%c: %s", monc, monname (monc));
X    if (monhist[monindex[m+1]].damage.count > 0)
X      printw (" (%d,%d)", monatt[m].expdam, monatt[m].maxdam);
X    else
X      printw (" <%d>", monatt[m].maxdam);
X    if (monhist[monindex[m+1]].atokill.count > 0)
X      printw (" [%d]", monatt[m].mtokill);
X  }
X
X  pauserogue ();
X}
X
X/* 
X * analyzeltm: Set the monatt array based on current long term memory.
X */
X
Xanalyzeltm ()
X{ register int m, i;
X  double avg_dam = 0.6*Level+3, max_dam = 7.0+Level, avg_arr = 4.0;
X  double phit, mean_dam, stdev_dam, three_dev;
X
X  /* Loop through each monster in this game (not whole ltm file) */
X  for (i=0; i<26; i++)
X  { m = monindex[i+1];
X
X    /* Calculate expected and maximum damage done by monster */
X    if (monhist[m].damage.count > 3)
X    { mean_dam = mean (&monhist[m].damage);
X      stdev_dam = stdev (&monhist[m].damage);
X      max_dam = monhist[m].damage.high;
X
X      avg_dam = mean_dam * prob (&monhist[m].theyhit);
X      three_dev = mean_dam + 3 * stdev_dam;
X      
X      if (max_dam > three_dev && monhist[m].damage.count > 10)
X      { max_dam = mean_dam + stdev_dam;
X        monhist[m].damage.high = max_dam;
X      }
X    }
X    else if (monhist[m].damage.high > 0.0)
X      max_dam = monhist[m].damage.high;
X
X    /* Calculate average arrows fired to killed monster */
X    if (monhist[m].atokill.count > 2)
X    { phit = prob (&monhist[m].arrowhit); phit = max (phit, 0.1);
X      avg_arr = mean (&monhist[m].atokill) / phit;
X    }
X
X    /* Now store the information in the monster tables */    
X    monatt[i].expdam = ceil (avg_dam*10);
X    monatt[i].maxdam = ceil (max_dam);
X    monatt[i].mtokill = ceil (avg_arr);
X  }
X}
/
echo 'x - monsters.c'
sed 's/^X//' > monsters.c << '/'
X/*
X * monsters.c: Rog-O-Matic XIV (CMU) Thu Jan 31 20:23:07 1985 - mlm
X * Copyright (C) 1985 by A. Appel, G. Jacobson, L. Hamey, and M. Mauldin
X *
X * This file contains all of the monster specific functions.
X */
X
X# include <stdio.h>
X# include <ctype.h>
X# include <curses.h>
X# include "types.h"
X# include "globals.h"
X
X# define ADJACENT(m) (max (abs (mlist[m].mrow - atrow),\
X			   abs (mlist[m].mcol - atcol)) == 1)
X
X/*
X * monname: Return a monster name given letter '@ABC..Z'
X */
X
Xchar *monname (m)
Xchar m;
X{ return (monhist[monindex[m-'A'+1]].m_name);
X}
X
X/*
X * addmonster: add a monster to this level. Remove any monsters on the
X * list which are in the same square.
X */
X
Xaddmonster (ch, row, col, quiescence)
Xchar  ch;
Xint   row, col, quiescence;
X{ char *monster = monname (ch);
X
X  if (row > 1 || col > 3)
X  { if (isholder (monster)) quiescence = AWAKE;
X    deletemonster (row, col);
X    mlist[mlistlen].chr = ch;
X    mlist[mlistlen].mrow = row;
X    mlist[mlistlen].mcol = col;
X    mlist[mlistlen].q = quiescence;
X    if (++mlistlen >= MAXMONST) dwait (D_FATAL, "Too many monsters");
X    setrc (MONSTER, row, col);
X    lyinginwait = 0;
X    new_arch = 1;
X
X    /* If we can see it, it is not really invisible */
X    if (stlmatch (monster, "invisible") || streq (monster, "phantom"))
X      beingstalked = 0;
X  }
X}
X
X/*
X * deletemonster: remove a monster from the list at location (row, col).
X */
X
Xdeletemonster (row, col)
Xint   row, col;
X{ int   i;
X
X  new_arch = 1;
X  unsetrc (MONSTER, row, col);
X
X  for (i = 0; i < mlistlen; ++i)
X    if (mlist[i].mcol == col && mlist[i].mrow == row)
X    { mlist[i] = mlist[--mlistlen]; i--; }
X}
X
X/*
X * dumpmonsters: (debugging) dump the list of monsters on this level.
X */
X
Xdumpmonster ()
X{ int   i;
X  at (1, 0);
X  for (i = 0; i < mlistlen; ++i)
X    printw ("%s at %d,%d(%c) \n",
X            mlist[i].q == AWAKE ? "alert" : 
X              mlist[i].q == ASLEEP ? "sleeping" :
X              mlist[i].q == HELD ? "held" : "unknown",
X            mlist[i].mrow, mlist[i].mcol,
X            mlist[i].chr);
X  printw ("You are at %d,%d.", atrow, atcol);
X  at (row, col);
X}
X
X/*
X * sleepmonster: Turn all unknown monsters into sleeping monsters.
X * This routine is called after we have executed a command, so if
X * the value of ASLEEP is not overridden by the monsters movement,
X * it sat still for a turn and must be asleep.
X */
X
Xsleepmonster ()
X{  register int m;
X
X  for (m = 0; m < mlistlen; ++m)
X  { if (mlist[m].q == 0 && ! ADJACENT (m))
X    { dwait (D_MONSTER, "Found a sleeping %s at %d,%d",
X             monname (mlist[m].chr), mlist[m].mrow, mlist[m].mcol);
X      
X      mlist[m].q = ASLEEP;
X    }
X  }
X}
X
X/*
X * holdmonsters: Mark all close monsters as being held.
X */
X
Xholdmonsters ()
X{ register int m;
X
X  for (m = 0; m < mlistlen; ++m)
X  { if (mlist[m].q == 0 &&
X        (max (abs (mlist[m].mrow - atrow),
X              abs (mlist[m].mcol - atcol)) < 3))
X    { dwait (D_MONSTER, "Holding %s at %d,%d",
X             monname (mlist[m].chr), mlist[m].mrow, mlist[m].mcol);
X      
X      mlist[m].q = HELD;
X    }
X  }
X}
X
X/*
X * wakemonster: Turn monsters into waking monsters
X *
X * dir = 0-7 means wake up adjacent plus monster in that dir
X * dir = 8   means wake up only adjacent monster
X * dir = ALL means wake up all monsters
X * dir = -m  means wake up all adjacent monsters of type m.
X */
X
Xwakemonster (dir)
Xint dir;
X{ register int m;
X
X  for (m = 0; m < mlistlen; ++m)
X  { if (mlist[m].q != AWAKE &&
X        (dir == ALL || 
X	 (dir < 0 && ADJACENT(m) && mlist[m].chr == -dir + 'A' - 1) ||
X         (dir >= 0 && dir < 8 &&
X          mlist[m].mrow == atdrow(dir) && mlist[m].mcol == atdcol(dir))))
X    { dwait (D_MONSTER, "Waking up %s at %d,%d",
X             monname (mlist[m].chr), mlist[m].mrow, mlist[m].mcol);
X      
X      mlist[m].q = AWAKE;
X      setrc (EVERCLR, mlist[m].mrow, mlist[m].mcol);
X    }
X  }
X}
X
X/*
X * seemonster: Return true if a particular monster is on the monster list.
X */
X
Xseemonster (monster)
Xchar *monster;
X{ register int m;
X
X  for (m = 0; m < mlistlen; ++m)
X    if (streq (monname (mlist[m].chr), monster))
X      return (1);
X
X  return (0);
X}
X
X/*
X * seeawakemonster: Returns true if there is a particular awake 
X * monster on the monster list.		DR UTexas 26 Jan 84
X */
X
Xseeawakemonster (monster)
Xchar *monster;
X{ register int m;
X
X  for (m = 0; m < mlistlen; ++m)
X   if (streq (monname (mlist[m].chr), monster) && mlist[m].q == AWAKE)
X     return (1);
X
X  return (0);
X}
X
X/*
X * monsternum: Given a string e.g. "umber hulk", return the monster
X *             number from 0 to 26, e.g. "umber hulk" ==> 21. Zero
X *             is used for unknown monsters (e.g. "it").
X */
X
Xmonsternum (monster)
Xchar *monster;
X{ int m, mh;
X
X  if ((mh = findmonster (monster)) != NONE) 
X    for (m=0; m<=26; m++)
X      if (monindex[m] == mh) return (m);
X
X  return (0);
X}
X
X/* 
X * newmonsterlevel: Starting a new level. Set the initial sleep status of
X * each monster.
X */
X
Xnewmonsterlevel ()
X{ register int m;
X  register char *monster;
X
X  for (m=0; m<mlistlen; m++)
X  { monster = monname (mlist[m].chr);
X
X    if (streq (monster, "floating eye")   ||
X        streq (monster, "leprechaun")     ||
X        streq (monster, "nymph")          ||
X        streq (monster, "ice monster"))
X      mlist[m].q = ASLEEP;
X    else
X      mlist[m].q = 0;
X  }
X}
X
X/* 
X * isholder: Return true if the monster can hold us.
X */
X
Xisholder (monster)
Xregister char *monster;
X{ 
X  return (streq (monster, "venus flytrap") || streq (monster, "violet fungi"));
X}
X
X/* 
X * stubs for Leonards stuff.  These are to be replaced with code which
X * determines what monsters we have seen that are not now on the screen.
X */ 
X
Xdomonster () {}
Xdonemonster () {}
Xkillmonster () {}
/
echo 'x - worth.c'
sed 's/^X//' > worth.c << '/'
X/*
X * worth.c: Rog-O-Matic XIV (CMU) Thu Jan 31 15:54:56 1985 - mlm
X * Copyright (C) 1985 by A. Appel, G. Jacobson, L. Hamey, and M. Mauldin
X *
X * This file contains the function worth (obj) which does the impossible
X * job of deciding how much each item in the pack is worth.
X *
X * The worth of an item is a number from 0 to 5000, with 0 indicating that
X * the object is completely useless, and 5000 indicating that its a really
X * nifty piece of work.  This function is used by 'tostuff' to decide
X * which is the "worst" object in the pack.
X */
X
X# include <curses.h>
X# include "types.h"
X# include "globals.h"
X
Xint   objval[] = { 
X/* strange */      0,
X/* food */       900,
X/* potion */     500,
X/* scroll */     400,
X/* wand */       600,
X/* ring */       800,
X/* hitter */     100,
X/* thrower */    100,
X/* missile */    300,
X/* armor */      200,
X/* amulet */    5000,
X/* gold */      1000,
X/* none */         0};
X
Xworth (obj)
Xint obj;
X{ int value, w;
X
X  /* Do we have an easy out? */
X  if (useless (obj)) return (0);
X
X  /* Poison has a use in RV52B and RV53A, so give it a low positive value */
X  if (stlmatch (inven[obj].str, "poison")) return (1);       
X
X  /* Set base value */
X  value = objval[(int) inven[obj].type];
X
X  /* Bonus if we know what it is */
X  if (itemis (obj, KNOWN))
X    value += 50;
X
X  /* 
X   * Armor values are based on armor class, bonus for best,
X   * second best, or leather armor (leather doesnt rust)
X   */
X
X  if (inven[obj].type == armor)
X  { value = (10 - armorclass (obj)) * 90;
X    
X    if (obj == havearmor (1, NOPRINT, ANY))		value += 2000;
X    else if (obj == havearmor (2, NOPRINT, ANY))	value += 1500;
X
X    if (!willrust (obj))				value += 150;
X  }
X
X  /* 
X   * Bow values are based on bow class, bonus for best
X   * or second best.
X   */
X
X  else if (inven[obj].type == thrower)
X  { value = (bowclass (obj)) * 5;
X    
X    if (obj == havebow (1, NOPRINT)) value += 1000;
X    else if (obj == havebow (2, NOPRINT)) value += 500;
X  }
X
X  /* Weapons values are counted by hit potential, bonus for best */
X  else if ((w = weaponclass (obj)) > 0)
X  { value = w * 5;
X    
X    if (obj == haveweapon (1, NOPRINT)) value += 1500;
X    else if (obj == haveweapon (2, NOPRINT)) value += 1000;
X  }
X
X  /* Rings values are counted by bonus */
X  else if ((w = ringclass (obj)) > 0)
X  { if (w > 1000) w -= 500; /* Subtract part of food bonus */
X    value = w + 400;
X  }
X
X  /* For arbitrary things, bonus for plus item */
X  else
X  { if (inven[obj].phit != UNKNOWN)
X      value += inven[obj].phit * 75;
X  }
X
X  /* Prefer larger bundles of missiles */
X  if (inven[obj].type == missile)
X    value += inven[obj].count * 50;
X
X  /* Prefer wands with more charges */
X  if (inven[obj].type == wand && inven[obj].charges != UNKNOWN)
X    value += inven[obj].charges * 35;
X
X  /* Special Values for Certain objects */
X  if (stlmatch (inven[obj].str, "raise level")) value = 1200;
X  else if (stlmatch (inven[obj].str, "restore strength")) value = 800;
X  else if (stlmatch (inven[obj].str, "scare monster")) value = 1400;
X  else if (stlmatch (inven[obj].str, "teleportation")) value = 1000;
X  else if (stlmatch (inven[obj].str, "enchant")) value = 800;
X
X  /* Now return the value, assure in the range [0..5000] */
X  return (value < 0 ? 0 : value > 5000 ? 5000 : value);
X}
X
X/*
X * useless: called with an integer from 0 to 25 it returns 1 if that
X * object is of no use. Used by worth to set value to 0.
X */
X
Xuseless (i)
Xint i;
X{
X  /* Not useless if we are using it */
X  if (itemis (i, INUSE))
X    return (0);
X
X  /* Worn out or bad wands are useless */
X  if ((inven[i].type == wand) &&
X      (inven[i].charges == 0 ||
X       stlmatch (inven[i].str, "teleport to") ||
X       stlmatch (inven[i].str, "haste monster")))
X    return (1);
X
X  /* Many potions are useless */
X  if (inven[i].type == potion && itemis (i, KNOWN) &&
X      (stlmatch (inven[i].str, "paralysi") ||
X       stlmatch (inven[i].str, "confusion") ||
X       stlmatch (inven[i].str, "hallucination") ||
X       stlmatch (inven[i].str, "blind") ||
X       stlmatch (inven[i].str, "monster detection") ||
X       stlmatch (inven[i].str, "magic detection") ||
X       stlmatch (inven[i].str, "thirst") ||
X       (stlmatch (inven[i].str, "haste self") && doublehasted) ||
X       (stlmatch (inven[i].str, "see invisible") && 
X        havenamed (ring, "see invisible") != NONE)))
X    return (1);
X
X  /* So are many scrolls */
X  if (inven[i].type == scroll && itemis (i, KNOWN) &&
X      (stlmatch (inven[i].str, "blank") ||
X       stlmatch (inven[i].str, "create monster") ||
X       stlmatch (inven[i].str, "sleep") ||
X       stlmatch (inven[i].str, "gold detection") ||
X       stlmatch (inven[i].str, "aggravate")))
X    return (1);
X
X  /* And bad rings are useless */
X  if (inven[i].type == ring && itemis (i, KNOWN) &&
X      ((inven[i].phit != UNKNOWN && inven[i].phit < 0) ||
X       stlmatch (inven[i].str, "teleport") ||
X       stlmatch (inven[i].str, "telport") ||     /* For R3.6 MLM */
X       stlmatch (inven[i].str, "adornment") ||
X       stlmatch (inven[i].str, "aggravate")))
X    return (1);
X
X  /* One of some rings is enough */
X  if (inven[i].type == ring && itemis (i, KNOWN) &&
X      havemult (ring, inven[i].str, 2) != NONE &&
X      (stlmatch (inven[i].str, "see invisible") ||
X       stlmatch (inven[i].str, "sustain strength") ||
X       stlmatch (inven[i].str, "searching") ||
X       stlmatch (inven[i].str, "increase damage") ||
X       stlmatch (inven[i].str, "stealth")))
X    return (1);
X
X  /* Three of any ring is too much */
X  if (inven[i].type == ring && havemult (ring, inven[i].str, 3) != NONE)
X    return (1);
X
X  /* If we are cheating and we have a good arrow */
X  /* then many rings do us no good at all.       */
X  if (inven[i].type == ring && usingarrow && goodarrow > 20 &&
X      (stlmatch (inven[i].str, "add strength") ||
X       stlmatch (inven[i].str, "dexterity") ||
X       stlmatch (inven[i].str, "increase damage")))
X    return (1);
X
X  return (0);
X}
/
echo 'Part 09 of Rog-O-Matic XIV complete.'
exit

mlm@cmu-cs-cad.ARPA (Michael Mauldin) (02/01/85)

#!/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@cmu-cs-a.arpa
#
echo 'Start of Rog-O-Matic XIV, part 10 of 10:'
echo 'x - database.c'
sed 's/^X//' > database.c << '/'
X/*
X * database.c: Rog-O-Matic XIV (CMU) Fri Dec 28 23:26:25 1984 - mlm
X * Copyright (C) 1985 by A. Appel, G. Jacobson, L. Hamey, and M. Mauldin
X * 
X * This file contains the code which handles the database of objects which
X * have been used, and what the real names of the items are. There are
X * five functions:
X *
X *      useobj (oldname)             enter the object type into the database
X *      infername (oldname, name)    make the real name of obj be name
X *      used (oldname)               returns TRUE if we have entered obj
X *      know (name)                  returns TRUE if we have inferred name
X *      realname (oldname)           returns the inferred name of obj
X */
X
X# include <curses.h>
X# include "types.h"
X# include "globals.h"
X
X# define TABLESIZE 101
X# define NOTFOUND  (-1)
X
Xstruct  { char  fakename[64];
X          char  roguenam[64]; } dbase[TABLESIZE];
X
Xint datalen = 0;
X
X/* 
X * findentry: find the database entry for 'string'
X */
X
Xfindentry (string)
Xchar *string;
X{ register int i;
X
X  for (i = 0; i < datalen; i++)
X    if (streq (dbase[i].fakename, string) ||
X        *dbase[i].roguenam && streq (dbase[i].roguenam, string))
X      return (i);
X
X  return (NOTFOUND);
X}
X
X/* 
X * useobj: Indicate that we have used (i.e. read, quaffed, or zapped) an
X *         object with name 'oldname'.
X */
X
Xuseobj (oldname)
Xchar *oldname;
X{ if (findentry (oldname) == NOTFOUND)
X  { strcpy (dbase[datalen].fakename, oldname);
X    strcpy (dbase[datalen++].roguenam, "");
X  }
X}
X
X/* 
X * infername: Note that we now think that the object named 'oldname' is
X * really named 'name' (e.g. scroll 'google plex' is really a scroll of
X * light).
X */
X
Xinfername (oldname, name)
Xchar *oldname;
Xchar *name;
X{ register int i;
X
X  i = findentry (oldname);
X
X  if (i == NOTFOUND)
X  { strcpy (dbase[datalen].fakename, oldname);
X    strcpy (dbase[datalen++].roguenam, name);
X  }
X  else
X  { if (*dbase[i].roguenam && strcmp (dbase[i].roguenam, name))
X      dwait (D_ERROR, "Inconsistent inference '%s', '%s'", 
X             dbase[i].roguenam, name);
X    else
X      strcpy (dbase[i].roguenam, name);
X    }
X}
X
X/* 
X * used: Return true if we have marked 'oldname' as used.
X */
X
Xint used (oldname)
Xchar *oldname;
X{ register int i;
X
X  for (i = 0; i < datalen; i++)
X    if (streq (dbase[i].fakename, oldname))
X      return (TRUE);
X
X  return (FALSE);
X}
X
X/* 
X * know: Return true if we know what the fake name for 'name' is.
X */
X
Xint know (name)
Xchar *name;
X{ register int i;
X
X  for (i = 0; i < datalen; i++)
X    if (*dbase[i].roguenam && streq (dbase[i].roguenam, name))
X      return (TRUE);
X
X  return (FALSE);
X}
X
X/* 
X * realname: Returns the real name of an object nmed 'oldname'.
X */
X
Xchar *realname (oldname)
Xchar *oldname;
X{ register int i;
X
X  for (i = 0; i < datalen; i++)
X    if (*dbase[i].roguenam && streq (dbase[i].fakename, oldname))
X      return (dbase[i].roguenam);
X
X  return ("");
X}
X
X/* 
X * dumpdatabase: Debugging, dump the database one the screen.
X */
X
Xdumpdatabase ()
X{ register int i;
X
X  for (i = 0; i < datalen; i++)
X  { at (i+1, 0);
X    printw ("%-32s '%s'", dbase[i].roguenam, dbase[i].fakename);
X  }
X}
/
echo 'x - findscore.c'
sed 's/^X//' > findscore.c << '/'
X/*
X * findscore.c: Rog-O-Matic XIV (CMU) Fri Dec 28 23:27:10 1984 - mlm
X * Copyright (C) 1985 by A. Appel, G. Jacobson, L. Hamey, and M. Mauldin
X *
X * Read the Rogue scoreboard to determine a goal score.
X */
X
X# include <stdio.h>
X# include "install.h"
X# define TEMPFL "/tmp/RscoreXXXXXX"
X# define ISDIGIT(c) ((c) >= '0' && (c) <= '9')
X
Xfindscore (rogue, roguename)
Xregister char *rogue, *roguename;
X{ register int score, best = -1;
X  char cmd[100], buffer[BUFSIZ];
X  register char *s, *tmpfname = TEMPFL;
X  FILE *tmpfil;
X
X  /* Run 'rogue -s', and put the scores into a temp file */
X  sprintf (cmd, "%s -s >%s", rogue, mktemp (tmpfname)); 
X  system (cmd); 
X
X  /* If no temp file created, return default score */
X  if ((tmpfil = fopen (tmpfname, "r")) == NULL)
X    return (best); 
X
X  /* Skip to the line starting with 'Rank...'. */
X  while (fgets (buffer, BUFSIZ, tmpfil) != NULL)
X    if (stlmatch (buffer, "Rank")) break;
X
X  if (! feof (tmpfil)) 
X  { best = BOGUS;
X    while (fgets (buffer, BUFSIZ, tmpfil) != NULL)
X    { s = buffer;				/* point s at buffer */
X      while (ISDIGIT (*s)) s++;			/* Skip over rank */
X      while (*s == ' ' || *s == '\t') s++;	/* Skip to score */
X      score = atoi (s);				/* Read score */
X      while (ISDIGIT (*s)) s++;			/* Skip over score */
X      while (*s == ' ' || *s == '\t') s++;	/* Skip to player */
X
X      if (score < best)				/* Save smallest score */
X        best = score;
X      if (stlmatch (s, roguename))		/* Found our heros name */
X        break; 
X    }
X  }
X
X  unlink (tmpfname); 
X  return (best);
X}
/
echo 'x - gene.c'
sed 's/^X//' > gene.c << '/'
X/*
X * gene.c: Rog-O-Matic XIV (CMU) Mon Jan 28 20:51:32 1985 - mlm
X * Copyright (C) 1985 by A. Appel, G. Jacobson, L. Hamey, and M. Mauldin
X *
X * Initialize and summarize the gene pool
X */
X
X# include <stdio.h>
X# include "types.h"
X# include "install.h"
X
Xint knob[MAXKNOB];
Xchar genelock[100];
Xchar genelog[100];
Xchar genepool[100];
X
Xmain (argc, argv)
Xint   argc;
Xchar *argv[];
X{ int m=10, init=0, seed=0, version=RV53A, full=0;
X
X  /* Get the options */
X  while (--argc > 0 && (*++argv)[0] == '-')
X  { while (*++(*argv))
X    { switch (**argv)
X      { when 'i':	init++;
X	when 'f':	full++;
X	when 'm':	m = atoi(*argv+1); SKIPARG;
X			printf ("Gene pool size %d.\n", m);
X	when 's':	seed = atoi(*argv+1); SKIPARG;
X			printf ("Random seed %d.\n", m);
X	when 'v':	version = atoi(*argv+1); SKIPARG;
X			printf ("Rogue version %d.\n", version);
X	otherwise:	quit (1, "Usage: gene [-i] [-msv<value>]\n");
X      }
X    }
X  }
X
X  /* Assign the gene log and pool file names */
X  sprintf (genelock, "%s/GeneLock%d", RGMDIR, version);
X  sprintf (genelog, "%s/GeneLog%d", RGMDIR, version);
X  sprintf (genepool, "%s/GenePool%d", RGMDIR, version);
X
X  critical ();				/* Disable interrupts */
X  if (lock_file (genelock, MAXLOCK))
X  { if (init) 
X    { srand (seed);			/* Set the random number generator */
X      openlog (genelog);		/* Open the gene log file */
X      initpool (MAXKNOB, m);		/* Random starting point */
X      writegenes (genepool);		/* Write out the gene pool */
X      closelog ();			/* Close the log file */
X    }
X    else if (! readgenes (genepool))	/* Read the gene pool */
X      quit (1, "Cannot read file '%s'\n", genepool);
X
X   unlock_file (genelock);
X  }
X  else
X    quit (1, "Cannot access file '%s'\n", genepool);
X
X  uncritical ();			/* Re-enable interrupts */
X  analyzepool (full);			/* Print a summary */
X}
/
echo 'x - install.h'
sed 's/^X//' > install.h << '/'
X/*
X * install.h: Rog-O-Matic XIV (CMU) Wed Jan 30 17:39:50 1985 - mlm
X * Copyright (C) 1985 by A. Appel, G. Jacobson, L. Hamey, and M. Mauldin
X *
X * This file contains (hopefully) all system dependent defines 
X * This version of Rog-O-Matic runs with Rogue version 5.2. 
X */
X
X/*
X * BSD41: Defined for 4.1bsd Unix systems (Undefined means 4.2bsd)
X */
X
X# define BSD41
X
X/*
X * Rog-O-Matic's best score against Rogue 5.3  (UTexas, Feb 1984)
X * Printed when no score file is available in dumpscore()
X */
X
X# define BEST		(11316)
X
X/* 
X * Rog-O-Matic will not try to beat scores higher than BOGUS which
X * appear on the Rogue scoreboard.
X */
X
X# define BOGUS		(50000)
X
X/* 
X * This variable defines the version of Rogue we are assumed to be playing
X * if the getrogueversion() routine can't figure it out.  This must be
X * defined, and can be either "5.2", "3.6", or "5.3"
X */
X
X# define DEFVER		"5.3"
X
X/* 
X * This file is created whenever the Rog-O-Matic score file is accessed to
X * prevent simulatneous accesses. This variable must be defined, but will
X * not be used unless RGMDIR is also defined.
X */
X
X# define LOCKFILE	"/tmp/Rgm Lock"
X
X/* 
X * This variable is the level at which we always start logging the game
X */
X
X# define GOODGAME	(16)
X
X/* 
X * This variable is the number of seconds after which a LOCKFILE is
X * considered to be invalid.  This is necessary to avoid requiring manual
X * intervention when Rog-O-Matic dies while the score file is open.
X * This variable must be defined, but will not be used unless RGMDIR
X * is also defined.
X */
X
X# define MAXLOCK	(120 /* seconds */)
X
X/* 
X * This variable defines the "local" copy of Rogue, which may have only
X * intermittent access.  This is useful at CMU, since Rogue 5.2 is not
X * supported on all machines.  First Rog-O-Matic looks for "rogue" in the
X * current directory, then this file is used.  This variable need not be
X * defined.
X */
X
X# define NEWROGUE	"/usr/mlm/bin/rogue" 
X
X/* 
X * This is the location of the player executable, which is the main
X * process for Rog-O-Matic.  If "player" does not exist in the current
X * directory, then this file is used. This variable need not be defined 
X * (but in that case there must be a "player" binary in the current 
X * directory).
X */
X
X# define PLAYER		"/usr/mlm/bin/player"
X
X/* 
X * This is the version of the "current" Rog-O-Matic, and is an uppercase
X * Roman numeral.  It must be defined.
X */
X
X# define RGMVER		"XIV"
X
X/* 
X * This is the standard system version of Rogue, and is used if "rogue"
X * and NEWROGUE are not available. It need not be defined, but if it is
X * not, and NEWROGUE is not defined, then there must be a "rogue" in the
X * current directory.
X */
X
X# define ROGUE		"/usr/games/rogue"
X
X/* 
X * This file is created in the current directory if the logging option is
X * enabled.  If the game terminates normally, this file is renamed to
X * <killer>.<level>.<score>.  This variable must be defined.
X */
X
X# define ROGUELOG	"roguelog"
X
X/* 
X * This directory must be defined.  It will contain logs of Rogomatic's
X * scores, an error.log file, and the long term memory file.  It must
X * be writeable by everyone, since score files must be created and
X * destroyed by anyone running the program.  Alternatively, the
X * player process could be made setuid, with that uid owning this
X * directory.
X */
X
X# define RGMDIR		"/usr/mlm/src/rog/ver14/rlog"
X
X/* 
X * This file is created in the current directory if the snapshot command
X * is typed during a Rogue game.  It must be defined.
X */
X
X# define SNAPSHOT	"rgm.snapshot"
/
echo 'x - makefile'
sed 's/^X//' > makefile << '/'
X# makefile: Rog-O-Matic XIV (CMU) Thu Jan 31 18:23:25 1985 - mlm
X# Copyright (C) 1985 by A. Appel, G. Jacobson, L. Hamey, and M. Mauldin
X#
XBINARIES=   rogomatic player rgmplot datesub histplot gene
XBINDIR=     /usr/mlm/bin/test
XPUBDIR=     /usr/mlm/rgm/src14
XCCFLAGS=    -g
XLDFLAGS=    
XOBJS=	    arms.o command.o database.o debug.o explore.o io.o learn.o\
X	    ltm.o main.o mess.o monsters.o pack.o rand.o replay.o rooms.o\
X	    scorefile.o search.o stats.o strategy.o survival.o tactics.o\
X	    things.o titlepage.o utility.o worth.o 
XSRCS=	    arms.c command.c database.c debug.c explore.c io.c learn.c\
X	    ltm.c main.c mess.c monsters.c pack.c rand.c replay.c rooms.c\
X	    scorefile.c search.c stats.c strategy.c survival.c tactics.c\
X	    things.c titlepage.c utility.c worth.c 
XHDRS=	    types.h globals.h install.h termtokens.h
XOTHERS=     setup.c findscore.c datesub.l histplot.c rgmplot.c gene.c\
X	    rplot Bugreport
X#
X# The following commands are declared:
X#
Xall: $(BINARIES)
X	echo -n "" >/dev/tty
X#
X#
X# General makefile stuff:
X#
Xarms.o: types.h globals.h
X	cc -c $(CCFLAGS) arms.c
Xcommand.o: types.h globals.h
X	cc -c $(CCFLAGS) command.c
Xdatabase.o: types.h globals.h
X	cc -c $(CCFLAGS) database.c
Xdatesub.c: datesub.l
X	lex datesub.l
X	mv lex.yy.c datesub.c
Xdatesub.o: datesub.c
X	cc -c $(CCFLAGS) datesub.c
Xdatesub: datesub.o
X	cc $(LDFLAGS) -o datesub datesub.o
Xdebug.o: types.h globals.h install.h
X	cc -c $(CCFLAGS) debug.c
Xexplore.o: types.h globals.h
X	cc -c $(CCFLAGS) explore.c
Xfindscore.o: install.h
X	cc -c $(CCFLAGS) findscore.c
Xgene: gene.c rand.o learn.o stats.o utility.o types.h install.h
X	cc $(CCFLAGS) $(LDFLAGS) -o gene gene.c \
X		rand.o learn.o stats.o utility.o -lm
Xhistplot: histplot.o utility.o
X	cc $(LDFLAGS) -o histplot histplot.o utility.o
Xhistplot.o:
X	cc -c histplot.c
Xio.o: types.h globals.h termtokens.h
X	cc -c $(CCFLAGS) io.c
Xmess.o: types.h globals.h
X	cc -c $(CCFLAGS) mess.c
Xlearn.o: types.h  install.h
X	cc -c $(CCFLAGS) learn.c
Xltm.o: types.h globals.h
X	cc -c $(CCFLAGS) ltm.c
Xmain.o: install.h termtokens.h types.h globals.h
X	cc -c $(CCFLAGS) main.c
Xmonsters.o: types.h globals.h
X	cc -c $(CCFLAGS) monsters.c
Xpack.o: types.h globals.h
X	cc -c $(CCFLAGS) pack.c
Xplayer: $(OBJS)
X	cc $(LDFLAGS) -o player $(OBJS) -lm -lcurses -ltermcap
X	size player
Xrand.o: rand.c
X	cc -c $(CCFLAGS) rand.c
Xreplay.o: types.h globals.h
X	cc -c $(CCFLAGS) replay.c
Xrgmplot.o: rgmplot.c
X	cc -c $(CCFLAGS) rgmplot.c
Xrgmplot: rgmplot.o utility.o
X	cc $(LDFLAGS) -o rgmplot rgmplot.o utility.o
Xrogomatic: setup.o findscore.o scorefile.o utility.o
X	cc $(LDFLAGS) -o rogomatic setup.o findscore.o scorefile.o utility.o
X	size rogomatic
Xrooms.o: types.h globals.h
X	cc -c $(CCFLAGS) rooms.c
Xscorefile.o: types.h globals.h install.h
X	cc -c $(CCFLAGS) scorefile.c
Xsearch.o: types.h globals.h
X	cc -c $(CCFLAGS) search.c
Xsetup.o: install.h
X	cc -c $(CCFLAGS) setup.c
Xstats.o: types.h
X	cc -c $(CCFLAGS) stats.c
Xstrategy.o: types.h globals.h install.h
X	cc -c $(CCFLAGS) strategy.c
Xsurvival.o: types.h globals.h
X	cc -c $(CCFLAGS) survival.c
Xtactics.o: types.h globals.h
X	cc -c $(CCFLAGS) tactics.c
Xtestfind: testfind.o findscore.o utility.o
X	cc $(LDFLAGS) -o testfind testfind.o findscore.o utility.o
Xthings.o: types.h globals.h
X	cc -c $(CCFLAGS) things.c
Xtitlepage.o: titlepage.c
X	cc -c $(CCFLAGS) titlepage.c
Xtitler.o: titler.c
X	cc -c titler.c
Xutility.o:
X	cc -c $(CCFLAGS) utility.c
Xworth.o: types.h globals.h
X	cc -c $(CCFLAGS) worth.c
X#
X# Miscellaneous useful pseduo-makes
X#
Xbackup:
X	rm -f backup.tar
X	tar cvf backup.tar *.c *.h *.l rogomatic.6 makefile
X	chmod ugo-w backup.tar
Xclean:
X	rm -f *.CKP *.o datesub.c core
X	strip $(BINARIES)
Xinstall:
X	rm -f $(BINDIR)/player
X	ln player $(BINDIR)/player
X	rm -f $(BINDIR)/rogomatic
X	ln rogomatic $(BINDIR)/rogomatic
Xtitler: titler.c
X	cc -o titler titler.c -lcurses -ltermcap
Xanim: anim.c utility.o
X	cc -o anim anim.c utility.o -lcurses -ltermcap
Xindex: $(SRCS)
X	ctags -x $(SRCS) > index
Xfluff: $(SRCS)
X	lint *.c	| grep -v 'variable # of args' \
X			| grep -v 'unused in function' \
X			| grep -v 'used inconsistently' \
X			| grep -v 'declared inconsistently' \
X			| grep -v 'multiply declared' \
X			> fluff
Xprint: $(SRCS) $(HDRS)
X	@echo $? > printit
Xdist: $(SRCS) $(HDRS) $(OTHERS) makefile rogomatic.6 README
X	rm -rf $(PUBDIR)	
X	mkdir $(PUBDIR)
X	cp $(SRCS) $(HDRS) $(OTHERS) makefile rogomatic.6 README $(PUBDIR)
X	chmod 0444 $(PUBDIR)/*
X	du $(PUBDIR)
X
Xgenetest: genetest.o learn.o rand.o stats.o utility.o types.h
X	cc -g -o genetest genetest.o learn.o rand.o stats.o utility.o -lm
X
Xgplot: gplot.c
X	cc -g -o gplot gplot.c -lm
/
echo 'x - replay.c'
sed 's/^X//' > replay.c << '/'
X/*
X * replay.c: Rog-O-Matic XIV (CMU) Fri Dec 28 22:43:54 1984 - mlm
X * Copyright (C) 1985 by A. Appel, G. Jacobson, L. Hamey, and M. Mauldin
X * 
X * Make a table of offsets to the beginning of each level of a
X * Rog-O-Matic log file.
X */
X
X# include <curses.h>
X# include <ctype.h>
X# include "types.h"
X# include "globals.h"
X
X# define MAXNUMLEV 50
X# define FIRSTLEVSTR "\nR: "
X# define NEWLEVSTR "\nR: {ff}"
X# define POSITAT   "{ff}"
X
Xstruct levstruct {
X	long pos;
X	int  level, gold, hp, hpmax, str, strmax, ac, explev, exp;
X} levpos[MAXNUMLEV];
Xint numlev = 0;
X
X/* 
X * positionreplay: Called when user has typed the 'R' command, it fills
X * the level table by calling findlevel if necessary, and then positions
X * the log file to the level requested by the user.
X */
X
Xpositionreplay ()
X{ int curlev;
X  long curpos;
X  char cmd;
X
X  /* Prompt user for a command character, read it, and lower case it */
X  saynow ("Which level (f=first, p=previous, c=current, n=next, l=last): ");
X  if (isupper ((cmd = getch ()))) cmd = tolower (cmd);
X
X  /* Clear the prompt */
X  saynow ("");
X
X  /* If command is not in the list, clear the prompt and exit. */
X  switch (cmd)
X  { case 'f': case 'p': case 'c': case 'n': case 'l': break;
X    default:  return;
X  }
X
X  /* Save the current position in the file */
X  curpos = ftell (logfile);
X
X  /* Read the log file, if we have not already done so */
X  if (!logdigested)
X  { saynow ("Reading whole log file to find levels...");
X
X    if (!findlevel (logfile, levpos, &numlev, MAXNUMLEV))
X    { saynow ("Findlevel failed! Let's try to get back to where we were...");
X      fseek (logfile, curpos, 0);
X      return;
X    }
X    logdigested++;
X  }
X
X  /* Now figure out the current level (so relative commands will work) */  
X  for (curlev = 0; curlev < numlev-1; curlev++)
X    if (levpos[curlev+1].pos > curpos) break;
X
X  /* Now clear the screen, position the log file, and return */
X  switch (cmd)
X  { case 'f': fseek (logfile, levpos[0].pos, 0); break;
X    case 'p': if (curlev > 0) fseek (logfile, levpos[curlev-1].pos);
X              else            fseek (logfile, levpos[0].pos, 0); break;
X	      break;
X    case 'c': fseek (logfile, levpos[curlev].pos); break;
X    case 'n': if (curlev < numlev-1) fseek (logfile, levpos[curlev+1].pos);
X              else            fseek (logfile, levpos[curlev].pos, 0); break;
X	      break;
X    case 'l': fseek (logfile, levpos[numlev-1].pos);
X	      break;
X    default:  fseek (logfile, 0L, 0);
X  }
X
X  clearscreen ();	/* Clear the screen */
X  Level = -1; 		/* Force a newlevel() call */
X}
X
X/* 
X * findlevel: Make a table of offsets to the various levels of a
X *             Rog-O-Matic log file.
X */
X
Xfindlevel (f, levpos, numlev, maxnum)
XFILE *f;
Xstruct levstruct *levpos;
Xint *numlev, maxnum;
X{ char ch;
X
X  int l=0;
X  *numlev = 0;
X
X  /* Position file after first newline */  
X  rewind (f);
X  while ((ch = getc (f)) != '\n' && (int) ch != EOF);
X
X  /* This is that start of level one */  
X  levpos[l].pos = ftell (f);
X  
X  if (!findmatch (f, FIRSTLEVSTR))
X  { rewind (f);
X    return (FAILURE);
X  }
X  
X  fillstruct (f, &levpos[l]);
X  
X  while (++l <= maxnum && findmatch (f, NEWLEVSTR))
X  { fseek (f, (long) -strlen (POSITAT), 1);
X    levpos[l].pos = ftell (f);
X    fillstruct (f, &levpos[l]);      
X  }
X
X  *numlev = l;
X  rewind (f);
X  return (SUCCESS);
X}
X
X/* 
X * fillstruct: scan the logfile from the current point, and fill in the
X * fields of a levstruct.
X */
X
Xfillstruct (f, lev)
XFILE *f;
Xstruct levstruct *lev;
X{ 
X  lev->level  = 0;
X  lev->gold   = 0;
X  lev->hp     = 0;
X  lev->hpmax  = 0;
X  lev->str    = 0;
X  lev->strmax = 0;
X  lev->ac     = 0;
X  lev->explev = 0;
X  lev->exp    = 0;
X  
X  if (!findmatch (f, "Level:")) return;
X  fscanf (f, "%d", &lev->level);
X
X  if (!findmatch (f, "Gold:")) return;
X  fscanf (f, "%d", &lev->gold);
X
X  if (!findmatch (f, "Hp:")) return;
X  fscanf (f, "%d(%d)", &lev->hp, &lev->hpmax);
X
X  if (!findmatch (f, "Str:")) return;
X  fscanf (f, "%d(%d)", &lev->str, &lev->strmax);
X
X  if (!findmatch (f, ":")) return;		/* Armor class */
X  fscanf (f, "%d", &lev->ac);
X
X  if (!findmatch (f, "Exp:")) return;
X  fscanf (f, "%d/%d", &lev->explev, &lev->exp);
X
X  saynow ("Found level %d, has %d gold...", lev->level, lev->gold);
X}
X
X/* 
X * findmatch: read from a stream until string 's' has been read. Returns 0
X * if EOF is read, and 1 if the match is found.  The stream is left
X * immediately after the matched string.
X *
X * Restriction: 's' must not contain prefix of itself as a substring.
X */
X
Xint findmatch (f, s)
XFILE *f;
Xchar *s;
X{ char *m = s, ch;
X
X  while (*m && (int) (ch = fgetc (f)) != EOF)
X    if (ch != *(m++)) m = s;
X  
X  if (*m) return (0);
X  else    return (1);
X}
/
echo 'x - rgmplot.c'
sed 's/^X//' > rgmplot.c << '/'
X/*
X * rgmplot.c: Rog-O-Matic XIV (CMU) Thu Jan 31 20:04:11 1985 - mlm
X * Copyright (C) 1985 by A. Appel, G. Jacobson, L. Hamey, and M. Mauldin
X * 
X * This program takes a Rog-O-Matic score file sorted by date and score, 
X * and produces a scatter plot of the scores.
X */
X
X# include <stdio.h>
X# define WIDTH 50
X# define AVLEN 7
X# define SCALE(n) (((n)+100)/200)
X# define isdigit(c) ((c) >= '0' && (c) <= '9')
X
Xchar *month[] = 
X{ "Jan", "Feb", "Mar", "Apr", "May", "Jun",
X  "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" };
X
Xint doavg = 0, cheat = 0, min = -1;
X
Xmain (argc, argv)
Xint argc;
Xchar *argv[];
X{ int mm, dd, yy, score = 0, lastday = -1, lastmon = -1, h;
X  int sumscores = 0, numscores = 0, i;
X  int sum[AVLEN], num[AVLEN], rsum, rnum, davg, ravg;
X  char player[100], plot[128], cheated;  
X
X  /* Clear out the rolling average statistics */
X  for (i = 0; i < AVLEN; i++)
X    sum[i] = num[i] = 0;
X
X  /* Get the options */
X  while (--argc > 0 && (*++argv)[0] == '-')
X    while (*++(*argv))
X    { switch (**argv)
X      { case 'c': cheat++; break; /* List cheat games */
X        case 'a': doavg++; break; /* Print average */
X        default:  printf ("Usage: rgmplot [-ac] [mininum]\n");
X                  exit (1);
X      }
X    }
X
X  if (argc > 0) min = atoi (argv[0]);
X
X  /*  Print out the header */
X  printf ("           Scatter Plot of Rog-O-Matic Scores versus time\n\n");
X  if (min > 0) 
X    printf ("                      Scores greater than %d\n\n", min);
X  printf ("         0      2000      4000      6000      8000     10000\n");
X  printf ("         |----+----|----+----|----+----|----+----|----+----|\n");
X
X
X  /* Build an empty plot line */
X  strcpy (plot, "|                                                 |");
X
X  /* While more scores do action for each score */
X  while (getscore (&mm, &dd, &yy, player, &score, &cheated) != EOF)
X  { 
X    /* Change days, overprint the average for day, rolling avg */
X    if ((dd != lastday || mm != lastmon) && lastday > 0)
X    { if (doavg)
X      { rsum = *sum; rnum = *num;
X        for (i = 1; i < AVLEN; i++)
X        { rsum += sum[i]; rnum += num[i]; }
X
X        davg = SCALE ((*num > 0) ? (*sum / *num) : 0);
X        ravg = SCALE ((rnum > 0) ? (rsum / rnum) : 0);
X
X        /* Roll the daily average statistics */
X        for (i = AVLEN-1; i > 0; i--)
X        { sum[i] = sum[i-1]; num[i] = num[i-1]; } 
X        *sum = *num = 0;	  	
X
X        /* Print a '*' for the daily average */
X        if (davg > 0 && davg < WIDTH)
X	  plot[davg] = '*';
X
X        /* Print a '###' for the rolling average */
X        if (ravg > 0 && ravg < WIDTH-1)
X	  plot[ravg-1] = plot[ravg] = plot[ravg+1] = '#';
X      }
X          
X      printf ("%3s %2d   %s\n", month[lastmon-1], lastday, plot);
X      strcpy (plot, "|                                                 |");
X      
X    }
X    
X    if (score > EOF)
X    { if ((h = SCALE(score)) >= WIDTH)  sprintf (plot, "%s %d", plot, score);
X      else if (plot[h] == '9')          ;
X      else if (isdigit(plot[h]))        plot[h]++;
X      else                              plot[h] = '1';
X
X      *sum += score;
X      ++*num;
X
X      sumscores += score;
X      ++numscores;
X
X      lastday = dd; lastmon = mm;
X    }
X  }
X
X  printf ("         |----+----|----+----|----+----|----+----|----+----|\n");
X  printf ("         0      2000      4000      6000      8000     10000\n");
X  
X
X  if (numscores > 0)
X    printf ("\nAverage score %d, total games %d.\n\n", 
X            sumscores/numscores, numscores);
X
X  printf ("1-9    Number of games in range.\n");
X    
X  if (doavg)
X  { printf (" *     Average of day's scores.\n");
X    printf ("###    Rolling %d day average.\n", AVLEN);
X  }
X}
X
X
Xgetlin (s)
Xchar *s;
X{ int ch, i;
X  static int endfile = 0;
X
X  if (endfile) return (EOF);
X
X  for (i=0; (ch = getchar()) != EOF && ch != '\n'; i++)
X    s[i] = ch;
X
X  s[i] = '\0';
X  
X  if (ch == EOF)
X  { endfile = 1;
X    strcpy (s, "-1 -1, -1 string -1 ");
X    return (20);
X  }
X
X  return (i);
X}
X
Xgetscore (mm, dd, yy, player, score, cheated)
Xint *mm, *dd, *yy, *score;
Xchar *player, *cheated;
X{ char line[128], reason[32];
X  while (getlin (line) != EOF)
X  { sscanf (line, "%d %d, %d %10s%d%c%17s",
X            mm, dd, yy, player, score, cheated, reason);
X    if ((*score >= min || *score < 0) &&
X	(*cheated != '*' || cheat) &&
X        !stlmatch (reason, "saved") &&
X        (*score > 2000 || !stlmatch (reason, "user")))
X      return (1);
X  }
X  return (EOF);
X}
/
echo 'x - scorefile.c'
sed 's/^X//' > scorefile.c << '/'
X/*
X * scorefile.c: Rog-O-Matic XIV (CMU) Mon Jan  7 17:20:52 1985 - mlm
X * Copyright (C) 1985 by A. Appel, G. Jacobson, L. Hamey, and M. Mauldin
X *
X * This file contains the functions which update the rogomatic scorefile,
X * which lives in <RGMDIR>/rgmscore<versionstr>. LOCKFILE is used to
X * prevent simultaneous accesses to the file. rgmdelta<versionstr>
X * contains new scores, and whenever the score file is printed the delta
X * file is sorted and merged into the rgmscore file.
X */
X
X# include <stdio.h>
X# include <sys/types.h>
X# include <sys/stat.h>
X# include "types.h"
X# include "globals.h"
X# include "install.h"
X
X# define LINESIZE	2048
X# define SCORE(s,p)     (atoi (s+p))
X
Xstatic char lokfil[100];
X
X/* 
X * add_score: Write a new score line out to the correct rogomatic score
X * file by creating a temporary copy and inserting the new line in the
X * proper place. Be tense about preventing simultaneous access to the
X * score file and catching interrupts and things.
X */
X
Xadd_score (new_line, version, noterm)
Xchar *new_line, *version;
Xint noterm;
X{ 
X  int   wantscore = 1;
X  char  ch;
X  char  newfil[100];
X  FILE *newlog;
X
X  sprintf (lokfil, "%s %s", LOCKFILE, version);
X  sprintf (newfil, "%s/rgmdelta%s", RGMDIR, version);
X
X  /* Defer interrupts while mucking with the score file */
X  critical ();
X
X  /* 
X   * Lock the score file. If lock_file fails, asks the user whether he
X   * wishes to wait. If so, then try lock_file five times and then ask
X   * again.
X   */
X  
X  while (lock_file (lokfil, MAXLOCK) == 0)
X    if (--wantscore < 1 && !noterm)
X    { printf ("The score file is busy, do you wish to wait? [y/n] ");
X      while ((ch = getchar ()) != 'y' && ch != 'n');
X      if (ch == 'y')
X        wantscore = 5;
X      else
X      { uncritical (); return; }
X    }
X  
X  /* Now create a temporary to copy into */
X  if ((newlog = wopen (newfil, "a")) == NULL)
X  { printf ("\nUnable to write %s\n", newfil); }
X  else
X  { fprintf (newlog, "%s\n", new_line);
X    fclose (newlog);
X  }
X
X  /* Write the score to the end of the delta file */
X
X  /* Now close the file, relinquish control of scorefile, and exit */
X  unlock_file (lokfil);
X  uncritical ();
X}
X
X/* 
X * dumpscore: Print out the scoreboard.
X */
X
Xdumpscore (version)
Xchar *version;
X{ 
X  char  ch, scrfil[100], delfil[100], newfil[100], allfil[100], cmd[256];
X  FILE *scoref, *deltaf;
X  int   oldmask, intrupscore ();
X
X  sprintf (lokfil, "%s %s", LOCKFILE, version);
X  sprintf (scrfil, "%s/rgmscore%s", RGMDIR, version);
X  sprintf (delfil, "%s/rgmdelta%s", RGMDIR, version);
X  sprintf (newfil, "%s/NewScore%s", RGMDIR, version);
X  sprintf (allfil, "%s/AllScore%s", RGMDIR, version);
X
X  /* On interrupts we must relinquish control of the score file */
X  int_exit (intrupscore);
X
X  if (lock_file (lokfil, MAXLOCK) == 0)
X  { printf ("Score file busy.\n");
X    exit (1);
X  }
X  
X  deltaf = fopen (delfil, "r");
X  scoref = fopen (scrfil, "r");
X
X  /* If there are new scores, sort and merge them into the score file */
X  if (deltaf != NULL)
X  { fclose (deltaf);
X
X    /* Defer interrupts while mucking with the score file */
X    critical ();
X
X    /* Make certain any new files are world writeable */    
X    oldmask = umask (0);
X
X    /* If we have an old file and a delta file, merge them */
X    if (scoref != NULL)
X    { fclose (scoref);
X      sprintf (cmd, "sort +4nr -o %s %s; sort -m +4nr -o %s %s %s", 
X               newfil, delfil, allfil, newfil, scrfil);
X      system (cmd);
X      if (filelength (allfil) != filelength (delfil) + filelength (scrfil))
X      { fprintf (stderr, "Error, new file is wrong length!\n");
X        unlink (newfil); unlink (allfil);
X        unlock_file (lokfil);
X        exit (1);
X      }
X      else
X      { /* New file is okay, unlink old files and pointer swap score file */
X        unlink (delfil); unlink (newfil);
X	unlink (scrfil); link (allfil, scrfil); unlink (allfil);
X      }      
X      scoref = fopen (scrfil, "r");
X    }
X    else
X    /* Only have delta file, sort into scorefile and unlink delta */
X    { sprintf (cmd, "sort +4nr -o %s %s", scrfil, delfil);
X      system (cmd);
X      unlink (delfil);
X      scoref = fopen (scrfil, "r");
X    }
X 
X    /* Restore umask */
X    umask (oldmask);
X
X    /* Restore interrupt status after score file stable */
X    uncritical ();
X  }
X
X  /* Now any new scores have been put into scrfil, read it */
X  if (scoref == NULL)
X  { printf ("Can't find %s\nBest score was %d.\n", scrfil, BEST);
X    unlock_file (lokfil);
X    exit (1);
X  }
X
X  printf ("Rog-O-Matic Scores against version %s:\n\n", version);
X  printf ("%s%s", "Date         User        Gold    Killed by",
X          "      Lvl  Hp  Str  Ac  Exp\n\n");
X
X  while ((int) (ch = fgetc (scoref)) != EOF)
X    putchar (ch);
X
X  fclose (scoref);
X  unlock_file (lokfil);
X
X  exit (0);
X}
X
X/* 
X * intrupscore: We have an interrupt, clean up and unlock the score file.
X */
X
Xintrupscore ()
X{ unlock_file (lokfil);
X  exit (1);
X}
X
/
echo 'x - stats.c'
sed 's/^X//' > stats.c << '/'
X/*
X * stats.c: Rog-O-Matic XIV (CMU) Fri Dec 28 23:28:59 1984 - mlm
X * Copyright (C) 1985 by A. Appel, G. Jacobson, L. Hamey, and M. Mauldin
X * 
X * A package for maintaining probabilities and statistics.
X *
X * Functions:
X *
X *    A probability is a simple count of Bernoulli trials.
X *
X *	clearprob:	Clear a probability.
X *	addprob:	Add success/failure to a probability.
X *	prob:		Calculate p(success) of a statistic.
X *	parseprob:	Parse a probability from a string.
X *	writeprob:	Write a probability to a file.
X *
X *    A statistic is a random variable with a mean and stdev.
X *
X *	clearstat:	Clear a statistic.
X *	addstat:	Add a data point to a statistic.
X *	mean:		Calculate the mean of a statistic.
X *	stdev:		Calculate the std. dev. of a statistic.
X *	parsestat:	Parse a statistic from a string.
X *	writestat:	Write a statistic to a file.
X */
X
X# include <stdio.h>
X# include <math.h>
X# include "types.h"
X
X/* 
X * clearprob: zero a probability structure.
X */
X
Xclearprob (p)
Xregister  probability *p;
X{ p->fail = p->win = 0;
X}
X
X/* 
X * addprob: Add a data point to a probability
X */
X
Xaddprob (p, success)
Xregister probability *p;
Xregister int success;
X{ 
X  if (success)	p->win++;
X  else		p->fail++;
X}
X
X/* 
X * prob: Calculate a probability
X */
X
Xdouble prob (p)
Xregister probability *p;
X{ register int trials = p->fail + p->win;
X
X  if (trials < 1)	return (0.0);
X  else			return ((double) p->win / trials);
X}
X
X/* 
X * parseprob: Parse a probability structure from buffer 'buf'
X */
X
Xparseprob (buf, p)
Xregister char *buf;
Xregister probability *p;
X{ p->win = p->fail = 0;
X  sscanf (buf, "%d %d", &p->fail, &p->win);
X}
X
X/* 
X * writeprob. Write the value of a probability structure to file 'f'.
X */
X
Xwriteprob (f, p)
Xregister FILE *f;
Xregister probability *p;
X{ fprintf (f, "%d %d", p->fail, p->win);
X}
X
X/* 
X * clearstat: zero a statistic structure.
X */
X
Xclearstat (s)
Xregister  statistic * s;
X{ s->count = 0;
X  s->sum = s->sumsq = s->low = s->high = 0.0;
X}
X
X/* 
X * addstat: Add a data point to a statistic
X */
X
Xaddstat (s, datum)
Xregister statistic *s;
Xregister int datum;
X{ double d = (double) datum;
X
X  s->count++;
X  s->sum += d;
X  s->sumsq += d*d;
X
X  if (s->count < 2)	s->low = s->high = d;
X  else if (d < s->low)	s->low = d;
X  else if (d > s->high)	s->high = d;
X}
X
X/* 
X * mean: Return the mean of a statistic
X */
X
Xdouble mean (s)
Xregister statistic *s;
X{
X  if (s->count < 1)	return (0.0);
X  else			return (s->sum / s->count);
X}
X
X/* 
X * stdev: Return the standard deviation of a statistic
X */
X
Xdouble stdev (s)
Xregister statistic *s;
X{ register n = s->count;
X
X  if (n < 2)	return (0.0);
X  else		return (sqrt ((n * s->sumsq - s->sum * s->sum) / (n * (n-1))));
X}
X
X/* 
X * parsestat: Parse a statistic structure from buffer 'buf'
X */
X
Xparsestat (buf, s)
Xregister char *buf;
Xregister statistic *s;
X{ s->count = 0;
X  s->sum = s->sumsq = s->low = s->high = 0.0;
X  sscanf (buf, "%d %lf %lf %lf %lf",
X      &s->count, &s->sum, &s->sumsq, &s->low, &s->high);
X}
X
X/* 
X * writestat. Write the value of a statistic structure to file 'f'.
X */
X
Xwritestat (f, s)
Xregister FILE *f;
Xregister statistic *s;
X{ fprintf (f, "%d %lg %lg %lg %lg",
X           s->count, s->sum, s->sumsq, s->low, s->high);
X}
/
echo 'x - titlepage.c'
sed 's/^X//' > titlepage.c << '/'
X/*
X * titlepage.c: Rog-O-Matic XIV (CMU) Tue Jan  1 14:32:17 1985 - mlm
X * Copyright (C) 1985 by A. Appel, G. Jacobson, L. Hamey, and M. Mauldin
X *
X * This file contains the functions which display the animated copyright
X * notice on the screen.  A general movie facility is used to animate
X * the screen.
X */
X
X# include <stdio.h>
X# include <curses.h>
X# include "types.h"
X# include "globals.h"
X
Xstatic char *titlepage[]={
X/* The static part of the display */
X"  @ !@ \"@ #@ K@! @!$@!K@!P@\" @\"$@\"(@\")@\"*@\"/@\"0@\"1@\"6@\"7@\"8@",
X"\"=@\"?@\"C@\"D@\"E@\"I@\"J@\"K@\"L@\"M@\"U@\"V@\"W@\"X@\"]@\"a@\"c@\"e@",
X"\"i@# @#!@#\"@##@#'@#+@#.@#2@#5@#9@#<@#>@#@@#F@#K@#P@#T@#^@#`@#c@#e@#i@$",
X" @$$@$'@$+@$.@$2@$5@$9@$<@$@@$C@$D@$E@$F@$K@$P@$T@$_@$c@$e@$i@% @%$@%'@%",
X"+@%.@%2@%5@%9@%<@%@@%C@%F@%K@%P@%T@%^@%`@%c@%f@%h@& @&%@&(@&)@&*@&/@&0@&",
X"1@&2@&6@&7@&8@&<@&@@&D@&E@&G@&L@&Q@&U@&V@&W@&X@&]@&a@&c@&g@'2@(.@(/@(0@(",
X"1@);C)<o)=p)>y)?r)@i)Ag)Bh)Ct)E()Fc)G))I1)J9)K8)L5)Nb)Oy*'A*(n*)d**r*+e*",
X",w*.A*/p*0p*1e*2l*3,*5L*6e*7o*8n*9a*:r*;d*=H*>a*?m*@e*Ay*B,*DG*Eu*Fy*HJ*",
X"Ia*Jc*Ko*Lb*Ms*No*On*P,*Ra*Sn*Td*VM*Wi*Xc*Yh*Za*[e*\\l*^M*_a*`u*al*bd*ci",
X"*dn,)@,*@,+@,,@,[D,\\D,]D,^D,_D-(@-+@--@-[D-`D.(@.*@.-@.[D.`D/(@/*@/+@/,",
X"@/-@/[D/`D0)@0*@0+@0,@0[D0\\D0]D0^D0_D2 H2!o2\"n2#o2$r2%a2&b2'l2(e2*m2+e",
X"2,m2-b2.e2/r21o22f24t25h26e28F29i2:g2;h2<t2=e2>r2?'2@s2BG2Cu2Di2El2Fd3 T",
X"3!o3\"t3#a3$l3&w3'i3(n3)n3*e3+r3-a3.g3/a30i31n32s33t35R36o37g38u39e3;33<",
X".3=63>,3@S3Ae3Bp3Ct3De3Em3Fb3Ge3Hr3J23K63L,3N13O93P83Q24 T4!o4\"t4#a4$l4",
X"&w4'i4(n4)n4*e4+r4-a4.g4/a40i41n42s43t45R46o47g48u49e4;54<.4=24>,4@O4Ac4",
X"Bt4Co4Db4Ee4Fr4H14I04J,4L14M94N84O35 T5!o5\"t5#a5$l5&w5'i5(n5)n5*e5+r5-a",
X"5.g5/a50i51n52s53t55R56o57g58u59e5;55<.5=35>,5@F5Ae5Bb5Cr5Du5Ea5Fr5Gy5I1",
X"5J65K,5M15N95O85P4",
X
X/* The dynamic part of the display */
X"~~~~~~~~~~00/~/1/~.2)~-1\\~,0\\~~~.3>~.4=~.5=~.6=~.7=~.8=~.9>~~~.2>.3=.8",
X">.9 ~~~.1>.2=.7>.8 ~~~.0>.1=.6>.7 ~~~./>.0=.5>.6 ~~~..>./=.4>.5 ~~~~~~~~",
X"~~~~~.. ./>.4 .4=.5>~./ .0>.5=.6>~.0 .1>.6=.7>~.1 .2>.7=.8>~.2).3>.8=.9>",
X"~.3 .4>.9=.:>~.4 .5>.:=.;>~.5 .6>.;=.<>~.6 .7>.<=.=>~.7 .8>.==.>>~.8 .9>",
X".>=.?>~.9 .:>.?=.@>~.: .;>.@=.A>~.; .<>.A=.B>~.< .=>.B=.C>~.= .>>.C=.D>~",
X".> .?>.D=.E>~.? .@>.E=.F>~.@ .A>.F=.G>~.A .B>.G=.H>~.B .C>.H=.I>~.C .D>.",
X"I=.J>~.D .E>.J=.K>~.E .F>.K=.L>~.F .G>.L=.M>~.G .H>.M=.N>~.H .I>.N=.O>~.",
X"I .J>.O=.P>~.J .K>.P=.Q>~.K .L>.Q=.R>~.L .M>.R=.S>~.M .N>.S=.T>~.N .O>.T",
X"=.U>~.O .P>.U=.V>~.P .Q>.V=.W>~.Q .R>.W=.X>~.R .S>.X=.Y>~.S .T>.Y=.Z>~.T",
X" .U>.Z=.[>~.U .V>.[=.\\>~.V .W>.\\=.]>~.W .X>.]=.^>~.X .Y>.^=._>~.Y .Z>.",
X"_=.`>~.Z .[>.`=.a>~.[ .\\>.a=.b>~.\\ .]>.b=.c>~.] .^>.c=.d>~.^ ._>.d=.e>",
X"~._ .`>.e=.f>~.` .a>.f=.g>~.a .b>.g=.h>~.b .c>.h=.i>~.c .d>.i ~.d .e>~.e",
X" .f>~.f .g>~.g .h>~.h ~~~~~.[D,[ ,\\j,\\ -\\D-]d-]D-^D-_D,_ ,^ ,] ,]j,] ",
X"~-[ .ZD/ZD.[ .[L.[ .\\D.]S.]D.^D._D.`D/aD-\\ -\\L-\\ -] -^ -_ -` ~/YD.Z ",
X"/\\D/]D/^D/_D.\\ .] .^ ._ .` 0`D0aD/a ~0XD0YD0ZD/Y /Z /` ~0VD0WD/[ /\\ /",
X"^ /_ 0bD0cD/] 0UD0dD~~~~~~~~~~,0 ~~-1 ~~.2 ~~/1 ~~00 ~~~~~~~~~~~~~~~~~~~",
X"~~.5S~.6t~.7u~.8p~.9i~.:d~.<D~.=r~.>a~.?g~.@o~.An~.C!~.D!~.E!~~~~~~~~~~~",
X"~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~.5 .6 .7 .8 .9 .: .; .",
X"< .= .> .? .@ .A .B .C .D .E .F 6  ~~~~~~~~~~~~~~~~~~",
XNULL};
X
X# define NEXTCHAR (*cbf?*cbf++:(cbf=1+ *movie++)[-1])
X
X/* 
X * animate: Display a movie on the screen.  A movie is a list of strings
X * wherein each character is either a bell command '}', a synchronize
X * command '~', or a triplet <row+32, col+32, char> indicating a character
X * to be placed at a specific place on the screen.
X *
X * Movies run the same speed regardless of baudrate (if the baud rate
X * greater than 2400).
X */
X
Xanimate (movie)
Xchar *movie[];
X{ register int r, c, count = 0, delaychars = (baudrate () / 200);
X  register char *cbf = "";
X
X  if (emacs || terse) return;		/* No screen ==> no movie */
X
X  clear ();				/* Clear the screen */
X  while (*movie || *cbf)		/* While more animate commands */
X  { r = NEXTCHAR;			/* Get command character */
X
X    /* Ring the Bell */
X    if (r == '}') putchar (ctrl('G'));
X
X    /* Update the screen and delay until one timestep is gone */
X    else if (r == '~')
X    { refresh ();				/* Write out screen */
X      for (; count < delaychars; count++)	/* Pad with nulls */
X        putchar (0);
X      count = 0;				/* Reset char count */
X    }
X
X    /* Write out a single character and bump the character count */
X    else
X    { r -= 32;					/* Get screen row */
X      c = NEXTCHAR - 32;			/* Get screen col */
X      mvaddch (r, c, NEXTCHAR);			/* Write out character */
X      if (count++ < 4) count += 4;		/* Assume one cursor move */
X    }
X  }
X}
X
X/*
X * halftimeshow: If its time for a halftime show, call movie.  Variable 
X * 'nohalf' is true if the user does not want to see a halftime show.
X */
X
Xhalftimeshow (level)
Xint level;
X{ static int nextshow = 1;
X
X  /* If terminal is too slow, dont bother */
X  if (baudrate () < 1200)
X    return;
X
X  if (!nohalf && level >= nextshow)
X  { if (nextshow == 1)
X    { nextshow = 9999; animate (titlepage); }
X  }
X}
/
echo 'Part 10 of Rog-O-Matic XIV complete.'
exit

mlm@cmu-cs-cad.ARPA (Michael Mauldin) (02/01/85)

#!/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@cmu-cs-a.arpa
#
echo 'Start of Rog-O-Matic XIV, part 02 of 10:'
echo 'x - explore.c'
sed 's/^X//' > explore.c << '/'
X/*
X * explore.c: Rog-O-Matic XIV (CMU) Thu Jan 31 20:14:30 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 are used to search out
X * paths to explore, pick up something, or run away.
X */
X
X# include <curses.h>
X# include "types.h"
X# include "globals.h"
X
X# define SEARCHES(r,c)						\
X	(onrc(DEADEND,r,c) ?					\
X	    ((version < RV53A || !isexplored (r,c)) ?		\
X		(timestosearch + k_door / 5) :			\
X		(timestosearch - k_door / 5 + 5)) :		\
X	    timestosearch)
X
Xstatic int expDor, expavoidval;
Xstatic int avdmonsters[24][80];
X
Xint connect[9][4] = {
X    /* Room  top    bot   left  right*/
X    /* 0 */  {-1,     3,    -1,     1},
X    /* 1 */  {-1,     4,     0,     2},
X    /* 2 */  {-1,     5,     1,    -1},
X    /* 3 */  { 0,     6,    -1,     4},
X    /* 4 */  { 1,     7,     3,     5},
X    /* 5 */  { 2,     8,     4,    -1},
X    /* 6 */  { 3,    -1,    -1,     7},
X    /* 7 */  { 4,    -1,     6,     8},
X    /* 8 */  { 5,    -1,     7,    -1}
X};
X
X/*
X * genericinit: Initialize a 'standard' movement search.	MLM
X */
X
Xgenericinit ()
X{ expavoidval = avoid();
X  return (1);
X}
X
X/* Secret door search values and continuance tables:
X *
X *  Number of unsearched walls adjacent.
X *
X * 	Vert	Horiz	Value		Cont	Explanation
X *	---------------------------------------------------
X *	0	0	0		0	Valueless
X *	0	1	N-24-dep	16	Prefer (0,2) 1 move later
X *	0	2	N-22-dep	15	Prefer (0,3) 1 move later
X *	0	3	N-20-dep	14	Prefer (1,0) 10 moves later
X *	1	0	N-9-dep		4	Prefer (1,1) 2 moves later
X *	1	1	N-6-dep		2	Prefer (2,0) 1 move later
X *	1	2	N-5-dep		2	Prefer (2,0) 1 move later
X *	1	3	N-5-dep		2	Impossible
X *	2	0	N-3-dep		1	Prefer (3,0) 1 move later
X *	2	1	N-2-dep		0
X *	2	2	N-1-dep		0
X *	2	3	N-1-dep		0	Impossible
X *	3	0	N		0	Best possible
X *	3	1	N		0	Impossible
X *	3	2	N		0	Impossible
X *	3	3	N		0	Impossible
X */
X
X# define N 100
Xstatic int secretvalues[16]= { 0, N-24, N-22, N-20,
X		             N-9,  N-6,  N-5,  N-5,
X		             N-3,  N-2,  N-1,  N-1,
X		               N,    N,    N,    N };
X
Xstatic int secretcont[16] =  { 0, 16, 15, 14,
X 			       4,  2,  2,  2,
X			       1,  0,  0,  0,
X			       0,  0,  0,  0 };
X
X/*
X * gotowards: Move toward a square.
X */
X
Xint gotorow = NONE, gotocol = NONE;
X
Xgotowards (row, col, running)
Xint row, col, running;
X{ int gotoinit(), gotovalue();
X
X  gotorow = row; gotocol = col;
X  return (makemove (running ? RUNAWAY:GOTOMOVE, gotoinit, gotovalue, REUSE));
X}
X
X/*
X * gotoinit: Initialize a gotowards move.
X */
X
Xgotoinit ()
X{ expavoidval = avoid();
X  return (1);
X}
X
X/*
X * gotovalue: Only the current target square has a value.
X */
X
Xgotovalue (r, c, depth, val, avd, cont)
Xint r, c, depth, *val, *avd, *cont;
X{ 
X  *avd = onrc (SAFE, r, c)    ? 0 :
X	 onrc (ARROW, r, c)   ? 50 :
X         onrc (TRAPDOR, r, c) ? 175 :
X         onrc (TELTRAP, r, c) ? 50 :
X         onrc (GASTRAP, r, c) ? 50 :
X         onrc (BEARTRP, r, c) ? 50 :
X         onrc (DARTRAP, r, c) ? 200 :
X         onrc (WATERAP, r, c) ? 50 :
X         onrc (MONSTER, r, c) ? 150 :
X         expavoidval;
X
X  if (onrc (SCAREM, r, c) && version < RV53A && objcount != maxobj)
X    *avd += 200;
X
X  *val = r == gotorow && c == gotocol ? 1 : 0;
X  /*  *cont = 0; // default value when called // */
X  return (1);
X}
X
X/*
X * sleepvalue: Squares with sleeping monsters have value. 
X *             Use genericinit.		MLM
X */
X
Xsleepvalue (r, c, depth, val, avd, cont)
Xint r, c, depth, *val, *avd, *cont;
X{ 
X  *avd = onrc (SAFE, r, c)    ? 0 :
X	 onrc (ARROW, r, c)   ? 50 :
X         onrc (TRAPDOR, r, c) ? 175 :
X         onrc (TELTRAP, r, c) ? 50 :
X         onrc (GASTRAP, r, c) ? 50 :
X         onrc (BEARTRP, r, c) ? 50 :
X         onrc (DARTRAP, r, c) ? 200 :
X         onrc (WATERAP, r, c) ? 50 :
X         onrc (MONSTER, r, c) ? 150 :
X         expavoidval;
X
X  if (onrc (SCAREM, r, c) && version < RV53A && objcount != maxobj)
X    *avd += 200;
X
X  if (onrc (SLEEPER, r, c))
X  { *val = 1;
X    *avd = 0;
X    /* *cont = 0;  // default value when called // */
X  }
X
X  return (1);
X}
X
X/*
X * wallkind: given a row and column, determine which kind of wall if any
X *           is there. Part of doorinit   Guy Jacobson 5/82
X */
X
Xint wallkind (r, c)
Xint r, c;
X{
X  switch (screen[r][c]) 
X  { case '|': if (onrc (ROOM, r, c+1)) return (LEFTW);
X              else return (RIGHTW);
X    case '-': if (onrc (ROOM, r+1, c)) return (TOPW); 
X              else if (onrc (ROOM, r-1, c)) return (BOTW);
X              else return (CORNERW);
X    case '+': return (DOORW);
X    default:  return (NOTW);
X  }
X}
X
X/* 
X * setpsd: Initialize secret door search 
X *
X * Guy Jacobson 5/82
X * Modified to allow searching even when there are cango bits.	MLM.   10/82
X * Modified to reuse existing map while it is valid.		LGCH.  10/82
X * Modified to understand maze room secret doors.		MLM.   10/83
X */
X
Xsetpsd (print)
X{ register int i, j, k, whereto, numberpsd=0;
X
X  if (!print && reusepsd > 0) return (reusepsd-1);
X
X  /* find what rooms are missing */
X  markmissingrooms ();
X
X  /* Changed loop boundaries to ignore border around screen -- mlm 5/18/82 */
X  for (i=2; i<22; i++) for (j=1; j<79; j++) 
X  { unsetrc (PSD|DEADEND,i,j);
X
X    /* If attempt > 3, allow ANYTHING to be a secret door! */
X    if (attempt > 3 && ! onrc (BEEN|DOOR|HALL|ROOM|WALL|STAIRS, i, j) &&
X        nextto (CANGO, i, j))
X    { if (!onrc (PSD, i, j)) numberpsd++; setrc(PSD,i,j); }
X
X    /* Set Possible Secret Door for maze room secret doors */
X    else if (attempt > 0 && ! onrc (BEEN|DOOR|HALL|ROOM|WALL|STAIRS, i, j) &&
X        mazedoor (i, j))
X    { if (!onrc (PSD, i, j)) numberpsd++; setrc(PSD,i,j); }
X
X    /* Set Possible Secret Door for corridor secret door */
X    else if (version >= RV53A &&
X             ! onrc (BEEN|DOOR|HALL|ROOM|WALL|STAIRS, i, j) &&
X             nextto (DOOR, i, j))
X    { if (!onrc (PSD, i, j)) numberpsd++; setrc(PSD,i,j); }
X
X    /* Set Possible Secret Door for dead end corridors */
X    else if (! onrc (BEEN|DOOR|HALL|ROOM|WALL|STAIRS, i, j) &&
X             (onrc (HALL, i-1, j) + onrc (HALL, i+1, j) +
X              onrc (HALL, i, j-1) + onrc (HALL, i, j+1) == HALL) &&
X             !(onrc(HALL|DOOR, i-1, j-1) || onrc(HALL|DOOR, i+1, j+1) ||
X               onrc(HALL|DOOR, i-1, j+1) || onrc(HALL | DOOR, i+1, j-1)) &&
X             canbedoor (i, j))
X    { if (!onrc (PSD, i, j)) numberpsd++;
X      setrc(DEADEND,i,j); setrc(PSD,i,j);
X    }
X
X    /* Set PSD for walls which connect to empty space */
X
X    /* Modified to allow PSD for !ROOM (including the old CANGO des.) */
X    /* since potions and scrolls of detection can cause the CANGO bit */
X    /* to be set for a square on which we have never been.            */
X    /* 							mlm 10/8/82   */
X
X    /* If attempt > 2, then relax the constraint about empty space,   */
X    /* since we might have teleported into a disconnected part of the */
X    /* level. This means after we have searched twice, we look for    */
X    /* ANY possible door, not just doors leading to empty space.      */
X    /* 							mlm 10/11/82  */
X   
X    else 
X    { if ((k = wallkind (i,j)) >= 0)
X      { /* A legit sort of wall */
X        whereto = connect[whichroom (i,j)][k];
X        if (whereto >= 0 && (attempt > 1 || room[whereto] == 0))
X	{ if (!onrc (PSD, i, j)) numberpsd++;
X	  setrc (PSD,i,j);
X	}
X      }
X    }
X  }
X  
X  /* Now remove PSD bits from walls which already have doors */
X  for (i=2; i<22; i++) for (j=1; j<79; j++)
X  { if (onrc (DOOR, i, j))
X    { for (k = i-1; onrc (WALL, k, j); k--)
X      { if (onrc (PSD, k, j)) numberpsd--; unsetrc (PSD, k, j);}
X      for (k = i+1; onrc (WALL, k, j); k++)
X      { if (onrc (PSD, k, j)) numberpsd--; unsetrc (PSD, k, j);}
X      for (k = j-1; onrc (WALL, i, k); k--)
X      { if (onrc (PSD, i, k)) numberpsd--; unsetrc (PSD, i, k);}
X      for (k = j+1; onrc (WALL, i, k); k++)
X      { if (onrc (PSD, i, k)) numberpsd--; unsetrc (PSD, i, k);}
X    }
X  }
X
X  if (print || debug (D_SCREEN))
X    for (i=0; i<24; i++) for (j=0; j<80; j++)
X      if (onrc (PSD,i,j)) { at (i,j); addch ('P'); }
X
X  reusepsd = numberpsd+1;
X  return (numberpsd);
X}
X
X/*
X * downvalue: find nearest stairs or trapdoor (use genericinit for init).
X */
X
Xdownvalue (r, c, depth, val, avd, cont)
Xint r, c, depth, *val, *avd, *cont;
X{ 
X  *avd = onrc (SAFE, r, c)    ? 0 :
X	 onrc (ARROW, r, c)   ? 50 :
X         onrc (TRAPDOR, r, c) ? 175 :
X         onrc (TELTRAP, r, c) ? 50 :
X         onrc (GASTRAP, r, c) ? 50 :
X         onrc (BEARTRP, r, c) ? 50 :
X         onrc (DARTRAP, r, c) ? 200 :
X         onrc (WATERAP, r, c) ? 50 :
X         onrc (MONSTER, r, c) ? 150 :
X         expavoidval;
X
X  if (onrc (STAIRS | TRAPDOR, r, c)) { *val = 1; *avd = 0; }
X  else			             { *val = 0; }
X
X  return (1);
X}
X
X/* 
X * expruninit: same as expinit but don't bias against doors.
X */
X
Xexpruninit ()
X{ dwait (D_CONTROL | D_SEARCH, "expruninit called.");
X  expinit();
X  expDor = 0;
X  avoidmonsters ();
X  return (1);
X}
X
X/*
X * exprunvalue: When running, avoid monsters.
X *
X * Try to see a new square when running.
X */
X
Xexprunvalue (r, c, depth, val, avd, cont)
Xint r, c, depth, *val, *avd, *cont;
X{ if (r == atrow && c == atcol)		/* Current square useless MLM */
X    *val = 0;
X  else if (onrc (MONSTER | TRAP, r, c))	/* Added TRAP useless MLM */
X    *val = 0;
X  else if (!zigzagvalue (r, c, depth, val, avd, cont))
X    return (0);
X
X  if (*val > 0) { *val = *val * 1000 + depth; *cont = INFINITY; }
X  *avd += avdmonsters[r][c];
X  return (1);
X}
X
X/* 
X * expunpininit: same as exprunnit but try to unpin.
X */
X
Xexpunpininit ()
X{ dwait (D_CONTROL | D_SEARCH, "expunpininit called.");
X  expinit();
X  expDor = 0;
X  pinavoid ();
X  return (1);
X}
X
X/*
X * expunpinvalue: When unpinning, avoid monsters.
X *
X * Try to see a new square when unpinning, but unpin anywhere if need be.
X */
X
Xexpunpinvalue (r, c, depth, val, avd, cont)
Xint r, c, depth, *val, *avd, *cont;
X{ if (r == atrow && c == atcol)		/* Current square useless MLM */
X    *val = 0;
X  else if (onrc (MONSTER | TRAP, r, c))	/* Added TRAP useless MLM */
X    *val = 0;
X  else if (!zigzagvalue (r, c, depth, val, avd, cont))
X    return (0);
X
X  if (*val > 0) { *val = *val * 1000 + depth; *cont = INFINITY; }
X  *avd += avdmonsters[r][c];
X  return (1);
X}
X
X/*
X * runinit:  R U N   A W A Y   S E A R C H
X */
X
Xruninit ()
X{ avoidmonsters();
X  return (1);
X}
X
X/*
X * runvalue:
X *
X * Evaluate square for running away. Targets, in priority order are:
X *
X * STAIRS  TRAPDOR  TELTRAP
X * RUNOK (cycle door)
X * DOOR
X * ANYWHERE
X *
X * Traps are avoided for a variable number of moves, except for target traps
X * Gave GasTraps and BearTraps infinite avoidance.	MLM 10/11/83
X */
X
Xrunvalue (r, c, depth, val, avd, cont)
Xint r, c, depth, *val, *avd, *cont;
X{ *avd = onrc (ARROW, r, c) ? 50 :
X         onrc (TRAPDOR, r, c) ? 0 :
X         onrc (TELTRAP, r, c) ? 0 :
X         onrc (GASTRAP, r, c) ? INFINITY :
X         onrc (BEARTRP, r, c) ? INFINITY :
X         onrc (DARTRAP, r, c) ? 100 :
X         onrc (WATERAP, r, c) ? 100 :
X         onrc (MONSTER, r, c) ? 150 :
X         0;
X
X  if (onrc (SCAREM, r, c) && version < RV53A && objcount != maxobj)
X    *avd += 200;
X
X  if (onrc (MONSTER, r, c))
X    { *val = 0; }
X  if (onrc (STAIRS+TRAPDOR+TELTRAP, r, c))
X    { *val = 5000; *avd = 0; /* *cont = 0; */ }
X  else if (r == atrow && c == atcol)	/* If we are running, our current */
X    { *val = 0;}			/* cant be that great -- MLM      */
X  else if (onrc (RUNOK, r, c))
X    { *val = 4000; *cont = INFINITY;}
X  else if (onrc (DOOR | BEEN, r, c) == DOOR)
X    { *val = 2000+depth; *cont = INFINITY;}
X  else if (onrc (DOOR, r, c))
X    { *val = 1000+depth; *cont = INFINITY;}
X  else if (onrc (HALL, r, c))
X    { *val =      depth; *cont = INFINITY;}
X  /* ----------------------------------------------------------------
X  else if (onrc (CANGO | TRAP, r, c) == CANGO)
X    { *val = 1+depth; *cont = INFINITY;}
X  ---------------------------------------------------------------- */
X  else
X    { *val = 0; }
X
X  *avd += avdmonsters[r][c];
X}
X
X/*
X * unpininit:  U N P I N    S E A R C H
X *
X * Same as runint, but we are willing to take one hit to get away.
X */
X
Xunpininit ()
X{ pinavoid();
X  return (1);
X}
X
X/*
X * rundoorinit: Standard initialization routine.
X */
X
Xrundoorinit()
X{ avoidmonsters();
X  return (1);
X}
X
X/*
X * rundoorvalue: 
X *
X * Evaluate square for running into doorway.
X *
X * Targets, in priority order are:
X *
X * RUNOK (cycle door)
X * DOOR
X *
X * Traps are avoided for a variable number of moves, except for target traps
X * Gave GasTraps and BearTraps infinite avoidance.	MLM 10/11/83
X */
X
Xrundoorvalue (r, c, depth, val, avd, cont)
Xint r, c, depth;
Xint *val, *avd, *cont;
X{ *avd = onrc (ARROW, r, c) ? 50 :
X         onrc (TRAPDOR, r, c) ? 0 :
X         onrc (TELTRAP, r, c) ? 0 :
X         onrc (GASTRAP, r, c) ? INFINITY :
X         onrc (BEARTRP, r, c) ? INFINITY :
X         onrc (DARTRAP, r, c) ? 100 :
X         onrc (WATERAP, r, c) ? 100 :
X         onrc (MONSTER, r, c) ? 50 : 0;
X
X  if (onrc (SCAREM, r, c) && version < RV53A && objcount != maxobj)
X    *avd += 200;
X
X  if (onrc (RUNOK, r, c))	{ *val = 2;}
X  else if (onrc (DOOR, r, c))	{ *val = 1; *cont = INFINITY;}
X  else				{ *val = 0;}
X
X  *avd += avdmonsters[r][c];
X}
X
X/*
X *   E X P L O R A T I O N   S E A R C H
X */
X
Xexpinit ()
X{ /* avoidance values for doors */
X  expDor = 0;
X  expavoidval = avoid();
X  return (1);
X}
X
Xroominit ()
X{ expinit ();
X  expDor = INFINITY;
X  return (1);
X}
X
X/*
X * expvalue: evaluation function for exploration.  LGCH
X *
X * In order to prevent leaving orphan unseen squares, we have heuritics
X * which cause rogomatic to use the three-step pattern to scan along the
X * boundary of a room, and also have tests which detect any orphans (e.g.
X * corners and when an object interrupts the search pattern) and cause them
X * to be seen.
X *
X * Three-step pattern:
X *
X *        @@ @@
X *       @  @  @
X *      bbbbbbbbb
X */
X
Xexpvalue (r, c, depth, val, avd, cont)
Xint r, c, depth;
Xint *val, *avd, *cont;
X{ register int k, nr, nc, l;
X  int a, v = 0, nunseenb = 0, nseenb = 0, nearb = 0;
X
X  a = onrc (SAFE|DOOR|STAIRS|HALL, r, c) ? 0 :
X      onrc (ARROW, r, c)   ? 50 :
X      onrc (TRAPDOR, r, c) ? 300 :
X      onrc (TELTRAP, r, c) ? 100 :
X      onrc (GASTRAP, r, c) ? 50 :
X      onrc (BEARTRP, r, c) ? 50 :
X      onrc (DARTRAP, r, c) ? 200 :
X      onrc (TRAP, r, c)    ? 100 :
X      onrc (MONSTER, r, c) ? 150 :
X      expavoidval;
X
X  if (onrc (SCAREM, r, c) && version < RV53A && objcount != maxobj)
X  { *avd = a+1000; *val=0; return (1); }
X
X  if (onrc (BEEN+SEEN, r, c) == SEEN)  /* If been or not seen, not a target */
X  { for (k=0; k<8; k++)
X    { nr = r + deltr[k];
X      nc = c + deltc[k];
X      
X      /* For each unseen neighbour: add 10 to value. */
X      if (nr >= 1 && nr <= 22 && nc >= 0 && nc <= 80 &&
X        !onrc (SEEN, nr, nc))
X      { v += 10;
X
X        if (onrc (BOUNDARY, nr, nc))
X	{ /* Count unseen boundary neighbours. */
X	  nunseenb++;
X
X	  /* Count seen boundaries horiz/vert adjacent to unseen boundary */
X	  for (l=0; l<8; l+=2)
X	    if (onrc (SEEN+BOUNDARY, nr+deltr[l], nc+deltc[l]) ==
X	      SEEN+BOUNDARY)
X	      nseenb++;
X
X	}
X	else
X	{ /* Check for unseen boundary horiz/vert       */
X	  /* adjacent to neighbour and not a neighbour. */
X	  l = k / 2 * 2; 		     /* horizontal/vertical */
X	  if (onrc (BOUNDARY+SEEN, nr+deltr[l], nc+deltc[l]) == BOUNDARY)
X	    nearb = 1;
X	  else
X	  { l = ((k+1) / 2 * 2) % 8;
X	    if (onrc (BOUNDARY+SEEN, nr+deltr[l], nc+deltc[l]) == BOUNDARY)
X	      nearb = 1;
X	  }
X	}
X      }
X    }
X
X    /* To zig-zag: add number of unseen boundary neighbours * 6 */
X    v += nunseenb * 6;
X
X    /* To do the three-step: add 29 if an unseen neighbour had an unseen
X     * boundary horiz/vert adjacent */
X    if (nearb)
X      v += 29;
X
X    /* To prevent orphans: if three unseen neighbours are boundary and one
X     * has a seen boundary horiz/vert adjacent, add 200 */
X    if (nunseenb >= 3 && nseenb >= 1)
X      v += 200;
X
X    /* To clean up any orphans: if two seen boundaries are adjacent to any
X     * unseen boundary neighbours, add 400. */
X    if (nseenb >= 2)
X      v += 400;
X  }
X
X  if (onrc (DOOR, r, c))
X    a += expDor;
X  /* else if (onrc (BEEN+BOUNDARY, r, c) == BOUNDARY)
X    a++;   // Avoid running along the untrodden boundary. // */
X
X  *avd = a;
X  *val = v;
X  if (v < 50)
X    *cont = 4; 				     /* Look for something better */
X  if (debug (D_SCREEN) && v > 0)
X  { mvaddch (r, c, 'o'); dwait (D_SCREEN, "Value %d", v); }
X
X  return (1);
X}
X
X/*
X * zigzagvalue: evaluation function for exploration.  LGCH
X *
X * This is a copy of expvalue with the three-step code and the code to
X * detect orphans removed. It is used when running away and unpinning
X * to find a useful exploration move. The boundary moves must zig-zag
X * rather than three-step so that the door can be entered when it is seen
X * without taking a hit from the monster chasing us.
X *
X * Gave GasTraps and BearTraps infinite avoidance.	MLM 10/11/83
X */
X
Xzigzagvalue (r, c, depth, val, avd, cont)
Xint r, c, depth;
Xint *val, *avd, *cont;
X{ register int k, nr, nc, l;
X  int a, v = 0, nunseenb = 0, nseenb = 0, nearb = 0;
X
X  a = onrc (SAFE|DOOR|STAIRS|HALL, r, c) ? 0 :
X      onrc (ARROW, r, c)   ? 50 :
X      onrc (TRAPDOR, r, c) ? 300 :
X      onrc (TELTRAP, r, c) ? 100 :
X      onrc (GASTRAP, r, c) ? 50 :
X      onrc (BEARTRP, r, c) ? 50 :
X      onrc (DARTRAP, r, c) ? 200 :
X      onrc (TRAP, r, c)    ? 100 :
X      onrc (MONSTER, r, c) ? 150 :
X      expavoidval;
X
X  if (onrc (SCAREM, r, c) && version < RV53A && objcount != maxobj)
X  { *avd = a+1000; *val=0; return (1); }
X
X  if (onrc (BEEN+SEEN, r, c) == SEEN)  /* If been or not seen, not a target */
X  { for (k=0; k<8; k++)
X    { nr = r + deltr[k];
X      nc = c + deltc[k];
X      
X      /* For each unseen neighbour: add 10 to value. */
X      if (nr >= 1 && nr <= 22 && nc >= 0 && nc <= 80 &&
X        !onrc (SEEN, nr, nc))
X      { v += 10;
X
X        if (onrc (BOUNDARY, nr, nc))
X	{ /* Count unseen boundary neighbours. */
X	  nunseenb++;
X	}
X        if (debug (D_SCREEN)) mvaddch (nr, nc, 'o');
X      }
X    }
X
X    /* To zig-zag: add number of unseen boundary neighbours * 6 */
X    v += nunseenb * 6;
X  }
X
X  if (onrc (DOOR, r, c))
X    a += expDor;
X  /* else if (onrc (BEEN+BOUNDARY, r, c) == BOUNDARY)
X    a++;   // Avoid running along the untrodden boundary. // */
X
X  *avd = a;
X  *val = v;
X  *cont = 0; 				     /* Look for orphans */
X
X  return (1);
X}
X
X/*
X *   S E C R E T   D O O R   S E A R C H
X */
X
Xsecretinit ()
X{ expinit ();
X  if (setpsd ())
X    return (1);
X  return (0);
X}
X
Xsecretvalue (r, c, depth, val, avd, cont)
Xint r, c, depth;
Xint *val, *avd, *cont;
X{ register int v, a, k;
X
X  *val=0;
X  v = 0;	/* establish value of square */
X  a = onrc (SAFE, r, c)    ? 0 :
X      onrc (ARROW, r, c)   ? 50 :
X      onrc (TRAPDOR, r, c) ? 175 :
X      onrc (TELTRAP, r, c) ? 50 :
X      onrc (GASTRAP, r, c) ? 50 :
X      onrc (BEARTRP, r, c) ? 50 :
X      onrc (DARTRAP, r, c) ? 200 :
X      onrc (WATERAP, r, c) ? 50 :
X      onrc (MONSTER, r, c) ? 150 :
X      expavoidval;
X
X  if (onrc (SCAREM, r, c) && version < RV53A && objcount != maxobj)
X    a += 200;
X
X  for (k=0; k<8; k++)    /* examine adjacent squares */
X  { register int nr = r + deltr[k];
X    register int nc = c + deltc[k];
X    if (nr >= 1 && nr <= 22 &&
X      nc >= 0 && nc <= 80 &&
X      onrc (PSD, nr, nc) && timessearched[nr][nc] < SEARCHES(nr,nc))
X    { /* If adjacent square is on the screen */
X      /* and if it has PSD set but has not been searched completely */
X      /* count useful neighbours */
X      if (screen[nr][nc] == '|')	v += 4;
X      else				v ++;
X      if (debug (D_SCREEN | D_INFORM)) mvaddch (nr, nc, 'S');
X    }
X  }
X
X  if (v>0)
X  { if (version >= RV53A &&
X        onrc (DOOR|BEEN, r, c) == DOOR|BEEN && 
X        (onrc (CANGO|WALL, r+1, c) == 0 || onrc (CANGO|WALL, r-1, c) == 0 ||
X         onrc (CANGO|WALL, r, c+1) == 0 || onrc (CANGO|WALL, r, c-1) == 0))
X    { *val = v+100; *cont = 5; }
X    else
X    { v = min (15, v);
X      *val = secretvalues[v]; *cont = secretcont[v];  
X      if (onrc (DOOR, r, c)) a += expDor;
X    }
X  }
X  *avd = a;
X
X  return (1);
X}
X
X/*
X *   E S T A B L I S H   A V O I D A N C E   M A P   to avoid monsters.
X */
X
X# define AVOID(r,c,ch) \
X  { avdmonsters[r][c] = INFINITY; \
X    if (debug (D_SCREEN)) { at((r),(c)); addch(ch); at(row,col); }}
X
Xavoidmonsters ()
X{ register int i, r, c, wearingstealth;
X
X  /* Clear old avoid monster values */
X  for (i = 24*80; i--; ) avdmonsters[0][i] = 0;
X  
X  /* Set stealth status */
X  wearingstealth = (wearing ("stealth") != NONE);
X
X  /* Avoid each monster in turn */
X  for (i=0; i<mlistlen; i++)
X  { /* First check whether this monster is really wimpy */
X    if (maxhit(i) < Hp/2)
X    { AVOID (mlist[i].mrow, mlist[i].mcol, '$')
X    }
X    /* If not a wimp and awake, avoid him all together */
X    else if (mlist[i].q == AWAKE) 
X    { int d, dr, dc, mr = mlist[i].mrow, mc = mlist[i].mcol;
X      d = direc (searchstartr-mr,searchstartc-mc);
X      dr = (searchstartr-mr)/2+mr; dc=(searchstartc-mc)/2+mc;
X      if (d & 1)
X      { caddycorner (dr, dc, (d-1) & 7, (d-3)&7, '$');
X        caddycorner (dr, dc, (d+1) & 7, (d+3)&7, '$');
X      }
X      else 
X      { caddycorner (dr, dc, (d-2) & 7, d, '$');
X        caddycorner (dr, dc, (d+2) & 7, d, '$');
X      }
X    }
X    /* If he'll wake up, give him a wide berth */
X    else if (!wearingstealth)
X    { for (r = mlist[i].mrow-1; r<= mlist[i].mrow+1; r++)
X        for (c = mlist[i].mcol-1; c<= mlist[i].mcol+1; c++)
X          AVOID (r, c, '$')
X    }
X    /* He's asleep, don't try to run through him */
X    else 
X      AVOID (mlist[i].mrow, mlist[i].mcol, '$')
X  }
X  
X  /* Don't avoid current position */
X  avdmonsters[searchstartr][searchstartc] = 0;
X  dwait (D_SEARCH, "Avoidmonsters: avoiding the $s");
X}
X
X/* 
X * caddycorner: Find sqaures the monster can reach before we can and mark
X * them for avoidance
X */
X
Xcaddycorner (r, c, d1, d2, ch)
Xint r,c,d1,d2;
Xchar ch;
X{ while (onrc (CANGO, r, c))
X  { AVOID (r, c, ch);
X    r += deltr[d1]; c += deltc[d1];
X    if (!onrc (CANGO, r, c)) break;
X    AVOID (r, c, ch);
X    r += deltr[d2]; c += deltc[d2];
X  }
X}
X
X/*
X *   E S T A B L I S H   A V O I D A N C E   M A P   when pinned
X *
X * This routine is basically the same as avoidmonsters, except that
X * the value are calculated to allow the monster one hit instead of
X * avoiding him entirely. This allows us to escape from situations where
X * we are pinned, but could get free if we had an extra turn.   MLM
X */
X
Xpinavoid ()
X{ register int i;
X
X  /* Clear old avoid monster values */
X  for (i = 24*80; i--; ) avdmonsters[0][i] = 0;
X
X  /* Avoid each monster in turn */
X  for (i=0; i<mlistlen; i++)
X  { if (mlist[i].q == AWAKE) 
X    { register int d, dr, dc, mr = mlist[i].mrow, mc = mlist[i].mcol;
X      d = direc (searchstartr-mr,searchstartc-mc);
X      dr = (searchstartr-mr)/2+mr - deltr[d];		/* MLM */
X      dc=(searchstartc-mc)/2+mc - deltc[d];		/* MLM */
X      if (d & 1)
X      { caddycorner (dr, dc, (d-1) & 7, (d-3)&7, '&');
X        caddycorner (dr, dc, (d+1) & 7, (d+3)&7, '&');
X      }
X      else 
X      { caddycorner (dr, dc, (d-2) & 7, (d-4) & 7, '&'); /* MLM */
X        caddycorner (dr, dc, (d+2) & 7, (d+4) & 7, '&'); /* MLM */
X      }
X    }
X    AVOID (mlist[i].mrow, mlist[i].mcol, '&');
X  }
X  
X  /* Don't avoid current position */
X  avdmonsters[searchstartr][searchstartc] = 0;
X  dwait (D_SEARCH, "Pinavoid: avoiding the &s");
X}
X
X/*
X *   S E C R E T : Search dead ends for secret doors.
X */
X
Xsecret ()
X{ int secretinit(), secretvalue();
X  
X  /* Secret passage adjacent to door? */
X  if (version >= RV53A && on (DOOR) && !blinded &&
X      (seerc (' ',atrow+1,atcol) || seerc (' ',atrow-1,atcol) ||
X       seerc (' ',atrow,atcol+1) || seerc (' ',atrow,atcol-1)) &&
X      SEARCHES (atrow, atcol) < timestosearch+20)
X  { int count = timessearched[atrow][atcol]+1;
X    saynow ("Searching dead end door (%d,%d) for the %d%s time...", 
X              atrow, atcol, count, ordinal (count));
X    command (T_DOORSRCH, "s"); return (1);
X  }
X
X  /* Verify that we are actually at a dead end */
X  if (onrc (CANGO,atrow-1,atcol) + onrc (CANGO,atrow,atcol-1) + 
X      onrc (CANGO,atrow+1,atcol) + onrc (CANGO,atrow,atcol+1) != CANGO)
X    return (0);
X
X  /* If Level 1 or edge of screen: dead end cannot be room, mark and return */
X  if (Level == 1 && attempt == 0 ||
X      version < RV53A && (atrow<=1 || atrow>=22 || atcol<=0 || atcol>=79))
X  { markexplored (atrow, atcol); return (0); }
X
X  /* Have we mapped this level? */
X  if (Level == didreadmap) return (0);
X
X  /* Found a dead end, should we search it? */
X  if (nexttowall (atrow, atcol) ||
X      canbedoor (atrow, atcol) && 
X      (version >= RV53A || !isexplored (atrow, atcol)))
X  { setrc (DEADEND, atrow, atcol);
X
X    if ((SEARCHES (atrow, atcol) - timessearched[atrow][atcol]) > 0)
X    { int count = timessearched[atrow][atcol]+1;
X      saynow ("Searching dead end (%d,%d) for the %d%s time...", 
X              atrow, atcol, count, ordinal (count));
X      command (T_DOORSRCH, "s");
X      return (1);
X    }
X    else
X    { markexplored (atrow, atcol);
X      return (0);
X    }
X  }
X
X  return (0);
X}
X
X/* 
X *   F I N D R O O M :  Try to find another room.
X */
X
Xfindroom ()
X{ int expinit(), expvalue();    /* LGCH */
X
X  if (new_findroom)
X  { if (!on (ROOM) && secret ())			return (1);
X    if (makemove (EXPLORE, expinit, expvalue, REUSE))	return (1);
X  }
X
X  new_findroom = 0;
X  dwait (D_SEARCH, "findroom failed.");
X  return (0);
X}
X
X/* 
X *   E X P L O R E   R O O M :  Explore the current room.
X */
X
Xexploreroom ()
X{ int roominit(), expvalue();    /* LGCH */
X
X  if (!on (ROOM) || isexplored (atrow, atcol)) return (0);
X  if (makemove (EXPLOREROOM, roominit, expvalue, REUSE)) return (1);
X  markexplored (atrow, atcol);
X
X  dwait (D_SEARCH, "exploreroom failed.");
X  return (0);
X}
X
X/*
X *   D O O R E X P L O R E : look for secret doors
X */
X
Xdoorexplore()
X{ static searchcount = 0;
X  int secretinit(), secretvalue();
X
X  /* If no new squares or read map, dont bother */
X  if (! new_search || Level == didreadmap)
X  { searchcount = 0; return (0); }
X
X  if (makemove (SECRETDOOR, secretinit, secretvalue, REUSE))  /* move */
X  { searchcount = 0; return (1); }
X
X  if (searchcount > 20)
X  { new_search = 0; return (0); }
X
X  if (ontarget)  /* Moved to a possible secret door, search it */
X  { searchcount++;
X    saynow ("Searching square (%d,%d) for the %d%s time...", 
X            atrow, atcol, searchcount, ordinal (searchcount));
X    command (T_DOORSRCH, "s");
X    return (1);
X  }
X
X  new_search = searchcount = 0;
X  return (0);
X}
X
X/*
X *   S A F E   S Q U A R E   S E A R C H 	Use genericinit.
X */
X
Xsafevalue (r, c, depth, val, avd, cont)
Xint r, c, depth, *val, *avd, *cont;
X{ register int k, v;
X
X  *avd = onrc (SAFE, r, c)    ? 0 :
X	 onrc (TRAPDOR | BEARTRP | GASTRAP, r, c) ? INFINITY :
X	 onrc (ARROW, r, c)   ? 50 :
X         onrc (TELTRAP, r, c) ? 50 :
X         onrc (DARTRAP, r, c) ? 200 :
X         onrc (WATERAP, r, c) ? 50 :
X         onrc (MONSTER, r, c) ? 150 :
X         expavoidval;
X  *val = 0;
X
X  if (onrc (SCAREM, r, c) && version < RV53A && objcount != maxobj)
X    *avd += 500;
X
X  if (onrc(CANGO, r, c))
X  { v = 0;
X    for (k=0; k<8; k++)
X      if (onrc(CANGO, r+deltr[k], c+deltc[k]) &&
X          onrc(CANGO, r+deltr[k], c) &&
X          onrc(CANGO, r, c+deltc[k])) v++;
X    if (v < 3)
X      *val = 1;        /* *cont = 0; // default // */
X  }
X  return (1);
X}
X
X/* findsafe: find a spot with 2 or fewer moves, for when blinded */
X
Xfindsafe()
X{ 
X  return (makemove (FINDSAFE, genericinit, safevalue, REEVAL));
X}
X
X/* How scared are we of hitting a trap? */
X
Xavoid ()
X{ if (cheat && !foundarrowtrap && !usingarrow) return (0);
X  else if (Level < 5) return (0);       /* Don't bother */
X  else return (2);                      /* Avoid a little */
X}
X
X/*
X * archery: Initialize a archery move. We find a good place to
X * shoot from and stand there. Then mark the monster as awake, and 
X * battlestations will handle firing at him.
X */
X
Xstatic int archrow = NONE, archcol = NONE, archturns = NONE, archval[24][80];
X
Xarchmonster (m, turns)
Xregister int m;		/* Monster to attack */
Xregister int turns;	/* Minimum number of arrows to make it worthwhile */
X{ int archeryinit(), archeryvalue();
X  register int mr, mc;
X
X  dwait (D_CONTROL | D_BATTLE, "archmonster: m=%d, turns=%d", m, turns);
X
X  if (! new_arch) return (0);
X
X  /* Useless without arrows */
X  if (havemult (missile, "", turns) < 0) 
X  { dwait (D_BATTLE, "archmonster, fewer than %d missiles", turns); 
X    return (0); }
X
X  /* For now, only work for sleeping monsters */
X  if (mlist[m].q != ASLEEP) 
X  { dwait (D_BATTLE, "archmonster, monster not asleep"); return (0); }
X
X  /* Save globals */
X  archrow = mlist[m].mrow; archcol = mlist[m].mcol; archturns = turns;
X
X  /* Can we get to a suitable square */
X  if (makemove (ARCHERYMOVE, archeryinit, archeryvalue, REUSE))
X  { dwait (D_BATTLE, "archmonster, made a move"); return (1); }
X
X  /* If no move made and not on target, no path to monster */
X  if (!ontarget) { new_arch = 0; return (0); }
X
X  /* On target: wake him up and set darkdir/turns if necessary */
X  mr = mlist[m].mrow; mc = mlist[m].mcol; targetmonster = mlist[m].chr;
X  mlist[m].q = AWAKE; dwait (D_BATTLE, "archmonster, waking him up"); 
X    
X  /* Set dark room archery variables, add goal of standing on square */
X  if (darkroom ())
X  { darkdir = direc (mr-atrow, mc-atcol);
X    darkturns = max (abs (mr-atrow), abs (mc-atcol));
X    agoalr = mr; agoalc = mc;	/* Go here to pick up what (s)he drops */
X  }
X
X  /* Tell the user about it */
X  saynow ("Arching at %s", monname (mlist[m].chr));
X
X  return (1);
X}
X
X/*
X * archeryinit: Initialize a archery move. Must avoid monsters to avoid
X * waking our potential victim up.
X */
X
Xarcheryinit ()
X{ register int dir, r, c, dr, dc, dist;
X
X   /* Clear the archery value array */
X  for (r = 24*80; r--; ) archval[0][r] = 0;
X
X  /* Scan around monster to see how far away we can shoot from */
X  for (dir = 0; dir < 8; dir++)
X  { dr = deltr[dir]; dc = deltc[dir];
X    for (dist = 1, r = archrow+dr, c = archcol+dc;
X         onrc (CANGO | HALL | MONSTER, r, c) == CANGO;
X	 r += dr, c += dc, dist++)
X      if (dist > archturns && !onrc (TRAP, r, c))
X      { archval[r][c] = dist - 1; /* number of arrows we get to shoot */
X        if (debug (D_SCREEN)) { at (r, c); addch ('=');  at (row, col); }
X      }
X  }
X
X  expavoidval = avoid();
X  avoidmonsters ();
X  return (1);
X}
X
X/*
X * archeryvalue: Get the value of the square from the archery array.
X * Value is non-zero only if we can fire arrows at beast and value is
X * number of shots we can fire.
X */
X
Xarcheryvalue (r, c, depth, val, avd, cont)
Xint r, c, depth, *val, *avd, *cont;
X{ 
X  *avd = (onrc (SAFE, r, c)	? 0 :
X	  onrc (TRAPDOR, r, c)	? INFINITY :
X	  onrc (HALL, r, c)	? INFINITY :
X	  onrc (ARROW, r, c)	? 50 :
X          onrc (TELTRAP, r, c)	? 50 :
X          onrc (GASTRAP, r, c)	? 50 :
X          onrc (BEARTRP, r, c)	? 50 :
X          onrc (DARTRAP, r, c)	? 200 :
X          onrc (WATERAP, r, c)	? 50 :
X          onrc (MONSTER, r, c)	? 150 :
X          expavoidval) + avdmonsters[r][c];
X
X  if (onrc (SCAREM, r, c) && version < RV53A && objcount != maxobj)
X    *avd += 500;
X
X  *val = archval[r][c];
X  *cont = INFINITY;
X
X  return (1);
X}
X
X/* 
X *   M O V E   T O   R E S T :  Find a safe square to rest up on.
X */
X
Xstatic restinlight = 0;			/* True only in lit rooms */
Xstatic restinroom = 0;			/* True only in a room */
Xstatic restr = NONE, restc = NONE;	/* Square to rest on */
X
X/* Set new resting goal */
Xunrest ()
X{ restr = restc = NONE;
X}
X
X/* Move to a good square to rest up on */
Xmovetorest ()
X{ int restinit(), restvalue();    /* LGCH */
X
X  if (markcycles (NOPRINT))
X    unrest ();
X
X  /* If we are where we want to rest, do so */
X  if (restr >= 0 && atrow == restr && atcol == restc)
X  { dwait (D_SEARCH, "movetorest: already on square"); return (0); }
X
X  /* Try to move to a better square (remember position) */
X  if (makemove (RESTMOVE, restinit, restvalue, REUSE))
X  { dwait (D_SEARCH, "movetorest wins.");
X    restr = targetrow; restc = targetcol;
X    return (1);
X  }
X
X  /* Cant move anywhere better, stay here */
X  dwait (D_SEARCH, "movetorest fails.");
X  restr = atrow; restc = atcol;
X
X  return (0);
X}
X
Xrestinit ()
X{ expavoidval = avoid();
X  restinlight = (on (ROOM) && !darkroom ());
X  restinroom = on (ROOM);
X  return (1);
X}
X
Xrestvalue (r, c, depth, val, avd, cont)
Xregister int r, c;
Xint depth, *val, *avd, *cont;
X{ register int dr, dc, ar, ac;
X  int count, dir, rm;
X
X  /* Find room number for diagonal selection */
X  if ((rm = whichroom (r, c)) < 0) rm = 4;
X
X  /* Default is no value, no avoidance */
X  *avd = *val = 0;
X
X  /* Set base value of square */
X  if (onrc (TRAP|MONSTER,r, c))               { *avd = INFINITY; return (0); }
X  else if (restinroom && onrc (DOOR,r, c))    { *avd = INFINITY; return (0); }
X  else if (onrc (SCAREM, r, c))
X  { if (objcount == maxobj || version >= RV53A) { *val = 500; return (1); }
X    else                                      { *avd = INFINITY; return (0); }
X  }
X  else if (onrc (STAIRS, r, c))               { *val = 400; return (1); }
X  else if (onrc (ROOM, r, c))                 { *val = 1; *cont = 99;}
X  else if (!onrc (SAFE|BEEN|STUFF, r, c))     { *avd = 5; }
X
X  /* Give bonus for being next to a trap door or a teleport trap */
X  if (onrc (TRAPDOR|TELTRAP, r-1, c-1) || onrc (TRAPDOR|TELTRAP, r+1, c-1) ||
X      onrc (TRAPDOR|TELTRAP, r-1, c+1) || onrc (TRAPDOR|TELTRAP, r+1, c+1))
X  { *val += 80; *cont = 99;}
X
X  if (onrc (TRAPDOR|TELTRAP, r-1, c) || onrc (TRAPDOR|TELTRAP, r+1, c) ||
X      onrc (TRAPDOR|TELTRAP, r, c-1) || onrc (TRAPDOR|TELTRAP, r, c+1))
X  { *val += 30; *cont = 99;}
X
X  /* In lit rooms (with ammo) stay away from doors, this gives us time */
X  /* to shoot arrows at monsters coming in at us          MLM 06/21/83 */
X  if (restinlight && ammo)
X  { for (dir = 0; dir < 8; dir += 2)
X    { dr = deltr[dir]; dc = deltc[dir];
X      for (count = 0, ar = r+dr, ac = c+dc;
X           onrc (CANGO | HALL | MONSTER, ar, ac) == CANGO;
X           ar += dr, ac += dc, count++)
X      { /* Bonus of 'count' if this square covers a door */
X        if (onrc(DOOR,ar+deltr[(dir+2)%8],ac+deltc[(dir+2)%8])) *val += count;
X        if (onrc(DOOR,ar+deltr[(dir+6)%8],ac+deltc[(dir+6)%8])) *val += count;
X        if (onrc(DOOR,ar,ac)) *val += count;
X      }
X    }
X  }
X
X  /* In dark rooms, stand diagonally away from doors (1 extra turn) */
X  else if (onrc (ROOM, r, c))
X  { if (onrc (DOOR,r-1,c-1) && (rm!=0 && rm!=1 && rm!=3)) {*val+=80;*cont=99;}
X    if (onrc (DOOR,r+1,c-1) && (rm!=3 && rm!=6 && rm!=7)) {*val+=80;*cont=99;}
X    if (onrc (DOOR,r-1,c+1) && (rm!=1 && rm!=2 && rm!=5)) {*val+=80;*cont=99;}
X    if (onrc (DOOR,r+1,c+1) && (rm!=5 && rm!=7 && rm!=8)) {*val+=80;*cont=99;}
X
X    /* Bonus for door also orthogonally away */
X    if(onrc(DOOR,r,c-1)||onrc(DOOR,r-1,c)||onrc(DOOR,r,c+1)||onrc(DOOR,r+1,c))
X    { *val+=30; *cont=99; }
X  }
X
X  return (1);
X}
/
echo 'x - utility.c'
sed 's/^X//' > utility.c << '/'
X/*
X * utility.c: Rog-O-Matic XIV (CMU) Thu Jan 31 18:18:22 1985 - mlm
X * Copyright (C) 1985 by A. Appel, G. Jacobson, L. Hamey, and M. Mauldin
X *
X * This file contains all of the miscellaneous system functions which
X * determine the baud rate, time of day, etc.
X */
X
X# include <sgtty.h>
X# include <stdio.h>
X# include <signal.h>
X# include <sys/types.h>
X# include <sys/stat.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# define TRUE 1
X# define FALSE 0
X
X/*
X * baudrate: Determine the baud rate of the terminal
X */
X
Xbaudrate ()
X{ static short  baud_convert[] =
X  { 0, 50, 75, 110, 135, 150, 200, 300, 600, 1200, 1800, 2400, 4800, 9600 };
X  static struct sgttyb  sg;
X  static short  baud_rate;
X
X  gtty (fileno (stdin), &sg);
X  baud_rate = sg.sg_ospeed == 0 ? 1200
X    : sg.sg_ospeed < sizeof baud_convert / sizeof baud_convert[0]
X    ? baud_convert[sg.sg_ospeed] : 9600;
X
X  return (baud_rate);
X}
X
X/*
X * stlmatch  --  match leftmost part of string
X *
X *  Usage:  i = stlmatch (big,small)
X *	int i;
X *	char *small, *big;
X *
X *  Returns 1 iff initial characters of big match small exactly;
X *  else 0.
X *
X *  HISTORY
X * 18-May-82 Michael Mauldin (mlm) at Carnegie-Mellon University
X *      Ripped out of CMU lib for Rog-O-Matic portability
X * 20-Nov-79  Steven Shafer (sas) at Carnegie-Mellon University
X *	Rewritten for VAX from Ken Greer's routine.
X *
X *  Originally from klg (Ken Greer) on IUS/SUS UNIX
X */
X
Xint   stlmatch (big, small)
Xchar *small, *big;
X{ register char *s, *b;
X  s = small;
X  b = big;
X  do
X  { if (*s == '\0')
X      return (1);
X  }
X  while (*s++ == *b++);
X  return (0);
X}
X
X/*
X * getname: get userid of player.
X */
X
Xchar *getname ()
X{ static char name[100];
X  int   i;
X
X  getpw (getuid (), name);
X  i = 0;
X  while (name[i] != ':' && name[i] != ',')
X    i++;
X  name[i] = '\0';
X
X  return (name);
X}
X
X/*
X *  putenv  --  put value into environment
X *
X *  Usage:  i = putenv (name,value)
X *	int i;
X *	char *name, *value;
X *
X *  Putenv associates "value" with the environment parameter "name".
X *  If "value" is 0, then "name" will be deleted from the environment.
X *  Putenv returns 0 normally, -1 on error (not enough core for malloc).
X *
X *  Putenv may need to add a new name into the environment, or to
X *  associate a value longer than the current value with a particular
X *  name.  So, to make life simpler, putenv() copies your entire
X *  environment into the heap (i.e. malloc()) from the stack
X *  (i.e. where it resides when your process is initiated) the first
X *  time you call it.
X *
X *  HISTORY
X * 25-Nov-82 Michael Mauldin (mlm) at Carnegie-Mellon University
X *      Ripped out of CMU lib for Rog-O-Matic portability
X * 20-Nov-79  Steven Shafer (sas) at Carnegie-Mellon University
X *	Created for VAX.  Too bad Bell Labs didn't provide this.  It's
X *	unfortunate that you have to copy the whole environment onto the
X *	heap, but the bookkeeping-and-not-so-much-copying approach turns
X *	out to be much hairier.  So, I decided to do the simple thing,
X *	copying the entire environment onto the heap the first time you
X *	call putenv(), then doing realloc() uniformly later on.
X *	Note that "putenv(name,getenv(name))" is a no-op; that's the reason
X *	for the use of a 0 pointer to tell putenv() to delete an entry.
X *
X */
X
X#define EXTRASIZE 5		/* increment to add to env. size */
X
Xchar *index (), *malloc (), *realloc ();
Xint   strlen ();
X
Xstatic int  envsize = -1;	/* current size of environment */
Xextern char **environ;		/* the global which is your env. */
X
Xstatic int  findenv ();		/* look for a name in the env. */
Xstatic int  newenv ();		/* copy env. from stack to heap */
Xstatic int  moreenv ();		/* incr. size of env. */
X
Xint   putenv (name, value)
Xchar *name, *value;
X{ register int  i, j;
X  register char *p;
X
X  if (envsize < 0)
X  {				/* first time putenv called */
X    if (newenv () < 0)		/* copy env. to heap */
X      return (-1);
X  }
X
X  i = findenv (name);		/* look for name in environment */
X
X  if (value)
X  {				/* put value into environment */
X    if (i < 0)
X    {				/* name must be added */
X      for (i = 0; environ[i]; i++);
X      if (i >= (envsize - 1))
X      {				/* need new slot */
X	if (moreenv () < 0)
X	  return (-1);
X      }
X      p = malloc (strlen (name) + strlen (value) + 2);
X      if (p == 0)		/* not enough core */
X	return (-1);
X      environ[i + 1] = 0;	/* new end of env. */
X    }
X    else
X    {				/* name already in env. */
X      p = realloc (environ[i],
X	  strlen (name) + strlen (value) + 2);
X      if (p == 0)
X	return (-1);
X    }
X    sprintf (p, "%s=%s", name, value);/* copy into env. */
X    environ[i] = p;
X  }
X  else
X  {				/* delete name from environment */
X    if (i >= 0)
X    {				/* name is currently in env. */
X      free (environ[i]);
X      for (j = i; environ[j]; j++);
X      environ[i] = environ[j - 1];
X      environ[j - 1] = 0;
X    }
X  }
X
X  return (0);
X}
X
Xstatic int  findenv (name)
Xchar *name;
X{ register char *namechar, *envchar;
X  register int  i, found;
X
X  found = 0;
X  for (i = 0; environ[i] && !found; i++)
X  { envchar = environ[i];
X    namechar = name;
X    while (*namechar && (*namechar == *envchar))
X    { namechar++;
X      envchar++;
X    }
X    found = (*namechar == '\0' && *envchar == '=');
X  }
X  return (found ? i - 1 : -1);
X}
X
Xstatic int  newenv ()
X{ register char **env, *elem;
X  register int  i, esize;
X
X  for (i = 0; environ[i]; i++);
X  esize = i + EXTRASIZE + 1;
X  env = (char **) malloc (esize * sizeof (elem));
X  if (env == 0)
X    return (-1);
X
X  for (i = 0; environ[i]; i++)
X  { elem = malloc (strlen (environ[i]) + 1);
X    if (elem == 0)
X      return (-1);
X    env[i] = elem;
X    strcpy (elem, environ[i]);
X  }
X
X  env[i] = 0;
X  environ = env;
X  envsize = esize;
X  return (0);
X}
X
Xstatic int  moreenv ()
X{ register int  esize;
X  register char **env;
X
X  esize = envsize + EXTRASIZE;
X  env = (char **) realloc (environ, esize * sizeof (*env));
X  if (env == 0)
X    return (-1);
X  environ = env;
X  envsize = esize;
X  return (0);
X}
X
X/*
X * wopen: Open a file for world access.
X */
X
XFILE *wopen(fname, mode)
Xchar *fname, *mode;
X{ int oldmask;
X  FILE *newlog;
X
X  oldmask = umask (0111);
X  newlog = fopen (fname, mode);
X  umask (oldmask);
X
X  return (newlog);  
X}
X
X/*
X * fexists: return a boolean if the named file exists
X */
X
Xfexists (fn)
Xchar *fn;
X{ struct stat pbuf;
X
X  return (stat (fn, &pbuf) == 0);
X}
X
X/*
X * filelength: Do a stat and return the length of a file.
X */
X
Xint filelength (f)
X{ struct stat sbuf;
X
X  if (stat (f, &sbuf) == 0)
X    return (sbuf.st_size);
X  else
X    return (-1);
X}
X
X/*
X * critical: Disable interrupts
X */
X
Xstatic int   (*hstat)(), (*istat)(), (*qstat)();
X
Xcritical ()
X{
X  hstat = signal (SIGHUP, SIG_IGN);
X  istat = signal (SIGINT, SIG_IGN);
X  qstat = signal (SIGQUIT, SIG_IGN);
X}
X
X/*
X * uncritical: Enable interrupts
X */
X
Xuncritical ()
X{
X  signal (SIGHUP, hstat);
X  signal (SIGINT, istat);
X  signal (SIGQUIT, qstat);
X}
X
X/*
X * reset_int: Set all interrupts to default
X */
X
Xreset_int ()
X{
X  signal (SIGHUP, SIG_DFL);
X  signal (SIGINT, SIG_DFL);
X  signal (SIGQUIT, SIG_DFL);
X}
X
X/*
X * int_exit: Set up a function to call if we get an interrupt
X */
X
Xint_exit (exitproc)
Xint (*exitproc)();
X{
X  if (signal (SIGINT, SIG_IGN) != SIG_IGN)  signal (SIGINT, exitproc);
X  if (signal (SIGPIPE, SIG_IGN) != SIG_IGN) signal (SIGPIPE, exitproc);
X  if (signal (SIGQUIT, SIG_IGN) != SIG_IGN) signal (SIGQUIT, exitproc);
X}
X
X/*
X * lock_file: lock a file for a maximum number of seconds.
X *            Based on the method used in Rogue 5.2.
X */
X
X# define NOWRITE 0
X
Xlock_file (lokfil, maxtime)
Xchar *lokfil;
Xint maxtime;
X{ int try;
X  struct stat statbuf;
X  time_t time ();
X
X  start:
X  if (creat (lokfil, NOWRITE) > 0)
X    return TRUE;
X
X  for (try = 0; try < 60; try++)
X  { sleep (1);
X    if (creat (lokfil, NOWRITE) > 0)
X      return TRUE;
X  }
X
X  if (stat (lokfil, &statbuf) < 0)
X  { creat (lokfil, NOWRITE);
X    return TRUE;
X  }
X
X  if (time (NULL) - statbuf.st_mtime > maxtime)
X  { if (unlink (lokfil) < 0)
X      return FALSE;
X    goto start;
X  }
X  else
X    return FALSE;
X}
X
X/*
X * unlock_file: Unlock a lock file.
X */
X
Xunlock_file (lokfil)
Xchar *lokfil;
X{ unlink (lokfil);
X}
X
X/*
X * quit: Defined for compatibility with Berkeley 4.2 system
X */
X
Xquit (code, fmt, a1, a2, a3, a4)
Xint code, a1, a2, a3, a4;
Xchar *fmt;
X{
X  fprintf (stderr, fmt, a1, a2, a3, a4);
X  exit (code);
X}
/
echo 'Part 02 of Rog-O-Matic XIV complete.'
exit

mlm@cmu-cs-cad.ARPA (Michael Mauldin) (02/01/85)

#!/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@cmu-cs-a.arpa
#
echo 'Start of Rog-O-Matic XIV, part 05 of 10:'
echo 'x - main.c'
sed 's/^X//' > main.c << '/'
X/*
X * main.c: Rog-O-Matic XIV (CMU) Thu Jan 31 18:12:14 1985 - mlm
X */
X
X/*=========================================================================
X * Rog-O-Matic XIV
X * Automatically exploring the dungeons of doom
X * Copyright (C) 1985 by Appel, Jacobson, Hamey, and Mauldin
X *
X * The right is granted to any person, university, or company 
X * to copy, modify, or distribute (for free) these files,
X * provided that any person receiving a copy notifies Michael Mauldin
X *
X * (1) by electronic mail to	Mauldin@CMU-CS-A.ARPA		or
X *
X * (2) by US Mail to		Michael Mauldin
X *				Dept. of Computer Science
X *				Carnegie-Mellon University
X *				Pittsburgh, PA  15213
X *
X * All other rights, including those of publication and sale, are reserved.
X *========================================================================/
X
X/*****************************************************************
X * History:     I.    Andrew Appel & Guy Jacobson, 10/81 [created]
X *              II.   Andrew Appel & Guy Jacobson, 1/82  [added search]
X *              III.  Michael Mauldin, 3/82              [added termcap]
X *              IV.   Michael Mauldin, 3/82              [searching]
X *              V.    Michael Mauldin, 4/82              [cheat mode]
X *              VI.   Michael Mauldin, 4/82              [object database]
X *              VII.  All three, 5/82                    [running away]
X *              VIII. Michael Mauldin, 9/82              [improved cheating]
X *              IX.   Michael Mauldin, 10/82             [replaced termcap]
X *              X.    Mauldin, Hamey,  11/82             [Fixes, Rogue 5.2]
X *              XI.   Mauldin,  11/82                    [Fixes, Score lock]
X *              XII.  Hamey, Mauldin,  06/83             [Fixes, New Replay]
X *              XIII. Mauldin, Hamey,  11/83             [Fixes, Rogue 5.3]
X *              XIV.  Mauldin          01/85             [Fixes, UT mods]
X *
X * General:
X *
X * This is the main routine for the player process, which decodes the
X * Rogue output and sends commands back. This process is execl'd by the
X * rogomatic process (cf. setup.c) which also execl's the Rogue process,
X * conveniently connecting the two via two pipes.
X *
X * Source Files:
X *
X *      arms.c          Armor, Weapon, and Ring handling functions
X *      command.c       Effector interface, sends cmds to Rogue
X *      database.c      Memory for objects "discovered"
X *      debug.c         Contains the debugging functions
X *      explore.c       Path searching functions, exploration
X *      findscore.c     Reads Rogue scoreboard
X *      io.c            I/O functions, Sensory interface
X *      main.c          Main Program for 'player' (this file)
X *      mess.c          Handles messages from Rogue
X *      monsters.c      Monster handling utilities
X *      mover.c         Creates command strings to accomplish moves
X *      rooms.c         Room specific functions, new levels
X *      scorefile.c     Score file handling utilities
X *      search.c        Does shortest path
X *      setup.c         Main program for 'rogomatic'
X *      strategy.c      Makes high level decisions
X *      survival.c      Find cycles and places to run to
X *      tactics.c       Medium level intelligence
X *      things.c        Builds commands, part of Effector interface
X *      titlepage.c     Prints the animated copyright notice
X *      utility.c       Miscellaneous Unix (tm) functions
X *      worth.c         Evaluates the items in the pack
X *
X * Include files:
X *
X *      globals.h       External defs for all global variables
X *      install.h       Machine dependent DEFINES
X *      termtokens.h    Defines various tokens to/from Rogue
X *      types.h         Global DEFINES, macros, and typedefs.
X *
X * Other files which may be included with your distribution include
X *
X *      rplot           A shell script, prints a scatter plot of Rog's scores.
X *      rgmplot.c       A program used by rplot.
X *      datesub.l       A program used by rplot.
X *      histplot.c      A program which plots a histogram of Rgm's scores.
X *
X * Acknowledgments
X *
X *	The UTexas modifications included in this distribution
X *	came from Dan Reynolds, and are included by permission.
X *	Rog-O-Matics first total winner against version 5.3 was
X *	on a UTexas computer.
X *****************************************************************/
X
X# include <curses.h>
X# include <ctype.h>
X# include <signal.h>
X# include <setjmp.h>  
X# include "types.h"
X# include "termtokens.h"
X# include "install.h"
X
X/* global data - see globals.h for current definitions */
X
X/* Files */
XFILE  *fecho=NULL;		/* Game record file 'echo' option */
XFILE  *frogue=NULL;		/* Pipe from Rogue process */
XFILE  *logfile=NULL;		/* File for score log */
XFILE  *realstdout=NULL;		/* Real stdout for Emacs, terse mode */
XFILE  *snapshot=NULL;		/* File for snapshot command */
XFILE  *trogue=NULL;		/* Pipe to Rogue process */
X
X/* Characters */
Xchar  *logfilename = "";	/* Name of log file */
Xchar  afterid = '\0';           /* Letter of obj after identify */
Xchar  genelock[100];		/* Gene pool lock file */
Xchar  genelog[100];		/* Genetic learning log file */
Xchar  genepool[100];		/* Gene pool */
Xchar  *genocide;		/* List of monsters to be genocided */
Xchar  genocided[100];		/* List of monsters genocided */
Xchar  lastcmd[64];		/* Copy of last command sent to Rogue */
Xchar  lastname[64];		/* Name of last potion/scroll/wand */
Xchar  nextid = '\0';            /* Next object to identify */
Xchar  screen[24][80];		/* Map of current Rogue screen */
Xchar  sumline[128];		/* Termination message for Rogomatic */
Xchar  ourkiller[64];		/* How we died */
Xchar  versionstr[32];		/* Version of Rogue being used */
Xchar  *parmstr;			/* Pointer to process arguments */
X
X/* Integers */
Xint   aggravated = 0;		/* True if we have aggravated this level */
Xint   agoalc = NONE;		/* Goal square to arch from (col) */
Xint   agoalr = NONE;		/* Goal square to arch from (row) */
Xint   arglen = 0;		/* Length in bytes of argument space */
Xint   ammo = 0;                 /* How many missiles? */
Xint   arrowshot = 0;		/* True if an arrow shot us last turn */
Xint   atrow, atcol;		/* Current position of the Rogue (@) */
Xint   atrow0, atcol0;		/* Position at start of turn */
Xint   attempt = 0;		/* Number times we searched whole level */
Xint   badarrow = 0;		/* True if cursed/lousy arrow in hand */
Xint   beingheld = 0;		/* True if a fungus has ahold of us */
Xint   beingstalked = 0;		/* True if recently hit by inv. stalker */
Xint   blinded = 0;		/* True if blinded */
Xint   blindir = 0;		/* Last direction we moved when blind */
Xint   cancelled = 0;		/* True ==> recently zapped w/cancel */
Xint   cecho = 0;		/* Last kind of message to echo file */
Xint   cheat = 0;		/* True ==> cheat, use bugs, etc. */
Xint   checkrange = 0;           /* True ==> check range */
Xint   chicken = 0;		/* True ==> check run away code */
Xint   compression = 1;		/* True ==> move more than one square/turn */
Xint   confused = 0;		/* True if we are confused */
Xint   cosmic = 0;		/* True if we are hallucinating */
Xint   currentarmor = NONE;	/* Index of our armor */
Xint   currentweapon = NONE;     /* Index of our weapon */
Xint   cursedarmor = 0;		/* True if our armor is cursed */
Xint   cursedweapon = 0;		/* True if we are wielding cursed weapon */
Xint   darkdir = NONE;		/* Direction of monster being arched */
Xint   darkturns = 0;		/* Distance to monster being arched */
Xint   debugging = D_NORMAL;	/* Debugging options in effect */
Xint   didreadmap = 0;		/* Last level we read a map on */
Xint   doorlist[40];		/* List of doors on this level */
Xint   doublehasted = 0; 	/* True if double hasted (Rogue 3.6) */
Xint   droppedscare = 0;		/* True if we dropped 'scare' on this level */
Xint   emacs = 0;		/* True ==> format output for Emacs */
Xint   exploredlevel = 0;	/* We completely explored this level */
Xint   floating = 0;		/* True if we are levitating */
Xint   foughtmonster = 0;	/* True if recently fought a monster */
Xint   foundarrowtrap = 0;	/* Found arrow trap this level */
Xint   foundtrapdoor = 0;	/* Found trap door this level */
Xint   goalc = NONE;		/* Current goal square (col) */
Xint   goalr = NONE;		/* Current goal square (row) */
Xint   goodarrow = 0;		/* True if good (magic) arrow in hand */
Xint   goodweapon = 0;		/* True if weapon in hand worth >= 100 */
Xint   gplusdam = 1;		/* Our plus damage from strength */
Xint   gplushit = 0;		/* Our plus to hit from strength */
Xint   hasted = 0;		/* True if hasted */
Xint   hitstokill = 0;		/* # times we hit last monster killed */
Xint   interrupted = 0;		/* True if at commandtop from onintr() */
Xint   knowident = 0;            /* Found an identify scroll? */
Xint   larder = 1;               /* How much food? */
Xint   lastate = 0;		/* Time we last ate */
Xint   lastdamage = 0;           /* Amount of last hit by a monster */
Xint   lastdrop = NONE;		/* Last object we tried to drop */
Xint   lastfoodlevel = 1;	/* Last level we found food */
Xint   lastmonster = NONE;	/* Last monster we tried to hit */
Xint   lastobj = NONE;		/* What did we last use */
Xint   lastwand = NONE;		/* Index of last wand */
Xint   leftring = NONE;		/* Index of our left ring */
Xint   logdigested = 0;		/* True if log file has been read by replay */
Xint   logging = 0;		/* True if keeping record of game */
Xint   lyinginwait = 0;          /* True if we waited for a monster */
Xint   maxobj = 22;              /* How much can we carry */
Xint   missedstairs = 0;         /* True if we searched everywhere */
Xint   morecount = 0;            /* Number of messages since last command */
Xint   msgonscreen = 0;		/* Set implies message at top */
Xint   newarmor = 1;             /* Change in armor status? */
Xint  *newdoors = NULL;		/* New doors on screen */
Xint   newring = 1;              /* Change in ring status? */
Xint   newweapon = 1;            /* Change in weapon status? */
Xint   nohalf = 0;		/* True ==> no halftime show */
Xint   noterm = 0;		/* True ==> no user watching */
Xint   objcount = 0;             /* Number of objects */
Xint   ourscore = 0;		/* Final score when killed */
Xint   playing = 1;		/* True if still playing game */
Xint   poorarrow = 0;		/* True if arrow has missed */
Xint   protected = 0;		/* True if we protected our armor */
Xint   putonseeinv = 0;          /* Turn when last put on see inv ring */
Xint   quitat = BOGUS;		/* Score to beat, quit if within 10% more */
Xint   redhands = 0;		/* True if we have red hands */
Xint   replaying = 0;		/* True if replaying old game */
Xint   revvideo = 0;		/* True if in rev. video mode */
Xint   rightring = NONE;		/* Index of our right ring */
Xint   rogpid = 0;		/* Pid of rogue process */
Xint   room[9];			/* Flags for each room */
Xint   row, col;			/* Current cursor position */
Xint   scrmap[24][80];		/* Flags bits for level map */
Xint   singlestep = 0;		/* True ==> go one turn */
Xint   slowed = 0;		/* True ==> recently zapped w/slow monster */
Xint   stairrow, staircol;	/* Position of stairs on this level */
Xint   startecho = 0;		/* True ==> turn on echoing on startup */
Xint   teleported = 0;		/* # times teleported this level */
Xint   terse = 0;		/* True ==> terse mode */
Xint   transparent = 0;		/* True ==> user command mode */
Xint   trapc = NONE;		/* Location of arrow trap, this level (col) */
Xint   trapr = NONE;		/* Location of arrow trap, this level (row) */
Xint   urocnt = 0;               /* Un-identified Rogue Object count */
Xint   usesynch = 0;             /* Set when the inventory is correct */
Xint   usingarrow = 0;		/* True ==> wielding an arrow froma trap */
Xint   version;			/* Rogue version, integer */
Xint   wplusdam = 2;		/* Our plus damage from weapon bonus */
Xint   wplushit = 1;		/* Our plus hit from weapon bonus */
Xint   zone = NONE;		/* Current screen zone, 0..8 */
Xint   zonemap[9][9];		/* Map of zones connections */
X
X/* Functions */
Xint (*istat)(), onintr ();
Xchar getroguetoken (), *getname();
X
X/* Stuff list, list of objects on this level */
Xstuffrec slist[MAXSTUFF]; 	int slistlen=0;
X
X/* Monster list, list of monsters on this level */
Xmonrec mlist[MAXMONST];		int mlistlen=0;
X
Xchar targetmonster = '@';	/* Monster we are arching at */
X
X/* Monster attribute and Long term memory arrays */
Xattrec monatt[26];		/* Monster attributes */
Xlrnrec ltm;			/* Long term memory -- general */
Xltmrec monhist[MAXMON];		/* Long term memory -- creatures */
Xint nextmon = 0;		/* Length of LTM */
Xint monindex[27];		/* Index into monhist array */
X
X/* Genetic learning parameters (and defaults) */
Xint geneid = 0;		/* Id of genotype */
Xint genebest = 0;	/* Best score of genotype */
Xint geneavg = 0;	/* Average score of genotype */
Xint k_srch =	50;	/* Propensity for searching for traps */
Xint k_door =	50;	/* Propensity for searching for doors */
Xint k_rest =	50;	/* Propensity for resting */
Xint k_arch =	50;	/* Propensity for firing arrows */
Xint k_exper =	50;	/* Level*10 on which to experiment with items */
Xint k_run =	50;	/* Propensity for retreating */
Xint k_wake =	50;	/* Propensity for waking things up */
Xint k_food =	50;	/* Propensity for hoarding food (affects rings) */
Xint knob[MAXKNOB] = {50, 50, 50, 50, 50, 50, 50, 50};
X
X/* Door search map */
Xchar timessearched[24][80], timestosearch;
Xint  searchstartr = NONE, searchstartc = NONE, reusepsd=0;
Xint  new_mark=1, new_findroom=1, new_search=1, new_stairs=1, new_arch=1;
X
X/* Results of last call to makemove() */
Xint  ontarget= 0, targetrow= NONE, targetcol= NONE;
X
X/* Rog-O-Matics model of his stats */
Xint   Level = 0, MaxLevel = 0, Gold = 0, Hp = 12, Hpmax = 12;
Xint   Str = 16, Strmax = 16, Ac = 6, Exp = 0, Explev = 1, turns = 0;
Xchar  Ms[30];	/* The message about his state of hunger */
X
X/* Miscellaneous movement tables */
Xint   deltrc[8] = { 1,-79,-80,-81,-1,79,80,81 };
Xint   deltc[8]  = { 1, 1, 0, -1, -1, -1, 0, 1 };
Xint   deltr[8]  = { 0, -1, -1, -1, 0, 1, 1, 1 };
Xchar  keydir[8] = { 'l', 'u', 'k', 'y', 'h', 'b', 'j', 'n' };
Xint   movedir;
X
X/* Map characters on screen into object types */
Xstuff translate[128] =
X{    /* \00x */  none, none, none, none, none, none, none, none,
X     /* \01x */ none, none, none, none, none, none, none, none,
X     /* \02x */ none, none, none, none, none, none, none, none,
X     /* \03x */ none, none, none, none, none, none, none, none,
X     /* \04x */ none, potion, none, none, none, none, none, none,
X     /* \05x */ hitter, hitter, gold, none, amulet, none, none, wand,
X     /* \06x */ none, none, none, none, none, none, none, none,
X     /* \07x */ none, none, food, none, none, ring, none, scroll,
X     /* \10x */ none, none, none, none, none, none, none, none,
X     /* \11x */ none, none, none, none, none, none, none, none,
X     /* \12x */ none, none, none, none, none, none, none, none,
X     /* \13x */ none, none, none, armor, none, armor, none, none,
X     /* \14x */ none, none, none, none, none, none, none, none,
X     /* \15x */ none, none, none, none, none, none, none, none,
X     /* \16x */ none, none, none, none, none, none, none, none,
X     /* \17x */ none, none, none, none, none, none, none, none
X};
X
X/* Inventory, contents of our pack */
Xinvrec inven[MAXINV]; int invcount = 0;
X
X/* Time history */
Xtimerec timespent[50];
X
X/* End of the game messages */
Xchar *termination = "perditus";
Xchar *gamename = "Rog-O-Matic";
Xchar *roguename = "Rog-O-Matic                             ";
X
X/* Used by onintr() to restart Rgm at top of command loop */
Xjmp_buf  commandtop;
X
X/*
X * Main program
X */
X
Xmain (argc, argv)
Xint   argc;
Xchar *argv[];
X{ char  ch, *s, *getenv(), *statusline(), msg[128];
X  int startingup = 1;
X  register int  i;
X
X  /*
X   * Initialize some storage
X   */
X  
X  sprintf (genocided, "");
X  sprintf (lastcmd, "i");
X  sprintf (ourkiller, "unknown");
X  sprintf (sumline, "");
X  for (i = 80 * 24; i--; ) screen[0][i] = ' ';
X 
X  /* 
X   * The first argument to player is a two character string encoding
X   * the file descriptors of the pipe ends. See setup.c for call.
X   *
X   * If we get 'ZZ', then we are replaying an old game, and there
X   * are no pipes to read/write.
X   */
X
X  if (argv[1][0] == 'Z')
X  { replaying = 1;
X    gamename = "Iteratum Rog-O-Maticus";
X    termination = "finis";
X    logfilename = argv[4];
X    startreplay (&logfile, logfilename);
X  }
X  else
X  { frogue = fdopen (argv[1][0] - 'a', "r");
X    trogue = fdopen (argv[1][1] - 'a', "w");
X    setbuf (trogue, NULL);
X  }
X
X  /* The second argument to player is the process id of Rogue */
X  if (argc > 2) rogpid = atoi (argv[2]);                  
X
X  /* The third argument is an option list */
X  if (argc > 3) sscanf (argv[3], "%d,%d,%d,%d,%d,%d,%d,%d", 
X			&cheat, &noterm, &startecho, &nohalf,
X			&emacs, &terse, &transparent, &quitat);
X
X  /* The fourth argument is the Rogue name */
X  if (argc > 4)	strcpy (roguename, argv[4]);
X  else		sprintf (roguename, "Rog-O-Matic %s", RGMVER);
X
X  /* Now count argument space and assign a global pointer to it */
X  arglen = 0;
X  for (i=0; i<argc; i++)
X  { register int len = strlen (argv[i]);
X    arglen += len + 1;
X    while (len >= 0) argv[i][len--] = ' ';
X  }
X  parmstr = argv[0];	arglen--;
X
X  /* If we are in one-line mode, then squirrel away stdout */
X  if (emacs || terse)
X  { realstdout = fdopen (dup (fileno (stdout)), "w");
X    freopen ("/dev/null", "w", stdout);
X  }
X
X  initscr (); crmode (); noecho ();	/* Initialize the Curses package */
X  if (startecho) toggleecho ();		/* Start logging? */
X  clear ();				/* Clear the screen */
X  getrogver ();				/* Figure out Rogue version */
X
X  if (!replaying)
X  { restoreltm ();			/* Get long term memory of version */ 
X    startlesson ();			/* Start genetic learning */
X  }
X
X  /* 
X   * Give a hello message
X   */
X
X  sprintf (msg, " %s: version %s, genotype %d, quit at %d.",
X           roguename, versionstr, geneid, quitat);
X  
X  if (emacs)
X  { fprintf (realstdout, "%s  (%%b)", msg); fflush (realstdout); }
X  else if (terse)
X  { fprintf (realstdout, "%s\n", msg); fflush (realstdout); }
X  else
X  { saynow (msg); }
X
X  /* 
X   * Now that we have the version figured out, we can properly
X   * interpret the screen.  Force a redraw by sending a redraw
X   * screen command (^L for old, ^R for new).
X   *
X   * Also identify wands (/), so that we can differentiate
X   * older Rogue 3.6 from Rogue 3.6 with extra magic...
X   */
X
X  if (version < RV53A)
X    sendnow ("%c//;", ctrl('l'));
X  else
X    sendnow ("%c;", ctrl('r'));
X
X  /* 
X   * If we are not replaying an old game, we must position the
X   * input after the next form feed, which signals the start of
X   * the level drawing.
X   */
X  
X  if (!replaying)
X    while ((int) (ch = GETROGUECHAR) != CL_TOK && (int) ch != EOF);
X
X  /* 
X   * Note: If we are replaying, the logfile is now in synch
X   */
X
X  getrogue (ill, 2);  /* Read the input up to end of first command */
X  
X  /* Identify all 26 monsters */
X  if (!replaying)
X    for (ch = 'A'; ch <= 'Z'; ch++) send ("/%c", ch);
X
X  /*
X   * Signal handling. On an interrupt, Rogomatic goes into transparent
X   * mode and clears what state information it can. This code is styled
X   * after that in "UNIX Programming -- Second Edition" by Brian
X   * Kernigan & Dennis Ritchie. I sure wouldn't have thought of it.
X   */
X
X  istat = signal (SIGINT, SIG_IGN); /* save original status */
X  setjmp (commandtop);              /* save stack position */
X  if (istat != SIG_IGN)
X    signal (SIGINT, onintr);
X
X  if (interrupted)
X  { saynow ("Interrupt [enter command]:");
X    interrupted = 0;
X    transparent = 1;
X  }
X  
X  if (transparent) noterm = 0;
X
X  while (playing) 
X  { refresh ();
X
X    /* If we have any commands to send, send them */
X    while (resend ())
X    { if (startingup) showcommand (lastcmd);
X      sendnow (";"); getrogue (ill, 2);
X    }
X    
X    if (startingup)		/* All monsters identified */
X    { versiondep ();			/* Do version specific things */
X      startingup = 0;			/* Clear starting flag */
X    }
X    
X    if (!playing) break;	/* In case we died */
X
X    /*
X     * No more stored commands, so either get a command from the
X     * user (if we are in transparent mode or the user has typed
X     * something), or let the strategize module try its luck. If
X     * strategize fails we wait for the user to type something. If
X     * there is no user (noterm mode) then use ROGQUIT to signal a
X     * quit command.
X     */
X
X    if ((transparent && !singlestep) ||
X	(!emacs && charsavail ()) ||
X        !strategize())
X    { ch = (noterm) ? ROGQUIT : getch ();
X
X      switch (ch)
X      { case '?': givehelp (); break;
X      
X        case '\n': if (terse) 
X	           { printsnap (realstdout); fflush (realstdout); }
X	           else
X                   { singlestep = 1; transparent = 1; }
X		   break;
X	           
X        /* Rogue Command Characters */
X        case 'H': case 'J': case 'K': case 'L':
X        case 'Y': case 'U': case 'B': case 'N':
X        case 'h': case 'j': case 'k': case 'l':
X        case 'y': case 'u': case 'b': case 'n':
X        case 's': command (T_OTHER, "%c", ch); transparent = 1; break;
X
X        case 'f': ch = getch ();
X                  for (s = "hjklyubnHJKLYUBN"; *s; s++)
X                  { if (ch == *s)
X                    { if (version < RV53A) command (T_OTHER, "f%c", ch); 
X		      else                 command (T_OTHER, "%c", ctrl (ch)); 
X		    }
X                  }
X                  transparent = 1; break;
X
X        case '\f':  redrawscreen (); break;
X
X        case 'm':   dumpmonstertable (); break;
X
X        case 'M':   dumpmazedoor (); break;
X
X        case '>': if (atrow == stairrow && atcol == staircol) 
X                    command (T_OTHER, ">");
X                  transparent = 1; break;
X
X        case '<': if (atrow == stairrow && atcol == staircol &&
X                      have (amulet) != NONE) command (T_OTHER, "<");
X                  transparent = 1; break;
X
X        case 't': transparent = !transparent; break;
X
X        case ')': markcycles (DOPRINT); at (row, col); break;
X
X        case '+': setpsd (DOPRINT); at (row, col); break;
X
X        case 'A': attempt = (attempt+1) % 5;
X		  saynow ("Attempt %d", attempt); break;
X
X        case 'G': mvprintw (0, 0,
X               "%d: Sr %d Dr %d Re %d Ar %d Ex %d Rn %d Wk %d Fd %d, %d/%d",
X		  geneid, k_srch, k_door, k_rest, k_arch,
X		  k_exper, k_run, k_wake, k_food, genebest, geneavg);
X		  clrtoeol (); at (row, col); refresh (); break;
X
X        case ':': chicken = !chicken;
X                  say (chicken ? "chicken" : "aggressive");
X                  break;
X
X        case '~': saynow
X                  ("Rogomatic version %s, Rogue version %s (%d), quit at %d",
X                     RGMVER, versionstr, version, quitat);
X                  break;
X
X        case '[': at (0,0);
X                  printw ("%s = %d, %s = %d, %s = %d, %s = %d.",
X                     "hitstokill", hitstokill,
X                     "goodweapon", goodweapon,
X                     "usingarrow", usingarrow,
X                     "goodarrow", goodarrow);
X                  clrtoeol ();
X                  at (row, col);
X                  refresh ();
X                  break;
X
X        case '-': saynow (statusline ());
X                  break;
X
X        case '`': clear ();
X                  summary (NULL, '\n');
X                  pauserogue ();
X                  break;
X
X        case '|': clear ();
X                  timehistory (NULL, '\n', 0);
X                  pauserogue ();
X                  break;
X
X        case 'r': resetinv (); say ("Inventory reset."); break;
X
X        case 'i': clear (); dumpinv (NULL); pauserogue (); break;
X
X        case '/': dosnapshot ();
X                  break;
X
X        case '(': clear (); dumpdatabase (); pauserogue (); break;
X
X        case 'c': cheat = !cheat;
X                  say (cheat ? "cheating" : "righteous");
X                  break;
X
X        case 'd': toggledebug ();	break;
X
X        case 'e': toggleecho ();        break;
X
X        case '!': dumpstuff ();         break;
X
X        case '@': dumpmonster ();       break;
X
X        case '#': dumpwalls ();         break;
X
X        case '%': clear (); havearmor (1, DOPRINT, ANY); pauserogue (); break;
X
X        case '=': clear (); havering (1, DOPRINT); pauserogue (); break;
X
X        case '$': clear (); haveweapon (1, DOPRINT); pauserogue (); break;
X
X        case '^': clear (); havebow (1, DOPRINT); pauserogue (); break;
X
X        case '{': promptforflags (); break;
X
X        case '&': saynow ("Object count is %d.", objcount); break;
X
X        case '*': blinded = !blinded;
X                  saynow (blinded ? "blinded" : "sighted");
X                  break;
X
X        case 'C': cosmic = !cosmic;
X                  saynow (cosmic ? "cosmic" : "boring");
X                  break;
X
X        case 'E': dwait (D_ERROR, "Testing the ERROR trap..."); break;
X
X        case 'F': dwait (D_FATAL, "Testing the FATAL trap..."); break;
X
X        case 'R': if (replaying)
X		  { positionreplay (); getrogue (ill, 2);
X	            if (transparent) singlestep = 1; }
X		  else
X                    saynow ("Replay position only works in replay mode.");
X                  break;
X
X        case 'S': quitrogue ("saved", Gold, SAVED); 
X                  playing = 0; break;
X
X        case 'Q': quitrogue ("user typing quit", Gold, FINISHED); 
X                  playing = 0; break;
X
X        case ROGQUIT: dwait (D_ERROR, "Strategize failed, gave up.");
X                      quitrogue ("gave up", Gold, SAVED); break;
X      }
X    }
X    else
X    { singlestep = 0;
X    }
X  }
X  
X  if (! replaying)
X  { saveltm (Gold);			/* Save new long term memory */
X    endlesson ();			/* End genetic learning */  
X  }
X
X  /* Print termination messages */
X  at (23, 0); clrtoeol (); refresh ();
X  endwin (); nocrmode (); noraw (); echo ();
X  
X  if (emacs)  
X  { if (*sumline) fprintf (realstdout, " %s", sumline);
X  }
X  else if (terse)  
X  { if (*sumline) fprintf (realstdout, "%s\n",sumline);
X    fprintf (realstdout, "%s %s est.\n", gamename, termination);
X  }
X  else
X  { if (*sumline) printf ("%s\n",sumline);
X    printf ("%s %s est.\n", gamename, termination);
X  }
X
X  /* 
X   * Rename log file, if it is open
X   */
X
X  if (logging)
X  { char lognam[128];
X
X    /* Make up a new log file name */
X    sprintf (lognam, "%0.4s.%d.%d", ourkiller, MaxLevel, ourscore);
X
X    /* Close the open file */
X    toggleecho ();
X
X    /* Rename the log file */
X    if (link (ROGUELOG, lognam) == 0)
X    { unlink (ROGUELOG);
X      printf ("Log file left on %s\n", lognam);
X    }
X    else
X      printf ("Log file left on %s\n", ROGUELOG);
X  }
X
X  exit (0);
X}
X
X/*
X * onintr: The SIGINT handler. Pass interrupts to main loop, setting
X * transparent mode. Also send some synchronization characters to Rogue,
X * and reset some goal variables.
X */
X
Xonintr ()
X{ sendnow ("n\033");            /* Tell Rogue we don't want to quit */
X  if (logging) fflush (fecho);  /* Print out everything */
X  refresh ();                   /* Clear terminal output */
X  clearsendqueue ();            /* Clear command queue */
X  setnewgoal ();                /* Don't believe ex */
X  transparent = 1;              /* Drop into transprent mode */
X  interrupted = 1;              /* Mark as an interrupt */
X  noterm = 0;                   /* Allow commands */
X  longjmp (commandtop);         /* Back to command Process */
X}
X
X/*
X * startlesson: Genetic learning algorithm, pick a genotype to
X * test this game, and set the parameters (or "knobs") accordingly.
X */
X
Xstartlesson ()
X{ sprintf (genelog, "%s/GeneLog%d", RGMDIR, version);
X  sprintf (genepool, "%s/GenePool%d", RGMDIR, version);
X  sprintf (genelock, "%s/GeneLock%d", RGMDIR, version);
X
X  srand (0);				/* Start random number generator */
X  critical ();				/* Disable interrupts */
X
X  /* Serialize access to the gene pool */
X  if (lock_file (genelock, MAXLOCK))	/* Lock the gene pool */
X  { if (openlog (genelog) == NULL)	/* Open the gene log file */
X      saynow ("Could not open file %s", genelog);
X    if (! readgenes (genepool))		/* Read the gene pool */
X      initpool (MAXKNOB, 20);		/* Random starting point */
X    setknobs (&geneid, knob, &genebest, &geneavg); /* Select a genotype */
X    writegenes (genepool);		/* Write out the gene pool */
X    closelog ();			/* Close the gene log file */
X    unlock_file (genelock);		/* Unlock the gene pool */
X  }
X  else
X    fprintf (stderr, "Cannot lock gene pool to read '%s'\n", genepool);
X
X  uncritical ();			/* Reenable interrupts */
X
X  /* Cache the parameters for easier use */
X  k_srch = knob[K_SRCH];	k_door = knob[K_DOOR];
X  k_rest = knob[K_REST];	k_arch = knob[K_ARCH];
X  k_exper = knob[K_EXPER];	k_run = knob[K_RUN];
X  k_wake = knob[K_WAKE];	k_food = knob[K_FOOD];
X}
X
X/*
X * endlesson: if killed, total winner, or quit for scoreboard,
X * evaluate the performance of this genotype and save in genepool.
X */
X
Xendlesson ()
X{ if (geneid > 0 &&
X      (stlmatch (termination, "perditus") ||
X       stlmatch (termination, "victorius") ||
X       stlmatch (termination, "callidus")))
X  { critical ();			/* Disable interrupts */
X
X    if (lock_file (genelock, MAXLOCK))	/* Lock the score file */
X    { openlog (genelog);		/* Open the gene log file */
X      if (readgenes (genepool))		/* Read the gene pool */
X      { evalknobs (geneid,Gold,Level);	/* Add the trial to the pool */
X        writegenes (genepool); }	/* Write out the gene pool */
X      closelog ();
X      unlock_file (genelock);		/* Disable interrupts */
X    }
X    else 
X      fprintf (stderr, "Cannot lock gene pool to evaluate '%s'\n", genepool);
X
X    uncritical ();			/* Re-enable interrupts */
X  }
X}
/
echo 'x - rand.c'
sed 's/^X//' > rand.c << '/'
X/*
X * rand.c: Rog-O-Matic XIV (CMU) Fri Dec 28 23:42:39 1984 - mlm
X * Copyright (C) 1985 by A. Appel, G. Jacobson, L. Hamey, and M. Mauldin
X *
X * A very random generator, period approx 6.8064e16.
X *
X * Uses algorithm M, "Art of Computer Programming", Vol 2. 1969, D.E.Knuth.
X *
X * Two generators are used to derive the high and low parts of sequence X,
X * and another for sequence Y. These were derived by Michael Mauldin.
X *
X * Usage:  initialize by calling srand(seed), then rand() returns a random 
X *         number from 0..2147483647. srand(0) uses the current time as
X *         the seed.
X *
X * Author: Michael Mauldin, June 14, 1983.
X */
X
X/* Rand 1, period length 444674 */
X# define MUL1 1156
X# define OFF1 312342
X# define MOD1 1334025
X# define RAND1 (seed1=((seed1*MUL1+OFF1)%MOD1))
X# define Y      RAND1
X
X/* Rand 2, period length 690709 */
X# define MUL2 1366
X# define OFF2 827291
X# define MOD2 1519572
X# define RAND2 (seed2=((seed2*MUL2+OFF2)%MOD2))
X
X/* Rand 3, period length 221605 */
X# define MUL3 1156
X# define OFF3 198273
X# define MOD3 1329657
X# define RAND3 (seed3=((seed3*MUL3+OFF3)%MOD3))
X
X/*
X * RAND2 generates 19 random bits, RAND3 generates 17. The X sequence
X * is made up off both, and thus has 31 random bits.
X */
X
X# define X    ((RAND2<<13 ^ RAND3>>3) & 017777777777)
X
X# define AUXLEN 97
Xstatic int seed1=872978, seed2=518652, seed3=226543, auxtab[AUXLEN];
X
Xsrand (seed)
Xint seed;
X{ register int i;
X
X  if (seed == 0) seed = time();
X
X  /* Set the three random number seeds */
X  seed1 = (seed1+seed) % MOD1;
X  seed2 = (seed2+seed) % MOD2;
X  seed3 = (seed3+seed) % MOD3;
X  
X  for (i=AUXLEN; i--; )
X    auxtab[i] = X;
X}
X
Xint rand ()
X{ register int j, result;
X
X  j = AUXLEN * Y / MOD1;	/* j random from 0..AUXLEN-1 */
X  result = auxtab[j];
X  auxtab[j] = X;
X  return (result);
X}
X
Xrandint (max)
Xregister int max;
X{ register int j, result;
X
X  j = AUXLEN * Y / MOD1;	/* j random from 0..AUXLEN-1 */
X  result = auxtab[j];
X  auxtab[j] = X;
X  return (result % max);
X}
/
echo 'x - rplot'
sed 's/^X//' > rplot << '/'
Xcolrm 48 < /usr/mlm/games/rlog/rgmscore5.2 | datesub | sort -u +0n +1n +2n +4n +5 | rgmplot $* 
/
echo 'x - termtokens.h'
sed 's/^X//' > termtokens.h << '/'
X/*
X * termtokens.h: Rog-O-Matic XIV (CMU) Fri Dec 28 22:16:05 1984 - mlm
X * Copyright (C) 1985 by A. Appel, G. Jacobson, L. Hamey, and M. Mauldin
X *
X * Various tokens used by the screen reading package.
X */
X
X# define BS_TOK ctrl('H')
X# define CE_CHR ctrl('S')
X# define CE_TOK -2
X# define CL_CHR ctrl('L')
X# define CL_TOK ctrl('L')
X# define CM_CHR 'a'
X# define CM_TOK -3
X# define CR_TOK ctrl('M')
X# define DO_CHR '<'
X# define DO_TOK -4
X# define ER_TOK -5
X# define LF_TOK ctrl('J')
X# define ND_CHR '='
X# define ND_TOK -6
X# define SE_CHR 'd'
X# define SE_TOK -7
X# define SO_CHR 'D'
X# define SO_TOK -8
X# define TA_TOK ctrl('I')
X# define UP_CHR ';'
X# define UP_TOK -9
/
echo 'x - things.c'
sed 's/^X//' > things.c << '/'
X/*
X * things.c: Rog-O-Matic XIV (CMU) Thu Jan 31 18:13:32 1985 - mlm
X * Copyright (C) 1985 by A. Appel, G. Jacobson, L. Hamey, and M. Mauldin
X *
X * This file contains much of the code to handle Rog-O-Matics inventory.
X */
X
X# include <ctype.h>
X# include <curses.h>
X# include "types.h"
X# include "globals.h"
X
X/*
X * wear: This primitive function issues a command to put on armor.
X */
X
Xwear (obj)
Xint obj;
X{
X  if (currentarmor != NONE)
X  { dwait (D_FATAL, "Trying to put on a second coat of armor");
X    return (0);
X  }
X
X  if (cursedarmor) return (0);
X
X  command (T_HANDLING, "W%cI%c", LETTER (obj), LETTER (obj));
X  return (1);
X}
X
X/*
X * takeoff: Remove the current armor.
X */
X
Xtakeoff ()
X{
X  if (currentarmor == NONE)
X  { dwait (D_ERROR, "Trying to take off armor we don't have on!");
X    return (0);
X  }
X
X  if (cursedarmor) return (0);
X
X  command (T_HANDLING, "T");
X  return (1);
X}
X
X/*
X * wield: This primitive function issues a command to wield a weapon.
X */
X
Xwield (obj)
Xint obj;
X{
X  if (cursedweapon) return (0);
X
X  if (version < RV53A)
X    command (T_HANDLING, "w%cw%c%c", LETTER (obj), ESC, ctrl('r'));
X  else
X    command (T_HANDLING, "w%cw%c%c", LETTER (obj), ESC, ctrl('p'));
X
X  return (1);
X}
X
X/*
X * drop: called with an integer from 0 to 25, drops the object if possible
X * and returns 1 if it wins and 0 if it fails. Could be extended to
X * throw object into a wall to destroy it, but currently it merely sets
X * the USELESS bit for that square.
X */
X
Xdrop (obj)
Xint obj;
X{
X  /* Cant if there is not something there */
X  if (inven[obj].count < 1) return (0);
X
X  /* read unknown scrolls rather than dropping them */
X  if (inven[obj].type == scroll && !itemis (obj, KNOWN) && reads (obj))
X  { prepareident (pickident (), obj);
X    return (1);
X  }
X  
X  /* quaff unknown potions rather than dropping them */
X  if (inven[obj].type == potion && !itemis (obj, KNOWN) && quaff (obj))
X    return (1);
X
X  if (itemis (obj, INUSE) || on (STUFF | TRAP | STAIRS | DOOR))
X    return (0);
X
X  command (T_HANDLING, "d%c", LETTER (obj));
X  return (1);
X}
X
X/* 
X * quaff: build and send a quaff potion command.
X */
X
Xquaff (obj)
Xint obj;
X{
X  if (inven[obj].type != potion)
X  { dwait (D_ERROR, "Trying to quaff %c", LETTER (obj)); 
X    usesynch = 0;
X    return (0); 
X  }
X
X  command (T_HANDLING, "q%c", LETTER (obj));
X  return (1);
X}
X
X/*
X * reads: build and send a read scroll command.
X */
X
Xreads (obj)
Xint obj;
X{
X  if (inven[obj].type != scroll)
X  { dwait (D_ERROR, "Trying to read %c", LETTER (obj)); 
X    usesynch = 0;
X    return (0); 
X  }
X
X  command (T_HANDLING, "r%c", LETTER (obj));
X  return (1);
X}
X
X/*
X * build and send a point with wand command.
X */
X
Xpoint (obj, dir)
Xint obj, dir;
X{
X  if (inven[obj].type != wand)
X  { dwait (D_ERROR, "Trying to point %c", LETTER (obj)); 
X    return (0); 
X  }
X
X  command (T_HANDLING, "%c%c%c",
X           (version < RV52A) ? 'p' : 'z',	/* R5.2 MLM */
X           keydir[dir], LETTER (obj));
X  return (1);
X}
X
X/* 
X * throw: build and send a throw object command.
X */
X
Xthrow (obj, dir)
Xint obj, dir;
X{
X  if (obj < 0 || obj >= invcount)
X  { dwait (D_ERROR, "Trying to throw %c", LETTER (obj)); 
X    return (0); 
X  }
X
X  command (T_HANDLING, "t%c%c", keydir[dir], LETTER (obj));
X  return (1);
X}
X
X/* 
X * puton: build and send a command to put on a ring.
X */
X
Xputon (obj)
Xint obj;
X{
X  if (leftring == NONE && rightring == NONE)
X  { command (T_HANDLING, "P%cl", LETTER (obj)); return (1); }
X
X  if (leftring == NONE || rightring == NONE)
X  { command (T_HANDLING, "P%c", LETTER (obj)); return (1); }
X
X  return (0);
X}
X
X/*
X * removering: build a command to remove a ring. It is left in the pack.
X */
X
Xremovering (obj)
Xint obj;
X{
X  if (leftring != NONE && rightring != NONE && leftring == obj)
X  { command (T_HANDLING, "Rl"); return (1); }
X
X  if (leftring != NONE && rightring != NONE && rightring == obj)
X  { command (T_HANDLING, "Rr"); return (1); }
X
X  if (leftring == obj || rightring == obj)
X  { command (T_HANDLING, "R"); return (1); }
X
X  return (0);
X}
X
X/*
X * initstufflist: clear the list of objects on this level.
X */
X
Xinitstufflist ()
X{ slistlen = 0;
X}
X
X/*
X * addstuff: add an item to the list of items on this level.
X */
X
Xaddstuff (ch, row, col)
Xchar  ch;
Xint   row, col;
X{ /* if (seerc ('@', row, col)) return (0); */ /* Removed MLM 10/28/83 */
X  if (onrc (STUFF, row, col))
X    deletestuff (row, col);
X  slist[slistlen].what = translate[ch];
X  slist[slistlen].srow = row;
X  slist[slistlen].scol = col;
X  if (++slistlen >= MAXSTUFF) dwait (D_FATAL, "Too much stuff");
X  setrc (STUFF, row, col);
X}
X
X/*
X * deletestuff: remove the object from the stuff list at location (x,y)
X */
X
Xdeletestuff (row, col)
Xint   row, col;
X{ register int   i;
X  unsetrc (STUFF, row, col);
X  for (i = 0; i < slistlen; ++i)
X    if (slist[i].scol == col && slist[i].srow == row)
X    { slist[i] = slist[--slistlen];
X      i--;					/* MLM 10/23/82 */
X    }
X}
X
X/*
X * dumpstuff: (debugging) dump the list of objects on this level.
X */
X
Xdumpstuff ()
X{ register int   i;
X  at (1, 0);
X  for (i = 0; i < slistlen; ++i)
X    printw ("%d at %d,%d (%c)\n",
X        slist[i].what, slist[i].srow, slist[i].scol,
X        screen[slist[i].srow][slist[i].scol]);
X  printw ("You are at %d,%d.", atrow, atcol);
X  at (row, col);
X}
X
X/*
X * display: Print a message on line 1 of the screen.
X */
X
Xdisplay (s)
Xchar *s;
X{ saynow (s);
X  msgonscreen=1;
X}
X
X/* 
X * prepareident: Set nextid and afterid to proper values
X */
X
Xprepareident (obj, iscroll)
Xint obj, iscroll;
X{ nextid = LETTER (obj);
X  afterid = (iscroll > obj || inven[iscroll].count > 1) ? nextid : nextid-1;
X}
X
X/*
X * pickident: Pick an object to be identified.  This is a preference 
X * ordering of objects.  If nothing else, return 0 (the index of the 
X * first item in the pack).
X */
X
Xint pickident ()
X{ register int obj;
X
X  if      ((obj=unknown      (ring))   != NONE);
X  else if ((obj=unidentified (wand))   != NONE);
X  else if ((obj=unidentified (scroll)) != NONE);
X  else if ((obj=unidentified (potion)) != NONE);
X  else if ((obj=unknown      (scroll)) != NONE);
X  else if ((obj=unknown      (potion)) != NONE);
X  else if ((obj=unknown      (hitter)) != NONE);
X  else obj = 0;
X
X  return (obj);
X}
X
X/*
X * unknown: Return the index of any unknown object of type otype 
X */
X
Xint unknown (otype)
Xstuff otype;
X{ register int i;
X  for (i=0; i<invcount; ++i)
X    if (inven[i].count &&
X        (inven[i].type == otype) &&
X        (itemis (i, KNOWN) == 0) &&
X	(!used (inven[i].str)))
X      return (i);
X
X  return (NONE);
X}
X
X/*
X * unidentified: Return the index of any unidentified object of type otype 
X */
X
Xint unidentified (otype)
Xstuff otype;
X{ register int i;
X  for (i=0; i<invcount; ++i)
X    if (inven[i].count &&
X        (inven[i].type == otype) &&
X        (itemis (i, KNOWN) == 0) &&
X	(used (inven[i].str)))
X      return (i);
X
X  return (NONE);
X}
X
X/*
X * haveother: Return the index of any unknown object of type 'otype', 
X * but not 'other'.
X */
X
Xint haveother (otype,other)
Xstuff otype;
Xint other;
X{ register int i;
X  for (i=0; i<invcount; ++i)
X    if (inven[i].count &&
X        (inven[i].type == otype) &&
X        (itemis (i, KNOWN) == 0) &&
X        (i != other))
X      return (i);
X
X  return (NONE);
X}
X
X/*
X * have: Return the index of any object of type otype
X */
X
Xint have (otype)
Xstuff otype;
X{ register int i;
X  for (i=0; i<invcount; ++i)
X    if (inven[i].count &&
X        inven[i].type == otype) return (i);
X
X  return (NONE);
X}
X
X/*
X * havenamed: Return the index of any object of type otype named
X * name which is not in use .
X */
X
Xint havenamed (otype,name)
Xstuff otype;
Xchar *name;
X{ register int i;
X  for (i=0; i<invcount; ++i)
X    if (inven[i].count &&
X        inven[i].type == otype &&
X        (*name == 0 || streq (inven[i].str,name)) &&
X        !itemis (i, INUSE))
X      return (i);
X
X  return (NONE);
X}
X
X/*
X * havewand: Return the index of a charged wand or staff
X */
X
Xint havewand (name)
Xchar *name;
X{ register int i;
X
X  /* Find one with positive charges */
X  for (i=0; i<invcount; ++i)
X    if (inven[i].count &&
X        inven[i].type == wand &&
X        (*name == 0 || streq (inven[i].str,name)) &&
X        (inven[i].charges > 0))
X      return (i);
X
X  /* Find one with unknown charges */
X  for (i=0; i<invcount; ++i)
X    if (inven[i].count &&
X        inven[i].type == wand &&
X        (*name == 0 || streq (inven[i].str,name)) &&
X        inven[i].charges == UNKNOWN)
X      return (i);
X
X  return (NONE);
X}
X
X/*
X * wearing: Return the index if wearing a ring with this title
X */
X
Xwearing (name)
Xchar *name;
X{ register int result = NONE;
X
X  if (leftring != NONE && itemis (leftring, INUSE) &&
X        streq (inven[leftring].str, name))
X    result = leftring;
X
X  else if (rightring != NONE && itemis (rightring, INUSE) &&
X        streq (inven[rightring].str, name))
X    result = rightring;
X  
X  return (result);  
X}
X
X/* 
X * Return the index of any object of type otype and name name only
X * if we have count or more of them. This way we can avoid using the
X * last of something .
X */
X
Xint havemult (otype, name, count)
Xstuff otype;
Xchar *name;
Xint   count;
X{ register int i, num=count;
X  for (i=0; i<invcount; ++i)
X    if (inven[i].count &&
X        inven[i].type == otype &&
X        (*name == 0 || streq (inven[i].str,name)) &&
X        (num -= inven[i].count) <= 0)
X      return (i);
X
X  return (NONE);
X}
X
X/* 
X * haveminus: Return the index of something if it is a minus item
X * (used to throw away stuff at end)
X */
X
Xint haveminus ()
X{ register int i;
X  for (i=0; i<invcount; ++i)
X    if (inven[i].count &&
X        inven[i].phit != UNKNOWN &&
X        inven[i].phit < 0)
X      return (i);
X
X  return (NONE);
X}
X
X/* 
X * haveuseless: return the index of useless arrows, and empty wands.
X */
X
Xint haveuseless ()
X{ register int i;
X  for (i=0; i<invcount; ++i)
X    if (inven[i].count &&
X        inven[i].type == wand && inven[i].charges == 0 ||
X        itemis (i, WORTHLESS) && streq (inven[i].str, "arrow"))
X      return (i);
X
X  return (NONE);
X}
X
X/* 
X * willrust: return true if a suit of armor can rust
X */
X
Xwillrust (obj)
Xint obj;
X{ return (! (armorclass (obj) > 8 || armorclass (obj) < -5 ||
X	     itemis (obj, PROTECTED) ||
X	     stlmatch (inven[obj].str, "leather")));
X}
X
X/*
X * wielding: return true if we are wielding an object of type 'otype'
X */
X
Xwielding (otype)
Xstuff otype;
X{ 
X  return (inven[currentweapon].type == otype);
X}
X
X/* 
X * hungry: return true if we are hungry, weak, or fainting
X */
X
Xhungry ()
X{ return (*Ms == 'H' || *Ms == 'W' || *Ms == 'F'); }
X
X/* 
X * weak: return true if we are weak or fainting
X */
X
Xweak ()
X{ return (*Ms == 'W' || *Ms == 'F'); }
X
X/* 
X * fainting: return true if we are fainting
X */
X
Xfainting ()
X{ return (*Ms == 'F'); }
X
X/*
X * havefood: return true if we have more than 'n' foods, modified
X * by the genetic variable k_food (higher values of k_food mean this
X * routine returns true less often).
X */
X
Xint havefood (n)
Xint n;
X{ int remaining, foodest, desired;
X
X  if (hungry () || weak () || fainting ())
X    return (0);
X
X  remaining = 800 - turns + lastate;
X  if (remaining < 0) remaining = 0;
X  foodest = larder * 1000 + remaining;
X  desired = n * 1000 * 50 / (100-k_food);
X
X  return (foodest > desired);
X}
/
echo 'Part 05 of Rog-O-Matic XIV complete.'
exit