DataMuseum.dk

Presents historical artifacts from the history of:

DKUUG/EUUG Conference tapes

This is an automatic "excavation" of a thematic subset of
artifacts from Datamuseum.dk's BitArchive.

See our Wiki for more about DKUUG/EUUG Conference tapes

Excavated with: AutoArchaeologist - Free & Open Source Software.


top - metrics - download
Index: T t

⟦eb5b1f748⟧ TextFile

    Length: 25654 (0x6436)
    Types: TextFile
    Names: »tactics.c«

Derivation

└─⟦b20c6495f⟧ Bits:30007238 EUUGD18: Wien-båndet, efterår 1987
    └─⟦this⟧ »EUUGD18/General/Rog-O-Matic/tactics.c« 

TextFile

/*
 * tactics.c: Rog-O-Matic XIV (CMU) Thu Jan 31 20:31:22 1985 - mlm
 * Copyright (C) 1985 by A. Appel, G. Jacobson, L. Hamey, and M. Mauldin
 *
 * This file contains all of the 'medium level intelligence' of Rog-O-Matic. 
 */

# include <stdio.h>
# include <ctype.h>
# include <curses.h>
# include "types.h"
# include "globals.h"
# include "install.h"

/*
 * handlearmor: This routine is called to determine whether we should 
 * take off or put on armor.
 *
 * Current strategy:   Wear best armor on levels 1..7 or 19 on or
 *                     if protected or have maintain armor.
 *                     Wear 2nd best armor between levels 13..18.
 *                     Wear best leather armor between levels 8..12   
 *                     or 2nd best if no leather armor.   DR UTexas 12/15/83
 *
 * Note that leather armor does not rust.
 */

handlearmor ()
{ int obj;

  /* Only check when armor status is different */
  if (!newarmor || cursedarmor) return (0);

  /* 
   * Pick the armor we want to wear. If we are worried about rust monster
   * we wear the second best armor, but if we wont see any rust monsters,
   * if our armor is too good for a rust monster to hit it, or we have a
   * ring of maintain armor, then we should wear our best armor.  On
   * levels 13-18 we wear our second best no matter what.
   */
   
  obj = havearmor (1, NOPRINT, ANY);		/* Get best armor */

  if (Level > 7 && Level < 19 && 
      wearing ("maintain armor") == NONE &&
      willrust (obj) &&
      itemis (obj, KNOWN))
  { if (Level < 13)
      obj = havearmor (1, NOPRINT, RUSTPROOF);
    if (Level >= 13 || obj == NONE)
      obj = havearmor (2, NOPRINT, ANY);
  }
    
  /* If  the new armor is really bad, then don't bother wearing any */
  if (obj != NONE &&
      (armorclass (obj) > 9) ||
      (itemis (obj, CURSED) &&
       (havenamed(scroll, "remove curse") == NONE) &&
       (armorclass (obj) > 6))) 
  { obj = NONE; }

  /* If we are wearing the right armor, then dont bother */
  if (obj == currentarmor)
  { newarmor = 0; return (0); }

  /* Debugging */
  dwait (D_PACK, "handlearmor: obj %d, currentarmor %d", obj, currentarmor);

  /* Take off the wrong armor */
  if (currentarmor != NONE && takeoff ())
  { return (1); }

  /* Put on the right armor, avoid wearing cursed armor */
  if (obj != NONE)
  { return (wear (obj)); }

  /* If we have no armor, then forget it */
  newarmor = 0;
  return (0);
}

/* 
 * handleweapon: wield our best weapon. Calls haveweapon.
 *
 *  The current strategy is to wield the best weapon from haveweapon.
 */

handleweapon ()
{ int obj; 

  if ((!newweapon || cursedweapon) && !wielding (thrower)) return (0);

  /* haveweapon (1) returns the index of the best weapon in the pack */
  if ((obj = haveweapon (1, NOPRINT)) < 0) return (0);
  
  /* If we are not wielding our best weapon, do so */
  if (obj == currentweapon) { newweapon = 0; return (0); }
  else if (obj != NONE)        { return (wield (obj)); }
  else                      { newweapon = 0; return (0); }
}

