Rog-O-Matic XIV (part 07 of 10)
Michael Mauldin
mlm at cmu-cs-cad.ARPA
Sat Feb 2 02:31:01 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 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
More information about the Comp.sources.unix
mailing list