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

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


#!/bin/sh
#
# @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
# @ Here is part of your new automatic Rogue player, Rog-O-Matic XIV! @
# @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
# 
#     [Note: this is a Beta-Test release of version XIV, and almost
#      certainly contains bugs.  A new version will be made available
#      soon.  If you experience any problems with this version, please
#      contact Michael Mauldin as soon as possible, so your input can be
#      included in the new release]
# 
# Rog-O-Matic XIV is shipped via mail in pieces, files rgm14.01, rgm14.02,
# ..., rgm14.nn.  Each piece contains some number of smaller files. To
# retrieve them, run each file through the shell 'sh', as follows:
# 
# 	sh <rgm14.01
# 	sh <rgm14.02
# 	     ...
# 	sh <rgm14.nn
# 
# or do it all at once:
# 
# 	cat rgm14.* | sh
# 
# The README file contains all necessary information to edit the "install.h"
# file, after which "make" will build the rogomatic and player binary files.
# Please note that file 'Bugreport' contains modifications you may wish to
# make to the code BEFORE you compile it.  You can safely install ALL of
# them; depending on your version of Rogue, you may HAVE to install SOME of
# them.
# 
# Rog-O-Matic is copyrighted, but permission is given to copy and modify the
# source provided that (1) it is not used for profit (2) all authorship and
# copyright notices remain intact and (3) any person or site with a copy has
# notified Michael Mauldin either by electronic mail or US Post that they
# have Rog-O-Matic XIV.
# 
# We would appreciate hearing about any interesting additions or modifi-
# cations, and would especially like to know how well the program plays
# against your Rogue.  And we really, really want to know if Rog-O-Matic
# becomes a "Total Winner" against Rogue 5.2 or Rogue 5.3 again.
# 
# 				Michael Mauldin (Fuzzy)
# 				Department of Computer Science
# 				Carnegie-Mellon University
# 				Pittsburgh, PA  15213
# 				(412) 578-3065,  mauldin at cmu-cs-a.arpa
#
echo 'Start of Rog-O-Matic XIV, part 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 at 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



More information about the Comp.sources.unix mailing list