Source:NetHack 3.6.1/src/muse.c

From NetHackWiki
(Redirected from Source:Ref/find offensive)
Jump to: navigation, search

Below is the full text to muse.c from the source code of NetHack 3.6.1. To link to a particular line, write [[Source:NetHack 3.6.1/src/muse.c#line123]], for example.

Top of file

  1.  /* NetHack 3.6	muse.c	$NHDT-Date: 1505181522 2017/09/12 01:58:42 $  $NHDT-Branch: NetHack-3.6.0 $:$NHDT-Revision: 1.80 $ */
  2.  /*      Copyright (C) 1990 by Ken Arromdee                         */
  3.  /* NetHack may be freely redistributed.  See license for details.  */

The NetHack General Public License applies to screenshots, source code and other content from NetHack.

This content was modified from the original NetHack source code distribution (by splitting up NetHack content between wiki pages, and possibly further editing). See the page history for a list of who changed it, and on what dates.

  1.  
  2.  /*
  3.   * Monster item usage routines.
  4.   */
  5.  
  6.  #include "hack.h"
  7.  
  8.  extern const int monstr[];
  9.  
  10.  boolean m_using = FALSE;
  11.  
  12.  /* Let monsters use magic items.  Arbitrary assumptions: Monsters only use
  13.   * scrolls when they can see, monsters know when wands have 0 charges,
  14.   * monsters cannot recognize if items are cursed are not, monsters which
  15.   * are confused don't know not to read scrolls, etc....
  16.   */
  17.  
  18.  STATIC_DCL struct permonst *FDECL(muse_newcham_mon, (struct monst *));
  19.  STATIC_DCL int FDECL(precheck, (struct monst *, struct obj *));
  20.  STATIC_DCL void FDECL(mzapmsg, (struct monst *, struct obj *, BOOLEAN_P));
  21.  STATIC_DCL void FDECL(mreadmsg, (struct monst *, struct obj *));
  22.  STATIC_DCL void FDECL(mquaffmsg, (struct monst *, struct obj *));
  23.  STATIC_DCL boolean FDECL(m_use_healing, (struct monst *));
  24.  STATIC_PTR int FDECL(mbhitm, (struct monst *, struct obj *));
  25.  STATIC_DCL void FDECL(mbhit, (struct monst *, int,
  26.                                int FDECL((*), (MONST_P, OBJ_P)),
  27.                                int FDECL((*), (OBJ_P, OBJ_P)), struct obj *));
  28.  STATIC_DCL void FDECL(you_aggravate, (struct monst *));
  29.  STATIC_DCL void FDECL(mon_consume_unstone, (struct monst *, struct obj *,
  30.                                              BOOLEAN_P, BOOLEAN_P));
  31.  STATIC_DCL boolean FDECL(cures_stoning, (struct monst *, struct obj *,
  32.                                           BOOLEAN_P));
  33.  STATIC_DCL boolean FDECL(mcould_eat_tin, (struct monst *));
  34.  STATIC_DCL boolean FDECL(muse_unslime, (struct monst *, struct obj *,
  35.                                          struct trap *, BOOLEAN_P));
  36.  STATIC_DCL int FDECL(cures_sliming, (struct monst *, struct obj *));
  37.  STATIC_DCL boolean FDECL(green_mon, (struct monst *));
  38.  
  39.  static struct musable {
  40.      struct obj *offensive;
  41.      struct obj *defensive;
  42.      struct obj *misc;
  43.      int has_offense, has_defense, has_misc;
  44.      /* =0, no capability; otherwise, different numbers.
  45.       * If it's an object, the object is also set (it's 0 otherwise).
  46.       */
  47.  } m;
  48.  static int trapx, trapy;
  49.  static boolean zap_oseen; /* for wands which use mbhitm and are zapped at
  50.                             * players.  We usually want an oseen local to
  51.                             * the function, but this is impossible since the
  52.                             * function mbhitm has to be compatible with the
  53.                             * normal zap routines, and those routines don't
  54.                             * remember who zapped the wand. */
  55.  

precheck

  1.  /* Any preliminary checks which may result in the monster being unable to use
  2.   * the item.  Returns 0 if nothing happened, 2 if the monster can't do
  3.   * anything (i.e. it teleported) and 1 if it's dead.
  4.   */
  5.  STATIC_OVL int
  6.  precheck(mon, obj)
  7.  struct monst *mon;
  8.  struct obj *obj;
  9.  {
  10.      boolean vis;
  11.  
  12.      if (!obj)
  13.          return 0;
  14.      vis = cansee(mon->mx, mon->my);
  15.  
  16.      if (obj->oclass == POTION_CLASS) {
  17.          coord cc;
  18.          static const char *empty = "The potion turns out to be empty.";
  19.          const char *potion_descr;
  20.          struct monst *mtmp;
  21.  
  22.          potion_descr = OBJ_DESCR(objects[obj->otyp]);
  23.          if (potion_descr && !strcmp(potion_descr, "milky")) {
  24.              if (!(mvitals[PM_GHOST].mvflags & G_GONE)
  25.                  && !rn2(POTION_OCCUPANT_CHANCE(mvitals[PM_GHOST].born))) {
  26.                  if (!enexto(&cc, mon->mx, mon->my, &mons[PM_GHOST]))
  27.                      return 0;
  28.                  mquaffmsg(mon, obj);
  29.                  m_useup(mon, obj);
  30.                  mtmp = makemon(&mons[PM_GHOST], cc.x, cc.y, NO_MM_FLAGS);
  31.                  if (!mtmp) {
  32.                      if (vis)
  33.                          pline1(empty);
  34.                  } else {
  35.                      if (vis) {
  36.                          pline(
  37.                              "As %s opens the bottle, an enormous %s emerges!",
  38.                                mon_nam(mon),
  39.                                Hallucination ? rndmonnam(NULL)
  40.                                              : (const char *) "ghost");
  41.                          pline("%s is frightened to death, and unable to move.",
  42.                                Monnam(mon));
  43.                      }
  44.                      paralyze_monst(mon, 3);
  45.                  }
  46.                  return 2;
  47.              }
  48.          }
  49.          if (potion_descr && !strcmp(potion_descr, "smoky")
  50.              && !(mvitals[PM_DJINNI].mvflags & G_GONE)
  51.              && !rn2(POTION_OCCUPANT_CHANCE(mvitals[PM_DJINNI].born))) {
  52.              if (!enexto(&cc, mon->mx, mon->my, &mons[PM_DJINNI]))
  53.                  return 0;
  54.              mquaffmsg(mon, obj);
  55.              m_useup(mon, obj);
  56.              mtmp = makemon(&mons[PM_DJINNI], cc.x, cc.y, NO_MM_FLAGS);
  57.              if (!mtmp) {
  58.                  if (vis)
  59.                      pline1(empty);
  60.              } else {
  61.                  if (vis)
  62.                      pline("In a cloud of smoke, %s emerges!", a_monnam(mtmp));
  63.                  pline("%s speaks.", vis ? Monnam(mtmp) : Something);
  64.                  /* I suspect few players will be upset that monsters */
  65.                  /* can't wish for wands of death here.... */
  66.                  if (rn2(2)) {
  67.                      verbalize("You freed me!");
  68.                      mtmp->mpeaceful = 1;
  69.                      set_malign(mtmp);
  70.                  } else {
  71.                      verbalize("It is about time.");
  72.                      if (vis)
  73.                          pline("%s vanishes.", Monnam(mtmp));
  74.                      mongone(mtmp);
  75.                  }
  76.              }
  77.              return 2;
  78.          }
  79.      }
  80.      if (obj->oclass == WAND_CLASS && obj->cursed
  81.          && !rn2(WAND_BACKFIRE_CHANCE)) {
  82.          int dam = d(obj->spe + 2, 6);
  83.  
  84.          /* 3.6.1: no Deaf filter; 'if' message doesn't warrant it, 'else'
  85.             message doesn't need it since You_hear() has one of its own */
  86.          if (vis) {
  87.              pline("%s zaps %s, which suddenly explodes!", Monnam(mon),
  88.                    an(xname(obj)));
  89.          } else {
  90.              /* same near/far threshold as mzapmsg() */
  91.              int range = couldsee(mon->mx, mon->my) /* 9 or 5 */
  92.                             ? (BOLT_LIM + 1) : (BOLT_LIM - 3);
  93.  
  94.              You_hear("a zap and an explosion %s.",
  95.                       (distu(mon->mx, mon->my) <= range * range)
  96.                          ? "nearby" : "in the distance");
  97.          }
  98.          m_useup(mon, obj);
  99.          mon->mhp -= dam;
  100.          if (mon->mhp <= 0) {
  101.              monkilled(mon, "", AD_RBRE);
  102.              return 1;
  103.          }
  104.          m.has_defense = m.has_offense = m.has_misc = 0;
  105.          /* Only one needed to be set to 0 but the others are harmless */
  106.      }
  107.      return 0;
  108.  }
  109.  

mzapmsg

  1.  STATIC_OVL void
  2.  mzapmsg(mtmp, otmp, self)
  3.  struct monst *mtmp;
  4.  struct obj *otmp;
  5.  boolean self;
  6.  {
  7.      if (!canseemon(mtmp)) {
  8.          int range = couldsee(mtmp->mx, mtmp->my) /* 9 or 5 */
  9.                         ? (BOLT_LIM + 1) : (BOLT_LIM - 3);
  10.  
  11.          You_hear("a %s zap.", (distu(mtmp->mx, mtmp->my) <= range * range)
  12.                                   ? "nearby" : "distant");
  13.      } else if (self) {
  14.          pline("%s zaps %sself with %s!", Monnam(mtmp), mhim(mtmp),
  15.                doname(otmp));
  16.      } else {
  17.          pline("%s zaps %s!", Monnam(mtmp), an(xname(otmp)));
  18.          stop_occupation();
  19.      }
  20.  }
  21.  

mreadmsg

  1.  STATIC_OVL void
  2.  mreadmsg(mtmp, otmp)
  3.  struct monst *mtmp;
  4.  struct obj *otmp;
  5.  {
  6.      boolean vismon = canseemon(mtmp);
  7.      char onambuf[BUFSZ];
  8.      short saverole;
  9.      unsigned savebknown;
  10.  
  11.      if (!vismon && Deaf)
  12.          return; /* no feedback */
  13.  
  14.      otmp->dknown = 1; /* seeing or hearing it read reveals its label */
  15.      /* shouldn't be able to hear curse/bless status of unseen scrolls;
  16.         for priest characters, bknown will always be set during naming */
  17.      savebknown = otmp->bknown;
  18.      saverole = Role_switch;
  19.      if (!vismon) {
  20.          otmp->bknown = 0;
  21.          if (Role_if(PM_PRIEST))
  22.              Role_switch = 0;
  23.      }
  24.      Strcpy(onambuf, singular(otmp, doname));
  25.      Role_switch = saverole;
  26.      otmp->bknown = savebknown;
  27.  
  28.      if (vismon)
  29.          pline("%s reads %s!", Monnam(mtmp), onambuf);
  30.      else
  31.          You_hear("%s reading %s.",
  32.                   x_monnam(mtmp, ARTICLE_A, (char *) 0,
  33.                            (SUPPRESS_IT | SUPPRESS_INVISIBLE | SUPPRESS_SADDLE),
  34.                            FALSE),
  35.                   onambuf);
  36.  
  37.      if (mtmp->mconf)
  38.          pline("Being confused, %s mispronounces the magic words...",
  39.                vismon ? mon_nam(mtmp) : mhe(mtmp));
  40.  }
  41.  

mquaffmsg

  1.  STATIC_OVL void
  2.  mquaffmsg(mtmp, otmp)
  3.  struct monst *mtmp;
  4.  struct obj *otmp;
  5.  {
  6.      if (canseemon(mtmp)) {
  7.          otmp->dknown = 1;
  8.          pline("%s drinks %s!", Monnam(mtmp), singular(otmp, doname));
  9.      } else if (!Deaf)
  10.          You_hear("a chugging sound.");
  11.  }
  12.  
  13.  /* Defines for various types of stuff.  The order in which monsters prefer
  14.   * to use them is determined by the order of the code logic, not the
  15.   * numerical order in which they are defined.
  16.   */
  17.  #define MUSE_SCR_TELEPORTATION 1
  18.  #define MUSE_WAN_TELEPORTATION_SELF 2
  19.  #define MUSE_POT_HEALING 3
  20.  #define MUSE_POT_EXTRA_HEALING 4
  21.  #define MUSE_WAN_DIGGING 5
  22.  #define MUSE_TRAPDOOR 6
  23.  #define MUSE_TELEPORT_TRAP 7
  24.  #define MUSE_UPSTAIRS 8
  25.  #define MUSE_DOWNSTAIRS 9
  26.  #define MUSE_WAN_CREATE_MONSTER 10
  27.  #define MUSE_SCR_CREATE_MONSTER 11
  28.  #define MUSE_UP_LADDER 12
  29.  #define MUSE_DN_LADDER 13
  30.  #define MUSE_SSTAIRS 14
  31.  #define MUSE_WAN_TELEPORTATION 15
  32.  #define MUSE_BUGLE 16
  33.  #define MUSE_UNICORN_HORN 17
  34.  #define MUSE_POT_FULL_HEALING 18
  35.  #define MUSE_LIZARD_CORPSE 19
  36.  /*
  37.  #define MUSE_INNATE_TPT 9999
  38.   * We cannot use this.  Since monsters get unlimited teleportation, if they
  39.   * were allowed to teleport at will you could never catch them.  Instead,
  40.   * assume they only teleport at random times, despite the inconsistency
  41.   * that if you polymorph into one you teleport at will.
  42.   */
  43.  

m_use_healing

  1.  STATIC_OVL boolean
  2.  m_use_healing(mtmp)
  3.  struct monst *mtmp;
  4.  {
  5.      struct obj *obj = 0;
  6.      if ((obj = m_carrying(mtmp, POT_FULL_HEALING)) != 0) {
  7.          m.defensive = obj;
  8.          m.has_defense = MUSE_POT_FULL_HEALING;
  9.          return TRUE;
  10.      }
  11.      if ((obj = m_carrying(mtmp, POT_EXTRA_HEALING)) != 0) {
  12.          m.defensive = obj;
  13.          m.has_defense = MUSE_POT_EXTRA_HEALING;
  14.          return TRUE;
  15.      }
  16.      if ((obj = m_carrying(mtmp, POT_HEALING)) != 0) {
  17.          m.defensive = obj;
  18.          m.has_defense = MUSE_POT_HEALING;
  19.          return TRUE;
  20.      }
  21.      return FALSE;
  22.  }
  23.  

find_defensive

  1.  /* Select a defensive item/action for a monster.  Returns TRUE iff one is
  2.     found. */
  3.  boolean
  4.  find_defensive(mtmp)
  5.  struct monst *mtmp;
  6.  {
  7.      register struct obj *obj = 0;
  8.      struct trap *t;
  9.      int x = mtmp->mx, y = mtmp->my;
  10.      boolean stuck = (mtmp == u.ustuck);
  11.      boolean immobile = (mtmp->data->mmove == 0);
  12.      int fraction;
  13.  
  14.      if (is_animal(mtmp->data) || mindless(mtmp->data))
  15.          return FALSE;
  16.      if (dist2(x, y, mtmp->mux, mtmp->muy) > 25)
  17.          return FALSE;
  18.      if (u.uswallow && stuck)
  19.          return FALSE;
  20.  
  21.      m.defensive = (struct obj *) 0;
  22.      m.has_defense = 0;
  23.  
  24.      /* since unicorn horns don't get used up, the monster would look
  25.       * silly trying to use the same cursed horn round after round
  26.       */
  27.      if (mtmp->mconf || mtmp->mstun || !mtmp->mcansee) {
  28.          if (!is_unicorn(mtmp->data) && !nohands(mtmp->data)) {
  29.              for (obj = mtmp->minvent; obj; obj = obj->nobj)
  30.                  if (obj->otyp == UNICORN_HORN && !obj->cursed)
  31.                      break;
  32.          }
  33.          if (obj || is_unicorn(mtmp->data)) {
  34.              m.defensive = obj;
  35.              m.has_defense = MUSE_UNICORN_HORN;
  36.              return TRUE;
  37.          }
  38.      }
  39.  
  40.      if (mtmp->mconf || mtmp->mstun) {
  41.          struct obj *liztin = 0;
  42.  
  43.          for (obj = mtmp->minvent; obj; obj = obj->nobj) {
  44.              if (obj->otyp == CORPSE && obj->corpsenm == PM_LIZARD) {
  45.                  m.defensive = obj;
  46.                  m.has_defense = MUSE_LIZARD_CORPSE;
  47.                  return TRUE;
  48.              } else if (obj->otyp == TIN && obj->corpsenm == PM_LIZARD) {
  49.                  liztin = obj;
  50.              }
  51.          }
  52.          /* confused or stunned monster might not be able to open tin */
  53.          if (liztin && mcould_eat_tin(mtmp) && rn2(3)) {
  54.              m.defensive = liztin;
  55.              /* tin and corpse ultimately end up being handled the same */
  56.              m.has_defense = MUSE_LIZARD_CORPSE;
  57.              return TRUE;
  58.          }
  59.      }
  60.  
  61.      /* It so happens there are two unrelated cases when we might want to
  62.       * check specifically for healing alone.  The first is when the monster
  63.       * is blind (healing cures blindness).  The second is when the monster
  64.       * is peaceful; then we don't want to flee the player, and by
  65.       * coincidence healing is all there is that doesn't involve fleeing.
  66.       * These would be hard to combine because of the control flow.
  67.       * Pestilence won't use healing even when blind.
  68.       */
  69.      if (!mtmp->mcansee && !nohands(mtmp->data)
  70.          && mtmp->data != &mons[PM_PESTILENCE]) {
  71.          if (m_use_healing(mtmp))
  72.              return TRUE;
  73.      }
  74.  
  75.      fraction = u.ulevel < 10 ? 5 : u.ulevel < 14 ? 4 : 3;
  76.      if (mtmp->mhp >= mtmp->mhpmax
  77.          || (mtmp->mhp >= 10 && mtmp->mhp * fraction >= mtmp->mhpmax))
  78.          return FALSE;
  79.  
  80.      if (mtmp->mpeaceful) {
  81.          if (!nohands(mtmp->data)) {
  82.              if (m_use_healing(mtmp))
  83.                  return TRUE;
  84.          }
  85.          return FALSE;
  86.      }
  87.  
  88.      if (stuck || immobile) {
  89.          ; /* fleeing by stairs or traps is not possible */
  90.      } else if (levl[x][y].typ == STAIRS) {
  91.          if (x == xdnstair && y == ydnstair) {
  92.              if (!is_floater(mtmp->data))
  93.                  m.has_defense = MUSE_DOWNSTAIRS;
  94.          } else if (x == xupstair && y == yupstair) {
  95.              m.has_defense = MUSE_UPSTAIRS;
  96.          } else if (sstairs.sx && x == sstairs.sx && y == sstairs.sy) {
  97.              if (sstairs.up || !is_floater(mtmp->data))
  98.                  m.has_defense = MUSE_SSTAIRS;
  99.          }
  100.      } else if (levl[x][y].typ == LADDER) {
  101.          if (x == xupladder && y == yupladder) {
  102.              m.has_defense = MUSE_UP_LADDER;
  103.          } else if (x == xdnladder && y == ydnladder) {
  104.              if (!is_floater(mtmp->data))
  105.                  m.has_defense = MUSE_DN_LADDER;
  106.          } else if (sstairs.sx && x == sstairs.sx && y == sstairs.sy) {
  107.              if (sstairs.up || !is_floater(mtmp->data))
  108.                  m.has_defense = MUSE_SSTAIRS;
  109.          }
  110.      } else {
  111.          /* Note: trap doors take precedence over teleport traps. */
  112.          int xx, yy, i, locs[10][2];
  113.          boolean ignore_boulders = (verysmall(mtmp->data)
  114.                                     || throws_rocks(mtmp->data)
  115.                                     || passes_walls(mtmp->data)),
  116.              diag_ok = !NODIAG(monsndx(mtmp->data));
  117.  
  118.          for (i = 0; i < 10; ++i) /* 10: 9 spots plus sentinel */
  119.              locs[i][0] = locs[i][1] = 0;
  120.          /* collect viable spots; monster's <mx,my> comes first */
  121.          locs[0][0] = x, locs[0][1] = y;
  122.          i = 1;
  123.          for (xx = x - 1; xx <= x + 1; xx++)
  124.              for (yy = y - 1; yy <= y + 1; yy++)
  125.                  if (isok(xx, yy) && (xx != x || yy != y)) {
  126.                      locs[i][0] = xx, locs[i][1] = yy;
  127.                      ++i;
  128.                  }
  129.          /* look for a suitable trap among the viable spots */
  130.          for (i = 0; i < 10; ++i) {
  131.              xx = locs[i][0], yy = locs[i][1];
  132.              if (!xx)
  133.                  break; /* we've run out of spots */
  134.              /* skip if it's hero's location
  135.                 or a diagonal spot and monster can't move diagonally
  136.                 or some other monster is there */
  137.              if ((xx == u.ux && yy == u.uy)
  138.                  || (xx != x && yy != y && !diag_ok)
  139.                  || (level.monsters[xx][yy] && !(xx == x && yy == y)))
  140.                  continue;
  141.              /* skip if there's no trap or can't/won't move onto trap */
  142.              if ((t = t_at(xx, yy)) == 0
  143.                  || (!ignore_boulders && sobj_at(BOULDER, xx, yy))
  144.                  || onscary(xx, yy, mtmp))
  145.                  continue;
  146.              /* use trap if it's the correct type */
  147.              if ((t->ttyp == TRAPDOOR || t->ttyp == HOLE)
  148.                  && !is_floater(mtmp->data)
  149.                  && !mtmp->isshk && !mtmp->isgd && !mtmp->ispriest
  150.                  && Can_fall_thru(&u.uz)) {
  151.                  trapx = xx;
  152.                  trapy = yy;
  153.                  m.has_defense = MUSE_TRAPDOOR;
  154.                  break; /* no need to look at any other spots */
  155.              } else if (t->ttyp == TELEP_TRAP) {
  156.                  trapx = xx;
  157.                  trapy = yy;
  158.                  m.has_defense = MUSE_TELEPORT_TRAP;
  159.              }
  160.          }
  161.      }
  162.  
  163.      if (nohands(mtmp->data)) /* can't use objects */
  164.          goto botm;
  165.  
  166.      if (is_mercenary(mtmp->data) && (obj = m_carrying(mtmp, BUGLE)) != 0) {
  167.          int xx, yy;
  168.          struct monst *mon;
  169.  
  170.          /* Distance is arbitrary.  What we really want to do is
  171.           * have the soldier play the bugle when it sees or
  172.           * remembers soldiers nearby...
  173.           */
  174.          for (xx = x - 3; xx <= x + 3; xx++) {
  175.              for (yy = y - 3; yy <= y + 3; yy++) {
  176.                  if (!isok(xx, yy) || (xx == x && yy == y))
  177.                      continue;
  178.                  if ((mon = m_at(xx, yy)) != 0 && is_mercenary(mon->data)
  179.                      && mon->data != &mons[PM_GUARD]
  180.                      && (mon->msleeping || !mon->mcanmove)) {
  181.                      m.defensive = obj;
  182.                      m.has_defense = MUSE_BUGLE;
  183.                      goto toot; /* double break */
  184.                  }
  185.              }
  186.          }
  187.      toot:
  188.          ;
  189.      }
  190.  
  191.      /* use immediate physical escape prior to attempting magic */
  192.      if (m.has_defense) /* stairs, trap door or tele-trap, bugle alert */
  193.          goto botm;
  194.  
  195.      /* kludge to cut down on trap destruction (particularly portals) */
  196.      t = t_at(x, y);
  197.      if (t && (t->ttyp == PIT || t->ttyp == SPIKED_PIT || t->ttyp == WEB
  198.                || t->ttyp == BEAR_TRAP))
  199.          t = 0; /* ok for monster to dig here */
  200.  
  201.  #define nomore(x)       if (m.has_defense == x) continue;
  202.      /* selection could be improved by collecting all possibilities
  203.         into an array and then picking one at random */
  204.      for (obj = mtmp->minvent; obj; obj = obj->nobj) {
  205.          /* don't always use the same selection pattern */
  206.          if (m.has_defense && !rn2(3))
  207.              break;
  208.  
  209.          /* nomore(MUSE_WAN_DIGGING); */
  210.          if (m.has_defense == MUSE_WAN_DIGGING)
  211.              break;
  212.          if (obj->otyp == WAN_DIGGING && obj->spe > 0 && !stuck && !t
  213.              && !mtmp->isshk && !mtmp->isgd && !mtmp->ispriest
  214.              && !is_floater(mtmp->data)
  215.              /* monsters digging in Sokoban can ruin things */
  216.              && !Sokoban
  217.              /* digging wouldn't be effective; assume they know that */
  218.              && !(levl[x][y].wall_info & W_NONDIGGABLE)
  219.              && !(Is_botlevel(&u.uz) || In_endgame(&u.uz))
  220.              && !(is_ice(x, y) || is_pool(x, y) || is_lava(x, y))
  221.              && !(mtmp->data == &mons[PM_VLAD_THE_IMPALER]
  222.                   && In_V_tower(&u.uz))) {
  223.              m.defensive = obj;
  224.              m.has_defense = MUSE_WAN_DIGGING;
  225.          }
  226.          nomore(MUSE_WAN_TELEPORTATION_SELF);
  227.          nomore(MUSE_WAN_TELEPORTATION);
  228.          if (obj->otyp == WAN_TELEPORTATION && obj->spe > 0) {
  229.              /* use the TELEP_TRAP bit to determine if they know
  230.               * about noteleport on this level or not.  Avoids
  231.               * ineffective re-use of teleportation.  This does
  232.               * mean if the monster leaves the level, they'll know
  233.               * about teleport traps.
  234.               */
  235.              if (!level.flags.noteleport
  236.                  || !(mtmp->mtrapseen & (1 << (TELEP_TRAP - 1)))) {
  237.                  m.defensive = obj;
  238.                  m.has_defense = (mon_has_amulet(mtmp))
  239.                                      ? MUSE_WAN_TELEPORTATION
  240.                                      : MUSE_WAN_TELEPORTATION_SELF;
  241.              }
  242.          }
  243.          nomore(MUSE_SCR_TELEPORTATION);
  244.          if (obj->otyp == SCR_TELEPORTATION && mtmp->mcansee
  245.              && haseyes(mtmp->data)
  246.              && (!obj->cursed || (!(mtmp->isshk && inhishop(mtmp))
  247.                                   && !mtmp->isgd && !mtmp->ispriest))) {
  248.              /* see WAN_TELEPORTATION case above */
  249.              if (!level.flags.noteleport
  250.                  || !(mtmp->mtrapseen & (1 << (TELEP_TRAP - 1)))) {
  251.                  m.defensive = obj;
  252.                  m.has_defense = MUSE_SCR_TELEPORTATION;
  253.              }
  254.          }
  255.  
  256.          if (mtmp->data != &mons[PM_PESTILENCE]) {
  257.              nomore(MUSE_POT_FULL_HEALING);
  258.              if (obj->otyp == POT_FULL_HEALING) {
  259.                  m.defensive = obj;
  260.                  m.has_defense = MUSE_POT_FULL_HEALING;
  261.              }
  262.              nomore(MUSE_POT_EXTRA_HEALING);
  263.              if (obj->otyp == POT_EXTRA_HEALING) {
  264.                  m.defensive = obj;
  265.                  m.has_defense = MUSE_POT_EXTRA_HEALING;
  266.              }
  267.              nomore(MUSE_WAN_CREATE_MONSTER);
  268.              if (obj->otyp == WAN_CREATE_MONSTER && obj->spe > 0) {
  269.                  m.defensive = obj;
  270.                  m.has_defense = MUSE_WAN_CREATE_MONSTER;
  271.              }
  272.              nomore(MUSE_POT_HEALING);
  273.              if (obj->otyp == POT_HEALING) {
  274.                  m.defensive = obj;
  275.                  m.has_defense = MUSE_POT_HEALING;
  276.              }
  277.          } else { /* Pestilence */
  278.              nomore(MUSE_POT_FULL_HEALING);
  279.              if (obj->otyp == POT_SICKNESS) {
  280.                  m.defensive = obj;
  281.                  m.has_defense = MUSE_POT_FULL_HEALING;
  282.              }
  283.              nomore(MUSE_WAN_CREATE_MONSTER);
  284.              if (obj->otyp == WAN_CREATE_MONSTER && obj->spe > 0) {
  285.                  m.defensive = obj;
  286.                  m.has_defense = MUSE_WAN_CREATE_MONSTER;
  287.              }
  288.          }
  289.          nomore(MUSE_SCR_CREATE_MONSTER);
  290.          if (obj->otyp == SCR_CREATE_MONSTER) {
  291.              m.defensive = obj;
  292.              m.has_defense = MUSE_SCR_CREATE_MONSTER;
  293.          }
  294.      }
  295.  botm:
  296.      return (boolean) !!m.has_defense;
  297.  #undef nomore
  298.  }
  299.  

use_defensive

  1.  /* Perform a defensive action for a monster.  Must be called immediately
  2.   * after find_defensive().  Return values are 0: did something, 1: died,
  3.   * 2: did something and can't attack again (i.e. teleported).
  4.   */
  5.  int
  6.  use_defensive(mtmp)
  7.  struct monst *mtmp;
  8.  {
  9.      int i, fleetim, how = 0;
  10.      struct obj *otmp = m.defensive;
  11.      boolean vis, vismon, oseen;
  12.      const char *Mnam;
  13.  
  14.      if ((i = precheck(mtmp, otmp)) != 0)
  15.          return i;
  16.      vis = cansee(mtmp->mx, mtmp->my);
  17.      vismon = canseemon(mtmp);
  18.      oseen = otmp && vismon;
  19.  
  20.      /* when using defensive choice to run away, we want monster to avoid
  21.         rushing right straight back; don't override if already scared */
  22.      fleetim = !mtmp->mflee ? (33 - (30 * mtmp->mhp / mtmp->mhpmax)) : 0;
  23.  #define m_flee(m)                          \
  24.      if (fleetim && !m->iswiz) {            \
  25.          monflee(m, fleetim, FALSE, FALSE); \
  26.      }
  27.  
  28.      switch (m.has_defense) {
  29.      case MUSE_UNICORN_HORN:
  30.          if (vismon) {
  31.              if (otmp)
  32.                  pline("%s uses a unicorn horn!", Monnam(mtmp));
  33.              else
  34.                  pline_The("tip of %s's horn glows!", mon_nam(mtmp));
  35.          }
  36.          if (!mtmp->mcansee) {
  37.              mcureblindness(mtmp, vismon);
  38.          } else if (mtmp->mconf || mtmp->mstun) {
  39.              mtmp->mconf = mtmp->mstun = 0;
  40.              if (vismon)
  41.                  pline("%s seems steadier now.", Monnam(mtmp));
  42.          } else
  43.              impossible("No need for unicorn horn?");
  44.          return 2;
  45.      case MUSE_BUGLE:
  46.          if (vismon)
  47.              pline("%s plays %s!", Monnam(mtmp), doname(otmp));
  48.          else if (!Deaf)
  49.              You_hear("a bugle playing reveille!");
  50.          awaken_soldiers(mtmp);
  51.          return 2;
  52.      case MUSE_WAN_TELEPORTATION_SELF:
  53.          if ((mtmp->isshk && inhishop(mtmp)) || mtmp->isgd || mtmp->ispriest)
  54.              return 2;
  55.          m_flee(mtmp);
  56.          mzapmsg(mtmp, otmp, TRUE);
  57.          otmp->spe--;
  58.          how = WAN_TELEPORTATION;
  59.      mon_tele:
  60.          if (tele_restrict(mtmp)) { /* mysterious force... */
  61.              if (vismon && how)     /* mentions 'teleport' */
  62.                  makeknown(how);
  63.              /* monster learns that teleportation isn't useful here */
  64.              if (level.flags.noteleport)
  65.                  mtmp->mtrapseen |= (1 << (TELEP_TRAP - 1));
  66.              return 2;
  67.          }
  68.          if ((mon_has_amulet(mtmp) || On_W_tower_level(&u.uz)) && !rn2(3)) {
  69.              if (vismon)
  70.                  pline("%s seems disoriented for a moment.", Monnam(mtmp));
  71.              return 2;
  72.          }
  73.          if (oseen && how)
  74.              makeknown(how);
  75.          (void) rloc(mtmp, TRUE);
  76.          return 2;
  77.      case MUSE_WAN_TELEPORTATION:
  78.          zap_oseen = oseen;
  79.          mzapmsg(mtmp, otmp, FALSE);
  80.          otmp->spe--;
  81.          m_using = TRUE;
  82.          mbhit(mtmp, rn1(8, 6), mbhitm, bhito, otmp);
  83.          /* monster learns that teleportation isn't useful here */
  84.          if (level.flags.noteleport)
  85.              mtmp->mtrapseen |= (1 << (TELEP_TRAP - 1));
  86.          m_using = FALSE;
  87.          return 2;
  88.      case MUSE_SCR_TELEPORTATION: {
  89.          int obj_is_cursed = otmp->cursed;
  90.  
  91.          if (mtmp->isshk || mtmp->isgd || mtmp->ispriest)
  92.              return 2;
  93.          m_flee(mtmp);
  94.          mreadmsg(mtmp, otmp);
  95.          m_useup(mtmp, otmp); /* otmp might be free'ed */
  96.          how = SCR_TELEPORTATION;
  97.          if (obj_is_cursed || mtmp->mconf) {
  98.              int nlev;
  99.              d_level flev;
  100.  
  101.              if (mon_has_amulet(mtmp) || In_endgame(&u.uz)) {
  102.                  if (vismon)
  103.                      pline("%s seems very disoriented for a moment.",
  104.                            Monnam(mtmp));
  105.                  return 2;
  106.              }
  107.              nlev = random_teleport_level();
  108.              if (nlev == depth(&u.uz)) {
  109.                  if (vismon)
  110.                      pline("%s shudders for a moment.", Monnam(mtmp));
  111.                  return 2;
  112.              }
  113.              get_level(&flev, nlev);
  114.              migrate_to_level(mtmp, ledger_no(&flev), MIGR_RANDOM,
  115.                               (coord *) 0);
  116.              if (oseen)
  117.                  makeknown(SCR_TELEPORTATION);
  118.          } else
  119.              goto mon_tele;
  120.          return 2;
  121.      }
  122.      case MUSE_WAN_DIGGING: {
  123.          struct trap *ttmp;
  124.  
  125.          m_flee(mtmp);
  126.          mzapmsg(mtmp, otmp, FALSE);
  127.          otmp->spe--;
  128.          if (oseen)
  129.              makeknown(WAN_DIGGING);
  130.          if (IS_FURNITURE(levl[mtmp->mx][mtmp->my].typ)
  131.              || IS_DRAWBRIDGE(levl[mtmp->mx][mtmp->my].typ)
  132.              || (is_drawbridge_wall(mtmp->mx, mtmp->my) >= 0)
  133.              || (sstairs.sx && sstairs.sx == mtmp->mx
  134.                  && sstairs.sy == mtmp->my)) {
  135.              pline_The("digging ray is ineffective.");
  136.              return 2;
  137.          }
  138.          if (!Can_dig_down(&u.uz) && !levl[mtmp->mx][mtmp->my].candig) {
  139.              if (canseemon(mtmp))
  140.                  pline_The("%s here is too hard to dig in.",
  141.                            surface(mtmp->mx, mtmp->my));
  142.              return 2;
  143.          }
  144.          ttmp = maketrap(mtmp->mx, mtmp->my, HOLE);
  145.          if (!ttmp)
  146.              return 2;
  147.          seetrap(ttmp);
  148.          if (vis) {
  149.              pline("%s has made a hole in the %s.", Monnam(mtmp),
  150.                    surface(mtmp->mx, mtmp->my));
  151.              pline("%s %s through...", Monnam(mtmp),
  152.                    is_flyer(mtmp->data) ? "dives" : "falls");
  153.          } else if (!Deaf)
  154.              You_hear("%s crash through the %s.", something,
  155.                       surface(mtmp->mx, mtmp->my));
  156.          /* we made sure that there is a level for mtmp to go to */
  157.          migrate_to_level(mtmp, ledger_no(&u.uz) + 1, MIGR_RANDOM,
  158.                           (coord *) 0);
  159.          return 2;
  160.      }
  161.      case MUSE_WAN_CREATE_MONSTER: {
  162.          coord cc;
  163.          /* pm: 0 => random, eel => aquatic, croc => amphibious */
  164.          struct permonst *pm =
  165.              !is_pool(mtmp->mx, mtmp->my)
  166.                  ? 0
  167.                  : &mons[u.uinwater ? PM_GIANT_EEL : PM_CROCODILE];
  168.          struct monst *mon;
  169.  
  170.          if (!enexto(&cc, mtmp->mx, mtmp->my, pm))
  171.              return 0;
  172.          mzapmsg(mtmp, otmp, FALSE);
  173.          otmp->spe--;
  174.          mon = makemon((struct permonst *) 0, cc.x, cc.y, NO_MM_FLAGS);
  175.          if (mon && canspotmon(mon) && oseen)
  176.              makeknown(WAN_CREATE_MONSTER);
  177.          return 2;
  178.      }
  179.      case MUSE_SCR_CREATE_MONSTER: {
  180.          coord cc;
  181.          struct permonst *pm = 0, *fish = 0;
  182.          int cnt = 1;
  183.          struct monst *mon;
  184.          boolean known = FALSE;
  185.  
  186.          if (!rn2(73))
  187.              cnt += rnd(4);
  188.          if (mtmp->mconf || otmp->cursed)
  189.              cnt += 12;
  190.          if (mtmp->mconf)
  191.              pm = fish = &mons[PM_ACID_BLOB];
  192.          else if (is_pool(mtmp->mx, mtmp->my))
  193.              fish = &mons[u.uinwater ? PM_GIANT_EEL : PM_CROCODILE];
  194.          mreadmsg(mtmp, otmp);
  195.          while (cnt--) {
  196.              /* `fish' potentially gives bias towards water locations;
  197.                 `pm' is what to actually create (0 => random) */
  198.              if (!enexto(&cc, mtmp->mx, mtmp->my, fish))
  199.                  break;
  200.              mon = makemon(pm, cc.x, cc.y, NO_MM_FLAGS);
  201.              if (mon && canspotmon(mon))
  202.                  known = TRUE;
  203.          }
  204.          /* The only case where we don't use oseen.  For wands, you
  205.           * have to be able to see the monster zap the wand to know
  206.           * what type it is.  For teleport scrolls, you have to see
  207.           * the monster to know it teleported.
  208.           */
  209.          if (known)
  210.              makeknown(SCR_CREATE_MONSTER);
  211.          else if (!objects[SCR_CREATE_MONSTER].oc_name_known
  212.                   && !objects[SCR_CREATE_MONSTER].oc_uname)
  213.              docall(otmp);
  214.          m_useup(mtmp, otmp);
  215.          return 2;
  216.      }
  217.      case MUSE_TRAPDOOR:
  218.          /* trap doors on "bottom" levels of dungeons are rock-drop
  219.           * trap doors, not holes in the floor.  We check here for
  220.           * safety.
  221.           */
  222.          if (Is_botlevel(&u.uz))
  223.              return 0;
  224.          m_flee(mtmp);
  225.          if (vis) {
  226.              struct trap *t = t_at(trapx, trapy);
  227.  
  228.              Mnam = Monnam(mtmp);
  229.              pline("%s %s into a %s!", Mnam,
  230.                    vtense(Mnam, locomotion(mtmp->data, "jump")),
  231.                    (t->ttyp == TRAPDOOR) ? "trap door" : "hole");
  232.              if (levl[trapx][trapy].typ == SCORR) {
  233.                  levl[trapx][trapy].typ = CORR;
  234.                  unblock_point(trapx, trapy);
  235.              }
  236.              seetrap(t_at(trapx, trapy));
  237.          }
  238.  
  239.          /*  don't use rloc_to() because worm tails must "move" */
  240.          remove_monster(mtmp->mx, mtmp->my);
  241.          newsym(mtmp->mx, mtmp->my); /* update old location */
  242.          place_monster(mtmp, trapx, trapy);
  243.          if (mtmp->wormno)
  244.              worm_move(mtmp);
  245.          newsym(trapx, trapy);
  246.  
  247.          migrate_to_level(mtmp, ledger_no(&u.uz) + 1, MIGR_RANDOM,
  248.                           (coord *) 0);
  249.          return 2;
  250.      case MUSE_UPSTAIRS:
  251.          m_flee(mtmp);
  252.          if (ledger_no(&u.uz) == 1)
  253.              goto escape; /* impossible; level 1 upstairs are SSTAIRS */
  254.          if (Inhell && mon_has_amulet(mtmp) && !rn2(4)
  255.              && (dunlev(&u.uz) < dunlevs_in_dungeon(&u.uz) - 3)) {
  256.              if (vismon)
  257.                  pline(
  258.      "As %s climbs the stairs, a mysterious force momentarily surrounds %s...",
  259.                        mon_nam(mtmp), mhim(mtmp));
  260.              /* simpler than for the player; this will usually be
  261.                 the Wizard and he'll immediately go right to the
  262.                 upstairs, so there's not much point in having any
  263.                 chance for a random position on the current level */
  264.              migrate_to_level(mtmp, ledger_no(&u.uz) + 1, MIGR_RANDOM,
  265.                               (coord *) 0);
  266.          } else {
  267.              if (vismon)
  268.                  pline("%s escapes upstairs!", Monnam(mtmp));
  269.              migrate_to_level(mtmp, ledger_no(&u.uz) - 1, MIGR_STAIRS_DOWN,
  270.                               (coord *) 0);
  271.          }
  272.          return 2;
  273.      case MUSE_DOWNSTAIRS:
  274.          m_flee(mtmp);
  275.          if (vismon)
  276.              pline("%s escapes downstairs!", Monnam(mtmp));
  277.          migrate_to_level(mtmp, ledger_no(&u.uz) + 1, MIGR_STAIRS_UP,
  278.                           (coord *) 0);
  279.          return 2;
  280.      case MUSE_UP_LADDER:
  281.          m_flee(mtmp);
  282.          if (vismon)
  283.              pline("%s escapes up the ladder!", Monnam(mtmp));
  284.          migrate_to_level(mtmp, ledger_no(&u.uz) - 1, MIGR_LADDER_DOWN,
  285.                           (coord *) 0);
  286.          return 2;
  287.      case MUSE_DN_LADDER:
  288.          m_flee(mtmp);
  289.          if (vismon)
  290.              pline("%s escapes down the ladder!", Monnam(mtmp));
  291.          migrate_to_level(mtmp, ledger_no(&u.uz) + 1, MIGR_LADDER_UP,
  292.                           (coord *) 0);
  293.          return 2;
  294.      case MUSE_SSTAIRS:
  295.          m_flee(mtmp);
  296.          if (ledger_no(&u.uz) == 1) {
  297.          escape:
  298.              /* Monsters without the Amulet escape the dungeon and
  299.               * are gone for good when they leave up the up stairs.
  300.               * A monster with the Amulet would leave it behind
  301.               * (mongone -> mdrop_special_objs) but we force any
  302.               * monster who manages to acquire it or the invocation
  303.               * tools to stick around instead of letting it escape.
  304.               */
  305.              if (mon_has_special(mtmp))
  306.                  return 0;
  307.              if (vismon)
  308.                  pline("%s escapes the dungeon!", Monnam(mtmp));
  309.              mongone(mtmp);
  310.              return 2;
  311.          }
  312.          if (vismon)
  313.              pline("%s escapes %sstairs!", Monnam(mtmp),
  314.                    sstairs.up ? "up" : "down");
  315.          /* going from the Valley to Castle (Stronghold) has no sstairs
  316.             to target, but having sstairs.<sx,sy> == <0,0> will work the
  317.             same as specifying MIGR_RANDOM when mon_arrive() eventually
  318.             places the monster, so we can use MIGR_SSTAIRS unconditionally */
  319.          migrate_to_level(mtmp, ledger_no(&sstairs.tolev), MIGR_SSTAIRS,
  320.                           (coord *) 0);
  321.          return 2;
  322.      case MUSE_TELEPORT_TRAP:
  323.          m_flee(mtmp);
  324.          if (vis) {
  325.              Mnam = Monnam(mtmp);
  326.              pline("%s %s onto a teleport trap!", Mnam,
  327.                    vtense(Mnam, locomotion(mtmp->data, "jump")));
  328.              seetrap(t_at(trapx, trapy));
  329.          }
  330.          /*  don't use rloc_to() because worm tails must "move" */
  331.          remove_monster(mtmp->mx, mtmp->my);
  332.          newsym(mtmp->mx, mtmp->my); /* update old location */
  333.          place_monster(mtmp, trapx, trapy);
  334.          if (mtmp->wormno)
  335.              worm_move(mtmp);
  336.          newsym(trapx, trapy);
  337.  
  338.          goto mon_tele;
  339.      case MUSE_POT_HEALING:
  340.          mquaffmsg(mtmp, otmp);
  341.          i = d(6 + 2 * bcsign(otmp), 4);
  342.          mtmp->mhp += i;
  343.          if (mtmp->mhp > mtmp->mhpmax)
  344.              mtmp->mhp = ++mtmp->mhpmax;
  345.          if (!otmp->cursed && !mtmp->mcansee)
  346.              mcureblindness(mtmp, vismon);
  347.          if (vismon)
  348.              pline("%s looks better.", Monnam(mtmp));
  349.          if (oseen)
  350.              makeknown(POT_HEALING);
  351.          m_useup(mtmp, otmp);
  352.          return 2;
  353.      case MUSE_POT_EXTRA_HEALING:
  354.          mquaffmsg(mtmp, otmp);
  355.          i = d(6 + 2 * bcsign(otmp), 8);
  356.          mtmp->mhp += i;
  357.          if (mtmp->mhp > mtmp->mhpmax)
  358.              mtmp->mhp = (mtmp->mhpmax += (otmp->blessed ? 5 : 2));
  359.          if (!mtmp->mcansee)
  360.              mcureblindness(mtmp, vismon);
  361.          if (vismon)
  362.              pline("%s looks much better.", Monnam(mtmp));
  363.          if (oseen)
  364.              makeknown(POT_EXTRA_HEALING);
  365.          m_useup(mtmp, otmp);
  366.          return 2;
  367.      case MUSE_POT_FULL_HEALING:
  368.          mquaffmsg(mtmp, otmp);
  369.          if (otmp->otyp == POT_SICKNESS)
  370.              unbless(otmp); /* Pestilence */
  371.          mtmp->mhp = (mtmp->mhpmax += (otmp->blessed ? 8 : 4));
  372.          if (!mtmp->mcansee && otmp->otyp != POT_SICKNESS)
  373.              mcureblindness(mtmp, vismon);
  374.          if (vismon)
  375.              pline("%s looks completely healed.", Monnam(mtmp));
  376.          if (oseen)
  377.              makeknown(otmp->otyp);
  378.          m_useup(mtmp, otmp);
  379.          return 2;
  380.      case MUSE_LIZARD_CORPSE:
  381.          /* not actually called for its unstoning effect */
  382.          mon_consume_unstone(mtmp, otmp, FALSE, FALSE);
  383.          return 2;
  384.      case 0:
  385.          return 0; /* i.e. an exploded wand */
  386.      default:
  387.          impossible("%s wanted to perform action %d?", Monnam(mtmp),
  388.                     m.has_defense);
  389.          break;
  390.      }
  391.      return 0;
  392.  #undef m_flee
  393.  }
  394.  

rnd_defensive_item

  1.  int
  2.  rnd_defensive_item(mtmp)
  3.  struct monst *mtmp;
  4.  {
  5.      struct permonst *pm = mtmp->data;
  6.      int difficulty = monstr[(monsndx(pm))];
  7.      int trycnt = 0;
  8.  
  9.      if (is_animal(pm) || attacktype(pm, AT_EXPL) || mindless(mtmp->data)
  10.          || pm->mlet == S_GHOST || pm->mlet == S_KOP)
  11.          return 0;
  12.  try_again:
  13.      switch (rn2(8 + (difficulty > 3) + (difficulty > 6) + (difficulty > 8))) {
  14.      case 6:
  15.      case 9:
  16.          if (level.flags.noteleport && ++trycnt < 2)
  17.              goto try_again;
  18.          if (!rn2(3))
  19.              return WAN_TELEPORTATION;
  20.          /*FALLTHRU*/
  21.      case 0:
  22.      case 1:
  23.          return SCR_TELEPORTATION;
  24.      case 8:
  25.      case 10:
  26.          if (!rn2(3))
  27.              return WAN_CREATE_MONSTER;
  28.          /*FALLTHRU*/
  29.      case 2:
  30.          return SCR_CREATE_MONSTER;
  31.      case 3:
  32.          return POT_HEALING;
  33.      case 4:
  34.          return POT_EXTRA_HEALING;
  35.      case 5:
  36.          return (mtmp->data != &mons[PM_PESTILENCE]) ? POT_FULL_HEALING
  37.                                                      : POT_SICKNESS;
  38.      case 7:
  39.          if (is_floater(pm) || mtmp->isshk || mtmp->isgd || mtmp->ispriest)
  40.              return 0;
  41.          else
  42.              return WAN_DIGGING;
  43.      }
  44.      /*NOTREACHED*/
  45.      return 0;
  46.  }
  47.  
  48.  #define MUSE_WAN_DEATH 1
  49.  #define MUSE_WAN_SLEEP 2
  50.  #define MUSE_WAN_FIRE 3
  51.  #define MUSE_WAN_COLD 4
  52.  #define MUSE_WAN_LIGHTNING 5
  53.  #define MUSE_WAN_MAGIC_MISSILE 6
  54.  #define MUSE_WAN_STRIKING 7
  55.  #define MUSE_SCR_FIRE 8
  56.  #define MUSE_POT_PARALYSIS 9
  57.  #define MUSE_POT_BLINDNESS 10
  58.  #define MUSE_POT_CONFUSION 11
  59.  #define MUSE_FROST_HORN 12
  60.  #define MUSE_FIRE_HORN 13
  61.  #define MUSE_POT_ACID 14
  62.  /*#define MUSE_WAN_TELEPORTATION 15*/
  63.  #define MUSE_POT_SLEEPING 16
  64.  #define MUSE_SCR_EARTH 17
  65.  

find_offensive

  1.  /* Select an offensive item/action for a monster.  Returns TRUE iff one is
  2.   * found.
  3.   */
  4.  boolean
  5.  find_offensive(mtmp)
  6.  struct monst *mtmp;
  7.  {
  8.      register struct obj *obj;
  9.      boolean reflection_skip = (Reflecting && rn2(2));
  10.      struct obj *helmet = which_armor(mtmp, W_ARMH);
  11.  
  12.      m.offensive = (struct obj *) 0;
  13.      m.has_offense = 0;
  14.      if (mtmp->mpeaceful || is_animal(mtmp->data) || mindless(mtmp->data)
  15.          || nohands(mtmp->data))
  16.          return FALSE;
  17.      if (u.uswallow)
  18.          return FALSE;
  19.      if (in_your_sanctuary(mtmp, 0, 0))
  20.          return FALSE;
  21.      if (dmgtype(mtmp->data, AD_HEAL)
  22.          && !uwep && !uarmu && !uarm && !uarmh
  23.          && !uarms && !uarmg && !uarmc && !uarmf)
  24.          return FALSE;
  25.      /* all offensive items require orthogonal or diagonal targetting */
  26.      if (!lined_up(mtmp))
  27.          return FALSE;
  28.  
  29.  #define nomore(x)       if (m.has_offense == x) continue;
  30.      /* this picks the last viable item rather than prioritizing choices */
  31.      for (obj = mtmp->minvent; obj; obj = obj->nobj) {
  32.          if (!reflection_skip) {
  33.              nomore(MUSE_WAN_DEATH);
  34.              if (obj->otyp == WAN_DEATH && obj->spe > 0) {
  35.                  m.offensive = obj;
  36.                  m.has_offense = MUSE_WAN_DEATH;
  37.              }
  38.              nomore(MUSE_WAN_SLEEP);
  39.              if (obj->otyp == WAN_SLEEP && obj->spe > 0 && multi >= 0) {
  40.                  m.offensive = obj;
  41.                  m.has_offense = MUSE_WAN_SLEEP;
  42.              }
  43.              nomore(MUSE_WAN_FIRE);
  44.              if (obj->otyp == WAN_FIRE && obj->spe > 0) {
  45.                  m.offensive = obj;
  46.                  m.has_offense = MUSE_WAN_FIRE;
  47.              }
  48.              nomore(MUSE_FIRE_HORN);
  49.              if (obj->otyp == FIRE_HORN && obj->spe > 0 && can_blow(mtmp)) {
  50.                  m.offensive = obj;
  51.                  m.has_offense = MUSE_FIRE_HORN;
  52.              }
  53.              nomore(MUSE_WAN_COLD);
  54.              if (obj->otyp == WAN_COLD && obj->spe > 0) {
  55.                  m.offensive = obj;
  56.                  m.has_offense = MUSE_WAN_COLD;
  57.              }
  58.              nomore(MUSE_FROST_HORN);
  59.              if (obj->otyp == FROST_HORN && obj->spe > 0 && can_blow(mtmp)) {
  60.                  m.offensive = obj;
  61.                  m.has_offense = MUSE_FROST_HORN;
  62.              }
  63.              nomore(MUSE_WAN_LIGHTNING);
  64.              if (obj->otyp == WAN_LIGHTNING && obj->spe > 0) {
  65.                  m.offensive = obj;
  66.                  m.has_offense = MUSE_WAN_LIGHTNING;
  67.              }
  68.              nomore(MUSE_WAN_MAGIC_MISSILE);
  69.              if (obj->otyp == WAN_MAGIC_MISSILE && obj->spe > 0) {
  70.                  m.offensive = obj;
  71.                  m.has_offense = MUSE_WAN_MAGIC_MISSILE;
  72.              }
  73.          }
  74.          nomore(MUSE_WAN_STRIKING);
  75.          if (obj->otyp == WAN_STRIKING && obj->spe > 0) {
  76.              m.offensive = obj;
  77.              m.has_offense = MUSE_WAN_STRIKING;
  78.          }
  79.  #if 0   /* use_offensive() has had some code to support wand of teleportation
  80.           * for a long time, but find_offensive() never selected one;
  81.           * so for the time being, this is still disabled */
  82.          nomore(MUSE_WAN_TELEPORTATION);
  83.          if (obj->otyp == WAN_TELEPORTATION && obj->spe > 0
  84.              /* don't give controlled hero a free teleport */
  85.              && !Teleport_control
  86.              /* do try to move hero to a more vulnerable spot */
  87.              && (onscary(u.ux, u.uy, mtmp)
  88.                  || (u.ux == xupstair && u.uy == yupstair)
  89.                  || (u.ux == xdnstair && u.uy == ydnstair)
  90.                  || (u.ux == sstairs.sx && u.uy == sstairs.sy)
  91.                  || (u.ux == xupladder && u.uy == yupladder)
  92.                  || (u.ux == xdnladder && u.uy == ydnladder))) {
  93.              m.offensive = obj;
  94.              m.has_offense = MUSE_WAN_TELEPORTATION;
  95.          }
  96.  #endif
  97.          nomore(MUSE_POT_PARALYSIS);
  98.          if (obj->otyp == POT_PARALYSIS && multi >= 0) {
  99.              m.offensive = obj;
  100.              m.has_offense = MUSE_POT_PARALYSIS;
  101.          }
  102.          nomore(MUSE_POT_BLINDNESS);
  103.          if (obj->otyp == POT_BLINDNESS && !attacktype(mtmp->data, AT_GAZE)) {
  104.              m.offensive = obj;
  105.              m.has_offense = MUSE_POT_BLINDNESS;
  106.          }
  107.          nomore(MUSE_POT_CONFUSION);
  108.          if (obj->otyp == POT_CONFUSION) {
  109.              m.offensive = obj;
  110.              m.has_offense = MUSE_POT_CONFUSION;
  111.          }
  112.          nomore(MUSE_POT_SLEEPING);
  113.          if (obj->otyp == POT_SLEEPING) {
  114.              m.offensive = obj;
  115.              m.has_offense = MUSE_POT_SLEEPING;
  116.          }
  117.          nomore(MUSE_POT_ACID);
  118.          if (obj->otyp == POT_ACID) {
  119.              m.offensive = obj;
  120.              m.has_offense = MUSE_POT_ACID;
  121.          }
  122.          /* we can safely put this scroll here since the locations that
  123.           * are in a 1 square radius are a subset of the locations that
  124.           * are in wand or throwing range (in other words, always lined_up())
  125.           */
  126.          nomore(MUSE_SCR_EARTH);
  127.          if (obj->otyp == SCR_EARTH
  128.              && ((helmet && is_metallic(helmet)) || mtmp->mconf
  129.                  || amorphous(mtmp->data) || passes_walls(mtmp->data)
  130.                  || noncorporeal(mtmp->data) || unsolid(mtmp->data)
  131.                  || !rn2(10))
  132.              && dist2(mtmp->mx, mtmp->my, mtmp->mux, mtmp->muy) <= 2
  133.              && mtmp->mcansee && haseyes(mtmp->data)
  134.              && !Is_rogue_level(&u.uz)
  135.              && (!In_endgame(&u.uz) || Is_earthlevel(&u.uz))) {
  136.              m.offensive = obj;
  137.              m.has_offense = MUSE_SCR_EARTH;
  138.          }
  139.  #if 0
  140.          nomore(MUSE_SCR_FIRE);
  141.          if (obj->otyp == SCR_FIRE && resists_fire(mtmp)
  142.              && dist2(mtmp->mx, mtmp->my, mtmp->mux, mtmp->muy) <= 2
  143.              && mtmp->mcansee && haseyes(mtmp->data)) {
  144.              m.offensive = obj;
  145.              m.has_offense = MUSE_SCR_FIRE;
  146.          }
  147.  #endif /* 0 */
  148.      }
  149.      return (boolean) !!m.has_offense;
  150.  #undef nomore
  151.  }
  152.  

mbhitm

  1.  STATIC_PTR
  2.  int
  3.  mbhitm(mtmp, otmp)
  4.  register struct monst *mtmp;
  5.  register struct obj *otmp;
  6.  {
  7.      int tmp;
  8.      boolean reveal_invis = FALSE;
  9.  
  10.      if (mtmp != &youmonst) {
  11.          mtmp->msleeping = 0;
  12.          if (mtmp->m_ap_type)
  13.              seemimic(mtmp);
  14.      }
  15.      switch (otmp->otyp) {
  16.      case WAN_STRIKING:
  17.          reveal_invis = TRUE;
  18.          if (mtmp == &youmonst) {
  19.              if (zap_oseen)
  20.                  makeknown(WAN_STRIKING);
  21.              if (Antimagic) {
  22.                  shieldeff(u.ux, u.uy);
  23.                  pline("Boing!");
  24.              } else if (rnd(20) < 10 + u.uac) {
  25.                  pline_The("wand hits you!");
  26.                  tmp = d(2, 12);
  27.                  if (Half_spell_damage)
  28.                      tmp = (tmp + 1) / 2;
  29.                  losehp(tmp, "wand", KILLED_BY_AN);
  30.              } else
  31.                  pline_The("wand misses you.");
  32.              stop_occupation();
  33.              nomul(0);
  34.          } else if (resists_magm(mtmp)) {
  35.              shieldeff(mtmp->mx, mtmp->my);
  36.              pline("Boing!");
  37.          } else if (rnd(20) < 10 + find_mac(mtmp)) {
  38.              tmp = d(2, 12);
  39.              hit("wand", mtmp, exclam(tmp));
  40.              (void) resist(mtmp, otmp->oclass, tmp, TELL);
  41.              if (cansee(mtmp->mx, mtmp->my) && zap_oseen)
  42.                  makeknown(WAN_STRIKING);
  43.          } else {
  44.              miss("wand", mtmp);
  45.              if (cansee(mtmp->mx, mtmp->my) && zap_oseen)
  46.                  makeknown(WAN_STRIKING);
  47.          }
  48.          break;
  49.  #if 0   /* disabled because find_offensive() never picks WAN_TELEPORTATION */
  50.      case WAN_TELEPORTATION:
  51.          if (mtmp == &youmonst) {
  52.              if (zap_oseen)
  53.                  makeknown(WAN_TELEPORTATION);
  54.              tele();
  55.          } else {
  56.              /* for consistency with zap.c, don't identify */
  57.              if (mtmp->ispriest && *in_rooms(mtmp->mx, mtmp->my, TEMPLE)) {
  58.                  if (cansee(mtmp->mx, mtmp->my))
  59.                      pline("%s resists the magic!", Monnam(mtmp));
  60.              } else if (!tele_restrict(mtmp))
  61.                  (void) rloc(mtmp, TRUE);
  62.          }
  63.          break;
  64.  #endif
  65.      case WAN_CANCELLATION:
  66.      case SPE_CANCELLATION:
  67.          (void) cancel_monst(mtmp, otmp, FALSE, TRUE, FALSE);
  68.          break;
  69.      }
  70.      if (reveal_invis) {
  71.          if (mtmp->mhp > 0 && cansee(bhitpos.x, bhitpos.y)
  72.              && !canspotmon(mtmp))
  73.              map_invisible(bhitpos.x, bhitpos.y);
  74.      }
  75.      return 0;
  76.  }
  77.  

mbhit

  1.  /* A modified bhit() for monsters.  Based on bhit() in zap.c.  Unlike
  2.   * buzz(), bhit() doesn't take into account the possibility of a monster
  3.   * zapping you, so we need a special function for it.  (Unless someone wants
  4.   * to merge the two functions...)
  5.   */
  6.  STATIC_OVL void
  7.  mbhit(mon, range, fhitm, fhito, obj)
  8.  struct monst *mon;  /* monster shooting the wand */
  9.  register int range; /* direction and range */
  10.  int FDECL((*fhitm), (MONST_P, OBJ_P));
  11.  int FDECL((*fhito), (OBJ_P, OBJ_P)); /* fns called when mon/obj hit */
  12.  struct obj *obj;                     /* 2nd arg to fhitm/fhito */
  13.  {
  14.      register struct monst *mtmp;
  15.      register struct obj *otmp;
  16.      register uchar typ;
  17.      int ddx, ddy;
  18.  
  19.      bhitpos.x = mon->mx;
  20.      bhitpos.y = mon->my;
  21.      ddx = sgn(mon->mux - mon->mx);
  22.      ddy = sgn(mon->muy - mon->my);
  23.  
  24.      while (range-- > 0) {
  25.          int x, y;
  26.  
  27.          bhitpos.x += ddx;
  28.          bhitpos.y += ddy;
  29.          x = bhitpos.x;
  30.          y = bhitpos.y;
  31.  
  32.          if (!isok(x, y)) {
  33.              bhitpos.x -= ddx;
  34.              bhitpos.y -= ddy;
  35.              break;
  36.          }
  37.          if (find_drawbridge(&x, &y))
  38.              switch (obj->otyp) {
  39.              case WAN_STRIKING:
  40.                  destroy_drawbridge(x, y);
  41.              }
  42.          if (bhitpos.x == u.ux && bhitpos.y == u.uy) {
  43.              (*fhitm)(&youmonst, obj);
  44.              range -= 3;
  45.          } else if ((mtmp = m_at(bhitpos.x, bhitpos.y)) != 0) {
  46.              if (cansee(bhitpos.x, bhitpos.y) && !canspotmon(mtmp))
  47.                  map_invisible(bhitpos.x, bhitpos.y);
  48.              (*fhitm)(mtmp, obj);
  49.              range -= 3;
  50.          }
  51.          /* modified by GAN to hit all objects */
  52.          if (fhito) {
  53.              int hitanything = 0;
  54.              register struct obj *next_obj;
  55.  
  56.              for (otmp = level.objects[bhitpos.x][bhitpos.y]; otmp;
  57.                   otmp = next_obj) {
  58.                  /* Fix for polymorph bug, Tim Wright */
  59.                  next_obj = otmp->nexthere;
  60.                  hitanything += (*fhito)(otmp, obj);
  61.              }
  62.              if (hitanything)
  63.                  range--;
  64.          }
  65.          typ = levl[bhitpos.x][bhitpos.y].typ;
  66.          if (IS_DOOR(typ) || typ == SDOOR) {
  67.              switch (obj->otyp) {
  68.              /* note: monsters don't use opening or locking magic
  69.                 at present, but keep these as placeholders */
  70.              case WAN_OPENING:
  71.              case WAN_LOCKING:
  72.              case WAN_STRIKING:
  73.                  if (doorlock(obj, bhitpos.x, bhitpos.y)) {
  74.                      if (zap_oseen)
  75.                          makeknown(obj->otyp);
  76.                      /* if a shop door gets broken, add it to
  77.                         the shk's fix list (no cost to player) */
  78.                      if (levl[bhitpos.x][bhitpos.y].doormask == D_BROKEN
  79.                          && *in_rooms(bhitpos.x, bhitpos.y, SHOPBASE))
  80.                          add_damage(bhitpos.x, bhitpos.y, 0L);
  81.                  }
  82.                  break;
  83.              }
  84.          }
  85.          if (!ZAP_POS(typ)
  86.              || (IS_DOOR(typ) && (levl[bhitpos.x][bhitpos.y].doormask
  87.                                   & (D_LOCKED | D_CLOSED)))) {
  88.              bhitpos.x -= ddx;
  89.              bhitpos.y -= ddy;
  90.              break;
  91.          }
  92.      }
  93.  }
  94.  

use_offensive

  1.  /* Perform an offensive action for a monster.  Must be called immediately
  2.   * after find_offensive().  Return values are same as use_defensive().
  3.   */
  4.  int
  5.  use_offensive(mtmp)
  6.  struct monst *mtmp;
  7.  {
  8.      int i;
  9.      struct obj *otmp = m.offensive;
  10.      boolean oseen;
  11.  
  12.      /* offensive potions are not drunk, they're thrown */
  13.      if (otmp->oclass != POTION_CLASS && (i = precheck(mtmp, otmp)) != 0)
  14.          return i;
  15.      oseen = otmp && canseemon(mtmp);
  16.  
  17.      switch (m.has_offense) {
  18.      case MUSE_WAN_DEATH:
  19.      case MUSE_WAN_SLEEP:
  20.      case MUSE_WAN_FIRE:
  21.      case MUSE_WAN_COLD:
  22.      case MUSE_WAN_LIGHTNING:
  23.      case MUSE_WAN_MAGIC_MISSILE:
  24.          mzapmsg(mtmp, otmp, FALSE);
  25.          otmp->spe--;
  26.          if (oseen)
  27.              makeknown(otmp->otyp);
  28.          m_using = TRUE;
  29.          buzz((int) (-30 - (otmp->otyp - WAN_MAGIC_MISSILE)),
  30.               (otmp->otyp == WAN_MAGIC_MISSILE) ? 2 : 6, mtmp->mx, mtmp->my,
  31.               sgn(mtmp->mux - mtmp->mx), sgn(mtmp->muy - mtmp->my));
  32.          m_using = FALSE;
  33.          return (mtmp->mhp <= 0) ? 1 : 2;
  34.      case MUSE_FIRE_HORN:
  35.      case MUSE_FROST_HORN:
  36.          if (oseen) {
  37.              makeknown(otmp->otyp);
  38.              pline("%s plays a %s!", Monnam(mtmp), xname(otmp));
  39.          } else
  40.              You_hear("a horn being played.");
  41.          otmp->spe--;
  42.          m_using = TRUE;
  43.          buzz(-30 - ((otmp->otyp == FROST_HORN) ? AD_COLD - 1 : AD_FIRE - 1),
  44.               rn1(6, 6), mtmp->mx, mtmp->my, sgn(mtmp->mux - mtmp->mx),
  45.               sgn(mtmp->muy - mtmp->my));
  46.          m_using = FALSE;
  47.          return (mtmp->mhp <= 0) ? 1 : 2;
  48.      case MUSE_WAN_TELEPORTATION:
  49.      case MUSE_WAN_STRIKING:
  50.          zap_oseen = oseen;
  51.          mzapmsg(mtmp, otmp, FALSE);
  52.          otmp->spe--;
  53.          m_using = TRUE;
  54.          mbhit(mtmp, rn1(8, 6), mbhitm, bhito, otmp);
  55.          m_using = FALSE;
  56.          return 2;
  57.      case MUSE_SCR_EARTH: {
  58.          /* TODO: handle steeds */
  59.          register int x, y;
  60.          /* don't use monster fields after killing it */
  61.          boolean confused = (mtmp->mconf ? TRUE : FALSE);
  62.          int mmx = mtmp->mx, mmy = mtmp->my;
  63.          boolean is_cursed = otmp->cursed;
  64.  
  65.          mreadmsg(mtmp, otmp);
  66.          /* Identify the scroll */
  67.          if (canspotmon(mtmp)) {
  68.              pline_The("%s rumbles %s %s!", ceiling(mtmp->mx, mtmp->my),
  69.                        otmp->blessed ? "around" : "above", mon_nam(mtmp));
  70.              if (oseen)
  71.                  makeknown(otmp->otyp);
  72.          } else if (cansee(mtmp->mx, mtmp->my)) {
  73.              pline_The("%s rumbles in the middle of nowhere!",
  74.                        ceiling(mtmp->mx, mtmp->my));
  75.              if (mtmp->minvis)
  76.                  map_invisible(mtmp->mx, mtmp->my);
  77.              if (oseen)
  78.                  makeknown(otmp->otyp);
  79.          }
  80.  
  81.          /* Loop through the surrounding squares */
  82.          for (x = mmx - 1; x <= mmx + 1; x++) {
  83.              for (y = mmy - 1; y <= mmy + 1; y++) {
  84.                  /* Is this a suitable spot? */
  85.                  if (isok(x, y) && !closed_door(x, y)
  86.                      && !IS_ROCK(levl[x][y].typ) && !IS_AIR(levl[x][y].typ)
  87.                      && (((x == mmx) && (y == mmy)) ? !otmp->blessed
  88.                                                     : !otmp->cursed)
  89.                      && (x != u.ux || y != u.uy)) {
  90.                      (void) drop_boulder_on_monster(x, y, confused, FALSE);
  91.                  }
  92.              }
  93.          }
  94.          m_useup(mtmp, otmp);
  95.          /* Attack the player */
  96.          if (distmin(mmx, mmy, u.ux, u.uy) == 1 && !is_cursed) {
  97.              drop_boulder_on_player(confused, !is_cursed, FALSE, TRUE);
  98.          }
  99.  
  100.          return (mtmp->mhp <= 0) ? 1 : 2;
  101.      }
  102.  #if 0
  103.      case MUSE_SCR_FIRE: {
  104.          boolean vis = cansee(mtmp->mx, mtmp->my);
  105.  
  106.          mreadmsg(mtmp, otmp);
  107.          if (mtmp->mconf) {
  108.              if (vis)
  109.                  pline("Oh, what a pretty fire!");
  110.          } else {
  111.              struct monst *mtmp2;
  112.              int num;
  113.  
  114.              if (vis)
  115.                  pline_The("scroll erupts in a tower of flame!");
  116.              shieldeff(mtmp->mx, mtmp->my);
  117.              pline("%s is uninjured.", Monnam(mtmp));
  118.              (void) destroy_mitem(mtmp, SCROLL_CLASS, AD_FIRE);
  119.              (void) destroy_mitem(mtmp, SPBOOK_CLASS, AD_FIRE);
  120.              (void) destroy_mitem(mtmp, POTION_CLASS, AD_FIRE);
  121.              num = (2 * (rn1(3, 3) + 2 * bcsign(otmp)) + 1) / 3;
  122.              if (Fire_resistance)
  123.                  You("are not harmed.");
  124.              burn_away_slime();
  125.              if (Half_spell_damage)
  126.                  num = (num + 1) / 2;
  127.              else
  128.                  losehp(num, "scroll of fire", KILLED_BY_AN);
  129.              for (mtmp2 = fmon; mtmp2; mtmp2 = mtmp2->nmon) {
  130.                  if (DEADMONSTER(mtmp2))
  131.                      continue;
  132.                  if (mtmp == mtmp2)
  133.                      continue;
  134.                  if (dist2(mtmp2->mx, mtmp2->my, mtmp->mx, mtmp->my) < 3) {
  135.                      if (resists_fire(mtmp2))
  136.                          continue;
  137.                      mtmp2->mhp -= num;
  138.                      if (resists_cold(mtmp2))
  139.                          mtmp2->mhp -= 3 * num;
  140.                      if (mtmp2->mhp < 1) {
  141.                          mondied(mtmp2);
  142.                          break;
  143.                      }
  144.                  }
  145.              }
  146.          }
  147.          return 2;
  148.      }
  149.  #endif /* 0 */
  150.      case MUSE_POT_PARALYSIS:
  151.      case MUSE_POT_BLINDNESS:
  152.      case MUSE_POT_CONFUSION:
  153.      case MUSE_POT_SLEEPING:
  154.      case MUSE_POT_ACID:
  155.          /* Note: this setting of dknown doesn't suffice.  A monster
  156.           * which is out of sight might throw and it hits something _in_
  157.           * sight, a problem not existing with wands because wand rays
  158.           * are not objects.  Also set dknown in mthrowu.c.
  159.           */
  160.          if (cansee(mtmp->mx, mtmp->my)) {
  161.              otmp->dknown = 1;
  162.              pline("%s hurls %s!", Monnam(mtmp), singular(otmp, doname));
  163.          }
  164.          m_throw(mtmp, mtmp->mx, mtmp->my, sgn(mtmp->mux - mtmp->mx),
  165.                  sgn(mtmp->muy - mtmp->my),
  166.                  distmin(mtmp->mx, mtmp->my, mtmp->mux, mtmp->muy), otmp);
  167.          return 2;
  168.      case 0:
  169.          return 0; /* i.e. an exploded wand */
  170.      default:
  171.          impossible("%s wanted to perform action %d?", Monnam(mtmp),
  172.                     m.has_offense);
  173.          break;
  174.      }
  175.      return 0;
  176.  }
  177.  

rnd_offensive_item

  1.  int
  2.  rnd_offensive_item(mtmp)
  3.  struct monst *mtmp;
  4.  {
  5.      struct permonst *pm = mtmp->data;
  6.      int difficulty = monstr[(monsndx(pm))];
  7.  
  8.      if (is_animal(pm) || attacktype(pm, AT_EXPL) || mindless(mtmp->data)
  9.          || pm->mlet == S_GHOST || pm->mlet == S_KOP)
  10.          return 0;
  11.      if (difficulty > 7 && !rn2(35))
  12.          return WAN_DEATH;
  13.      switch (rn2(9 - (difficulty < 4) + 4 * (difficulty > 6))) {
  14.      case 0: {
  15.          struct obj *helmet = which_armor(mtmp, W_ARMH);
  16.  
  17.          if ((helmet && is_metallic(helmet)) || amorphous(pm)
  18.              || passes_walls(pm) || noncorporeal(pm) || unsolid(pm))
  19.              return SCR_EARTH;
  20.      } /* fall through */
  21.      case 1:
  22.          return WAN_STRIKING;
  23.      case 2:
  24.          return POT_ACID;
  25.      case 3:
  26.          return POT_CONFUSION;
  27.      case 4:
  28.          return POT_BLINDNESS;
  29.      case 5:
  30.          return POT_SLEEPING;
  31.      case 6:
  32.          return POT_PARALYSIS;
  33.      case 7:
  34.      case 8:
  35.          return WAN_MAGIC_MISSILE;
  36.      case 9:
  37.          return WAN_SLEEP;
  38.      case 10:
  39.          return WAN_FIRE;
  40.      case 11:
  41.          return WAN_COLD;
  42.      case 12:
  43.          return WAN_LIGHTNING;
  44.      }
  45.      /*NOTREACHED*/
  46.      return 0;
  47.  }
  48.  
  49.  #define MUSE_POT_GAIN_LEVEL 1
  50.  #define MUSE_WAN_MAKE_INVISIBLE 2
  51.  #define MUSE_POT_INVISIBILITY 3
  52.  #define MUSE_POLY_TRAP 4
  53.  #define MUSE_WAN_POLYMORPH 5
  54.  #define MUSE_POT_SPEED 6
  55.  #define MUSE_WAN_SPEED_MONSTER 7
  56.  #define MUSE_BULLWHIP 8
  57.  #define MUSE_POT_POLYMORPH 9
  58.  

find_misc

  1.  boolean
  2.  find_misc(mtmp)
  3.  struct monst *mtmp;
  4.  {
  5.      register struct obj *obj;
  6.      struct permonst *mdat = mtmp->data;
  7.      int x = mtmp->mx, y = mtmp->my;
  8.      struct trap *t;
  9.      int xx, yy, pmidx = NON_PM;
  10.      boolean immobile = (mdat->mmove == 0);
  11.      boolean stuck = (mtmp == u.ustuck);
  12.  
  13.      m.misc = (struct obj *) 0;
  14.      m.has_misc = 0;
  15.      if (is_animal(mdat) || mindless(mdat))
  16.          return 0;
  17.      if (u.uswallow && stuck)
  18.          return FALSE;
  19.  
  20.      /* We arbitrarily limit to times when a player is nearby for the
  21.       * same reason as Junior Pac-Man doesn't have energizers eaten until
  22.       * you can see them...
  23.       */
  24.      if (dist2(x, y, mtmp->mux, mtmp->muy) > 36)
  25.          return FALSE;
  26.  
  27.      if (!stuck && !immobile && (mtmp->cham == NON_PM)
  28.          && monstr[(pmidx = monsndx(mdat))] < 6) {
  29.          boolean ignore_boulders = (verysmall(mdat) || throws_rocks(mdat)
  30.                                     || passes_walls(mdat)),
  31.              diag_ok = !NODIAG(pmidx);
  32.  
  33.          for (xx = x - 1; xx <= x + 1; xx++)
  34.              for (yy = y - 1; yy <= y + 1; yy++)
  35.                  if (isok(xx, yy) && (xx != u.ux || yy != u.uy)
  36.                      && (diag_ok || xx == x || yy == y)
  37.                      && ((xx == x && yy == y) || !level.monsters[xx][yy]))
  38.                      if ((t = t_at(xx, yy)) != 0
  39.                          && (ignore_boulders || !sobj_at(BOULDER, xx, yy))
  40.                          && !onscary(xx, yy, mtmp)) {
  41.                          /* use trap if it's the correct type */
  42.                          if (t->ttyp == POLY_TRAP) {
  43.                              trapx = xx;
  44.                              trapy = yy;
  45.                              m.has_misc = MUSE_POLY_TRAP;
  46.                              return TRUE;
  47.                          }
  48.                      }
  49.      }
  50.      if (nohands(mdat))
  51.          return 0;
  52.  
  53.  #define nomore(x)       if (m.has_misc == x) continue
  54.      /*
  55.       * [bug?]  Choice of item is not prioritized; the last viable one
  56.       * in the monster's inventory will be chosen.
  57.       * 'nomore()' is nearly worthless because it only screens checking
  58.       * of duplicates when there is no alternate type in between them.
  59.       */
  60.      for (obj = mtmp->minvent; obj; obj = obj->nobj) {
  61.          /* Monsters shouldn't recognize cursed items; this kludge is
  62.             necessary to prevent serious problems though... */
  63.          if (obj->otyp == POT_GAIN_LEVEL
  64.              && (!obj->cursed
  65.                  || (!mtmp->isgd && !mtmp->isshk && !mtmp->ispriest))) {
  66.              m.misc = obj;
  67.              m.has_misc = MUSE_POT_GAIN_LEVEL;
  68.          }
  69.          nomore(MUSE_BULLWHIP);
  70.          if (obj->otyp == BULLWHIP && !mtmp->mpeaceful
  71.              /* the random test prevents whip-wielding
  72.                 monster from attempting disarm every turn */
  73.              && uwep && !rn2(5) && obj == MON_WEP(mtmp)
  74.              /* hero's location must be known and adjacent */
  75.              && mtmp->mux == u.ux && mtmp->muy == u.uy
  76.              && distu(mtmp->mx, mtmp->my) <= 2
  77.              /* don't bother if it can't work (this doesn't
  78.                 prevent cursed weapons from being targetted) */
  79.              && (canletgo(uwep, "")
  80.                  || (u.twoweap && canletgo(uswapwep, "")))) {
  81.              m.misc = obj;
  82.              m.has_misc = MUSE_BULLWHIP;
  83.          }
  84.          /* Note: peaceful/tame monsters won't make themselves
  85.           * invisible unless you can see them.  Not really right, but...
  86.           */
  87.          nomore(MUSE_WAN_MAKE_INVISIBLE);
  88.          if (obj->otyp == WAN_MAKE_INVISIBLE && obj->spe > 0 && !mtmp->minvis
  89.              && !mtmp->invis_blkd && (!mtmp->mpeaceful || See_invisible)
  90.              && (!attacktype(mtmp->data, AT_GAZE) || mtmp->mcan)) {
  91.              m.misc = obj;
  92.              m.has_misc = MUSE_WAN_MAKE_INVISIBLE;
  93.          }
  94.          nomore(MUSE_POT_INVISIBILITY);
  95.          if (obj->otyp == POT_INVISIBILITY && !mtmp->minvis
  96.              && !mtmp->invis_blkd && (!mtmp->mpeaceful || See_invisible)
  97.              && (!attacktype(mtmp->data, AT_GAZE) || mtmp->mcan)) {
  98.              m.misc = obj;
  99.              m.has_misc = MUSE_POT_INVISIBILITY;
  100.          }
  101.          nomore(MUSE_WAN_SPEED_MONSTER);
  102.          if (obj->otyp == WAN_SPEED_MONSTER && obj->spe > 0
  103.              && mtmp->mspeed != MFAST && !mtmp->isgd) {
  104.              m.misc = obj;
  105.              m.has_misc = MUSE_WAN_SPEED_MONSTER;
  106.          }
  107.          nomore(MUSE_POT_SPEED);
  108.          if (obj->otyp == POT_SPEED && mtmp->mspeed != MFAST && !mtmp->isgd) {
  109.              m.misc = obj;
  110.              m.has_misc = MUSE_POT_SPEED;
  111.          }
  112.          nomore(MUSE_WAN_POLYMORPH);
  113.          if (obj->otyp == WAN_POLYMORPH && obj->spe > 0
  114.              && (mtmp->cham == NON_PM) && monstr[monsndx(mdat)] < 6) {
  115.              m.misc = obj;
  116.              m.has_misc = MUSE_WAN_POLYMORPH;
  117.          }
  118.          nomore(MUSE_POT_POLYMORPH);
  119.          if (obj->otyp == POT_POLYMORPH && (mtmp->cham == NON_PM)
  120.              && monstr[monsndx(mdat)] < 6) {
  121.              m.misc = obj;
  122.              m.has_misc = MUSE_POT_POLYMORPH;
  123.          }
  124.      }
  125.      return (boolean) !!m.has_misc;
  126.  #undef nomore
  127.  }
  128.  

muse_newcham_mon

  1.  /* type of monster to polymorph into; defaults to one suitable for the
  2.     current level rather than the totally arbitrary choice of newcham() */
  3.  static struct permonst *
  4.  muse_newcham_mon(mon)
  5.  struct monst *mon;
  6.  {
  7.      struct obj *m_armr;
  8.  
  9.      if ((m_armr = which_armor(mon, W_ARM)) != 0) {
  10.          if (Is_dragon_scales(m_armr))
  11.              return Dragon_scales_to_pm(m_armr);
  12.          else if (Is_dragon_mail(m_armr))
  13.              return Dragon_mail_to_pm(m_armr);
  14.      }
  15.      return rndmonst();
  16.  }
  17.  

use_misc

  1.  int
  2.  use_misc(mtmp)
  3.  struct monst *mtmp;
  4.  {
  5.      int i;
  6.      struct obj *otmp = m.misc;
  7.      boolean vis, vismon, oseen;
  8.      char nambuf[BUFSZ];
  9.  
  10.      if ((i = precheck(mtmp, otmp)) != 0)
  11.          return i;
  12.      vis = cansee(mtmp->mx, mtmp->my);
  13.      vismon = canseemon(mtmp);
  14.      oseen = otmp && vismon;
  15.  
  16.      switch (m.has_misc) {
  17.      case MUSE_POT_GAIN_LEVEL:
  18.          mquaffmsg(mtmp, otmp);
  19.          if (otmp->cursed) {
  20.              if (Can_rise_up(mtmp->mx, mtmp->my, &u.uz)) {
  21.                  register int tolev = depth(&u.uz) - 1;
  22.                  d_level tolevel;
  23.  
  24.                  get_level(&tolevel, tolev);
  25.                  /* insurance against future changes... */
  26.                  if (on_level(&tolevel, &u.uz))
  27.                      goto skipmsg;
  28.                  if (vismon) {
  29.                      pline("%s rises up, through the %s!", Monnam(mtmp),
  30.                            ceiling(mtmp->mx, mtmp->my));
  31.                      if (!objects[POT_GAIN_LEVEL].oc_name_known
  32.                          && !objects[POT_GAIN_LEVEL].oc_uname)
  33.                          docall(otmp);
  34.                  }
  35.                  m_useup(mtmp, otmp);
  36.                  migrate_to_level(mtmp, ledger_no(&tolevel), MIGR_RANDOM,
  37.                                   (coord *) 0);
  38.                  return 2;
  39.              } else {
  40.              skipmsg:
  41.                  if (vismon) {
  42.                      pline("%s looks uneasy.", Monnam(mtmp));
  43.                      if (!objects[POT_GAIN_LEVEL].oc_name_known
  44.                          && !objects[POT_GAIN_LEVEL].oc_uname)
  45.                          docall(otmp);
  46.                  }
  47.                  m_useup(mtmp, otmp);
  48.                  return 2;
  49.              }
  50.          }
  51.          if (vismon)
  52.              pline("%s seems more experienced.", Monnam(mtmp));
  53.          if (oseen)
  54.              makeknown(POT_GAIN_LEVEL);
  55.          m_useup(mtmp, otmp);
  56.          if (!grow_up(mtmp, (struct monst *) 0))
  57.              return 1;
  58.          /* grew into genocided monster */
  59.          return 2;
  60.      case MUSE_WAN_MAKE_INVISIBLE:
  61.      case MUSE_POT_INVISIBILITY:
  62.          if (otmp->otyp == WAN_MAKE_INVISIBLE) {
  63.              mzapmsg(mtmp, otmp, TRUE);
  64.              otmp->spe--;
  65.          } else
  66.              mquaffmsg(mtmp, otmp);
  67.          /* format monster's name before altering its visibility */
  68.          Strcpy(nambuf, mon_nam(mtmp));
  69.          mon_set_minvis(mtmp);
  70.          if (vismon && mtmp->minvis) { /* was seen, now invisible */
  71.              if (canspotmon(mtmp)) {
  72.                  pline("%s body takes on a %s transparency.",
  73.                        upstart(s_suffix(nambuf)),
  74.                        Hallucination ? "normal" : "strange");
  75.              } else {
  76.                  pline("Suddenly you cannot see %s.", nambuf);
  77.                  if (vis)
  78.                      map_invisible(mtmp->mx, mtmp->my);
  79.              }
  80.              if (oseen)
  81.                  makeknown(otmp->otyp);
  82.          }
  83.          if (otmp->otyp == POT_INVISIBILITY) {
  84.              if (otmp->cursed)
  85.                  you_aggravate(mtmp);
  86.              m_useup(mtmp, otmp);
  87.          }
  88.          return 2;
  89.      case MUSE_WAN_SPEED_MONSTER:
  90.          mzapmsg(mtmp, otmp, TRUE);
  91.          otmp->spe--;
  92.          mon_adjust_speed(mtmp, 1, otmp);
  93.          return 2;
  94.      case MUSE_POT_SPEED:
  95.          mquaffmsg(mtmp, otmp);
  96.          /* note difference in potion effect due to substantially
  97.             different methods of maintaining speed ratings:
  98.             player's character becomes "very fast" temporarily;
  99.             monster becomes "one stage faster" permanently */
  100.          mon_adjust_speed(mtmp, 1, otmp);
  101.          m_useup(mtmp, otmp);
  102.          return 2;
  103.      case MUSE_WAN_POLYMORPH:
  104.          mzapmsg(mtmp, otmp, TRUE);
  105.          otmp->spe--;
  106.          (void) newcham(mtmp, muse_newcham_mon(mtmp), TRUE, FALSE);
  107.          if (oseen)
  108.              makeknown(WAN_POLYMORPH);
  109.          return 2;
  110.      case MUSE_POT_POLYMORPH:
  111.          mquaffmsg(mtmp, otmp);
  112.          if (vismon)
  113.              pline("%s suddenly mutates!", Monnam(mtmp));
  114.          (void) newcham(mtmp, muse_newcham_mon(mtmp), FALSE, FALSE);
  115.          if (oseen)
  116.              makeknown(POT_POLYMORPH);
  117.          m_useup(mtmp, otmp);
  118.          return 2;
  119.      case MUSE_POLY_TRAP:
  120.          if (vismon) {
  121.              const char *Mnam = Monnam(mtmp);
  122.  
  123.              pline("%s deliberately %s onto a polymorph trap!", Mnam,
  124.                    vtense(Mnam, locomotion(mtmp->data, "jump")));
  125.          }
  126.          if (vis)
  127.              seetrap(t_at(trapx, trapy));
  128.  
  129.          /*  don't use rloc() due to worms */
  130.          remove_monster(mtmp->mx, mtmp->my);
  131.          newsym(mtmp->mx, mtmp->my);
  132.          place_monster(mtmp, trapx, trapy);
  133.          if (mtmp->wormno)
  134.              worm_move(mtmp);
  135.          newsym(trapx, trapy);
  136.  
  137.          (void) newcham(mtmp, (struct permonst *) 0, FALSE, FALSE);
  138.          return 2;
  139.      case MUSE_BULLWHIP:
  140.          /* attempt to disarm hero */
  141.          {
  142.              const char *The_whip = vismon ? "The bullwhip" : "A whip";
  143.              int where_to = rn2(4);
  144.              struct obj *obj = uwep;
  145.              const char *hand;
  146.              char the_weapon[BUFSZ];
  147.  
  148.              if (!obj || !canletgo(obj, "")
  149.                  || (u.twoweap && canletgo(uswapwep, "") && rn2(2)))
  150.                  obj = uswapwep;
  151.              if (!obj)
  152.                  break; /* shouldn't happen after find_misc() */
  153.  
  154.              Strcpy(the_weapon, the(xname(obj)));
  155.              hand = body_part(HAND);
  156.              if (bimanual(obj))
  157.                  hand = makeplural(hand);
  158.  
  159.              if (vismon)
  160.                  pline("%s flicks a bullwhip towards your %s!", Monnam(mtmp),
  161.                        hand);
  162.              if (obj->otyp == HEAVY_IRON_BALL) {
  163.                  pline("%s fails to wrap around %s.", The_whip, the_weapon);
  164.                  return 1;
  165.              }
  166.              pline("%s wraps around %s you're wielding!", The_whip,
  167.                    the_weapon);
  168.              if (welded(obj)) {
  169.                  pline("%s welded to your %s%c",
  170.                        !is_plural(obj) ? "It is" : "They are", hand,
  171.                        !obj->bknown ? '!' : '.');
  172.                  /* obj->bknown = 1; */ /* welded() takes care of this */
  173.                  where_to = 0;
  174.              }
  175.              if (!where_to) {
  176.                  pline_The("whip slips free."); /* not `The_whip' */
  177.                  return 1;
  178.              } else if (where_to == 3 && mon_hates_silver(mtmp)
  179.                         && objects[obj->otyp].oc_material == SILVER) {
  180.                  /* this monster won't want to catch a silver
  181.                     weapon; drop it at hero's feet instead */
  182.                  where_to = 2;
  183.              }
  184.              remove_worn_item(obj, FALSE);
  185.              freeinv(obj);
  186.              switch (where_to) {
  187.              case 1: /* onto floor beneath mon */
  188.                  pline("%s yanks %s from your %s!", Monnam(mtmp), the_weapon,
  189.                        hand);
  190.                  place_object(obj, mtmp->mx, mtmp->my);
  191.                  break;
  192.              case 2: /* onto floor beneath you */
  193.                  pline("%s yanks %s to the %s!", Monnam(mtmp), the_weapon,
  194.                        surface(u.ux, u.uy));
  195.                  dropy(obj);
  196.                  break;
  197.              case 3: /* into mon's inventory */
  198.                  pline("%s snatches %s!", Monnam(mtmp), the_weapon);
  199.                  (void) mpickobj(mtmp, obj);
  200.                  break;
  201.              }
  202.              return 1;
  203.          }
  204.          return 0;
  205.      case 0:
  206.          return 0; /* i.e. an exploded wand */
  207.      default:
  208.          impossible("%s wanted to perform action %d?", Monnam(mtmp),
  209.                     m.has_misc);
  210.          break;
  211.      }
  212.      return 0;
  213.  }
  214.  

you_aggravate

  1.  STATIC_OVL void
  2.  you_aggravate(mtmp)
  3.  struct monst *mtmp;
  4.  {
  5.      pline("For some reason, %s presence is known to you.",
  6.            s_suffix(noit_mon_nam(mtmp)));
  7.      cls();
  8.  #ifdef CLIPPING
  9.      cliparound(mtmp->mx, mtmp->my);
  10.  #endif
  11.      show_glyph(mtmp->mx, mtmp->my, mon_to_glyph(mtmp));
  12.      display_self();
  13.      You_feel("aggravated at %s.", noit_mon_nam(mtmp));
  14.      display_nhwindow(WIN_MAP, TRUE);
  15.      docrt();
  16.      if (unconscious()) {
  17.          multi = -1;
  18.          nomovemsg = "Aggravated, you are jolted into full consciousness.";
  19.      }
  20.      newsym(mtmp->mx, mtmp->my);
  21.      if (!canspotmon(mtmp))
  22.          map_invisible(mtmp->mx, mtmp->my);
  23.  }
  24.  

rnd_misc_item

  1.  int
  2.  rnd_misc_item(mtmp)
  3.  struct monst *mtmp;
  4.  {
  5.      struct permonst *pm = mtmp->data;
  6.      int difficulty = monstr[(monsndx(pm))];
  7.  
  8.      if (is_animal(pm) || attacktype(pm, AT_EXPL) || mindless(mtmp->data)
  9.          || pm->mlet == S_GHOST || pm->mlet == S_KOP)
  10.          return 0;
  11.      /* Unlike other rnd_item functions, we only allow _weak_ monsters
  12.       * to have this item; after all, the item will be used to strengthen
  13.       * the monster and strong monsters won't use it at all...
  14.       */
  15.      if (difficulty < 6 && !rn2(30))
  16.          return rn2(6) ? POT_POLYMORPH : WAN_POLYMORPH;
  17.  
  18.      if (!rn2(40) && !nonliving(pm) && !is_vampshifter(mtmp))
  19.          return AMULET_OF_LIFE_SAVING;
  20.  
  21.      switch (rn2(3)) {
  22.      case 0:
  23.          if (mtmp->isgd)
  24.              return 0;
  25.          return rn2(6) ? POT_SPEED : WAN_SPEED_MONSTER;
  26.      case 1:
  27.          if (mtmp->mpeaceful && !See_invisible)
  28.              return 0;
  29.          return rn2(6) ? POT_INVISIBILITY : WAN_MAKE_INVISIBLE;
  30.      case 2:
  31.          return POT_GAIN_LEVEL;
  32.      }
  33.      /*NOTREACHED*/
  34.      return 0;
  35.  }
  36.  

searches_for_item

  1.  boolean
  2.  searches_for_item(mon, obj)
  3.  struct monst *mon;
  4.  struct obj *obj;
  5.  {
  6.      int typ = obj->otyp;
  7.  
  8.      if (is_animal(mon->data) || mindless(mon->data)
  9.          || mon->data == &mons[PM_GHOST]) /* don't loot bones piles */
  10.          return FALSE;
  11.  
  12.      if (typ == WAN_MAKE_INVISIBLE || typ == POT_INVISIBILITY)
  13.          return (boolean) (!mon->minvis && !mon->invis_blkd
  14.                            && !attacktype(mon->data, AT_GAZE));
  15.      if (typ == WAN_SPEED_MONSTER || typ == POT_SPEED)
  16.          return (boolean) (mon->mspeed != MFAST);
  17.  
  18.      switch (obj->oclass) {
  19.      case WAND_CLASS:
  20.          if (obj->spe <= 0)
  21.              return FALSE;
  22.          if (typ == WAN_DIGGING)
  23.              return (boolean) !is_floater(mon->data);
  24.          if (typ == WAN_POLYMORPH)
  25.              return (boolean) (monstr[monsndx(mon->data)] < 6);
  26.          if (objects[typ].oc_dir == RAY || typ == WAN_STRIKING
  27.              || typ == WAN_TELEPORTATION || typ == WAN_CREATE_MONSTER)
  28.              return TRUE;
  29.          break;
  30.      case POTION_CLASS:
  31.          if (typ == POT_HEALING || typ == POT_EXTRA_HEALING
  32.              || typ == POT_FULL_HEALING || typ == POT_POLYMORPH
  33.              || typ == POT_GAIN_LEVEL || typ == POT_PARALYSIS
  34.              || typ == POT_SLEEPING || typ == POT_ACID || typ == POT_CONFUSION)
  35.              return TRUE;
  36.          if (typ == POT_BLINDNESS && !attacktype(mon->data, AT_GAZE))
  37.              return TRUE;
  38.          break;
  39.      case SCROLL_CLASS:
  40.          if (typ == SCR_TELEPORTATION || typ == SCR_CREATE_MONSTER
  41.              || typ == SCR_EARTH || typ == SCR_FIRE)
  42.              return TRUE;
  43.          break;
  44.      case AMULET_CLASS:
  45.          if (typ == AMULET_OF_LIFE_SAVING)
  46.              return (boolean) !(nonliving(mon->data) || is_vampshifter(mon));
  47.          if (typ == AMULET_OF_REFLECTION)
  48.              return TRUE;
  49.          break;
  50.      case TOOL_CLASS:
  51.          if (typ == PICK_AXE)
  52.              return (boolean) needspick(mon->data);
  53.          if (typ == UNICORN_HORN)
  54.              return (boolean) (!obj->cursed && !is_unicorn(mon->data));
  55.          if (typ == FROST_HORN || typ == FIRE_HORN)
  56.              return (obj->spe > 0 && can_blow(mon));
  57.          break;
  58.      case FOOD_CLASS:
  59.          if (typ == CORPSE)
  60.              return (boolean) (((mon->misc_worn_check & W_ARMG) != 0L
  61.                                 && touch_petrifies(&mons[obj->corpsenm]))
  62.                                || (!resists_ston(mon)
  63.                                    && cures_stoning(mon, obj, FALSE)));
  64.          if (typ == TIN)
  65.              return (boolean) (mcould_eat_tin(mon)
  66.                                && (!resists_ston(mon)
  67.                                    && cures_stoning(mon, obj, TRUE)));
  68.          if (typ == EGG)
  69.              return (boolean) touch_petrifies(&mons[obj->corpsenm]);
  70.          break;
  71.      default:
  72.          break;
  73.      }
  74.  
  75.      return FALSE;
  76.  }
  77.  

mon_reflects

  1.  boolean
  2.  mon_reflects(mon, str)
  3.  struct monst *mon;
  4.  const char *str;
  5.  {
  6.      struct obj *orefl = which_armor(mon, W_ARMS);
  7.  
  8.      if (orefl && orefl->otyp == SHIELD_OF_REFLECTION) {
  9.          if (str) {
  10.              pline(str, s_suffix(mon_nam(mon)), "shield");
  11.              makeknown(SHIELD_OF_REFLECTION);
  12.          }
  13.          return TRUE;
  14.      } else if (arti_reflects(MON_WEP(mon))) {
  15.          /* due to wielded artifact weapon */
  16.          if (str)
  17.              pline(str, s_suffix(mon_nam(mon)), "weapon");
  18.          return TRUE;
  19.      } else if ((orefl = which_armor(mon, W_AMUL))
  20.                 && orefl->otyp == AMULET_OF_REFLECTION) {
  21.          if (str) {
  22.              pline(str, s_suffix(mon_nam(mon)), "amulet");
  23.              makeknown(AMULET_OF_REFLECTION);
  24.          }
  25.          return TRUE;
  26.      } else if ((orefl = which_armor(mon, W_ARM))
  27.                 && (orefl->otyp == SILVER_DRAGON_SCALES
  28.                     || orefl->otyp == SILVER_DRAGON_SCALE_MAIL)) {
  29.          if (str)
  30.              pline(str, s_suffix(mon_nam(mon)), "armor");
  31.          return TRUE;
  32.      } else if (mon->data == &mons[PM_SILVER_DRAGON]
  33.                 || mon->data == &mons[PM_CHROMATIC_DRAGON]) {
  34.          /* Silver dragons only reflect when mature; babies do not */
  35.          if (str)
  36.              pline(str, s_suffix(mon_nam(mon)), "scales");
  37.          return TRUE;
  38.      }
  39.      return FALSE;
  40.  }
  41.  

ureflects

  1.  boolean
  2.  ureflects(fmt, str)
  3.  const char *fmt, *str;
  4.  {
  5.      /* Check from outermost to innermost objects */
  6.      if (EReflecting & W_ARMS) {
  7.          if (fmt && str) {
  8.              pline(fmt, str, "shield");
  9.              makeknown(SHIELD_OF_REFLECTION);
  10.          }
  11.          return TRUE;
  12.      } else if (EReflecting & W_WEP) {
  13.          /* Due to wielded artifact weapon */
  14.          if (fmt && str)
  15.              pline(fmt, str, "weapon");
  16.          return TRUE;
  17.      } else if (EReflecting & W_AMUL) {
  18.          if (fmt && str) {
  19.              pline(fmt, str, "medallion");
  20.              makeknown(AMULET_OF_REFLECTION);
  21.          }
  22.          return TRUE;
  23.      } else if (EReflecting & W_ARM) {
  24.          if (fmt && str)
  25.              pline(fmt, str, uskin ? "luster" : "armor");
  26.          return TRUE;
  27.      } else if (youmonst.data == &mons[PM_SILVER_DRAGON]) {
  28.          if (fmt && str)
  29.              pline(fmt, str, "scales");
  30.          return TRUE;
  31.      }
  32.      return FALSE;
  33.  }
  34.  

mcureblindness

  1.  /* cure mon's blindness (use_defensive, dog_eat, meatobj) */
  2.  void
  3.  mcureblindness(mon, verbos)
  4.  struct monst *mon;
  5.  boolean verbos;
  6.  {
  7.      if (!mon->mcansee) {
  8.          mon->mcansee = 1;
  9.          mon->mblinded = 0;
  10.          if (verbos && haseyes(mon->data))
  11.              pline("%s can see again.", Monnam(mon));
  12.      }
  13.  }
  14.  

munstone

  1.  /* TRUE if the monster ate something */
  2.  boolean
  3.  munstone(mon, by_you)
  4.  struct monst *mon;
  5.  boolean by_you;
  6.  {
  7.      struct obj *obj;
  8.      boolean tinok;
  9.  
  10.      if (resists_ston(mon))
  11.          return FALSE;
  12.      if (mon->meating || !mon->mcanmove || mon->msleeping)
  13.          return FALSE;
  14.      mon->mstrategy &= ~STRAT_WAITFORU;
  15.  
  16.      tinok = mcould_eat_tin(mon);
  17.      for (obj = mon->minvent; obj; obj = obj->nobj) {
  18.          if (cures_stoning(mon, obj, tinok)) {
  19.              mon_consume_unstone(mon, obj, by_you, TRUE);
  20.              return TRUE;
  21.          }
  22.      }
  23.      return FALSE;
  24.  }
  25.  

mon_consume_unstone

  1.  STATIC_OVL void
  2.  mon_consume_unstone(mon, obj, by_you, stoning)
  3.  struct monst *mon;
  4.  struct obj *obj;
  5.  boolean by_you;
  6.  boolean stoning; /* True: stop petrification, False: cure stun && confusion */
  7.  {
  8.      boolean vis = canseemon(mon), tinned = obj->otyp == TIN,
  9.              food = obj->otyp == CORPSE || tinned,
  10.              acid = obj->otyp == POT_ACID
  11.                     || (food && acidic(&mons[obj->corpsenm])),
  12.              lizard = food && obj->corpsenm == PM_LIZARD;
  13.      int nutrit = food ? dog_nutrition(mon, obj) : 0; /* also sets meating */
  14.  
  15.      /* give a "<mon> is slowing down" message and also remove
  16.         intrinsic speed (comparable to similar effect on the hero) */
  17.      if (stoning)
  18.          mon_adjust_speed(mon, -3, (struct obj *) 0);
  19.  
  20.      if (vis) {
  21.          long save_quan = obj->quan;
  22.  
  23.          obj->quan = 1L;
  24.          pline("%s %s %s.", Monnam(mon),
  25.                (obj->oclass == POTION_CLASS)
  26.                    ? "quaffs"
  27.                    : (obj->otyp == TIN) ? "opens and eats the contents of"
  28.                                         : "eats",
  29.                distant_name(obj, doname));
  30.          obj->quan = save_quan;
  31.      } else if (!Deaf)
  32.          You_hear("%s.",
  33.                   (obj->oclass == POTION_CLASS) ? "drinking" : "chewing");
  34.  
  35.      m_useup(mon, obj);
  36.      /* obj is now gone */
  37.  
  38.      if (acid && !tinned && !resists_acid(mon)) {
  39.          mon->mhp -= rnd(15);
  40.          if (vis)
  41.              pline("%s has a very bad case of stomach acid.", Monnam(mon));
  42.          if (mon->mhp <= 0) {
  43.              pline("%s dies!", Monnam(mon));
  44.              if (by_you)
  45.                  /* hero gets credit (experience) and blame (possible loss
  46.                     of alignment and/or luck and/or telepathy depending on
  47.                     mon) for the kill but does not break pacifism conduct */
  48.                  xkilled(mon, XKILL_NOMSG | XKILL_NOCONDUCT);
  49.              else
  50.                  mondead(mon);
  51.              return;
  52.          }
  53.      }
  54.      if (stoning && vis) {
  55.          if (Hallucination)
  56.              pline("What a pity - %s just ruined a future piece of art!",
  57.                    mon_nam(mon));
  58.          else
  59.              pline("%s seems limber!", Monnam(mon));
  60.      }
  61.      if (lizard && (mon->mconf || mon->mstun)) {
  62.          mon->mconf = 0;
  63.          mon->mstun = 0;
  64.          if (vis && !is_bat(mon->data) && mon->data != &mons[PM_STALKER])
  65.              pline("%s seems steadier now.", Monnam(mon));
  66.      }
  67.      if (mon->mtame && !mon->isminion && nutrit > 0) {
  68.          struct edog *edog = EDOG(mon);
  69.  
  70.          if (edog->hungrytime < monstermoves)
  71.              edog->hungrytime = monstermoves;
  72.          edog->hungrytime += nutrit;
  73.          mon->mconf = 0;
  74.      }
  75.      /* use up monster's next move */
  76.      mon->movement -= NORMAL_SPEED;
  77.      mon->mlstmv = monstermoves;
  78.  }
  79.  

cures_stoning

  1.  /* decide whether obj can cure petrification; also used when picking up */
  2.  STATIC_OVL boolean
  3.  cures_stoning(mon, obj, tinok)
  4.  struct monst *mon;
  5.  struct obj *obj;
  6.  boolean tinok;
  7.  {
  8.      if (obj->otyp == POT_ACID)
  9.          return TRUE;
  10.      if (obj->otyp != CORPSE && (obj->otyp != TIN || !tinok))
  11.          return FALSE;
  12.      /* corpse, or tin that mon can open */
  13.      return (boolean) (obj->corpsenm == PM_LIZARD
  14.                        || (acidic(&mons[obj->corpsenm])
  15.                            && (obj->corpsenm != PM_GREEN_SLIME
  16.                                || slimeproof(mon->data))));
  17.  }
  18.  

mcould_eat_tin

  1.  STATIC_OVL boolean
  2.  mcould_eat_tin(mon)
  3.  struct monst *mon;
  4.  {
  5.      struct obj *obj, *mwep;
  6.      boolean welded_wep;
  7.  
  8.      /* monkeys who manage to steal tins can't open and eat them
  9.         even if they happen to also have the appropriate tool */
  10.      if (is_animal(mon->data))
  11.          return FALSE;
  12.  
  13.      mwep = MON_WEP(mon);
  14.      welded_wep = mwep && mwelded(mwep);
  15.      /* this is different from the player; tin opener or dagger doesn't
  16.         have to be wielded, and knife can be used instead of dagger */
  17.      for (obj = mon->minvent; obj; obj = obj->nobj) {
  18.          /* if stuck with a cursed weapon, don't check rest of inventory */
  19.          if (welded_wep && obj != mwep)
  20.              continue;
  21.  
  22.          if (obj->otyp == TIN_OPENER
  23.              || (obj->oclass == WEAPON_CLASS
  24.                  && (objects[obj->otyp].oc_skill == P_DAGGER
  25.                      || objects[obj->otyp].oc_skill == P_KNIFE)))
  26.              return TRUE;
  27.      }
  28.      return FALSE;
  29.  }
  30.  

munslime

  1.  /* TRUE if monster does something to avoid turning into green slime */
  2.  boolean
  3.  munslime(mon, by_you)
  4.  struct monst *mon;
  5.  boolean by_you;
  6.  {
  7.      struct obj *obj, odummy;
  8.      struct permonst *mptr = mon->data;
  9.  
  10.      /*
  11.       * muse_unslime() gives "mon starts turning green", "mon zaps
  12.       * itself with a wand of fire", and "mon's slime burns away"
  13.       * messages.  Monsters who don't get any chance at that just have
  14.       * (via our caller) newcham()'s "mon turns into slime" feedback.
  15.       */
  16.  
  17.      if (slimeproof(mptr))
  18.          return FALSE;
  19.      if (mon->meating || !mon->mcanmove || mon->msleeping)
  20.          return FALSE;
  21.      mon->mstrategy &= ~STRAT_WAITFORU;
  22.  
  23.      /* if monster can breathe fire, do so upon self; a monster who deals
  24.         fire damage by biting, clawing, gazing, and especially exploding
  25.         isn't able to cure itself of green slime with its own attack
  26.         [possible extension: monst capable of casting high level clerical
  27.         spells could toss pillar of fire at self--probably too suicidal] */
  28.      if (!mon->mcan && !mon->mspec_used
  29.          && attacktype_fordmg(mptr, AT_BREA, AD_FIRE)) {
  30.          odummy = zeroobj; /* otyp == STRANGE_OBJECT */
  31.          return muse_unslime(mon, &odummy, (struct trap *) 0, by_you);
  32.      }
  33.  
  34.      /* same MUSE criteria as use_defensive() */
  35.      if (!is_animal(mptr) && !mindless(mptr)) {
  36.          struct trap *t;
  37.  
  38.          for (obj = mon->minvent; obj; obj = obj->nobj)
  39.              if (cures_sliming(mon, obj))
  40.                  return muse_unslime(mon, obj, (struct trap *) 0, by_you);
  41.  
  42.          if (((t = t_at(mon->mx, mon->my)) == 0 || t->ttyp != FIRE_TRAP)
  43.              && mptr->mmove && !mon->mtrapped) {
  44.              int xy[2][8], x, y, idx, ridx, nxy = 0;
  45.  
  46.              for (x = mon->mx - 1; x <= mon->mx + 1; ++x)
  47.                  for (y = mon->my - 1; y <= mon->my + 1; ++y)
  48.                      if (isok(x, y) && accessible(x, y)
  49.                          && !m_at(x, y) && (x != u.ux || y != u.uy)) {
  50.                          xy[0][nxy] = x, xy[1][nxy] = y;
  51.                          ++nxy;
  52.                      }
  53.              for (idx = 0; idx < nxy; ++idx) {
  54.                  ridx = rn1(nxy - idx, idx);
  55.                  if (ridx != idx) {
  56.                      x = xy[0][idx];
  57.                      xy[0][idx] = xy[0][ridx];
  58.                      xy[0][ridx] = x;
  59.                      y = xy[1][idx];
  60.                      xy[1][idx] = xy[1][ridx];
  61.                      xy[1][ridx] = y;
  62.                  }
  63.                  if ((t = t_at(xy[0][idx], xy[1][idx])) != 0
  64.                      && t->ttyp == FIRE_TRAP)
  65.                      break;
  66.              }
  67.          }
  68.          if (t && t->ttyp == FIRE_TRAP)
  69.              return muse_unslime(mon, &zeroobj, t, by_you);
  70.  
  71.      } /* MUSE */
  72.  
  73.      return FALSE;
  74.  }
  75.  

muse_unslime

  1.  /* mon uses an item--selected by caller--to burn away incipient slime */
  2.  STATIC_OVL boolean
  3.  muse_unslime(mon, obj, trap, by_you)
  4.  struct monst *mon;
  5.  struct obj *obj;
  6.  struct trap *trap;
  7.  boolean by_you; /* true: if mon kills itself, hero gets credit/blame */
  8.  {               /* [by_you not honored if 'mon' triggers fire trap]. */
  9.      struct obj *odummyp;
  10.      int otyp = obj->otyp, dmg = 0;
  11.      boolean vis = canseemon(mon), res = TRUE;
  12.  
  13.      if (vis)
  14.          pline("%s starts turning %s.", Monnam(mon),
  15.                green_mon(mon) ? "into ooze" : hcolor(NH_GREEN));
  16.      /* -4 => sliming, causes quiet loss of enhanced speed */
  17.      mon_adjust_speed(mon, -4, (struct obj *) 0);
  18.  
  19.      if (trap) {
  20.          const char *Mnam = vis ? Monnam(mon) : 0;
  21.  
  22.          if (mon->mx == trap->tx && mon->my == trap->ty) {
  23.              if (vis)
  24.                  pline("%s triggers %s fire trap!", Mnam,
  25.                        trap->tseen ? "the" : "a");
  26.          } else {
  27.              remove_monster(mon->mx, mon->my);
  28.              newsym(mon->mx, mon->my);
  29.              place_monster(mon, trap->tx, trap->ty);
  30.              if (mon->wormno) /* won't happen; worms don't MUSE to unslime */
  31.                  worm_move(mon);
  32.              newsym(mon->mx, mon->my);
  33.              if (vis)
  34.                  pline("%s %s %s %s fire trap!", Mnam,
  35.                        vtense(Mnam, locomotion(mon->data, "move")),
  36.                        is_floater(mon->data) ? "over" : "onto",
  37.                        trap->tseen ? "the" : "a");
  38.          }
  39.          /* hack to avoid mintrap()'s chance of avoiding known trap */
  40.          mon->mtrapseen &= ~(1 << (FIRE_TRAP - 1));
  41.          mintrap(mon);
  42.      } else if (otyp == STRANGE_OBJECT) {
  43.          /* monster is using fire breath on self */
  44.          if (vis)
  45.              pline("%s breathes fire on %sself.", Monnam(mon), mhim(mon));
  46.          if (!rn2(3))
  47.              mon->mspec_used = rn1(10, 5);
  48.          /* -21 => monster's fire breath; 1 => # of damage dice */
  49.          dmg = zhitm(mon, by_you ? 21 : -21, 1, &odummyp);
  50.      } else if (otyp == SCR_FIRE) {
  51.          mreadmsg(mon, obj);
  52.          if (mon->mconf) {
  53.              if (cansee(mon->mx, mon->my))
  54.                  pline("Oh, what a pretty fire!");
  55.              if (vis && !objects[otyp].oc_name_known
  56.                  && !objects[otyp].oc_uname)
  57.                  docall(obj);
  58.              m_useup(mon, obj); /* after docall() */
  59.              vis = FALSE;       /* skip makeknown() below */
  60.              res = FALSE;       /* failed to cure sliming */
  61.          } else {
  62.              m_useup(mon, obj); /* before explode() */
  63.              dmg = (2 * (rn1(3, 3) + 2 * bcsign(obj)) + 1) / 3;
  64.              /* -11 => monster's fireball */
  65.              explode(mon->mx, mon->my, -11, dmg, SCROLL_CLASS,
  66.                      /* by_you: override -11 for mon but not others */
  67.                      by_you ? -EXPL_FIERY : EXPL_FIERY);
  68.              dmg = 0; /* damage has been applied by explode() */
  69.          }
  70.      } else { /* wand/horn of fire w/ positive charge count */
  71.          mzapmsg(mon, obj, TRUE);
  72.          obj->spe--;
  73.          /* -1 => monster's wand of fire; 2 => # of damage dice */
  74.          dmg = zhitm(mon, by_you ? 1 : -1, 2, &odummyp);
  75.      }
  76.  
  77.      if (dmg) {
  78.          /* zhitm() applies damage but doesn't kill creature off;
  79.             for fire breath, dmg is going to be 0 (fire breathers are
  80.             immune to fire damage) but for wand of fire or fire horn,
  81.             'mon' could have taken damage so might die */
  82.          if (mon->mhp <= 0) {
  83.              if (by_you) {
  84.                  /* mon killed self but hero gets credit and blame (except
  85.                     for pacifist conduct); xkilled()'s message would say
  86.                     "You killed/destroyed <mon>" so give our own message */
  87.                  if (vis)
  88.                      pline("%s is %s by the fire!", Monnam(mon),
  89.                            nonliving(mon->data) ? "destroyed" : "killed");
  90.                  xkilled(mon, XKILL_NOMSG | XKILL_NOCONDUCT);
  91.              } else
  92.                  monkilled(mon, "fire", AD_FIRE);
  93.          } else {
  94.              /* non-fatal damage occurred */
  95.              if (vis)
  96.                  pline("%s is burned%s", Monnam(mon), exclam(dmg));
  97.          }
  98.      }
  99.      if (vis) {
  100.          if (res && mon->mhp > 0)
  101.              pline("%s slime is burned away!", s_suffix(Monnam(mon)));
  102.          if (otyp != STRANGE_OBJECT)
  103.              makeknown(otyp);
  104.      }
  105.      /* use up monster's next move */
  106.      mon->movement -= NORMAL_SPEED;
  107.      mon->mlstmv = monstermoves;
  108.      return res;
  109.  }
  110.  

cures_sliming

  1.  /* decide whether obj can be used to cure green slime */
  2.  STATIC_OVL int
  3.  cures_sliming(mon, obj)
  4.  struct monst *mon;
  5.  struct obj *obj;
  6.  {
  7.      /* scroll of fire, non-empty wand or horn of fire */
  8.      if (obj->otyp == SCR_FIRE)
  9.          return (haseyes(mon->data) && mon->mcansee);
  10.      /* hero doesn't need hands or even limbs to zap, so mon doesn't either */
  11.      return ((obj->otyp == WAN_FIRE
  12.               || (obj->otyp == FIRE_HORN && can_blow(mon)))
  13.              && obj->spe > 0);
  14.  }
  15.  

green_mon

  1.  /* TRUE if monster appears to be green; for active TEXTCOLOR, we go by
  2.     the display color, otherwise we just pick things that seem plausibly
  3.     green (which doesn't necessarily match the TEXTCOLOR categorization) */
  4.  STATIC_OVL boolean
  5.  green_mon(mon)
  6.  struct monst *mon;
  7.  {
  8.      struct permonst *ptr = mon->data;
  9.  
  10.      if (Hallucination)
  11.          return FALSE;
  12.  #ifdef TEXTCOLOR
  13.      if (iflags.use_color)
  14.          return (ptr->mcolor == CLR_GREEN || ptr->mcolor == CLR_BRIGHT_GREEN);
  15.  #endif
  16.      /* approximation */
  17.      if (strstri(ptr->mname, "green"))
  18.          return TRUE;
  19.      switch (monsndx(ptr)) {
  20.      case PM_FOREST_CENTAUR:
  21.      case PM_GARTER_SNAKE:
  22.      case PM_GECKO:
  23.      case PM_GREMLIN:
  24.      case PM_HOMUNCULUS:
  25.      case PM_JUIBLEX:
  26.      case PM_LEPRECHAUN:
  27.      case PM_LICHEN:
  28.      case PM_LIZARD:
  29.      case PM_WOOD_NYMPH:
  30.          return TRUE;
  31.      default:
  32.          if (is_elf(ptr) && !is_prince(ptr) && !is_lord(ptr)
  33.              && ptr != &mons[PM_GREY_ELF])
  34.              return TRUE;
  35.          break;
  36.      }
  37.      return FALSE;
  38.  }
  39.  
  40.  /*muse.c*/