/*
 * quaffpotion: check whether we should quaff a potion, and call
 * quaff if so.  We quaff add strength, restore strength, healing, 
 * extra healing, and raise level here.  Potions of seeinvisible
 * are handled in 'fightinvisible'.
 *
 * If we are at or below the exp. level, then experiment with unknown potions.
 */

# define MAXSTR (version < RV52A ? 1900 : 3100)

quaffpotion ()
{ int obj = NONE, obj2 = NONE;

  /* Take advantage of double haste bug -- assures permanent haste */
  if (!doublehasted && version < RV52A &&
      ((hasted && (obj = havenamed (potion, "haste self")) != NONE) ||
       ((obj = havemult (potion, "haste self", 2)) != NONE)) &&
      quaff (obj))
    return (1);

  /* 
   * Can we use a gain strength to our advantage? Or a restore?
   * If we have a Gain Strength, or our strength is very bad,
   * then we quaff a Regain Strength.
   */
   
  if (Str == Strmax && (obj = havenamed (potion, "gain strength")) != NONE &&
      quaff (obj))
    return (1);

  if ((Str < 700 ||
       (Str != Strmax && (havenamed (potion, "gain strength") != NONE))) &&
      (obj = havenamed (potion, "restore strength")) != NONE &&
      quaff (obj))
    return (1);

  if ((Str < 1600 || Level > 12) &&
      (obj = havemult (potion, "restore strength", 2)) != NONE &&
      quaff (obj))
    return (1);

  /* Try to get unblinded by quaffing a potion */
  if (blinded && 
      ((obj = havenamed (potion, "healing")) != NONE ||
       (obj = havenamed (potion, "extra healing")) != NONE ||
       (obj = havenamed (potion, "see invisible")) != NONE) &&
      quaff (obj))
    return (1);

  /* Try to get uncosmic by quaffing a potion */
  if (cosmic &&
      (obj = havenamed(potion, "extra healing")) != NONE &&
      quaff (obj))
    return (1);

  if (cosmic && Str != Strmax &&
      (obj = havenamed (potion, "poison")) != NONE)
  { if (wearing ("sustain strength") != NONE && quaff (obj) ||
        findring ("sustain strength"))
      return (1);
  }

  /* 
   * Quaff healing to raise our MaxHp
   * Wait for cosmic known to quaff extra healing. DR,TG  UTexas
   */

  if (Hp == Hpmax &&
      ((obj = havemult (potion, "healing", 2)) != NONE ||
       (obj = havemult (potion, "extra healing", 2)) != NONE ||
       know ("blindness") && (obj = havenamed (potion, "healing")) != NONE ||
       know ("blindness") && (know ("hallucination") || version < RV53A)  &&
        Level < 15 && (obj = havenamed (potion, "extra healing")) != NONE) &&
      quaff (obj))
    return (1);

  /*
   * Quaff a raise level potion?
   */
  
  if ((Explev > 8 || Level > 13) &&
      (obj = havenamed (potion, "raise level")) != NONE && 
      quaff (obj))
    return (1);

  /* Quaff an unknown potion? */
  if ((Level >= (k_exper/10) || objcount >= maxobj || Str<1000 || blinded) &&
      (obj = unknown (potion)) != NONE)
  { if ((obj2 = wearing ("add strength")) != NONE && removering (obj2))
      return (1);
    else if (wearing ("sustain strength") < 0 &&
             (obj2 = havenamed (ring, "sustain strength")) != NONE &&
             puton (obj2))
      return (1);
    else if (quaff (obj))
      return (1);
  }

  return (0);
}

/*
 * readscroll: check whether we should read a scroll, and call reads
 * to actually read it.
 *
 * Scrolls of identify, remove curse, genocide, enchant weapon, 
 * enchant armor, magic mapping are defined.  Scrolls of scare
 * monster and confuse monster are handled in 'battlestations'.
 * 
 * If we are at or below (k_exper/10), experiment with unknown scrolls.
 * Make certain that we are wearing our best armor when reading
 * enchant armor or an unknown scroll (which could be enchant
 * armor).
 */

