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 03 of 10) Message-ID: <266@cmu-cs-cad.ARPA> Date: Fri, 1-Feb-85 11:27:20 EST Article-I.D.: cmu-cs-c.266 Posted: Fri Feb 1 11:27:20 1985 Date-Received: Sun, 3-Feb-85 09:07:51 EST Organization: Carnegie-Mellon University, CS/RI Lines: 1366 #!/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 mess.c << '/' X/* X * mess.c: Rog-O-Matic XIV (CMU) Thu Jan 31 15:33:12 1985 - mlm X * Copyright (C) 1985 by A. Appel, G. Jacobson, L. Hamey, and M. Mauldin X * X * mess.c: This file contains all of the functions which parse the X * message line. X */ X X# include X# include X# include "types.h" X# include "globals.h" X X/* Matching macros */ X# define MATCH(p) smatch(mess,p,result) X X/* Local data recording statistics */ Xstatic int monkilled[] = { X 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, X 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; Xstatic int totalkilled=0, timeshit=0, timesmissed=0, hits=0, misses=0; Xstatic int sumgold=0, sumsqgold=0, numgold=0; X Xstatic mhit=0, mmiss=0, mtarget= NONE; X X/* Other local data */ Xidentifying = 0; /* Next message is from identify scroll */ Xstatic int justreadid = 0; /* True if just read identify scroll */ Xstatic int gushed = 0; /* True ==> water on the head msg recently */ Xstatic int echoit; /* True ==> echo this message to the user */ X X/* Results from star matcher */ Xstatic char res1[NAMSIZ], res2[NAMSIZ], res3[NAMSIZ], res4[NAMSIZ]; Xstatic char *result[] = { res1, res2, res3, res4 }; X X/* X * terpmes: called when a message from Rogue is on the top line, X * this function parses the message and notes the information. X * Note that the messages are all lower cased, to help with X * compatability bewtween 3.6 and 5.2, since 5.2 capitalizes more X * messages than does 3.6. Trailing punctuation is also ignored. X * X * As of Rogue 5.3, multiple messages are broken into single X * messages before being passed to parsemsg. Periods separate X * multiple messages. X */ X Xterpmes () X{ char mess[128]; X register char *m, *mend, *s = screen[0], *t; X X /* Set 't' to the tail of the message, skip backward over blank & dot */ X for (t=s+79; *t==' ' || *t=='.'; t--) ; /* Find last non-blank */ X t++; /* t -> beyond string */ X X /* X * Loop through each message, finding the beginning and end, and X * copying it to mess, lower-casing it as we go. Then call parsemsg. X */ X X while (s 50) dwait (D_WARNING, "More loop msg '%s'", mess); X else if (unknown) dwait (D_WARNING, "Unknown message '%s'", mess); X X /* Send it to dwait; if dwait doesnt print it (and echo is on) echo it */ X if (echoit & !dwait (D_MESSAGE, mess)) X saynow (mess); X} X X/* X * smatch: Given a data string and a pattern containing one or X * more embedded stars (*) (which match any number of characters) X * return true if the match succeeds, and set res[i] to the X * characters matched by the 'i'th *. X */ X Xsmatch (dat, pat, res) Xregister char *dat, *pat, **res; X{ register char *star = 0, *starend, *resp; X int nres = 0; X X while (1) X { if (*pat == '*') X { star = ++pat; /* Pattern after * */ X starend = dat; /* Data after * match */ X resp = res[nres++]; /* Result string */ X *resp = '\0'; /* Initially null */ X } X else if (*dat == *pat) /* Characters match */ X { if (*pat == '\0') /* Pattern matches */ X return (1); X pat++; /* Try next position */ X dat++; X } X else X { if (*dat == '\0') /* Pattern fails - no more */ X return (0); /* data */ X if (star == 0) /* Pattern fails - no * to */ X return (0); /* adjust */ X pat = star; /* Restart pattern after * */ X *resp++ = *starend; /* Copy character to result */ X *resp = '\0'; /* null terminate */ X dat = ++starend; /* Rescan after copied char */ X } X } X} X X/* X * readident: read an identify scroll. X */ X Xreadident (name) Xchar *name; X{ int obj; char id = '*'; /* Default is "* for list" */ X X if (!replaying && version <= RV53A && X (nextid < LETTER (0) || nextid > LETTER (invcount))) X { dwait (D_FATAL, "Readident: nextid %d, afterid %d, invcount %d.", X nextid, afterid, invcount); } X X infer (name); /* Record what kind of scroll this is */ X X if (version < RV53A) /* Rogue 3.6, Rogue 5.2 */ X { deleteinv (OBJECT (afterid)); /* Assume object gone */ X sendnow (" %c", nextid); /* Identify it */ X send ("I%c", afterid); /* Generate a message about it */ X knowident = identifying = 1; /* Set variables */ X } X else /* Rogue 5.3 */ X { if (streq (name, "identify scroll")) X { if ((obj = unknown (scroll)) != NONE || (obj = have (scroll)) != NONE) X id = LETTER (obj); X } X else if (streq (name, "identify potion")) X { if ((obj = unknown (potion)) != NONE || (obj = have (potion)) != NONE) X id = LETTER (obj); X } X else if (streq (name, "identify armor")) X { if ((obj = unknown (armor)) != NONE || (obj = have (armor)) != NONE) X id = LETTER (obj); X } X else if (streq (name, "identify weapon")) X { if ((obj = unknown (hitter)) != NONE || X (obj = unknown (thrower)) != NONE || X (obj = unknown (missile)) != NONE || X (obj = have (hitter)) != NONE || X (obj = have (thrower)) != NONE || X (obj = have (missile)) != NONE) X id = LETTER (obj); X } X else if (streq (name, "identify ring, wand or staff")) X { if ((obj = unknown (ring)) != NONE || (obj = unknown (wand)) != NONE || X (obj = have (ring)) != NONE || (obj = have (wand)) != NONE) X id = LETTER (obj); X } X else dwait (D_FATAL, "Unknown identify scroll '%s'", name); X X waitfor ("not a valid item"); waitfor ("--More--"); X sendnow (" %c;", id); /* Pick an object to identify */ X usesynch = 0; justreadid=1; /* Must resest inventory */ X } X X newring = newweapon = 1; afterid = nextid = '\0'; X} X X/* X * rampage: read a scroll of genocide. X */ X Xrampage () X{ char monc; X X /* Check the next monster in the list, we may not fear him */ X while (monc = *genocide) X { /* Do not waste genocide on stalkers if we have the right ring */ X if ((streq (monname (monc), "invisible stalker") || X streq (monname (monc), "phantom")) && X havenamed (ring, "see invisible") != NONE) X { genocide++; } X X /* Do not waste genocide on rusties if we have the right ring */ X else if ((streq (monname (monc), "rust monster") || X streq (monname (monc), "aquator")) && X havenamed (ring, "maintain armor") != NONE) X { genocide++; } X X /* No fancy magic for this monster, use the genocide scroll */ X else break; X } X X /* If we found a monster, send his character, else send ESC */ X if (monc) X { saynow ("About to rampage against %s", monname (monc)); X sendnow (" %c;", monc); /* Send the monster */ X X /* Add to the list of 'gone' monsters */ X sprintf (genocided, "%s%c", genocided, monc); X genocide++; X } X else X { dwait (D_ERROR, "Out of monsters to genocide!"); X sendnow (" %c;", ESC); /* Cancel the command */ X } X} X X/* X * curseditem: the last object we tried to drop (unwield, etc.) was cursed. X * X * Note that cursed rings are not a problem since we only put on X * Good rings we have identified, so dont bother marking rings. X */ X Xcurseditem () X{ usesynch = 0; /* Force a reset inventory */ X X /* lastdrop is index of last item we tried to use which could be cursed */ X if (lastdrop != NONE && lastdrop < invcount) X { remember (lastdrop, CURSED); X X /* Is our armor cursed? */ X if (inven[lastdrop].type == armor) X { currentarmor = lastdrop; cursedarmor = 1; return; } X X /* Is it our weapon (may be wielding a hitter or a bogus magic arrow)? */ X else if (inven[lastdrop].type==hitter || inven[lastdrop].type==missile) X { currentweapon = lastdrop; cursedweapon = 1; return; } X } X X /* Dont know what was cursed, so assume the worst */ X cursedarmor=1; X cursedweapon=1; X} X X/* X * First copy the title of the last scroll into the appropriate slot, X * then find the real name of the object by looking through the data X * base, and then zap that name into all of the same objects X */ X Xinfer (roguename) Xchar *roguename; X{ register int i; X X if (*lastname && *roguename && !stlmatch (roguename, lastname)) X { infername (lastname, roguename); X X for (i=0; i0 && streq (monster, "it")) X { monster = monname (targetmonster); } X if ((mh = getmonhist (monster, 0)) != NONE) X { monster = monhist[mh].m_name; m = monsternum (monster); } X X /* Tell the user what we killed */ X dwait (D_BATTLE | D_MONSTER, "Killed '%s'", monster); X X /* If cheating against Rogue 3.6, check out our arrow */ X if (version < RV52A && cheat) X { if (usingarrow && hitstokill > 1 && !beingstalked && goodarrow < 20) X { saynow ("Oops, bad arrow..."); X newweapon = badarrow = 1; remember (currentweapon, WORTHLESS); } X else if (usingarrow) goodarrow++; X } X X /* Echo the number arrows we pumped into him */ X if (mh >=0 && mhit+mmiss > 0 && mtarget == mh) X dwait (D_BATTLE | D_MONSTER, "%d out of %d missiles hit the %s", X mhit, mhit+mmiss, monster); X X /* If we killed it by hacking, add the result to long term memory */ X if (hitstokill > 0 && mh != NONE) X addstat (&monhist[mh].htokill, hitstokill); X X /* If we killed it with arrows, add that fact to long term memory */ X if (mhit > 0 && mh != NONE) X addstat (&monhist[mh].atokill, mhit); X X /* Stop shooting arrows if we killed the right monster */ X if (targetmonster == (m+'A'-1)) X { darkturns = 0; darkdir = NONE; targetmonster = 0; } X X goalr = goalc = NONE; /* Clear old movement goal */ X killmonster (m+'A'-1); /* Notify lost monster functions */ X monkilled[m]++; totalkilled++; /* Bump kill count */ X hitstokill = mhit = mmiss = 0; /* Clear indiviual monster stats */ X mtarget = NONE; /* Clear target */ X beingheld = cancelled = 0; /* Clear flags */ X X /* If we killed an invisible, assume no more invisible around */ X if (!cosmic && !blinded && X (streq (monster, "invisible stalker") || streq (monster, "phantom"))) X beingstalked = 0; X} X X/* X * washit: Record being hit by a monster. X */ X Xwashit (monster) Xchar *monster; X{ register int mh = 0, m = 0; X X /* Find out what really hit us */ X if ((mh = getmonhist (monster, 1)) != NONE) X { monster = monhist[mh].m_name; m = monsternum (monster); } X X dwait (D_MONSTER, "was hit by a '%s'", monster); X X timeshit++; /* Bump global count */ X if (m>0) wakemonster(-m); /* Wake him up */ X terpbot (); /* Hit points changed, read bottom */ X X /* Add data about the event to long term memory */ X if (mh != NONE) X { addprob (&monhist[mh].theyhit, SUCCESS); X addstat (&monhist[mh].damage, lastdamage); X analyzeltm (); X } X} X X/* X * wasmissed: Record being missed by a monster. X */ X Xwasmissed (monster) Xchar *monster; X{ register int mh = 0, m = 0; X X /* Find out what really missed us */ X if ((mh = getmonhist (monster, 1)) != NONE) X { monster = monhist[mh].m_name; m = monsternum (monster); } X X dwait (D_MONSTER, "was missed by a '%s'", monster); X X timesmissed++; /* Bump global count */ X if (m>0) wakemonster(-m); /* Wake him up */ X X /* Add data to long term memory */ X if (mh != NONE) X { addprob (&monhist[mh].theyhit, FAILURE); X analyzeltm (); X } X} X X/* X * didhit: Record hitting a monster. X */ X Xdidhit () X{ register int m = 0; X X /* Record our hit */ X if (!cosmic) m = lastmonster; X X hits++; hitstokill++; X addprob (&monhist[monindex[m]].wehit, SUCCESS); X X if (wielding (wand)) X { inven[currentweapon].charges--; newweapon++; } X} X X/* X * didmiss: Record missing a monster. X */ X Xdidmiss () X{ register int m = 0; X X /* Record our miss */ X if (!cosmic) m = lastmonster; X X misses++; X addprob (&monhist[monindex[m]].wehit, FAILURE); X X if (usingarrow && goodarrow < 20) X { newweapon = badarrow = 1; remember (currentweapon, WORTHLESS); } X} X X/* X * mshit: Record hitting a monster with a missile. X */ X Xmshit (monster) Xchar *monster; X{ register int mh; X X /* Arching in a dark room? */ X if (!cosmic && !blinded && targetmonster > 0 && streq (monster, "it")) X monster = monname (targetmonster); X X /* Add data about the event to long term memory */ X if ((mh = getmonhist (monster, 0)) < 0) return; X { addprob (&monhist[monindex[mh]].arrowhit, SUCCESS); X if (mh == mtarget) { mhit++; } X else { mhit=1; mmiss = 0; mtarget=mh; } X } X} X X/* X * msmiss: Record missing a monster with a missile. X */ X Xmsmiss (monster) Xchar *monster; X{ register int mh; X X /* Arching in a dark room? */ X if (!cosmic && !blinded && targetmonster > 0 && streq (monster, "it")) X monster = monname (targetmonster); X X /* Add data about the event to long term memory */ X if ((mh = getmonhist (monster, 0)) < 0) return; X { addprob (&monhist[monindex[mh]].arrowhit, FAILURE); X if (mh == mtarget) { mmiss++; } X else { mmiss=1; mhit=0; mtarget=mh; } X } X} X X/* X * Countgold: called whenever msg contains a message about the number X * of gold pieces we just picked up. This routine keeps X * statistics about the amount of gold picked up. X */ X Xcountgold (amount) Xregister char *amount; X{ int pot; X X if ((pot = atoi (amount)) > 0) X { sumgold += pot; sumsqgold += pot*pot; numgold ++; } X} X X/* X * Summary: print a summary of the game. X */ X Xsummary (f, sep) XFILE *f; Xchar sep; X{ register int m; X char s[1024], *monname (); X X sprintf (s, "Monsters killed:%c%c", sep, sep); X X for (m=0; m<=26; m++) X if (monkilled[m] > 0) X { sprintf (s, "%s\t%d %s%s%c", s, monkilled[m], monname (m+'A'-1), X plural (monkilled[m]), sep); X } X X sprintf (s, "%s%cTotal: %d%c%c", s, sep, totalkilled, sep, sep); X X sprintf (s, "%sHit %d out of %d times, was hit %d out of %d times.%c", s, X hits, misses+hits, X timeshit, timesmissed+timeshit, sep); X X if (numgold > 0) X sprintf (s, "%sGold %d total, %d pots, %d average.%c", s, X sumgold, numgold, (sumgold*10+5) / (numgold*10), sep); X X if (f == NULL) X addstr (s); X else X fprintf (f, "%s", s); X} X X/* X * versiondep: Set version dependent variables. X */ X Xversiondep () X{ X if (version >= RV53A) genocide = "DMJGU"; X else if (version >= RV52A) genocide = "UDVPX"; X else genocide = "UXDPW"; X X analyzeltm (); X} X X/* X * getmonhist: Retrieve the index in the history array of a monster, X * taking our status into account. This code is responsible for determining X * when we are being stalked by an invisible monster. X */ X Xgetmonhist (monster, hitormiss) Xchar *monster; Xint hitormiss; X{ if (cosmic || blinded) X { return (findmonster ("it")); } X else X { if (streq (monster, "it") && hitormiss) X { if (version < RV53A) X { if (! seemonster ("invisible stalker")) beingstalked=INVHIT; X return (findmonster ("invisible stalker")); X } X else X { if (! seemonster ("phantom")) beingstalked=INVHIT; X return (findmonster ("phantom")); X } X } X else X { if (version < RV52B && streq (monster, "invisible stalker") && X ! seemonster (monster)) X beingstalked = INVHIT; X return (findmonster (monster)); X } X } X} / echo 'x - search.c' sed 's/^X//' > search.c << '/' X/* X * search.c: Rog-O-Matic XIV (CMU) Mon Jan 28 18:28:07 1985 - mlm X * Copyright (C) 1985 by A. Appel, G. Jacobson, L. Hamey, and M. Mauldin X * X * This file contains the very basic search mechanisms for exploration etc. X */ X X# include X# include X# include "types.h" X# include "globals.h" X X# define QSIZE (4000) X X# define QUEUEBREAK (111) X# define FROM (20) X# define UNREACHABLE (12) X# define NOTTRIED (11) X# define TARGET (10) X Xstatic int moveavd[24][80], moveval[24][80], movecont[24][80], X movedepth[24][80]; Xstatic char mvdir[24][80]; Xstatic int mvtype=0; Xstatic int didinit=0; X X/* X * makemove: repeat move from here towards some sort of target. X * Modified to use findmove. 5/13 MLM X */ X Xmakemove (movetype, evalinit, evaluate, reevaluate) Xint movetype, (*evalinit)(), (*evaluate)(), reevaluate; X{ X if (findmove (movetype, evalinit, evaluate, reevaluate)) X return (followmap (movetype)); X X return (0); X} X X/* X * findmove: search for a move of type movetype. The move map is left in X * the correct state for validatemap or followmap to work. MLM X */ X Xfindmove (movetype, evalinit, evaluate, reevaluate) Xint movetype, (*evalinit)(), (*evaluate)(), reevaluate; X{ int result; X X didinit = ontarget = 0; X X if (!reevaluate) /* First try to reuse the movement map */ X { result = validatemap (movetype, evalinit, evaluate); X if (result == 1) return (1); /* Success */ X if (result == 2) return (0); /* Evalinit failed, no move */ X } X X /* Must rebuild the movement map */ X mvtype = 0; /* Will become 'if (mvtype==movetype) movetype=0;' */ X X dwait (D_SEARCH, "Findmove: computing new search path."); X X /* currentrectangle(); */ /* always done after each move of the rogue */ X X searchstartr = atrow; searchstartc = atcol; X X if (!(*evalinit)()) /* Compute evalinit from current location */ X { dwait (D_SEARCH, "Findmove: evalinit failed."); return (0); } X X if (!searchfrom (atrow, atcol, evaluate, mvdir, &targetrow, &targetcol)) X { return (0); } /* move failed */ X X if (targetrow == atrow && targetcol == atcol) X { ontarget = 1; return (0); } X X /* <> */ X mvtype = movetype; /* mvtype will be the type of saved map */ X X return (1); X} X X/* X * followmap: Assuming that the mvdir map is correct, send a movement X * command following the map (possibly searching first). X * X * <> X * X * May 13, MLM X */ X Xfollowmap (movetype) Xregister int movetype; X{ register int dir, dr, dc, r, c; X int timemode, searchit, count=1; X X dir=mvdir[atrow][atcol]-FROM; dr=deltr[dir]; dc=deltc[dir]; X X if (dir > 7 || dir < 0) X { dwait (D_ERROR, "Followmap: direction invalid!"); X return (0); /* Something Broke */ X } X X r=atrow+dr; c=atcol+dc; /* Save next square in registers */ X X /* If exploring and are moving to a new hall square, use fmove */ X if (movetype == EXPLORE && X onrc (HALL|BEEN, targetrow, targetcol) != HALL|BEEN && X onrc (HALL,r,c)) X { fmove (dir); return (1); } X X /* Timemode tells why we are moving this way, T_RUNNING ==> no search */ X timemode = (movetype == GOTOMOVE) ? T_MOVING : X (movetype == EXPLORE) ? T_EXPLORING : X (movetype == EXPLOREROOM) ? T_EXPLORING : X (movetype == FINDROOM) ? T_EXPLORING : X (movetype == EXPLORERUN) ? T_RUNNING : X (movetype == RUNTODOOR) ? T_RUNNING : X (movetype == RUNAWAY) ? T_RUNNING : X (movetype == UNPIN) ? T_RUNNING : X (movetype == UNPINEXP) ? T_RUNNING : X (movetype == RUNAWAY) ? T_RUNNING : X (movetype == RUNDOWN) ? T_RUNNING : X (movetype == ATTACKSLEEP) ? T_FIGHTING : T_MOVING; X X /* How many times do we wish to search each square before moving? */ X /* Search up to k times if 2 or more foods and deeper than level 6 */ X searchit = max (0, min (k_srch/20, min (larder - 1, Level - 6))); X X /* Can we move more than one square at a time? */ X if (compression) X { while (mvdir[r][c]-FROM==dir && (onrc (SAFE, r+=dr, c+=dc) || !searchit)) X count++; X } X X /* Maybe search unsafe square before moving onto it */ X if (timemode != T_RUNNING && !onrc (SAFE, atrow+dr, atcol+dc) && X timessearched[atrow+dr][atcol+dc] < searchit) X { command (T_SEARCHING, "s"); return (1); } X X /* Maybe take armor off before stepping on rust trap */ X if (timemode != T_RUNNING && onrc (WATERAP, atrow+dr, atcol+dc) && X currentarmor != NONE && willrust () && takeoff ()) X { rmove (1, dir, timemode); return (1); } X X /* If we are about to step onto a scare monster scroll, use the 'm' cmd */ X if (version >= RV53A && onrc (SCAREM, atrow+dr, atcol+dc)) X { mmove (dir, timemode); return (1); } X X /* Send the movement command and return success */ X rmove (count, dir, timemode); return (1); X} X X/* X * validatemap: If we have a stored move, make it and return true. X * X * <> X * X * Called only by findmove. MLM X */ X Xvalidatemap (movetype, evalinit, evaluate) Xint movetype, (*evalinit)(), (*evaluate)(); X{ register int thedir, dir, r, c; X int val, avd, cont; X X dwait (D_CONTROL | D_SEARCH, "Validatemap: type %d", movetype); X X if (mvtype != movetype) X { dwait (D_SEARCH, "Validatemap: move type mismatch, map invalid."); X return (0); X } X X thedir = mvdir[atrow][atcol] - FROM; X if (thedir > 7 || thedir < 0) X { dwait (D_SEARCH, "Validatemap: direction in map invalid."); X return (0); /* Something Broke */ X } X X /* X * Check that the planned path is still valid. This is done by X * proceeding along it and checking that the value and avoidance X * returned from the evaluation function are the same as X * when the search was first performed. The initialisation function X * is re-performed and then the evaluation function done. X */ X X if (!didinit && !(*evalinit)()) X { dwait (D_SEARCH, "Validatemap: evalinit failed."); X return (2); /* evalinit failed */ X } X didinit=1; X X r=atrow; c=atcol; X while (1) X { val = avd = cont = 0; X if (!(*evaluate)(r, c, movedepth[r][c], &val, &avd, &cont)) X { dwait (D_SEARCH, "Validatemap: evaluate failed."); X return (0); X } X if (!onrc (CANGO, r, c) || X avd!=moveavd[r][c] || val!=moveval[r][c] || cont!=movecont[r][c]) X { dwait (D_SEARCH, "Validatemap: map invalidated."); X return (0); X } X if ((dir=mvdir[r][c]-FROM) == TARGET) X { dwait (D_SEARCH, "Validatemap: existing map validated."); X break; X } X if (dir < 0 || dir > 7) X { dwait (D_SEARCH, "Validatemap: direction in map invalid."); X return (0); X } X r += deltr[dir]; c += deltc[dir]; X } X return (1); X} X X/* X * cancelmove: Invalidate all stored moves of a particular type. X */ X Xcancelmove (movetype) Xint movetype; X{ if (movetype == mvtype) mvtype = 0; X} X X/* X * setnewgoal: Invalidate all stored moves. X */ X Xsetnewgoal () X{ mvtype = 0; X goalr = goalc = NONE; X} X X/* X * searchfrom: By means of breadth first search, find a path X * from the given row and column to a target. This is done by using X * searchto and then reversing the path to the row, col from the selected X * target. Note that this means that the resultant direction map can X * only be re-used if the new row, col is on the existing path. The X * reversed path consists of directions offset by FROM. X * arguments and results otherwise the same as searchto. LGCH X */ X Xsearchfrom (row, col, evaluate, dir, trow, tcol) Xint row, col, *trow, *tcol; Xint (*evaluate)(); Xchar dir[24][80]; X{ register int r, c, sdir, tempdir; X if (!searchto (row, col, evaluate, dir, trow, tcol)) X { return (0); X } X X for (r = *trow, c = *tcol, sdir = FROM+TARGET; ; ) X { tempdir = dir[r][c]; X dir[r][c] = sdir; X if (debug (D_SCREEN | D_INFORM | D_SEARCH)) X { at (r, c); printw ("%c", ">/^\\= INFINITY) X { /* Infinite avoidance */ X dir[r][c]=UNREACHABLE; /* we cant get here */ X continue; /* discard the square from consideration. */ X } X else X { saveavd[r][c]=avd; X } X } X else /* If evaluate fails, forget it for now. */ X { dwait (D_SEARCH, "Searchto: evaluate failed."); X continue; X } X } X X if (saveavd[r][c]) X { /* If to be avoided, leave in queue for a while */ X *(tail++) = r; *(tail++) = c; --(saveavd[r][c]); /* Dec avoidance */ X if (tail == end) tail = begin; X continue; X } X X if (moveval[r][c] > havetarget) X { /* It becomes the target if it has value bigger than the best found X so far, and if it has a non-zero value. X */ X X if (debug (D_SCREEN | D_SEARCH | D_INFORM)) X { mvprintw (r, c, "="); X dwait (D_SEARCH, "Searchto: target value %d.", moveval[r][c]); X } X searchcontinue = movecont[r][c]; X *trow = r; *tcol = c; havetarget = moveval[r][c]; X } X X type = SAFE; X while (1) X { for (k=0; k<8; k++) X { register int S; X X /* examine adjacent squares. */ X nr = r + sdeltr[k]; X nc = c + sdeltc[k]; X S = scrmap[nr][nc]; X X /* IF we have not considered stepping on the square yet */ X /* and if it is accessible THEN: Put it on the queue */ X if (dir[nr][nc] == NOTTRIED && (CANGO&S) && (type&S) == type && X (k<4 || onrc (CANGO,r,nc) && onrc (CANGO,nr,c))) X { moveval[nr][nc] = NONE; /* flag unevaluated */ X X *(tail++) = nr; *(tail++) = nc; if (tail == end) tail = begin; X X dir[nr][nc] = sdirect[k]; /* direction we used to get here */ X X if (debug (D_SCREEN | D_SEARCH | D_INFORM)) X { at (nr, nc); printw ("%c", ">/^\\