Relay-Version: version B 2.10 5/3/83; site utzoo.UUCP Posting-Version: version B 2.10 5/3/83; site cmu-cs-cad.ARPA Path: utzoo!watmath!clyde!burl!ulysses!allegra!mit-eddie!godot!harvard!seismo!rochester!cmu-cs-pt!cmu-cs-cad!mlm From: mlm@cmu-cs-cad.ARPA (Michael Mauldin) Newsgroups: net.sources Subject: Rog-O-Matic XIV (part 07 of 10) Message-ID: <270@cmu-cs-cad.ARPA> Date: Fri, 1-Feb-85 11:31:01 EST Article-I.D.: cmu-cs-c.270 Posted: Fri Feb 1 11:31:01 1985 Date-Received: Sun, 3-Feb-85 09:43:13 EST Organization: Carnegie-Mellon University, CS/RI Lines: 1667 #!/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 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 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; gmother) 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; idna[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; gid) 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; gid, g->creation, X g->father, g->mother); X X /* Write out dna */ X for (i=0; idna[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; idna[i] = (idna[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; idna[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; idna[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= length) X { genes[g] = (genotype *) malloc (sizeof (**genes)); X length++; X } X initgene (genes[g]); X genes[g]->id = ++lastid; X for (i=0; idna[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; gscore)); */ 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); gscore)); */ 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; gdna[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; gscore)); 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 X# include X# include 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