readscroll ()
{ register int obj, obj2;

  /* Check the item specific identify scrolls first */
  if (((obj = havenamed (scroll, "identify armor")) != NONE &&
       (obj2 = unknown (armor)) != NONE) ||
      ((obj = havenamed (scroll, "identify weapon")) != NONE &&
       (obj2 = unknown (hitter)) != NONE) ||
      ((obj = havenamed (scroll, "identify potion")) != NONE &&
       (obj2 = unknown (potion)) != NONE) ||
      ((obj = havenamed (scroll, "identify scroll")) != NONE &&
       (obj2 = unknown (scroll)) != NONE) ||
      ((obj = havenamed (scroll, "identify ring, wand or staff")) != NONE &&
       ((obj2 = unknown (ring)) != NONE || (obj2 = unknown (wand)) != NONE)))
  { prepareident (obj2, obj);
    return (reads (obj)); }

  /* In older version, have multiple uses for generic identify scrolls */
  if ((obj = havenamed (scroll, "identify")) != NONE &&
      (currentweapon != NONE) &&
      (!itemis (currentweapon, KNOWN) && 
        (!usingarrow || goodarrow > 20)))
  { prepareident (currentweapon, obj);
    return (reads (obj)); }

  if ((obj = havenamed (scroll, "identify")) != NONE &&
      ((obj2 = unknown (ring)) != NONE ||
       (obj2 = unidentified (wand)) != NONE ||
       (obj2 = unidentified (scroll)) != NONE ||
       Level > 10 && (obj2 = unknown (wand)) != NONE ||
       ((cheat || version == RV36A) &&
        ((obj2 = unknown (potion)) != NONE ||
         (obj2 = haveother (scroll)) != NONE))))
  { prepareident (obj2, obj);
    return (reads (obj)); }

  if ((cursedarmor || cursedweapon) &&
      (obj = havenamed (scroll, "remove curse")) != NONE)
    return (reads (obj));

  if ((obj = havenamed (scroll, "genocide")) != NONE)
    return (reads (obj));

  if (currentweapon != NONE && 
      (goodweapon || usingarrow || MaxLevel > 12) &&
      (obj = havenamed (scroll, "enchant weapon")) != NONE)
    return (reads (obj));

  if (Level != didreadmap && Level > 12 &&
       (obj = havenamed (scroll, "magic mapping")) != NONE)
    return (reads (obj));

  /* About to read an unknown scroll. We will assure that we have */
  /* a weapon in hand, and put on our best armor for the occasion */
  /* We must also prepare to identify something, just in case.    */

  if ((obj = havenamed (scroll, "enchant armor")) != NONE ||
      (obj = havenamed (scroll, "protect armor")) != NONE ||
      ((currentweapon != NONE) &&
       (Level >= (k_exper/10) || objcount >= maxobj ||
        cursedarmor || cursedweapon) &&
       (exploredlevel || know ("aggravate monster")) &&
       (obj = unknown (scroll)) != NONE))
  { prepareident (pickident (), obj);

    /* Go to a corner to read the scroll */
    if (version <= RV36B && know ("create monster") == '\0' && gotocorner ())
      return (1);

    /* Must put on our good armor first */
    if (!cursedarmor && 
        (!know("enchant armor") || stlmatch(inven[obj].str, "enchant armor") ||
         !know("protect armor") || stlmatch(inven[obj].str, "protect armor")))
    { int obj2 = havearmor (1, NOPRINT, ANY); /* Pick our best armor */

      if (obj2 == currentarmor);

      /* Take off the bad stuff */
      else if (currentarmor != NONE && takeoff ()) return (1);

      /* Put on the good stuff */
      else if (obj2 != NONE && wear (obj2)) return (1);
    }

    /* No armor handling, so read the scroll */    
    return (reads (obj));
  }

  return (0);
}

/*
 * handlering: check whether we should put on a ring, and call
 * puton to wear it.  Calls 'havering' to find the two best rings
 * and wears them if their evaluations are greater than 1000.
 *
 * 'havering' understands about when different rings are good, and how
 * much food we need to use each ring.
 */

handlering ()
{ int ring1, ring2;

  if (!newring && !beingstalked) return (0);

  ring1 = havering (1, NOPRINT);
  ring2 = havering (2, NOPRINT);

  dwait (D_PACK, "Handlering: ring1 %d, ring2 %d, left %d, right %d", 
	 ring1, ring2, leftring, rightring);

  if ((leftring == ring1 && rightring == ring2) ||
      (rightring == ring1 && leftring == ring2))
  { newring = 0; return (0);
  }

  if (leftring != NONE && leftring != ring1 && leftring != ring2 &&
      removering (leftring))
  { return (1);
  }

  if (rightring != NONE && rightring != ring1 && rightring != ring2 &&
      removering (rightring))
  { return (1);
  }

  if (ring1 != leftring && ring1 != rightring && puton (ring1))
  { return (1);
  }

  if (ring2 != leftring && ring2 != rightring && puton (ring2))
  { return (1);
  }
  
  return (0);
}

/*
 * findring: called with the named of a ring, attempts to locate such
 * a ring in the pack and wear it. It will remove rings (other than
 * maintain armor) to accomplish this task if it we are wearing two
 * rings.
 *
 * Could be extended to have an ordering of rings to wear.
 */

findring (name)
char *name;
{ int obj;

  if ((obj = havenamed (ring, name)) < 0 ||
      wearing (name) != NONE)
    return (0);

  if (leftring != NONE && rightring != NONE)
  { if (stlmatch (inven[leftring].str, "maintain armor"))
      return (removering (rightring));
    else
      return (removering (leftring));
  }

  return (puton (obj));
}

/*
 * grope: get to a safe square and sit and vibrate (move back and forth)
 * and then sleep for 'turns' turns.
 *
 * Problem: We need to know which side of us the monster is on. Then
 * we could zap him with wands or staves.  This requires some kind of
 * memory and the ability to detect when the motion command (ie 'hit'
 * fails to move us).		MLM
 */

grope (turns)
register int turns;
{ register int k, moves;

  if (atrow < 2 || atcol < 1)
  { command (T_GROPING, "%ds", (turns > 0) ? turns : 1);  
    return (1);
  }

  /* Count adjacent CANGO squares */  
  for (k=0, moves=0; k<8; k++)
    if (onrc(CANGO, atdrow(k), atdcol(k))) moves++;

  if (moves > 2 && findsafe ()) /* find a spot with 2 or fewer moves */
    return (1);

  /* blindir is direction of adjacent CANGO square which is not a trap */
  for (k=0; k<4; k++, blindir = (blindir+2) % 8)
    if ((onrc(CANGO|TRAP, atdrow(blindir), atdcol(blindir)) == CANGO)) 
      break;

  if (turns) command (T_GROPING, "%c%c%ds", keydir[blindir],
                      keydir[(blindir+4)&7], turns);
  else       command (T_GROPING, "%c%c", keydir[blindir],
                      keydir[(blindir+4)&7]);

  blindir = (blindir+2) % 8;
  return (1);
}

/*
 * findarrow: This function tries to run over an arrow trap to get a 
 *            magic arrow. Make certain we have some food.
 */

findarrow ()
{
  /* If wrong version, not cheating or must go find food, then forget it */
  if (version > RV36B || !cheat || hungry())  
    return (0);

  else if (!usingarrow && foundarrowtrap && !on (ARROW) &&
           gotowards (trapr, trapc, 0))
  { display ("Trying for arrow..."); return (1); }
  
  return (0);
}

/* 
 * checkcango: verify that a missile fired in direction 'dir' will
 *             travel 'turns' turns.
 *
 * Modified by mlm, 5/31/83: Return false if a monster is in the way.
 * only return true if the missile will travel EXACTLY the distance
 * specified.  Also changed it to not check the current square (since
 * we can fire from a door, even if we cant shoot through one).
 */

checkcango (dir, turns)
register int dir, turns;
{ register int r, c, dr, dc;

  for (dr = deltr[dir], dc = deltc[dir], r=atrow+dr, c=atcol+dc;
       turns > 0 && onrc (CANGO | DOOR, r, c) == CANGO;
       r+=dr, c+=dc, turns--)
    ;

  return (turns==0);
}

/*
 * godownstairs: issues a down command and check for the halftimeshow.
 */

godownstairs (running)
register int running; /* True ==> dont do anything fancy */
{ register int p;
  int genericinit(), downvalue();

  /* We dont want to go down if we have just gotten an arrow, since */
  /* It is probably bad, and we will want to go back to the trap;   */
  /* Dont go down until we have killed five monsters in one blow.   */
  /* While waiting, run back and forth to look for monsters.        */

  if (cheat && version <= RV36B && !running &&
      foundarrowtrap && usingarrow && 
      have (food) != NONE && goodarrow < 5 && waitaround ())
  { saynow ("Checking out arrow...");
    return (1);
  }

  /* Check for applicability of this rule */
  if (! new_stairs) return (0);

  /* If we are on the stairs, perhaps we should rest up some */
  p = between ((Explev+larder)*10, 60, 100);
             
  if (atrow == stairrow && atcol == staircol && 
      !running && larder > 0 && Hp < max (10, percent (Hpmax, p)))
  { command (T_RESTING, "s");
    display ("Resting on stairs before next level");
    return (1);
  }

  /* Allow other rules a chance to notice that we are done with the level */
  if (on (STAIRS) && !exploredlevel)
  { exploredlevel = 1; return (1); }

  /* If we are floating, we cant go down, either rest or fail */
  if (floating && running)
  { saynow ("Cannot escape, floating in mid-air!"); return (0); }
  else if (floating)
  { saynow ("Floating above stairs...");
    command (T_RESTING, "s"); return (1); }

  /* If we are on the stairs, go down */
  if (on (STAIRS))
  { halftimeshow (Level);

    /* Start logging at Level GOODGAME, if we arent already */
    if (Level > (GOODGAME-2) && !replaying && !logging) toggleecho ();

    /* Send the DOWN command and return */
    command (T_MOVING, ">");
    return (1);
  }

  /* If we are running and can run to the next level, do that */
  if (running && makemove (RUNDOWN, genericinit, downvalue, REEVAL))
  { return (1);
  }

  /* If we see the stairs or a trap door, go there */
  if (!running && makemove (DOWNMOVE, genericinit, downvalue, REUSE))
  { goalr = targetrow; goalc = targetcol;   /* Set a goal (CPU time hack) */
    return (1);
  }
   
 new_stairs = 0;
 return (0);
}

/* 
 * plunge: Should we head down immediately?
 *
 * If we are being teleported too much or
 *    we are on a bad level (19 to 25) or
 *    we want to get past Rust Monsters (level 18) or
 *    we have aggravated all of the monsters then
 *
 * we head down immediately.
 */
 
plunge ()
{
  /* Check for applicability of this rule */
  if (stairrow < 0 && !foundtrapdoor) return (0);

  if (teleported > (larder+1)*5 && godownstairs (NOTRUNNING))
  { if (!on (STAIRS)) saynow ("Giving up on level, too much teleporting");
    return (1);
  }

  if (Level > 17 && Level < 26 && godownstairs (NOTRUNNING))
  { if (!on (STAIRS)) saynow ("Plunge mode!!!");
    return (1);
  }

  if (aggravated && godownstairs (NOTRUNNING))
  { if (!on (STAIRS)) saynow ("Running from aggravated monsters");
    return (1);
  }

  if (haveexplored (9) && godownstairs (NOTRUNNING))
  { if (!on (STAIRS)) saynow ("Level explored");
    return (1);
  }

  return (0);
}

/*
 * waitaround: Hang around here waiting for monsters.
 */

static struct { int vertstart, 
		    vertend, 
		    vertdelt, 
		    horstart, 
		    horend, 
		    hordelt; } cb [4] = 
	{ {  3, 21,  1,  1, 78,  1},	/* Top left corner */
	  {  3, 21,  1, 78,  1, -1},	/* Top right corner */
	  { 21,  3, -1, 78,  1, -1},	/* Bottom right corner */
	  { 21,  3, -1,  1, 78,  1} };  /* Bottom left corner */

static gc = 0; /* Goal corner from 0..3 */

/* 
 * waitaround: For some reason we want to stay on this level for a while.
 * Try running to each corner of the level.
 */

waitaround ()
{ register int i, j;

  if (gotowardsgoal ()) return (1);

  gc = ++gc % 4;

  for (i = cb[gc].vertstart; i != cb[gc].vertend; i += cb[gc].vertdelt)
    for (j = cb[gc].horstart; j != cb[gc].horend; j += cb[gc].hordelt)
      if (onrc (BEEN | CANGO | ROOM, i, j) &&
          !onrc (TRAP, i, j) && gotowards (i, j, 0))
      { goalr = i; goalc = j; return (1); }

  return (0);
}

/*
 * goupstairs:
 *
 *      If we have the amulet, and our score is good enough, then
 *      go up stairs. This function also checks for the end of the
 *      game, and issues the proper calls to get the score written.
 */

goupstairs (running)
int running;
{ int obj;

  /* Check for applicability of this rule */
  if (stairrow < 0 || have(amulet) < 0 ||
      (!running && quitat < BOGUS && Gold <= quitat))
    return (0);
      
  /* If we are on the stairs, then check for win, else go up */
  if (atrow == stairrow && atcol == staircol)
  { 
    /* If we are about to win, dump any magic arrows or minus things */
    if (Level == 1 && 
        ((obj = havearrow ()) != NONE || (obj = haveminus ()) != NONE))
    { throw (obj, 0); return (1); }

    /* No magic arrows, time to leave */
    else if (Level == 1)
    { 
      /* Send an up command and a space to clear the 'You Made It' */
      sendnow ("< ");

      /* Now read chars until we have the end of the inventory. */
      /* Note misspelling in Rogue 'Peices', so dont assume anything */
      waitfor ("Gold P");

      /* Note that quitrogue sends a '\n' to get the score */
      quitrogue ("total winner", Gold, 0);
      return (1);
    }

    /* Not at the top yet, keep on trucking */
    else
    { command (T_MOVING, "<"); return (1); }
  }

  /* If we know where the stairs are, go there */
  else if ((goalr = stairrow) > 0 && (goalc = staircol) > 0 &&
           gotowards (goalr, goalc, running)) 
    return (1);

  return (0);
}

/*
 * restup: If we are low on hit points, sit for a while. Since handlering 
 * was called first, we will be wearing a ring of regeneration if need be.
 * 
 * First we find a good place to rest (we will move into a room, but not
 * out of one).  In lit rooms, stand far from doors so we can shoot
 * arrows at things coming in.  In dark rooms, stand diagonally away
 * from doors (so we get a one turn warning of monsters coming in that
 * door).  In either case, stand on stairs or next to trap doors and
 * teleport traps).
 *  
 * Then rest by searching 's'.  If one blow would not kill us, and we
 * dont plan to shoot arrows, then rest up so as to heal one hit point.
 * If we are critically low, rest up one turn at a time.
 * 
 * Other considerations:	Dont move if confused or cosmic.
 *				Drink healing potions if really low.
 *				Dont rest when hungry (and no food)
 */

restup ()
{ register int obj, turns;

  /* If we are confused, sit still so we dont bump into anything bad */
  if (confused) { command (T_RESTING, "s"); return (1); }

  /* If cosmic and plenty of hit points and food, rest for long periods */
  if (cosmic && (Hp >= percent (Hpmax, 80)) && larder > 2)
  { display ("Oh wow man, I'm contemplating my navel!");
    command (T_RESTING, "100s"); return (1); }  

  /* If we are well, return */
  if (Hp >= max (8, percent (Hpmax, between (Explev*10+k_rest-50, 40, 80))))
  { unrest ();  return (0); }

  /*
   * If we are really ill then try a healing potion (save a healing
   * potion for blindness, extra healing for hallucination).
   */

  if (Hp < Level+10 && Hp < Hpmax/3 &&
      ((obj = havemult (potion, "extra healing", 2)) != NONE ||
       (obj = havemult (potion, "healing", 2)) != NONE ||
       (know ("hallucination") &&
        (obj = havenamed (potion, "extra healing")) != NONE) ||
       (know ("blindness") &&
        (obj = havenamed (potion, "healing")) != NONE)) &&
      quaff (obj))
  { return (1); }

  /* Dont rest when we havent enough to eat */
  if (hungry ()) return (0);

  display ("Resting up...");

  /*
   * Look for a good place to rest
   */

  if (movetorest ()) return (1);

  /* 
   * If we are very ill, or we are very deep, or we are in a lit room
   * and can shoot at things as they come ate us, rest only one turn so
   * monsters dont get the first shot. Otherwise rest enough turns 
   * to heal one step.
   */
  
  turns = (Level < 8) ? (20-Explev*2) : 3;
  if ((!darkroom () && ammo) || Hp < Level*2+8 || Level > 15) turns = 1;

  command (T_RESTING, "%ds", turns);
  return (1);
}

/*
 * If goalr and goalc are set (not -1,-1) then attempt to move towards
 * that square. Calls gotowards which calls bfsearch.
 */

gotowardsgoal ()
{ if (goalr > 0 && goalc > 0)   /* Keep on trucking */
  { if (goalr == atrow && goalc == atcol) { goalr = NONE; goalc = NONE; }
    else if (gotowards (goalr, goalc, 0)) { return (1); }
    else                                  { goalr = NONE; goalc = NONE; }
  }
  
  return (0);
}

/*
 * gotocorner:	Find a corner using downright and try to go there.
 *		This is done so we can destroy old wands by throwing
 *		them into the corner (which destroys them).
 */

gotocorner ()
{ int r, c;
  if (!downright (&r, &c)) return (0);
  if (debug (D_SCREEN))
  { saynow ("Gotocorner called:"); mvaddch (r, c, 'T'); at (row, col); }
  if (gotowards (r, c, 0)) { goalr=r; goalc=c; return (1); }
  return (0);
}

/*
 * lightroom: Try to light up the room if we are below level 17.
 */

light ()
{ if (Level < 17) return (0);
  return (lightroom ());
}

/*
 * shootindark: If we are arching at an old monster, fire another arrow.
 */

shootindark ()
{ register int obj, bow;

  /* If no longer arching in the dark, fail */
  if (darkturns < 1 || darkdir == NONE || !darkroom ()) return (0);
  
  darkturns--;			/* Count off turns till he reaches us */

  /* If he is one turn away, switch back to our sword */
  if (!cursedweapon && wielding (thrower) && darkturns==0 && handleweapon ())
  { dwait (D_BATTLE, "Switching to sword [4]"); return (1); }

  /* If we have room, switch to our bow */
  if (!cursedweapon && !wielding (thrower) && darkturns > 3 && 
      (bow = havebow (1, NOPRINT)) != NONE && wield (bow))
    return (1);

  /* Fail if we have run out of arrows */
  if ((obj = havemissile ()) < 0) return (0);

  /* Throw the arrow in the arching direction */
  return (throw (obj, darkdir));
}

/* 
 * dinnertime: Eat if we are hungry or if we have a surplus of food.
 */
 
dinnertime ()
{
  if ((havefood (5) && objcount == maxobj && ! droppedscare) ||
      (larder > 0 && hungry ()))
  { return (eat ()); }
  
  return (0);
}

/* 
 * trywand: Zap a blank wall with an unknown and unused wand in an attempt
 * to generate a message which identifies the wand.
 */

trywand ()
{ register int obj, dir, r, c, count;

  /* If we arent in a room, if there are monsters around,  */
  /* or we are in the dark, then we cant try this strategy */
  if (!on (ROOM) || mlistlen || darkroom ()) return (0);

  /* Have we a wand to identify? */
  if ((obj = unknown (wand)) < 0)
    return (0);

  /* Look for a wall either 3 or 4 away */
  for (dir = 0; dir < 8; dir += 2)
  { for (count = 0, r=atrow, c=atcol;
         onrc (CANGO | DOOR, r, c) == CANGO;
         r += deltr[dir], c += deltc[dir])
      count++;

    if (count == 4 || count == 5) break;	/* Found a likely wall */
  }

  /* If we couldnt find room, then fail */
  if (dir > 7) return (0);

  /* Set to do a reset inventory (usesynch) and point the wand */
  usesynch = 0;  
  return (point (obj, dir));
}

/*
 * eat: If we have food, eat it.
 */

eat ()
{ int obj;

  if ((obj = have (food)) != NONE)
  { command (T_HANDLING, "e%c", LETTER (obj));
    return (1);
  }

  return (0);
}