Source:NetHack 3.6.1/src/mhitu.c

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

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

Top of file

  1.  /* NetHack 3.6	mhitu.c	$NHDT-Date: 1513297347 2017/12/15 00:22:27 $  $NHDT-Branch: NetHack-3.6.0 $:$NHDT-Revision: 1.149 $ */
  2.  /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
  3.  /*-Copyright (c) Robert Patrick Rankin, 2012. */
  4.  /* 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.  #include "hack.h"
  3.  #include "artifact.h"
  4.  
  5.  STATIC_VAR NEARDATA struct obj *mon_currwep = (struct obj *) 0;
  6.  
  7.  STATIC_DCL boolean FDECL(u_slip_free, (struct monst *, struct attack *));
  8.  STATIC_DCL int FDECL(passiveum, (struct permonst *, struct monst *,
  9.                                   struct attack *));
  10.  STATIC_DCL void FDECL(mayberem, (struct obj *, const char *));
  11.  STATIC_DCL boolean FDECL(diseasemu, (struct permonst *));
  12.  STATIC_DCL int FDECL(hitmu, (struct monst *, struct attack *));
  13.  STATIC_DCL int FDECL(gulpmu, (struct monst *, struct attack *));
  14.  STATIC_DCL int FDECL(explmu, (struct monst *, struct attack *, BOOLEAN_P));
  15.  STATIC_DCL void FDECL(missmu, (struct monst *, BOOLEAN_P, struct attack *));
  16.  STATIC_DCL void FDECL(mswings, (struct monst *, struct obj *));
  17.  STATIC_DCL void FDECL(wildmiss, (struct monst *, struct attack *));
  18.  STATIC_DCL void FDECL(hitmsg, (struct monst *, struct attack *));
  19.  
  20.  /* See comment in mhitm.c.  If we use this a lot it probably should be */
  21.  /* changed to a parameter to mhitu. */
  22.  static int dieroll;
  23.  

hitmsg

  1.  STATIC_OVL void
  2.  hitmsg(mtmp, mattk)
  3.  struct monst *mtmp;
  4.  struct attack *mattk;
  5.  {
  6.      int compat;
  7.      const char *pfmt = 0;
  8.      char *Monst_name = Monnam(mtmp);
  9.  
  10.      /* Note: if opposite gender, "seductively" */
  11.      /* If same gender, "engagingly" for nymph, normal msg for others */
  12.      if ((compat = could_seduce(mtmp, &youmonst, mattk)) != 0
  13.          && !mtmp->mcan && !mtmp->mspec_used) {
  14.          pline("%s %s you %s.", Monst_name,
  15.                Blind ? "talks to" : "smiles at",
  16.                (compat == 2) ? "engagingly" : "seductively");
  17.      } else {
  18.          switch (mattk->aatyp) {
  19.          case AT_BITE:
  20.              pfmt = "%s bites!";
  21.              break;
  22.          case AT_KICK:
  23.              pline("%s kicks%c", Monst_name,
  24.                    thick_skinned(youmonst.data) ? '.' : '!');
  25.              break;
  26.          case AT_STNG:
  27.              pfmt = "%s stings!";
  28.              break;
  29.          case AT_BUTT:
  30.              pfmt = "%s butts!";
  31.              break;
  32.          case AT_TUCH:
  33.              pfmt = "%s touches you!";
  34.              break;
  35.          case AT_TENT:
  36.              pfmt = "%s tentacles suck you!";
  37.              Monst_name = s_suffix(Monst_name);
  38.              break;
  39.          case AT_EXPL:
  40.          case AT_BOOM:
  41.              pfmt = "%s explodes!";
  42.              break;
  43.          default:
  44.              pfmt = "%s hits!";
  45.          }
  46.          if (pfmt)
  47.              pline(pfmt, Monst_name);
  48.      }
  49.  }
  50.  

missmu

  1.  /* monster missed you */
  2.  STATIC_OVL void
  3.  missmu(mtmp, nearmiss, mattk)
  4.  struct monst *mtmp;
  5.  boolean nearmiss;
  6.  struct attack *mattk;
  7.  {
  8.      if (!canspotmon(mtmp))
  9.          map_invisible(mtmp->mx, mtmp->my);
  10.  
  11.      if (could_seduce(mtmp, &youmonst, mattk) && !mtmp->mcan)
  12.          pline("%s pretends to be friendly.", Monnam(mtmp));
  13.      else
  14.          pline("%s %smisses!", Monnam(mtmp),
  15.                (nearmiss && flags.verbose) ? "just " : "");
  16.  
  17.      stop_occupation();
  18.  }
  19.  

mswings

  1.  /* monster swings obj */
  2.  STATIC_OVL void
  3.  mswings(mtmp, otemp)
  4.  struct monst *mtmp;
  5.  struct obj *otemp;
  6.  {
  7.      if (flags.verbose && !Blind && mon_visible(mtmp)) {
  8.          pline("%s %s %s%s %s.", Monnam(mtmp),
  9.                (objects[otemp->otyp].oc_dir & PIERCE) ? "thrusts" : "swings",
  10.                (otemp->quan > 1L) ? "one of " : "", mhis(mtmp), xname(otemp));
  11.      }
  12.  }
  13.  

mpoisons_subj

  1.  /* return how a poison attack was delivered */
  2.  const char *
  3.  mpoisons_subj(mtmp, mattk)
  4.  struct monst *mtmp;
  5.  struct attack *mattk;
  6.  {
  7.      if (mattk->aatyp == AT_WEAP) {
  8.          struct obj *mwep = (mtmp == &youmonst) ? uwep : MON_WEP(mtmp);
  9.          /* "Foo's attack was poisoned." is pretty lame, but at least
  10.             it's better than "sting" when not a stinging attack... */
  11.          return (!mwep || !mwep->opoisoned) ? "attack" : "weapon";
  12.      } else {
  13.          return (mattk->aatyp == AT_TUCH) ? "contact"
  14.                    : (mattk->aatyp == AT_GAZE) ? "gaze"
  15.                         : (mattk->aatyp == AT_BITE) ? "bite" : "sting";
  16.      }
  17.  }
  18.  

u_slow_down

  1.  /* called when your intrinsic speed is taken away */
  2.  void
  3.  u_slow_down()
  4.  {
  5.      HFast = 0L;
  6.      if (!Fast)
  7.          You("slow down.");
  8.      else /* speed boots */
  9.          Your("quickness feels less natural.");
  10.      exercise(A_DEX, FALSE);
  11.  }
  12.  

wildmiss

  1.  /* monster attacked your displaced image */
  2.  STATIC_OVL void
  3.  wildmiss(mtmp, mattk)
  4.  struct monst *mtmp;
  5.  struct attack *mattk;
  6.  {
  7.      int compat;
  8.      const char *Monst_name; /* Monnam(mtmp) */
  9.  
  10.      /* no map_invisible() -- no way to tell where _this_ is coming from */
  11.  
  12.      if (!flags.verbose)
  13.          return;
  14.      if (!cansee(mtmp->mx, mtmp->my))
  15.          return;
  16.      /* maybe it's attacking an image around the corner? */
  17.  
  18.      compat = ((mattk->adtyp == AD_SEDU || mattk->adtyp == AD_SSEX)
  19.                && could_seduce(mtmp, &youmonst, (struct attack *) 0));
  20.      Monst_name = Monnam(mtmp);
  21.  
  22.      if (!mtmp->mcansee || (Invis && !perceives(mtmp->data))) {
  23.          const char *swings = (mattk->aatyp == AT_BITE) ? "snaps"
  24.                               : (mattk->aatyp == AT_KICK) ? "kicks"
  25.                                 : (mattk->aatyp == AT_STNG
  26.                                    || mattk->aatyp == AT_BUTT
  27.                                    || nolimbs(mtmp->data)) ? "lunges"
  28.                                   : "swings";
  29.  
  30.          if (compat)
  31.              pline("%s tries to touch you and misses!", Monst_name);
  32.          else
  33.              switch (rn2(3)) {
  34.              case 0:
  35.                  pline("%s %s wildly and misses!", Monst_name, swings);
  36.                  break;
  37.              case 1:
  38.                  pline("%s attacks a spot beside you.", Monst_name);
  39.                  break;
  40.              case 2:
  41.                  pline("%s strikes at %s!", Monst_name,
  42.                        (levl[mtmp->mux][mtmp->muy].typ == WATER)
  43.                          ? "empty water"
  44.                          : "thin air");
  45.                  break;
  46.              default:
  47.                  pline("%s %s wildly!", Monst_name, swings);
  48.                  break;
  49.              }
  50.  
  51.      } else if (Displaced) {
  52.          if (compat)
  53.              pline("%s smiles %s at your %sdisplaced image...", Monst_name,
  54.                    (compat == 2) ? "engagingly" : "seductively",
  55.                    Invis ? "invisible " : "");
  56.          else
  57.              pline("%s strikes at your %sdisplaced image and misses you!",
  58.                    /* Note: if you're both invisible and displaced,
  59.                     * only monsters which see invisible will attack your
  60.                     * displaced image, since the displaced image is also
  61.                     * invisible.
  62.                     */
  63.                    Monst_name, Invis ? "invisible " : "");
  64.  
  65.      } else if (Underwater) {
  66.          /* monsters may miss especially on water level where
  67.             bubbles shake the player here and there */
  68.          if (compat)
  69.              pline("%s reaches towards your distorted image.", Monst_name);
  70.          else
  71.              pline("%s is fooled by water reflections and misses!",
  72.                    Monst_name);
  73.  
  74.      } else
  75.          impossible("%s attacks you without knowing your location?",
  76.                     Monst_name);
  77.  }
  78.  

expels

  1.  void
  2.  expels(mtmp, mdat, message)
  3.  struct monst *mtmp;
  4.  struct permonst *mdat; /* if mtmp is polymorphed, mdat != mtmp->data */
  5.  boolean message;
  6.  {
  7.      if (message) {
  8.          if (is_animal(mdat)) {
  9.              You("get regurgitated!");
  10.          } else {
  11.              char blast[40];
  12.              struct attack *attk = attacktype_fordmg(mdat, AT_ENGL, AD_ANY);
  13.  
  14.              blast[0] = '\0';
  15.              if (!attk) {
  16.                  impossible("Swallower has no engulfing attack?");
  17.              } else {
  18.                  if (is_whirly(mdat)) {
  19.                      switch (attk->adtyp) {
  20.                      case AD_ELEC:
  21.                          Strcpy(blast, " in a shower of sparks");
  22.                          break;
  23.                      case AD_COLD:
  24.                          Strcpy(blast, " in a blast of frost");
  25.                          break;
  26.                      }
  27.                  } else {
  28.                      Strcpy(blast, " with a squelch");
  29.                  }
  30.                  You("get expelled from %s%s!", mon_nam(mtmp), blast);
  31.              }
  32.          }
  33.      }
  34.      unstuck(mtmp); /* ball&chain returned in unstuck() */
  35.      mnexto(mtmp);
  36.      newsym(u.ux, u.uy);
  37.      spoteffects(TRUE);
  38.      /* to cover for a case where mtmp is not in a next square */
  39.      if (um_dist(mtmp->mx, mtmp->my, 1))
  40.          pline("Brrooaa...  You land hard at some distance.");
  41.  }
  42.  

getmattk

  1.  /* select a monster's next attack, possibly substituting for its usual one */
  2.  struct attack *
  3.  getmattk(magr, mdef, indx, prev_result, alt_attk_buf)
  4.  struct monst *magr, *mdef;
  5.  int indx, prev_result[];
  6.  struct attack *alt_attk_buf;
  7.  {
  8.      struct permonst *mptr = magr->data;
  9.      struct attack *attk = &mptr->mattk[indx];
  10.      struct obj *weap = (magr == &youmonst) ? uwep : MON_WEP(magr);
  11.  
  12.      /* prevent a monster with two consecutive disease or hunger attacks
  13.         from hitting with both of them on the same turn; if the first has
  14.         already hit, switch to a stun attack for the second */
  15.      if (indx > 0 && prev_result[indx - 1] > 0
  16.          && (attk->adtyp == AD_DISE || attk->adtyp == AD_PEST
  17.              || attk->adtyp == AD_FAMN)
  18.          && attk->adtyp == mptr->mattk[indx - 1].adtyp) {
  19.          *alt_attk_buf = *attk;
  20.          attk = alt_attk_buf;
  21.          attk->adtyp = AD_STUN;
  22.  
  23.      /* make drain-energy damage be somewhat in proportion to energy */
  24.      } else if (attk->adtyp == AD_DREN && mdef == &youmonst) {
  25.          int ulev = max(u.ulevel, 6);
  26.  
  27.          *alt_attk_buf = *attk;
  28.          attk = alt_attk_buf;
  29.          /* 3.6.0 used 4d6 but since energy drain came out of max energy
  30.             once current energy was gone, that tended to have a severe
  31.             effect on low energy characters; it's now 2d6 with ajustments */
  32.          if (u.uen <= 5 * ulev && attk->damn > 1) {
  33.              attk->damn -= 1; /* low energy: 2d6 -> 1d6 */
  34.              if (u.uenmax <= 2 * ulev && attk->damd > 3)
  35.                  attk->damd -= 3; /* very low energy: 1d6 -> 1d3 */
  36.          } else if (u.uen > 12 * ulev) {
  37.              attk->damn += 1; /* high energy: 2d6 -> 3d6 */
  38.              if (u.uenmax > 20 * ulev)
  39.                  attk->damd += 3; /* very high energy: 3d6 -> 3d9 */
  40.              /* note: 3d9 is slightly higher than previous 4d6 */
  41.          }
  42.  
  43.      } else if (attk->aatyp == AT_ENGL && magr->mspec_used) {
  44.          /* can't re-engulf yet; switch to simpler attack */
  45.          *alt_attk_buf = *attk;
  46.          attk = alt_attk_buf;
  47.          if (attk->adtyp == AD_ACID || attk->adtyp == AD_ELEC
  48.              || attk->adtyp == AD_COLD || attk->adtyp == AD_FIRE) {
  49.              attk->aatyp = AT_TUCH;
  50.          } else {
  51.              attk->aatyp = AT_CLAW; /* attack message will be "<foo> hits" */
  52.              attk->adtyp = AD_PHYS;
  53.          }
  54.          attk->damn = 1; /* relatively weak: 1d6 */
  55.          attk->damd = 6;
  56.  
  57.      /* barrow wight, Nazgul, erinys have weapon attack for non-physical
  58.         damage; force physical damage if attacker has been cancelled or
  59.         if weapon is sufficiently interesting; a few unique creatures
  60.         have two weapon attacks where one does physical damage and other
  61.         doesn't--avoid forcing physical damage for those */
  62.      } else if (indx == 0 && magr != &youmonst
  63.                 && attk->aatyp == AT_WEAP && attk->adtyp != AD_PHYS
  64.                 && !(mptr->mattk[1].aatyp == AT_WEAP
  65.                      && mptr->mattk[1].adtyp == AD_PHYS)
  66.                 && (magr->mcan
  67.                     || (weap && ((weap->otyp == CORPSE
  68.                                   && touch_petrifies(&mons[weap->corpsenm]))
  69.                                  || weap->oartifact == ART_STORMBRINGER
  70.                                  || weap->oartifact == ART_VORPAL_BLADE)))) {
  71.          *alt_attk_buf = *attk;
  72.          attk = alt_attk_buf;
  73.          attk->adtyp = AD_PHYS;
  74.      }
  75.      return attk;
  76.  }
  77.  

mattacku

  1.  /*
  2.   * mattacku: monster attacks you
  3.   *      returns 1 if monster dies (e.g. "yellow light"), 0 otherwise
  4.   *      Note: if you're displaced or invisible the monster might attack the
  5.   *              wrong position...
  6.   *      Assumption: it's attacking you or an empty square; if there's another
  7.   *              monster which it attacks by mistake, the caller had better
  8.   *              take care of it...
  9.   */
  10.  int
  11.  mattacku(mtmp)
  12.  register struct monst *mtmp;
  13.  {
  14.      struct attack *mattk, alt_attk;
  15.      int i, j = 0, tmp, sum[NATTK];
  16.      struct permonst *mdat = mtmp->data;
  17.      boolean ranged = (distu(mtmp->mx, mtmp->my) > 3);
  18.      /* Is it near you?  Affects your actions */
  19.      boolean range2 = !monnear(mtmp, mtmp->mux, mtmp->muy);
  20.      /* Does it think it's near you?  Affects its actions */
  21.      boolean foundyou = (mtmp->mux == u.ux && mtmp->muy == u.uy);
  22.      /* Is it attacking you or your image? */
  23.      boolean youseeit = canseemon(mtmp);
  24.      /* Might be attacking your image around the corner, or
  25.       * invisible, or you might be blind....
  26.       */
  27.      boolean skipnonmagc = FALSE;
  28.      /* Are further physical attack attempts useless? */
  29.  
  30.      if (!ranged)
  31.          nomul(0);
  32.      if (mtmp->mhp <= 0 || (Underwater && !is_swimmer(mtmp->data)))
  33.          return 0;
  34.  
  35.      /* If swallowed, can only be affected by u.ustuck */
  36.      if (u.uswallow) {
  37.          if (mtmp != u.ustuck)
  38.              return 0;
  39.          u.ustuck->mux = u.ux;
  40.          u.ustuck->muy = u.uy;
  41.          range2 = 0;
  42.          foundyou = 1;
  43.          if (u.uinvulnerable)
  44.              return 0; /* stomachs can't hurt you! */
  45.  
  46.      } else if (u.usteed) {
  47.          if (mtmp == u.usteed)
  48.              /* Your steed won't attack you */
  49.              return 0;
  50.          /* Orcs like to steal and eat horses and the like */
  51.          if (!rn2(is_orc(mtmp->data) ? 2 : 4)
  52.              && distu(mtmp->mx, mtmp->my) <= 2) {
  53.              /* Attack your steed instead */
  54.              i = mattackm(mtmp, u.usteed);
  55.              if ((i & MM_AGR_DIED))
  56.                  return 1;
  57.              /* make sure steed is still alive and within range */
  58.              if ((i & MM_DEF_DIED) || !u.usteed
  59.                  || distu(mtmp->mx, mtmp->my) > 2)
  60.                  return 0;
  61.              /* Let your steed retaliate */
  62.              return !!(mattackm(u.usteed, mtmp) & MM_DEF_DIED);
  63.          }
  64.      }
  65.  
  66.      if (u.uundetected && !range2 && foundyou && !u.uswallow) {
  67.          if (!canspotmon(mtmp))
  68.              map_invisible(mtmp->mx, mtmp->my);
  69.          u.uundetected = 0;
  70.          if (is_hider(youmonst.data) && u.umonnum != PM_TRAPPER) {
  71.              /* ceiling hider */
  72.              coord cc; /* maybe we need a unexto() function? */
  73.              struct obj *obj;
  74.  
  75.              You("fall from the %s!", ceiling(u.ux, u.uy));
  76.              /* take monster off map now so that its location
  77.                 is eligible for placing hero; we assume that a
  78.                 removed monster remembers its old spot <mx,my> */
  79.              remove_monster(mtmp->mx, mtmp->my);
  80.              if (!enexto(&cc, u.ux, u.uy, youmonst.data)
  81.                  /* a fish won't voluntarily swap positions
  82.                     when it's in water and hero is over land */
  83.                  || (mtmp->data->mlet == S_EEL
  84.                      && is_pool(mtmp->mx, mtmp->my)
  85.                      && !is_pool(u.ux, u.uy))) {
  86.                  /* couldn't find any spot for hero; this used to
  87.                     kill off attacker, but now we just give a "miss"
  88.                     message and keep both mtmp and hero at their
  89.                     original positions; hero has become unconcealed
  90.                     so mtmp's next move will be a regular attack */
  91.                  place_monster(mtmp, mtmp->mx, mtmp->my); /* put back */
  92.                  newsym(u.ux, u.uy); /* u.uundetected was toggled */
  93.                  pline("%s draws back as you drop!", Monnam(mtmp));
  94.                  return 0;
  95.              }
  96.  
  97.              /* put mtmp at hero's spot and move hero to <cc.x,.y> */
  98.              newsym(mtmp->mx, mtmp->my); /* finish removal */
  99.              place_monster(mtmp, u.ux, u.uy);
  100.              if (mtmp->wormno) {
  101.                  worm_move(mtmp);
  102.                  /* tail hasn't grown, so if it now occupies <cc.x,.y>
  103.                     then one of its original spots must be free */
  104.                  if (m_at(cc.x, cc.y))
  105.                      (void) enexto(&cc, u.ux, u.uy, youmonst.data);
  106.              }
  107.              teleds(cc.x, cc.y, TRUE); /* move hero */
  108.              set_apparxy(mtmp);
  109.              newsym(u.ux, u.uy);
  110.  
  111.              if (youmonst.data->mlet != S_PIERCER)
  112.                  return 0; /* lurkers don't attack */
  113.  
  114.              obj = which_armor(mtmp, WORN_HELMET);
  115.              if (obj && is_metallic(obj)) {
  116.                  Your("blow glances off %s %s.", s_suffix(mon_nam(mtmp)),
  117.                       helm_simple_name(obj));
  118.              } else {
  119.                  if (3 + find_mac(mtmp) <= rnd(20)) {
  120.                      pline("%s is hit by a falling piercer (you)!",
  121.                            Monnam(mtmp));
  122.                      if ((mtmp->mhp -= d(3, 6)) < 1)
  123.                          killed(mtmp);
  124.                  } else
  125.                      pline("%s is almost hit by a falling piercer (you)!",
  126.                            Monnam(mtmp));
  127.              }
  128.  
  129.          } else {
  130.              /* surface hider */
  131.              if (!youseeit) {
  132.                  pline("It tries to move where you are hiding.");
  133.              } else {
  134.                  /* Ugly kludge for eggs.  The message is phrased so as
  135.                   * to be directed at the monster, not the player,
  136.                   * which makes "laid by you" wrong.  For the
  137.                   * parallelism to work, we can't rephrase it, so we
  138.                   * zap the "laid by you" momentarily instead.
  139.                   */
  140.                  struct obj *obj = level.objects[u.ux][u.uy];
  141.  
  142.                  if (obj || u.umonnum == PM_TRAPPER
  143.                      || (youmonst.data->mlet == S_EEL
  144.                          && is_pool(u.ux, u.uy))) {
  145.                      int save_spe = 0; /* suppress warning */
  146.  
  147.                      if (obj) {
  148.                          save_spe = obj->spe;
  149.                          if (obj->otyp == EGG)
  150.                              obj->spe = 0;
  151.                      }
  152.                      /* note that m_monnam() overrides hallucination, which is
  153.                         what we want when message is from mtmp's perspective */
  154.                      if (youmonst.data->mlet == S_EEL
  155.                          || u.umonnum == PM_TRAPPER)
  156.                          pline(
  157.                               "Wait, %s!  There's a hidden %s named %s there!",
  158.                                m_monnam(mtmp), youmonst.data->mname, plname);
  159.                      else
  160.                          pline(
  161.                            "Wait, %s!  There's a %s named %s hiding under %s!",
  162.                                m_monnam(mtmp), youmonst.data->mname, plname,
  163.                                doname(level.objects[u.ux][u.uy]));
  164.                      if (obj)
  165.                          obj->spe = save_spe;
  166.                  } else
  167.                      impossible("hiding under nothing?");
  168.              }
  169.              newsym(u.ux, u.uy);
  170.          }
  171.          return 0;
  172.      }
  173.  
  174.      /* hero might be a mimic, concealed via #monster */
  175.      if (youmonst.data->mlet == S_MIMIC && youmonst.m_ap_type && !range2
  176.          && foundyou && !u.uswallow) {
  177.          boolean sticky = sticks(youmonst.data);
  178.  
  179.          if (!canspotmon(mtmp))
  180.              map_invisible(mtmp->mx, mtmp->my);
  181.          if (sticky && !youseeit)
  182.              pline("It gets stuck on you.");
  183.          else /* see note about m_monnam() above */
  184.              pline("Wait, %s!  That's a %s named %s!", m_monnam(mtmp),
  185.                    youmonst.data->mname, plname);
  186.          if (sticky)
  187.              u.ustuck = mtmp;
  188.          youmonst.m_ap_type = M_AP_NOTHING;
  189.          youmonst.mappearance = 0;
  190.          newsym(u.ux, u.uy);
  191.          return 0;
  192.      }
  193.  
  194.      /* non-mimic hero might be mimicking an object after eating m corpse */
  195.      if (youmonst.m_ap_type == M_AP_OBJECT && !range2 && foundyou
  196.          && !u.uswallow) {
  197.          if (!canspotmon(mtmp))
  198.              map_invisible(mtmp->mx, mtmp->my);
  199.          if (!youseeit)
  200.              pline("%s %s!", Something, (likes_gold(mtmp->data)
  201.                                          && youmonst.mappearance == GOLD_PIECE)
  202.                                             ? "tries to pick you up"
  203.                                             : "disturbs you");
  204.          else /* see note about m_monnam() above */
  205.              pline("Wait, %s!  That %s is really %s named %s!", m_monnam(mtmp),
  206.                    mimic_obj_name(&youmonst), an(mons[u.umonnum].mname),
  207.                    plname);
  208.          if (multi < 0) { /* this should always be the case */
  209.              char buf[BUFSZ];
  210.  
  211.              Sprintf(buf, "You appear to be %s again.",
  212.                      Upolyd ? (const char *) an(youmonst.data->mname)
  213.                             : (const char *) "yourself");
  214.              unmul(buf); /* immediately stop mimicking */
  215.          }
  216.          return 0;
  217.      }
  218.  
  219.      /*  Work out the armor class differential   */
  220.      tmp = AC_VALUE(u.uac) + 10; /* tmp ~= 0 - 20 */
  221.      tmp += mtmp->m_lev;
  222.      if (multi < 0)
  223.          tmp += 4;
  224.      if ((Invis && !perceives(mdat)) || !mtmp->mcansee)
  225.          tmp -= 2;
  226.      if (mtmp->mtrapped)
  227.          tmp -= 2;
  228.      if (tmp <= 0)
  229.          tmp = 1;
  230.  
  231.      /* make eels visible the moment they hit/miss us */
  232.      if (mdat->mlet == S_EEL && mtmp->minvis && cansee(mtmp->mx, mtmp->my)) {
  233.          mtmp->minvis = 0;
  234.          newsym(mtmp->mx, mtmp->my);
  235.      }
  236.  
  237.      /*  Special demon handling code */
  238.      if ((mtmp->cham == NON_PM) && is_demon(mdat) && !range2
  239.          && mtmp->data != &mons[PM_BALROG] && mtmp->data != &mons[PM_SUCCUBUS]
  240.          && mtmp->data != &mons[PM_INCUBUS])
  241.          if (!mtmp->mcan && !rn2(13))
  242.              (void) msummon(mtmp);
  243.  
  244.      /*  Special lycanthrope handling code */
  245.      if ((mtmp->cham == NON_PM) && is_were(mdat) && !range2) {
  246.          if (is_human(mdat)) {
  247.              if (!rn2(5 - (night() * 2)) && !mtmp->mcan)
  248.                  new_were(mtmp);
  249.          } else if (!rn2(30) && !mtmp->mcan)
  250.              new_were(mtmp);
  251.          mdat = mtmp->data;
  252.  
  253.          if (!rn2(10) && !mtmp->mcan) {
  254.              int numseen, numhelp;
  255.              char buf[BUFSZ], genericwere[BUFSZ];
  256.  
  257.              Strcpy(genericwere, "creature");
  258.              numhelp = were_summon(mdat, FALSE, &numseen, genericwere);
  259.              if (youseeit) {
  260.                  pline("%s summons help!", Monnam(mtmp));
  261.                  if (numhelp > 0) {
  262.                      if (numseen == 0)
  263.                          You_feel("hemmed in.");
  264.                  } else
  265.                      pline("But none comes.");
  266.              } else {
  267.                  const char *from_nowhere;
  268.  
  269.                  if (!Deaf) {
  270.                      pline("%s %s!", Something, makeplural(growl_sound(mtmp)));
  271.                      from_nowhere = "";
  272.                  } else
  273.                      from_nowhere = " from nowhere";
  274.                  if (numhelp > 0) {
  275.                      if (numseen < 1)
  276.                          You_feel("hemmed in.");
  277.                      else {
  278.                          if (numseen == 1)
  279.                              Sprintf(buf, "%s appears", an(genericwere));
  280.                          else
  281.                              Sprintf(buf, "%s appear",
  282.                                      makeplural(genericwere));
  283.                          pline("%s%s!", upstart(buf), from_nowhere);
  284.                      }
  285.                  } /* else no help came; but you didn't know it tried */
  286.              }
  287.          }
  288.      }
  289.  
  290.      if (u.uinvulnerable) {
  291.          /* monsters won't attack you */
  292.          if (mtmp == u.ustuck)
  293.              pline("%s loosens its grip slightly.", Monnam(mtmp));
  294.          else if (!range2) {
  295.              if (youseeit || sensemon(mtmp))
  296.                  pline("%s starts to attack you, but pulls back.",
  297.                        Monnam(mtmp));
  298.              else
  299.                  You_feel("%s move nearby.", something);
  300.          }
  301.          return 0;
  302.      }
  303.  
  304.      /* Unlike defensive stuff, don't let them use item _and_ attack. */
  305.      if (find_offensive(mtmp)) {
  306.          int foo = use_offensive(mtmp);
  307.  
  308.          if (foo != 0)
  309.              return (foo == 1);
  310.      }
  311.  
  312.      for (i = 0; i < NATTK; i++) {
  313.          sum[i] = 0;
  314.          mon_currwep = (struct obj *)0;
  315.          mattk = getmattk(mtmp, &youmonst, i, sum, &alt_attk);
  316.          if ((u.uswallow && mattk->aatyp != AT_ENGL)
  317.              || (skipnonmagc && mattk->aatyp != AT_MAGC))
  318.              continue;
  319.  
  320.          switch (mattk->aatyp) {
  321.          case AT_CLAW: /* "hand to hand" attacks */
  322.          case AT_KICK:
  323.          case AT_BITE:
  324.          case AT_STNG:
  325.          case AT_TUCH:
  326.          case AT_BUTT:
  327.          case AT_TENT:
  328.              if (!range2 && (!MON_WEP(mtmp) || mtmp->mconf || Conflict
  329.                              || !touch_petrifies(youmonst.data))) {
  330.                  if (foundyou) {
  331.                      if (tmp > (j = rnd(20 + i))) {
  332.                          if (mattk->aatyp != AT_KICK
  333.                              || !thick_skinned(youmonst.data))
  334.                              sum[i] = hitmu(mtmp, mattk);
  335.                      } else
  336.                          missmu(mtmp, (tmp == j), mattk);
  337.                  } else {
  338.                      wildmiss(mtmp, mattk);
  339.                      /* skip any remaining non-spell attacks */
  340.                      skipnonmagc = TRUE;
  341.                  }
  342.              }
  343.              break;
  344.  
  345.          case AT_HUGS: /* automatic if prev two attacks succeed */
  346.              /* Note: if displaced, prev attacks never succeeded */
  347.              if ((!range2 && i >= 2 && sum[i - 1] && sum[i - 2])
  348.                  || mtmp == u.ustuck)
  349.                  sum[i] = hitmu(mtmp, mattk);
  350.              break;
  351.  
  352.          case AT_GAZE: /* can affect you either ranged or not */
  353.              /* Medusa gaze already operated through m_respond in
  354.                 dochug(); don't gaze more than once per round. */
  355.              if (mdat != &mons[PM_MEDUSA])
  356.                  sum[i] = gazemu(mtmp, mattk);
  357.              break;
  358.  
  359.          case AT_EXPL: /* automatic hit if next to, and aimed at you */
  360.              if (!range2)
  361.                  sum[i] = explmu(mtmp, mattk, foundyou);
  362.              break;
  363.  
  364.          case AT_ENGL:
  365.              if (!range2) {
  366.                  if (foundyou) {
  367.                      if (u.uswallow
  368.                          || (!mtmp->mspec_used && tmp > (j = rnd(20 + i)))) {
  369.                          /* force swallowing monster to be displayed
  370.                             even when hero is moving away */
  371.                          flush_screen(1);
  372.                          sum[i] = gulpmu(mtmp, mattk);
  373.                      } else {
  374.                          missmu(mtmp, (tmp == j), mattk);
  375.                      }
  376.                  } else if (is_animal(mtmp->data)) {
  377.                      pline("%s gulps some air!", Monnam(mtmp));
  378.                  } else {
  379.                      if (youseeit)
  380.                          pline("%s lunges forward and recoils!", Monnam(mtmp));
  381.                      else
  382.                          You_hear("a %s nearby.",
  383.                                   is_whirly(mtmp->data) ? "rushing noise"
  384.                                                         : "splat");
  385.                  }
  386.              }
  387.              break;
  388.          case AT_BREA:
  389.              if (range2)
  390.                  sum[i] = breamu(mtmp, mattk);
  391.              /* Note: breamu takes care of displacement */
  392.              break;
  393.          case AT_SPIT:
  394.              if (range2)
  395.                  sum[i] = spitmu(mtmp, mattk);
  396.              /* Note: spitmu takes care of displacement */
  397.              break;
  398.          case AT_WEAP:
  399.              if (range2) {
  400.                  if (!Is_rogue_level(&u.uz))
  401.                      thrwmu(mtmp);
  402.              } else {
  403.                  int hittmp = 0;
  404.  
  405.                  /* Rare but not impossible.  Normally the monster
  406.                   * wields when 2 spaces away, but it can be
  407.                   * teleported or whatever....
  408.                   */
  409.                  if (mtmp->weapon_check == NEED_WEAPON || !MON_WEP(mtmp)) {
  410.                      mtmp->weapon_check = NEED_HTH_WEAPON;
  411.                      /* mon_wield_item resets weapon_check as appropriate */
  412.                      if (mon_wield_item(mtmp) != 0)
  413.                          break;
  414.                  }
  415.                  if (foundyou) {
  416.                      mon_currwep = MON_WEP(mtmp);
  417.                      if (mon_currwep) {
  418.                          hittmp = hitval(mon_currwep, &youmonst);
  419.                          tmp += hittmp;
  420.                          mswings(mtmp, mon_currwep);
  421.                      }
  422.                      if (tmp > (j = dieroll = rnd(20 + i)))
  423.                          sum[i] = hitmu(mtmp, mattk);
  424.                      else
  425.                          missmu(mtmp, (tmp == j), mattk);
  426.                      /* KMH -- Don't accumulate to-hit bonuses */
  427.                      if (mon_currwep)
  428.                          tmp -= hittmp;
  429.                  } else {
  430.                      wildmiss(mtmp, mattk);
  431.                      /* skip any remaining non-spell attacks */
  432.                      skipnonmagc = TRUE;
  433.                  }
  434.              }
  435.              break;
  436.          case AT_MAGC:
  437.              if (range2)
  438.                  sum[i] = buzzmu(mtmp, mattk);
  439.              else
  440.                  sum[i] = castmu(mtmp, mattk, TRUE, foundyou);
  441.              break;
  442.  
  443.          default: /* no attack */
  444.              break;
  445.          }
  446.          if (context.botl)
  447.              bot();
  448.          /* give player a chance of waking up before dying -kaa */
  449.          if (sum[i] == 1) { /* successful attack */
  450.              if (u.usleep && u.usleep < monstermoves && !rn2(10)) {
  451.                  multi = -1;
  452.                  nomovemsg = "The combat suddenly awakens you.";
  453.              }
  454.          }
  455.          if (sum[i] == 2)
  456.              return 1; /* attacker dead */
  457.          if (sum[i] == 3)
  458.              break; /* attacker teleported, no more attacks */
  459.          /* sum[i] == 0: unsuccessful attack */
  460.      }
  461.      return 0;
  462.  }
  463.  

diseasemu

  1.  STATIC_OVL boolean
  2.  diseasemu(mdat)
  3.  struct permonst *mdat;
  4.  {
  5.      if (Sick_resistance) {
  6.          You_feel("a slight illness.");
  7.          return FALSE;
  8.      } else {
  9.          make_sick(Sick ? Sick / 3L + 1L : (long) rn1(ACURR(A_CON), 20),
  10.                    mdat->mname, TRUE, SICK_NONVOMITABLE);
  11.          return TRUE;
  12.      }
  13.  }
  14.  

u_slip_free

  1.  /* check whether slippery clothing protects from hug or wrap attack */
  2.  STATIC_OVL boolean
  3.  u_slip_free(mtmp, mattk)
  4.  struct monst *mtmp;
  5.  struct attack *mattk;
  6.  {
  7.      struct obj *obj = (uarmc ? uarmc : uarm);
  8.  
  9.      if (!obj)
  10.          obj = uarmu;
  11.      if (mattk->adtyp == AD_DRIN)
  12.          obj = uarmh;
  13.  
  14.      /* if your cloak/armor is greased, monster slips off; this
  15.         protection might fail (33% chance) when the armor is cursed */
  16.      if (obj && (obj->greased || obj->otyp == OILSKIN_CLOAK)
  17.          && (!obj->cursed || rn2(3))) {
  18.          pline("%s %s your %s %s!", Monnam(mtmp),
  19.                (mattk->adtyp == AD_WRAP) ? "slips off of"
  20.                                          : "grabs you, but cannot hold onto",
  21.                obj->greased ? "greased" : "slippery",
  22.                /* avoid "slippery slippery cloak"
  23.                   for undiscovered oilskin cloak */
  24.                (obj->greased || objects[obj->otyp].oc_name_known)
  25.                    ? xname(obj)
  26.                    : cloak_simple_name(obj));
  27.  
  28.          if (obj->greased && !rn2(2)) {
  29.              pline_The("grease wears off.");
  30.              obj->greased = 0;
  31.              update_inventory();
  32.          }
  33.          return TRUE;
  34.      }
  35.      return FALSE;
  36.  }
  37.  

magic_negation

  1.  /* armor that sufficiently covers the body might be able to block magic */
  2.  int
  3.  magic_negation(mon)
  4.  struct monst *mon;
  5.  {
  6.      struct obj *o;
  7.      long wearmask;
  8.      int armpro, mc = 0;
  9.      boolean is_you = (mon == &youmonst),
  10.              gotprot = is_you ? (EProtection != 0L)
  11.                               /* high priests have innate protection */
  12.                               : (mon->data == &mons[PM_HIGH_PRIEST]);
  13.  
  14.      for (o = is_you ? invent : mon->minvent; o; o = o->nobj) {
  15.          /* a_can field is only applicable for armor (which must be worn) */
  16.          if ((o->owornmask & W_ARMOR) != 0L) {
  17.              armpro = objects[o->otyp].a_can;
  18.              if (armpro > mc)
  19.                  mc = armpro;
  20.          }
  21.          /* if we've already confirmed Protection, skip additional checks */
  22.          if (is_you || gotprot)
  23.              continue;
  24.  
  25.          /* omit W_SWAPWEP+W_QUIVER; W_ART+W_ARTI handled by protects() */
  26.          wearmask = W_ARMOR | W_ACCESSORY;
  27.          if (o->oclass == WEAPON_CLASS || is_weptool(o))
  28.              wearmask |= W_WEP;
  29.          if (protects(o, ((o->owornmask & wearmask) != 0L) ? TRUE : FALSE))
  30.              gotprot = TRUE;
  31.      }
  32.  
  33.      if (gotprot) {
  34.          /* extrinsic Protection increases mc by 1 */
  35.          if (mc < 3)
  36.              mc += 1;
  37.      } else if (mc < 1) {
  38.          /* intrinsic Protection is weaker (play balance; obtaining divine
  39.             protection is too easy); it confers minimum mc 1 instead of 0 */
  40.          if ((is_you && ((HProtection && u.ublessed > 0) || u.uspellprot))
  41.              /* aligned priests and angels have innate intrinsic Protection */
  42.              || (mon->data == &mons[PM_ALIGNED_PRIEST] || is_minion(mon->data)))
  43.              mc = 1;
  44.      }
  45.      return mc;
  46.  }
  47.  

hitmu

  1.  /*
  2.   * hitmu: monster hits you
  3.   *        returns 2 if monster dies (e.g. "yellow light"), 1 otherwise
  4.   *        3 if the monster lives but teleported/paralyzed, so it can't keep
  5.   *             attacking you
  6.   */
  7.  STATIC_OVL int
  8.  hitmu(mtmp, mattk)
  9.  register struct monst *mtmp;
  10.  register struct attack *mattk;
  11.  {
  12.      struct permonst *mdat = mtmp->data;
  13.      int uncancelled, ptmp;
  14.      int dmg, armpro, permdmg;
  15.      char buf[BUFSZ];
  16.      struct permonst *olduasmon = youmonst.data;
  17.      int res;
  18.  
  19.      if (!canspotmon(mtmp))
  20.          map_invisible(mtmp->mx, mtmp->my);
  21.  
  22.      /*  If the monster is undetected & hits you, you should know where
  23.       *  the attack came from.
  24.       */
  25.      if (mtmp->mundetected && (hides_under(mdat) || mdat->mlet == S_EEL)) {
  26.          mtmp->mundetected = 0;
  27.          if (!(Blind ? Blind_telepat : Unblind_telepat)) {
  28.              struct obj *obj;
  29.              const char *what;
  30.  
  31.              if ((obj = level.objects[mtmp->mx][mtmp->my]) != 0) {
  32.                  if (Blind && !obj->dknown)
  33.                      what = something;
  34.                  else if (is_pool(mtmp->mx, mtmp->my) && !Underwater)
  35.                      what = "the water";
  36.                  else
  37.                      what = doname(obj);
  38.  
  39.                  pline("%s was hidden under %s!", Amonnam(mtmp), what);
  40.              }
  41.              newsym(mtmp->mx, mtmp->my);
  42.          }
  43.      }
  44.  
  45.      /*  First determine the base damage done */
  46.      dmg = d((int) mattk->damn, (int) mattk->damd);
  47.      if ((is_undead(mdat) || is_vampshifter(mtmp)) && midnight())
  48.          dmg += d((int) mattk->damn, (int) mattk->damd); /* extra damage */
  49.  
  50.      /*  Next a cancellation factor.
  51.       *  Use uncancelled when cancellation factor takes into account certain
  52.       *  armor's special magic protection.  Otherwise just use !mtmp->mcan.
  53.       */
  54.      armpro = magic_negation(&youmonst);
  55.      uncancelled = !mtmp->mcan && (rn2(10) >= 3 * armpro);
  56.  
  57.      permdmg = 0;
  58.      /*  Now, adjust damages via resistances or specific attacks */
  59.      switch (mattk->adtyp) {
  60.      case AD_PHYS:
  61.          if (mattk->aatyp == AT_HUGS && !sticks(youmonst.data)) {
  62.              if (!u.ustuck && rn2(2)) {
  63.                  if (u_slip_free(mtmp, mattk)) {
  64.                      dmg = 0;
  65.                  } else {
  66.                      u.ustuck = mtmp;
  67.                      pline("%s grabs you!", Monnam(mtmp));
  68.                  }
  69.              } else if (u.ustuck == mtmp) {
  70.                  exercise(A_STR, FALSE);
  71.                  You("are being %s.", (mtmp->data == &mons[PM_ROPE_GOLEM])
  72.                                           ? "choked"
  73.                                           : "crushed");
  74.              }
  75.          } else { /* hand to hand weapon */
  76.              struct obj *otmp = mon_currwep;
  77.  
  78.              if (mattk->aatyp == AT_WEAP && otmp) {
  79.                  struct obj *marmg;
  80.                  int tmp;
  81.  
  82.                  if (otmp->otyp == CORPSE
  83.                      && touch_petrifies(&mons[otmp->corpsenm])) {
  84.                      dmg = 1;
  85.                      pline("%s hits you with the %s corpse.", Monnam(mtmp),
  86.                            mons[otmp->corpsenm].mname);
  87.                      if (!Stoned)
  88.                          goto do_stone;
  89.                  }
  90.                  dmg += dmgval(otmp, &youmonst);
  91.                  if ((marmg = which_armor(mtmp, W_ARMG)) != 0
  92.                      && marmg->otyp == GAUNTLETS_OF_POWER)
  93.                      dmg += rn1(4, 3); /* 3..6 */
  94.                  if (dmg <= 0)
  95.                      dmg = 1;
  96.                  if (!(otmp->oartifact
  97.                        && artifact_hit(mtmp, &youmonst, otmp, &dmg, dieroll)))
  98.                      hitmsg(mtmp, mattk);
  99.                  if (!dmg)
  100.                      break;
  101.                  if (objects[otmp->otyp].oc_material == SILVER
  102.                      && Hate_silver) {
  103.                      pline_The("silver sears your flesh!");
  104.                      exercise(A_CON, FALSE);
  105.                  }
  106.                  /* this redundancy necessary because you have
  107.                     to take the damage _before_ being cloned;
  108.                     need to have at least 2 hp left to split */
  109.                  tmp = dmg;
  110.                  if (u.uac < 0)
  111.                      tmp -= rnd(-u.uac);
  112.                  if (tmp < 1)
  113.                      tmp = 1;
  114.                  if (u.mh - tmp > 1
  115.                      && (objects[otmp->otyp].oc_material == IRON
  116.                          /* relevant 'metal' objects are scalpel and tsurugi */
  117.                          || objects[otmp->otyp].oc_material == METAL)
  118.                      && (u.umonnum == PM_BLACK_PUDDING
  119.                          || u.umonnum == PM_BROWN_PUDDING)) {
  120.                      if (tmp > 1)
  121.                          exercise(A_STR, FALSE);
  122.                      /* inflict damage now; we know it can't be fatal */
  123.                      u.mh -= tmp;
  124.                      context.botl = 1;
  125.                      dmg = 0; /* don't inflict more damage below */
  126.                      if (cloneu())
  127.                          You("divide as %s hits you!", mon_nam(mtmp));
  128.                  }
  129.                  rustm(&youmonst, otmp);
  130.              } else if (mattk->aatyp != AT_TUCH || dmg != 0
  131.                         || mtmp != u.ustuck)
  132.                  hitmsg(mtmp, mattk);
  133.          }
  134.          break;
  135.      case AD_DISE:
  136.          hitmsg(mtmp, mattk);
  137.          if (!diseasemu(mdat))
  138.              dmg = 0;
  139.          break;
  140.      case AD_FIRE:
  141.          hitmsg(mtmp, mattk);
  142.          if (uncancelled) {
  143.              pline("You're %s!", on_fire(youmonst.data, mattk));
  144.              if (completelyburns(youmonst.data)) { /* paper or straw golem */
  145.                  You("go up in flames!");
  146.                  /* KMH -- this is okay with unchanging */
  147.                  rehumanize();
  148.                  break;
  149.              } else if (Fire_resistance) {
  150.                  pline_The("fire doesn't feel hot!");
  151.                  dmg = 0;
  152.              }
  153.              if ((int) mtmp->m_lev > rn2(20))
  154.                  destroy_item(SCROLL_CLASS, AD_FIRE);
  155.              if ((int) mtmp->m_lev > rn2(20))
  156.                  destroy_item(POTION_CLASS, AD_FIRE);
  157.              if ((int) mtmp->m_lev > rn2(25))
  158.                  destroy_item(SPBOOK_CLASS, AD_FIRE);
  159.              burn_away_slime();
  160.          } else
  161.              dmg = 0;
  162.          break;
  163.      case AD_COLD:
  164.          hitmsg(mtmp, mattk);
  165.          if (uncancelled) {
  166.              pline("You're covered in frost!");
  167.              if (Cold_resistance) {
  168.                  pline_The("frost doesn't seem cold!");
  169.                  dmg = 0;
  170.              }
  171.              if ((int) mtmp->m_lev > rn2(20))
  172.                  destroy_item(POTION_CLASS, AD_COLD);
  173.          } else
  174.              dmg = 0;
  175.          break;
  176.      case AD_ELEC:
  177.          hitmsg(mtmp, mattk);
  178.          if (uncancelled) {
  179.              You("get zapped!");
  180.              if (Shock_resistance) {
  181.                  pline_The("zap doesn't shock you!");
  182.                  dmg = 0;
  183.              }
  184.              if ((int) mtmp->m_lev > rn2(20))
  185.                  destroy_item(WAND_CLASS, AD_ELEC);
  186.              if ((int) mtmp->m_lev > rn2(20))
  187.                  destroy_item(RING_CLASS, AD_ELEC);
  188.          } else
  189.              dmg = 0;
  190.          break;
  191.      case AD_SLEE:
  192.          hitmsg(mtmp, mattk);
  193.          if (uncancelled && multi >= 0 && !rn2(5)) {
  194.              if (Sleep_resistance)
  195.                  break;
  196.              fall_asleep(-rnd(10), TRUE);
  197.              if (Blind)
  198.                  You("are put to sleep!");
  199.              else
  200.                  You("are put to sleep by %s!", mon_nam(mtmp));
  201.          }
  202.          break;
  203.      case AD_BLND:
  204.          if (can_blnd(mtmp, &youmonst, mattk->aatyp, (struct obj *) 0)) {
  205.              if (!Blind)
  206.                  pline("%s blinds you!", Monnam(mtmp));
  207.              make_blinded(Blinded + (long) dmg, FALSE);
  208.              if (!Blind)
  209.                  Your1(vision_clears);
  210.          }
  211.          dmg = 0;
  212.          break;
  213.      case AD_DRST:
  214.          ptmp = A_STR;
  215.          goto dopois;
  216.      case AD_DRDX:
  217.          ptmp = A_DEX;
  218.          goto dopois;
  219.      case AD_DRCO:
  220.          ptmp = A_CON;
  221.      dopois:
  222.          hitmsg(mtmp, mattk);
  223.          if (uncancelled && !rn2(8)) {
  224.              Sprintf(buf, "%s %s", s_suffix(Monnam(mtmp)),
  225.                      mpoisons_subj(mtmp, mattk));
  226.              poisoned(buf, ptmp, mdat->mname, 30, FALSE);
  227.          }
  228.          break;
  229.      case AD_DRIN:
  230.          hitmsg(mtmp, mattk);
  231.          if (defends(AD_DRIN, uwep) || !has_head(youmonst.data)) {
  232.              You("don't seem harmed.");
  233.              /* Not clear what to do for green slimes */
  234.              break;
  235.          }
  236.          if (u_slip_free(mtmp, mattk))
  237.              break;
  238.  
  239.          if (uarmh && rn2(8)) {
  240.              /* not body_part(HEAD) */
  241.              Your("%s blocks the attack to your head.",
  242.                   helm_simple_name(uarmh));
  243.              break;
  244.          }
  245.          /* negative armor class doesn't reduce this damage */
  246.          if (Half_physical_damage)
  247.              dmg = (dmg + 1) / 2;
  248.          mdamageu(mtmp, dmg);
  249.          dmg = 0; /* don't inflict a second dose below */
  250.  
  251.          if (!uarmh || uarmh->otyp != DUNCE_CAP) {
  252.              /* eat_brains() will miss if target is mindless (won't
  253.                 happen here; hero is considered to retain his mind
  254.                 regardless of current shape) or is noncorporeal
  255.                 (can't happen here; no one can poly into a ghost
  256.                 or shade) so this check for missing is academic */
  257.              if (eat_brains(mtmp, &youmonst, TRUE, (int *) 0) == MM_MISS)
  258.                  break;
  259.          }
  260.          /* adjattrib gives dunce cap message when appropriate */
  261.          (void) adjattrib(A_INT, -rnd(2), FALSE);
  262.          forget_levels(25);  /* lose memory of 25% of levels */
  263.          forget_objects(25); /* lose memory of 25% of objects */
  264.          break;
  265.      case AD_PLYS:
  266.          hitmsg(mtmp, mattk);
  267.          if (uncancelled && multi >= 0 && !rn2(3)) {
  268.              if (Free_action) {
  269.                  You("momentarily stiffen.");
  270.              } else {
  271.                  if (Blind)
  272.                      You("are frozen!");
  273.                  else
  274.                      You("are frozen by %s!", mon_nam(mtmp));
  275.                  nomovemsg = You_can_move_again;
  276.                  nomul(-rnd(10));
  277.                  multi_reason = "paralyzed by a monster";
  278.                  exercise(A_DEX, FALSE);
  279.              }
  280.          }
  281.          break;
  282.      case AD_DRLI:
  283.          hitmsg(mtmp, mattk);
  284.          if (uncancelled && !rn2(3) && !Drain_resistance) {
  285.              losexp("life drainage");
  286.          }
  287.          break;
  288.      case AD_LEGS: {
  289.          long side = rn2(2) ? RIGHT_SIDE : LEFT_SIDE;
  290.          const char *sidestr = (side == RIGHT_SIDE) ? "right" : "left",
  291.                     *Monst_name = Monnam(mtmp), *leg = body_part(LEG);
  292.  
  293.          /* This case is too obvious to ignore, but Nethack is not in
  294.           * general very good at considering height--most short monsters
  295.           * still _can_ attack you when you're flying or mounted.
  296.           * [FIXME: why can't a flying attacker overcome this?]
  297.           */
  298.          if (u.usteed || Levitation || Flying) {
  299.              pline("%s tries to reach your %s %s!", Monst_name, sidestr, leg);
  300.              dmg = 0;
  301.          } else if (mtmp->mcan) {
  302.              pline("%s nuzzles against your %s %s!", Monnam(mtmp),
  303.                    sidestr, leg);
  304.              dmg = 0;
  305.          } else {
  306.              if (uarmf) {
  307.                  if (rn2(2) && (uarmf->otyp == LOW_BOOTS
  308.                                 || uarmf->otyp == IRON_SHOES)) {
  309.                      pline("%s pricks the exposed part of your %s %s!",
  310.                            Monst_name, sidestr, leg);
  311.                  } else if (!rn2(5)) {
  312.                      pline("%s pricks through your %s boot!", Monst_name,
  313.                            sidestr);
  314.                  } else {
  315.                      pline("%s scratches your %s boot!", Monst_name,
  316.                            sidestr);
  317.                      dmg = 0;
  318.                      break;
  319.                  }
  320.              } else
  321.                  pline("%s pricks your %s %s!", Monst_name, sidestr, leg);
  322.  
  323.              set_wounded_legs(side, rnd(60 - ACURR(A_DEX)));
  324.              exercise(A_STR, FALSE);
  325.              exercise(A_DEX, FALSE);
  326.          }
  327.          break;
  328.      }
  329.      case AD_STON: /* cockatrice */
  330.          hitmsg(mtmp, mattk);
  331.          if (!rn2(3)) {
  332.              if (mtmp->mcan) {
  333.                  if (!Deaf)
  334.                      You_hear("a cough from %s!", mon_nam(mtmp));
  335.              } else {
  336.                  if (!Deaf)
  337.                      You_hear("%s hissing!", s_suffix(mon_nam(mtmp)));
  338.                  if (!rn2(10)
  339.                      || (flags.moonphase == NEW_MOON && !have_lizard())) {
  340.                  do_stone:
  341.                      if (!Stoned && !Stone_resistance
  342.                          && !(poly_when_stoned(youmonst.data)
  343.                               && polymon(PM_STONE_GOLEM))) {
  344.                          int kformat = KILLED_BY_AN;
  345.                          const char *kname = mtmp->data->mname;
  346.  
  347.                          if (mtmp->data->geno & G_UNIQ) {
  348.                              if (!type_is_pname(mtmp->data))
  349.                                  kname = the(kname);
  350.                              kformat = KILLED_BY;
  351.                          }
  352.                          make_stoned(5L, (char *) 0, kformat, kname);
  353.                          return 1;
  354.                          /* done_in_by(mtmp, STONING); */
  355.                      }
  356.                  }
  357.              }
  358.          }
  359.          break;
  360.      case AD_STCK:
  361.          hitmsg(mtmp, mattk);
  362.          if (uncancelled && !u.ustuck && !sticks(youmonst.data))
  363.              u.ustuck = mtmp;
  364.          break;
  365.      case AD_WRAP:
  366.          if ((!mtmp->mcan || u.ustuck == mtmp) && !sticks(youmonst.data)) {
  367.              if (!u.ustuck && !rn2(10)) {
  368.                  if (u_slip_free(mtmp, mattk)) {
  369.                      dmg = 0;
  370.                  } else {
  371.                      pline("%s swings itself around you!", Monnam(mtmp));
  372.                      u.ustuck = mtmp;
  373.                  }
  374.              } else if (u.ustuck == mtmp) {
  375.                  if (is_pool(mtmp->mx, mtmp->my) && !Swimming && !Amphibious) {
  376.                      boolean moat = (levl[mtmp->mx][mtmp->my].typ != POOL)
  377.                                     && (levl[mtmp->mx][mtmp->my].typ != WATER)
  378.                                     && !Is_medusa_level(&u.uz)
  379.                                     && !Is_waterlevel(&u.uz);
  380.  
  381.                      pline("%s drowns you...", Monnam(mtmp));
  382.                      killer.format = KILLED_BY_AN;
  383.                      Sprintf(killer.name, "%s by %s",
  384.                              moat ? "moat" : "pool of water",
  385.                              an(mtmp->data->mname));
  386.                      done(DROWNING);
  387.                  } else if (mattk->aatyp == AT_HUGS)
  388.                      You("are being crushed.");
  389.              } else {
  390.                  dmg = 0;
  391.                  if (flags.verbose)
  392.                      pline("%s brushes against your %s.", Monnam(mtmp),
  393.                            body_part(LEG));
  394.              }
  395.          } else
  396.              dmg = 0;
  397.          break;
  398.      case AD_WERE:
  399.          hitmsg(mtmp, mattk);
  400.          if (uncancelled && !rn2(4) && u.ulycn == NON_PM
  401.              && !Protection_from_shape_changers && !defends(AD_WERE, uwep)) {
  402.              You_feel("feverish.");
  403.              exercise(A_CON, FALSE);
  404.              set_ulycn(monsndx(mdat));
  405.              retouch_equipment(2);
  406.          }
  407.          break;
  408.      case AD_SGLD:
  409.          hitmsg(mtmp, mattk);
  410.          if (youmonst.data->mlet == mdat->mlet)
  411.              break;
  412.          if (!mtmp->mcan)
  413.              stealgold(mtmp);
  414.          break;
  415.  
  416.      case AD_SSEX:
  417.          if (SYSOPT_SEDUCE) {
  418.              if (could_seduce(mtmp, &youmonst, mattk) == 1 && !mtmp->mcan)
  419.                  if (doseduce(mtmp))
  420.                      return 3;
  421.              break;
  422.          }
  423.          /*FALLTHRU*/
  424.      case AD_SITM: /* for now these are the same */
  425.      case AD_SEDU:
  426.          if (is_animal(mtmp->data)) {
  427.              hitmsg(mtmp, mattk);
  428.              if (mtmp->mcan)
  429.                  break;
  430.              /* Continue below */
  431.          } else if (dmgtype(youmonst.data, AD_SEDU)
  432.                     || (SYSOPT_SEDUCE && dmgtype(youmonst.data, AD_SSEX))) {
  433.              pline("%s %s.", Monnam(mtmp),
  434.                    mtmp->minvent
  435.                        ? "brags about the goods some dungeon explorer provided"
  436.                    : "makes some remarks about how difficult theft is lately");
  437.              if (!tele_restrict(mtmp))
  438.                  (void) rloc(mtmp, TRUE);
  439.              return 3;
  440.          } else if (mtmp->mcan) {
  441.              if (!Blind)
  442.                  pline("%s tries to %s you, but you seem %s.",
  443.                        Adjmonnam(mtmp, "plain"),
  444.                        flags.female ? "charm" : "seduce",
  445.                        flags.female ? "unaffected" : "uninterested");
  446.              if (rn2(3)) {
  447.                  if (!tele_restrict(mtmp))
  448.                      (void) rloc(mtmp, TRUE);
  449.                  return 3;
  450.              }
  451.              break;
  452.          }
  453.          buf[0] = '\0';
  454.          switch (steal(mtmp, buf)) {
  455.          case -1:
  456.              return 2;
  457.          case 0:
  458.              break;
  459.          default:
  460.              if (!is_animal(mtmp->data) && !tele_restrict(mtmp))
  461.                  (void) rloc(mtmp, TRUE);
  462.              if (is_animal(mtmp->data) && *buf) {
  463.                  if (canseemon(mtmp))
  464.                      pline("%s tries to %s away with %s.", Monnam(mtmp),
  465.                            locomotion(mtmp->data, "run"), buf);
  466.              }
  467.              monflee(mtmp, 0, FALSE, FALSE);
  468.              return 3;
  469.          }
  470.          break;
  471.  
  472.      case AD_SAMU:
  473.          hitmsg(mtmp, mattk);
  474.          /* when the Wizard or quest nemesis hits, there's a 1/20 chance
  475.             to steal a quest artifact (any, not just the one for the hero's
  476.             own role) or the Amulet or one of the invocation tools */
  477.          if (!rn2(20))
  478.              stealamulet(mtmp);
  479.          break;
  480.  
  481.      case AD_TLPT:
  482.          hitmsg(mtmp, mattk);
  483.          if (uncancelled) {
  484.              if (flags.verbose)
  485.                  Your("position suddenly seems very uncertain!");
  486.              tele();
  487.          }
  488.          break;
  489.      case AD_RUST:
  490.          hitmsg(mtmp, mattk);
  491.          if (mtmp->mcan)
  492.              break;
  493.          if (u.umonnum == PM_IRON_GOLEM) {
  494.              You("rust!");
  495.              /* KMH -- this is okay with unchanging */
  496.              rehumanize();
  497.              break;
  498.          }
  499.          erode_armor(&youmonst, ERODE_RUST);
  500.          break;
  501.      case AD_CORR:
  502.          hitmsg(mtmp, mattk);
  503.          if (mtmp->mcan)
  504.              break;
  505.          erode_armor(&youmonst, ERODE_CORRODE);
  506.          break;
  507.      case AD_DCAY:
  508.          hitmsg(mtmp, mattk);
  509.          if (mtmp->mcan)
  510.              break;
  511.          if (u.umonnum == PM_WOOD_GOLEM || u.umonnum == PM_LEATHER_GOLEM) {
  512.              You("rot!");
  513.              /* KMH -- this is okay with unchanging */
  514.              rehumanize();
  515.              break;
  516.          }
  517.          erode_armor(&youmonst, ERODE_ROT);
  518.          break;
  519.      case AD_HEAL:
  520.          /* a cancelled nurse is just an ordinary monster,
  521.           * nurses don't heal those that cause petrification */
  522.          if (mtmp->mcan || (Upolyd && touch_petrifies(youmonst.data))) {
  523.              hitmsg(mtmp, mattk);
  524.              break;
  525.          }
  526.          if (!uwep && !uarmu && !uarm && !uarmc
  527.              && !uarms && !uarmg && !uarmf && !uarmh) {
  528.              boolean goaway = FALSE;
  529.  
  530.              pline("%s hits!  (I hope you don't mind.)", Monnam(mtmp));
  531.              if (Upolyd) {
  532.                  u.mh += rnd(7);
  533.                  if (!rn2(7)) {
  534.                      /* no upper limit necessary; effect is temporary */
  535.                      u.mhmax++;
  536.                      if (!rn2(13))
  537.                          goaway = TRUE;
  538.                  }
  539.                  if (u.mh > u.mhmax)
  540.                      u.mh = u.mhmax;
  541.              } else {
  542.                  u.uhp += rnd(7);
  543.                  if (!rn2(7)) {
  544.                      /* hard upper limit via nurse care: 25 * ulevel */
  545.                      if (u.uhpmax < 5 * u.ulevel + d(2 * u.ulevel, 10))
  546.                          u.uhpmax++;
  547.                      if (!rn2(13))
  548.                          goaway = TRUE;
  549.                  }
  550.                  if (u.uhp > u.uhpmax)
  551.                      u.uhp = u.uhpmax;
  552.              }
  553.              if (!rn2(3))
  554.                  exercise(A_STR, TRUE);
  555.              if (!rn2(3))
  556.                  exercise(A_CON, TRUE);
  557.              if (Sick)
  558.                  make_sick(0L, (char *) 0, FALSE, SICK_ALL);
  559.              context.botl = 1;
  560.              if (goaway) {
  561.                  mongone(mtmp);
  562.                  return 2;
  563.              } else if (!rn2(33)) {
  564.                  if (!tele_restrict(mtmp))
  565.                      (void) rloc(mtmp, TRUE);
  566.                  monflee(mtmp, d(3, 6), TRUE, FALSE);
  567.                  return 3;
  568.              }
  569.              dmg = 0;
  570.          } else {
  571.              if (Role_if(PM_HEALER)) {
  572.                  if (!Deaf && !(moves % 5))
  573.                      verbalize("Doc, I can't help you unless you cooperate.");
  574.                  dmg = 0;
  575.              } else
  576.                  hitmsg(mtmp, mattk);
  577.          }
  578.          break;
  579.      case AD_CURS:
  580.          hitmsg(mtmp, mattk);
  581.          if (!night() && mdat == &mons[PM_GREMLIN])
  582.              break;
  583.          if (!mtmp->mcan && !rn2(10)) {
  584.              if (!Deaf) {
  585.                  if (Blind)
  586.                      You_hear("laughter.");
  587.                  else
  588.                      pline("%s chuckles.", Monnam(mtmp));
  589.              }
  590.              if (u.umonnum == PM_CLAY_GOLEM) {
  591.                  pline("Some writing vanishes from your head!");
  592.                  /* KMH -- this is okay with unchanging */
  593.                  rehumanize();
  594.                  break;
  595.              }
  596.              attrcurse();
  597.          }
  598.          break;
  599.      case AD_STUN:
  600.          hitmsg(mtmp, mattk);
  601.          if (!mtmp->mcan && !rn2(4)) {
  602.              make_stunned((HStun & TIMEOUT) + (long) dmg, TRUE);
  603.              dmg /= 2;
  604.          }
  605.          break;
  606.      case AD_ACID:
  607.          hitmsg(mtmp, mattk);
  608.          if (!mtmp->mcan && !rn2(3))
  609.              if (Acid_resistance) {
  610.                  pline("You're covered in %s, but it seems harmless.",
  611.                        hliquid("acid"));
  612.                  dmg = 0;
  613.              } else {
  614.                  pline("You're covered in %s!  It burns!", hliquid("acid"));
  615.                  exercise(A_STR, FALSE);
  616.              }
  617.          else
  618.              dmg = 0;
  619.          break;
  620.      case AD_SLOW:
  621.          hitmsg(mtmp, mattk);
  622.          if (uncancelled && HFast && !defends(AD_SLOW, uwep) && !rn2(4))
  623.              u_slow_down();
  624.          break;
  625.      case AD_DREN:
  626.          hitmsg(mtmp, mattk);
  627.          if (uncancelled && !rn2(4)) /* 25% chance */
  628.              drain_en(dmg);
  629.          dmg = 0;
  630.          break;
  631.      case AD_CONF:
  632.          hitmsg(mtmp, mattk);
  633.          if (!mtmp->mcan && !rn2(4) && !mtmp->mspec_used) {
  634.              mtmp->mspec_used = mtmp->mspec_used + (dmg + rn2(6));
  635.              if (Confusion)
  636.                  You("are getting even more confused.");
  637.              else
  638.                  You("are getting confused.");
  639.              make_confused(HConfusion + dmg, FALSE);
  640.          }
  641.          dmg = 0;
  642.          break;
  643.      case AD_DETH:
  644.          pline("%s reaches out with its deadly touch.", Monnam(mtmp));
  645.          if (is_undead(youmonst.data)) {
  646.              /* Still does normal damage */
  647.              pline("Was that the touch of death?");
  648.              break;
  649.          }
  650.          switch (rn2(20)) {
  651.          case 19:
  652.          case 18:
  653.          case 17:
  654.              if (!Antimagic) {
  655.                  killer.format = KILLED_BY_AN;
  656.                  Strcpy(killer.name, "touch of death");
  657.                  done(DIED);
  658.                  dmg = 0;
  659.                  break;
  660.              }
  661.              /*FALLTHRU*/
  662.          default: /* case 16: ... case 5: */
  663.              You_feel("your life force draining away...");
  664.              permdmg = 1; /* actual damage done below */
  665.              break;
  666.          case 4:
  667.          case 3:
  668.          case 2:
  669.          case 1:
  670.          case 0:
  671.              if (Antimagic)
  672.                  shieldeff(u.ux, u.uy);
  673.              pline("Lucky for you, it didn't work!");
  674.              dmg = 0;
  675.              break;
  676.          }
  677.          break;
  678.      case AD_PEST:
  679.          pline("%s reaches out, and you feel fever and chills.", Monnam(mtmp));
  680.          (void) diseasemu(mdat); /* plus the normal damage */
  681.          break;
  682.      case AD_FAMN:
  683.          pline("%s reaches out, and your body shrivels.", Monnam(mtmp));
  684.          exercise(A_CON, FALSE);
  685.          if (!is_fainted())
  686.              morehungry(rn1(40, 40));
  687.          /* plus the normal damage */
  688.          break;
  689.      case AD_SLIM:
  690.          hitmsg(mtmp, mattk);
  691.          if (!uncancelled)
  692.              break;
  693.          if (flaming(youmonst.data)) {
  694.              pline_The("slime burns away!");
  695.              dmg = 0;
  696.          } else if (Unchanging || noncorporeal(youmonst.data)
  697.                     || youmonst.data == &mons[PM_GREEN_SLIME]) {
  698.              You("are unaffected.");
  699.              dmg = 0;
  700.          } else if (!Slimed) {
  701.              You("don't feel very well.");
  702.              make_slimed(10L, (char *) 0);
  703.              delayed_killer(SLIMED, KILLED_BY_AN, mtmp->data->mname);
  704.          } else
  705.              pline("Yuck!");
  706.          break;
  707.      case AD_ENCH: /* KMH -- remove enchantment (disenchanter) */
  708.          hitmsg(mtmp, mattk);
  709.          /* uncancelled is sufficient enough; please
  710.             don't make this attack less frequent */
  711.          if (uncancelled) {
  712.              struct obj *obj = some_armor(&youmonst);
  713.  
  714.              if (!obj) {
  715.                  /* some rings are susceptible;
  716.                     amulets and blindfolds aren't (at present) */
  717.                  switch (rn2(5)) {
  718.                  case 0:
  719.                      break;
  720.                  case 1:
  721.                      obj = uright;
  722.                      break;
  723.                  case 2:
  724.                      obj = uleft;
  725.                      break;
  726.                  case 3:
  727.                      obj = uamul;
  728.                      break;
  729.                  case 4:
  730.                      obj = ublindf;
  731.                      break;
  732.                  }
  733.              }
  734.              if (drain_item(obj, FALSE)) {
  735.                  pline("%s less effective.", Yobjnam2(obj, "seem"));
  736.              }
  737.          }
  738.          break;
  739.      default:
  740.          dmg = 0;
  741.          break;
  742.      }
  743.      if ((Upolyd ? u.mh : u.uhp) < 1) {
  744.          /* already dead? call rehumanize() or done_in_by() as appropriate */
  745.          mdamageu(mtmp, 1);
  746.          dmg = 0;
  747.      }
  748.  
  749.      /*  Negative armor class reduces damage done instead of fully protecting
  750.       *  against hits.
  751.       */
  752.      if (dmg && u.uac < 0) {
  753.          dmg -= rnd(-u.uac);
  754.          if (dmg < 1)
  755.              dmg = 1;
  756.      }
  757.  
  758.      if (dmg) {
  759.          if (Half_physical_damage
  760.              /* Mitre of Holiness */
  761.              || (Role_if(PM_PRIEST) && uarmh && is_quest_artifact(uarmh)
  762.                  && (is_undead(mtmp->data) || is_demon(mtmp->data)
  763.                      || is_vampshifter(mtmp))))
  764.              dmg = (dmg + 1) / 2;
  765.  
  766.          if (permdmg) { /* Death's life force drain */
  767.              int lowerlimit, *hpmax_p;
  768.              /*
  769.               * Apply some of the damage to permanent hit points:
  770.               *  polymorphed         100% against poly'd hpmax
  771.               *  hpmax > 25*lvl      100% against normal hpmax
  772.               *  hpmax > 10*lvl  50..100%
  773.               *  hpmax >  5*lvl  25..75%
  774.               *  otherwise        0..50%
  775.               * Never reduces hpmax below 1 hit point per level.
  776.               */
  777.              permdmg = rn2(dmg / 2 + 1);
  778.              if (Upolyd || u.uhpmax > 25 * u.ulevel)
  779.                  permdmg = dmg;
  780.              else if (u.uhpmax > 10 * u.ulevel)
  781.                  permdmg += dmg / 2;
  782.              else if (u.uhpmax > 5 * u.ulevel)
  783.                  permdmg += dmg / 4;
  784.  
  785.              if (Upolyd) {
  786.                  hpmax_p = &u.mhmax;
  787.                  /* [can't use youmonst.m_lev] */
  788.                  lowerlimit = min((int) youmonst.data->mlevel, u.ulevel);
  789.              } else {
  790.                  hpmax_p = &u.uhpmax;
  791.                  lowerlimit = u.ulevel;
  792.              }
  793.              if (*hpmax_p - permdmg > lowerlimit)
  794.                  *hpmax_p -= permdmg;
  795.              else if (*hpmax_p > lowerlimit)
  796.                  *hpmax_p = lowerlimit;
  797.              /* else unlikely...
  798.               * already at or below minimum threshold; do nothing */
  799.              context.botl = 1;
  800.          }
  801.  
  802.          mdamageu(mtmp, dmg);
  803.      }
  804.  
  805.      if (dmg)
  806.          res = passiveum(olduasmon, mtmp, mattk);
  807.      else
  808.          res = 1;
  809.      stop_occupation();
  810.      return res;
  811.  }
  812.  

gulp_blnd_check

  1.  /* An interface for use when taking a blindfold off, for example,
  2.   * to see if an engulfing attack should immediately take affect, like
  3.   * a passive attack. TRUE if engulfing blindness occurred */
  4.  boolean
  5.  gulp_blnd_check()
  6.  {
  7.      struct attack *mattk;
  8.  
  9.      if (!Blinded && u.uswallow
  10.          && (mattk = attacktype_fordmg(u.ustuck->data, AT_ENGL, AD_BLND))
  11.          && can_blnd(u.ustuck, &youmonst, mattk->aatyp, (struct obj *) 0)) {
  12.          ++u.uswldtim; /* compensate for gulpmu change */
  13.          (void) gulpmu(u.ustuck, mattk);
  14.          return TRUE;
  15.      }
  16.      return FALSE;
  17.  }
  18.  

gulpmu

  1.  /* monster swallows you, or damage if u.uswallow */
  2.  STATIC_OVL int
  3.  gulpmu(mtmp, mattk)
  4.  struct monst *mtmp;
  5.  struct attack *mattk;
  6.  {
  7.      struct trap *t = t_at(u.ux, u.uy);
  8.      int tmp = d((int) mattk->damn, (int) mattk->damd);
  9.      int tim_tmp;
  10.      struct obj *otmp2;
  11.      int i;
  12.      boolean physical_damage = FALSE;
  13.  
  14.      if (!u.uswallow) { /* swallows you */
  15.          int omx = mtmp->mx, omy = mtmp->my;
  16.  
  17.          if (!engulf_target(mtmp, &youmonst))
  18.              return 0;
  19.          if ((t && ((t->ttyp == PIT) || (t->ttyp == SPIKED_PIT)))
  20.              && sobj_at(BOULDER, u.ux, u.uy))
  21.              return 0;
  22.  
  23.          if (Punished)
  24.              unplacebc(); /* ball&chain go away */
  25.          remove_monster(omx, omy);
  26.          mtmp->mtrapped = 0; /* no longer on old trap */
  27.          place_monster(mtmp, u.ux, u.uy);
  28.          u.ustuck = mtmp;
  29.          newsym(mtmp->mx, mtmp->my);
  30.          if (is_animal(mtmp->data) && u.usteed) {
  31.              char buf[BUFSZ];
  32.  
  33.              /* Too many quirks presently if hero and steed
  34.               * are swallowed. Pretend purple worms don't
  35.               * like horses for now :-)
  36.               */
  37.              Strcpy(buf, mon_nam(u.usteed));
  38.              pline("%s lunges forward and plucks you off %s!", Monnam(mtmp),
  39.                    buf);
  40.              dismount_steed(DISMOUNT_ENGULFED);
  41.          } else
  42.              pline("%s engulfs you!", Monnam(mtmp));
  43.          stop_occupation();
  44.          reset_occupations(); /* behave as if you had moved */
  45.  
  46.          if (u.utrap) {
  47.              You("are released from the %s!",
  48.                  u.utraptype == TT_WEB ? "web" : "trap");
  49.              u.utrap = 0;
  50.          }
  51.  
  52.          i = number_leashed();
  53.          if (i > 0) {
  54.              const char *s = (i > 1) ? "leashes" : "leash";
  55.  
  56.              pline_The("%s %s loose.", s, vtense(s, "snap"));
  57.              unleash_all();
  58.          }
  59.  
  60.          if (touch_petrifies(youmonst.data) && !resists_ston(mtmp)) {
  61.              /* put the attacker back where it started;
  62.                 the resulting statue will end up there */
  63.              remove_monster(mtmp->mx, mtmp->my); /* u.ux,u.uy */
  64.              place_monster(mtmp, omx, omy);
  65.              minstapetrify(mtmp, TRUE);
  66.              /* normally unstuck() would do this, but we're not
  67.                 fully swallowed yet so that won't work here */
  68.              if (Punished)
  69.                  placebc();
  70.              u.ustuck = 0;
  71.              return (mtmp->mhp > 0) ? 0 : 2;
  72.          }
  73.  
  74.          display_nhwindow(WIN_MESSAGE, FALSE);
  75.          vision_recalc(2); /* hero can't see anything */
  76.          u.uswallow = 1;
  77.          /* for digestion, shorter time is more dangerous;
  78.             for other swallowings, longer time means more
  79.             chances for the swallower to attack */
  80.          if (mattk->adtyp == AD_DGST) {
  81.              tim_tmp = 25 - (int) mtmp->m_lev;
  82.              if (tim_tmp > 0)
  83.                  tim_tmp = rnd(tim_tmp) / 2;
  84.              else if (tim_tmp < 0)
  85.                  tim_tmp = -(rnd(-tim_tmp) / 2);
  86.              /* having good armor & high constitution makes
  87.                 it take longer for you to be digested, but
  88.                 you'll end up trapped inside for longer too */
  89.              tim_tmp += -u.uac + 10 + (ACURR(A_CON) / 3 - 1);
  90.          } else {
  91.              /* higher level attacker takes longer to eject hero */
  92.              tim_tmp = rnd((int) mtmp->m_lev + 10 / 2);
  93.          }
  94.          /* u.uswldtim always set > 1 */
  95.          u.uswldtim = (unsigned) ((tim_tmp < 2) ? 2 : tim_tmp);
  96.          swallowed(1);
  97.          for (otmp2 = invent; otmp2; otmp2 = otmp2->nobj)
  98.              (void) snuff_lit(otmp2);
  99.      }
  100.  
  101.      if (mtmp != u.ustuck)
  102.          return 0;
  103.      if (u.uswldtim > 0)
  104.          u.uswldtim -= 1;
  105.  
  106.      switch (mattk->adtyp) {
  107.      case AD_DGST:
  108.          physical_damage = TRUE;
  109.          if (Slow_digestion) {
  110.              /* Messages are handled below */
  111.              u.uswldtim = 0;
  112.              tmp = 0;
  113.          } else if (u.uswldtim == 0) {
  114.              pline("%s totally digests you!", Monnam(mtmp));
  115.              tmp = u.uhp;
  116.              if (Half_physical_damage)
  117.                  tmp *= 2; /* sorry */
  118.          } else {
  119.              pline("%s%s digests you!", Monnam(mtmp),
  120.                    (u.uswldtim == 2) ? " thoroughly"
  121.                                      : (u.uswldtim == 1) ? " utterly" : "");
  122.              exercise(A_STR, FALSE);
  123.          }
  124.          break;
  125.      case AD_PHYS:
  126.          physical_damage = TRUE;
  127.          if (mtmp->data == &mons[PM_FOG_CLOUD]) {
  128.              You("are laden with moisture and %s",
  129.                  flaming(youmonst.data)
  130.                      ? "are smoldering out!"
  131.                      : Breathless ? "find it mildly uncomfortable."
  132.                                   : amphibious(youmonst.data)
  133.                                         ? "feel comforted."
  134.                                         : "can barely breathe!");
  135.              /* NB: Amphibious includes Breathless */
  136.              if (Amphibious && !flaming(youmonst.data))
  137.                  tmp = 0;
  138.          } else {
  139.              You("are pummeled with debris!");
  140.              exercise(A_STR, FALSE);
  141.          }
  142.          break;
  143.      case AD_ACID:
  144.          if (Acid_resistance) {
  145.              You("are covered with a seemingly harmless goo.");
  146.              tmp = 0;
  147.          } else {
  148.              if (Hallucination)
  149.                  pline("Ouch!  You've been slimed!");
  150.              else
  151.                  You("are covered in slime!  It burns!");
  152.              exercise(A_STR, FALSE);
  153.          }
  154.          break;
  155.      case AD_BLND:
  156.          if (can_blnd(mtmp, &youmonst, mattk->aatyp, (struct obj *) 0)) {
  157.              if (!Blind) {
  158.                  long was_blinded = Blinded;
  159.                  if (!Blinded)
  160.                      You_cant("see in here!");
  161.                  make_blinded((long) tmp, FALSE);
  162.                  if (!was_blinded && !Blind)
  163.                      Your1(vision_clears);
  164.              } else
  165.                  /* keep him blind until disgorged */
  166.                  make_blinded(Blinded + 1, FALSE);
  167.          }
  168.          tmp = 0;
  169.          break;
  170.      case AD_ELEC:
  171.          if (!mtmp->mcan && rn2(2)) {
  172.              pline_The("air around you crackles with electricity.");
  173.              if (Shock_resistance) {
  174.                  shieldeff(u.ux, u.uy);
  175.                  You("seem unhurt.");
  176.                  ugolemeffects(AD_ELEC, tmp);
  177.                  tmp = 0;
  178.              }
  179.          } else
  180.              tmp = 0;
  181.          break;
  182.      case AD_COLD:
  183.          if (!mtmp->mcan && rn2(2)) {
  184.              if (Cold_resistance) {
  185.                  shieldeff(u.ux, u.uy);
  186.                  You_feel("mildly chilly.");
  187.                  ugolemeffects(AD_COLD, tmp);
  188.                  tmp = 0;
  189.              } else
  190.                  You("are freezing to death!");
  191.          } else
  192.              tmp = 0;
  193.          break;
  194.      case AD_FIRE:
  195.          if (!mtmp->mcan && rn2(2)) {
  196.              if (Fire_resistance) {
  197.                  shieldeff(u.ux, u.uy);
  198.                  You_feel("mildly hot.");
  199.                  ugolemeffects(AD_FIRE, tmp);
  200.                  tmp = 0;
  201.              } else
  202.                  You("are burning to a crisp!");
  203.              burn_away_slime();
  204.          } else
  205.              tmp = 0;
  206.          break;
  207.      case AD_DISE:
  208.          if (!diseasemu(mtmp->data))
  209.              tmp = 0;
  210.          break;
  211.      case AD_DREN:
  212.          /* AC magic cancellation doesn't help when engulfed */
  213.          if (!mtmp->mcan && rn2(4)) /* 75% chance */
  214.              drain_en(tmp);
  215.          tmp = 0;
  216.          break;
  217.      default:
  218.          physical_damage = TRUE;
  219.          tmp = 0;
  220.          break;
  221.      }
  222.  
  223.      if (physical_damage)
  224.          tmp = Maybe_Half_Phys(tmp);
  225.  
  226.      mdamageu(mtmp, tmp);
  227.      if (tmp)
  228.          stop_occupation();
  229.  
  230.      if (touch_petrifies(youmonst.data) && !resists_ston(mtmp)) {
  231.          pline("%s very hurriedly %s you!", Monnam(mtmp),
  232.                is_animal(mtmp->data) ? "regurgitates" : "expels");
  233.          expels(mtmp, mtmp->data, FALSE);
  234.      } else if (!u.uswldtim || youmonst.data->msize >= MZ_HUGE) {
  235.          You("get %s!", is_animal(mtmp->data) ? "regurgitated" : "expelled");
  236.          if (flags.verbose
  237.              && (is_animal(mtmp->data)
  238.                  || (dmgtype(mtmp->data, AD_DGST) && Slow_digestion)))
  239.              pline("Obviously %s doesn't like your taste.", mon_nam(mtmp));
  240.          expels(mtmp, mtmp->data, FALSE);
  241.      }
  242.      return 1;
  243.  }
  244.  

explmu

  1.  /* monster explodes in your face */
  2.  STATIC_OVL int
  3.  explmu(mtmp, mattk, ufound)
  4.  struct monst *mtmp;
  5.  struct attack *mattk;
  6.  boolean ufound;
  7.  {
  8.      boolean physical_damage = TRUE, kill_agr = TRUE;
  9.  
  10.      if (mtmp->mcan)
  11.          return 0;
  12.  
  13.      if (!ufound)
  14.          pline("%s explodes at a spot in %s!",
  15.                canseemon(mtmp) ? Monnam(mtmp) : "It",
  16.                levl[mtmp->mux][mtmp->muy].typ == WATER ? "empty water"
  17.                                                        : "thin air");
  18.      else {
  19.          int tmp = d((int) mattk->damn, (int) mattk->damd);
  20.          boolean not_affected = defends((int) mattk->adtyp, uwep);
  21.  
  22.          hitmsg(mtmp, mattk);
  23.  
  24.          switch (mattk->adtyp) {
  25.          case AD_COLD:
  26.              physical_damage = FALSE;
  27.              not_affected |= Cold_resistance;
  28.              goto common;
  29.          case AD_FIRE:
  30.              physical_damage = FALSE;
  31.              not_affected |= Fire_resistance;
  32.              goto common;
  33.          case AD_ELEC:
  34.              physical_damage = FALSE;
  35.              not_affected |= Shock_resistance;
  36.          common:
  37.  
  38.              if (!not_affected) {
  39.                  if (ACURR(A_DEX) > rnd(20)) {
  40.                      You("duck some of the blast.");
  41.                      tmp = (tmp + 1) / 2;
  42.                  } else {
  43.                      if (flags.verbose)
  44.                          You("get blasted!");
  45.                  }
  46.                  if (mattk->adtyp == AD_FIRE)
  47.                      burn_away_slime();
  48.                  if (physical_damage)
  49.                      tmp = Maybe_Half_Phys(tmp);
  50.                  mdamageu(mtmp, tmp);
  51.              }
  52.              break;
  53.  
  54.          case AD_BLND:
  55.              not_affected = resists_blnd(&youmonst);
  56.              if (!not_affected) {
  57.                  /* sometimes you're affected even if it's invisible */
  58.                  if (mon_visible(mtmp) || (rnd(tmp /= 2) > u.ulevel)) {
  59.                      You("are blinded by a blast of light!");
  60.                      make_blinded((long) tmp, FALSE);
  61.                      if (!Blind)
  62.                          Your1(vision_clears);
  63.                  } else if (flags.verbose)
  64.                      You("get the impression it was not terribly bright.");
  65.              }
  66.              break;
  67.  
  68.          case AD_HALU:
  69.              not_affected |= Blind || (u.umonnum == PM_BLACK_LIGHT
  70.                                        || u.umonnum == PM_VIOLET_FUNGUS
  71.                                        || dmgtype(youmonst.data, AD_STUN));
  72.              if (!not_affected) {
  73.                  boolean chg;
  74.                  if (!Hallucination)
  75.                      You("are caught in a blast of kaleidoscopic light!");
  76.                  /* avoid hallucinating the black light as it dies */
  77.                  mondead(mtmp);    /* remove it from map now */
  78.                  kill_agr = FALSE; /* already killed (maybe lifesaved) */
  79.                  chg =
  80.                      make_hallucinated(HHallucination + (long) tmp, FALSE, 0L);
  81.                  You("%s.", chg ? "are freaked out" : "seem unaffected");
  82.              }
  83.              break;
  84.  
  85.          default:
  86.              break;
  87.          }
  88.          if (not_affected) {
  89.              You("seem unaffected by it.");
  90.              ugolemeffects((int) mattk->adtyp, tmp);
  91.          }
  92.      }
  93.      if (kill_agr)
  94.          mondead(mtmp);
  95.      wake_nearto(mtmp->mx, mtmp->my, 7 * 7);
  96.      return (mtmp->mhp > 0) ? 0 : 2;
  97.  }
  98.  

gazemu

  1.  /* monster gazes at you */
  2.  int
  3.  gazemu(mtmp, mattk)
  4.  struct monst *mtmp;
  5.  struct attack *mattk;
  6.  {
  7.      static const char *const reactions[] = {
  8.          "confused",              /* [0] */
  9.          "stunned",               /* [1] */
  10.          "puzzled",   "dazzled",  /* [2,3] */
  11.          "irritated", "inflamed", /* [4,5] */
  12.          "tired",                 /* [6] */
  13.          "dulled",                /* [7] */
  14.      };
  15.      int react = -1;
  16.      boolean cancelled = (mtmp->mcan != 0), already = FALSE;
  17.  
  18.      /* assumes that hero has to see monster's gaze in order to be
  19.         affected, rather than monster just having to look at hero;
  20.         when hallucinating, hero's brain doesn't register what
  21.         it's seeing correctly so the gaze is usually ineffective
  22.         [this could be taken a lot farther and select a gaze effect
  23.         appropriate to what's currently being displayed, giving
  24.         ordinary monsters a gaze attack when hero thinks he or she
  25.         is facing a gazing creature, but let's not go that far...] */
  26.      if (Hallucination && rn2(4))
  27.          cancelled = TRUE;
  28.  
  29.      switch (mattk->adtyp) {
  30.      case AD_STON:
  31.          if (cancelled || !mtmp->mcansee) {
  32.              if (!canseemon(mtmp))
  33.                  break; /* silently */
  34.              pline("%s %s.", Monnam(mtmp),
  35.                    (mtmp->data == &mons[PM_MEDUSA] && mtmp->mcan)
  36.                        ? "doesn't look all that ugly"
  37.                        : "gazes ineffectually");
  38.              break;
  39.          }
  40.          if (Reflecting && couldsee(mtmp->mx, mtmp->my)
  41.              && mtmp->data == &mons[PM_MEDUSA]) {
  42.              /* hero has line of sight to Medusa and she's not blind */
  43.              boolean useeit = canseemon(mtmp);
  44.  
  45.              if (useeit)
  46.                  (void) ureflects("%s gaze is reflected by your %s.",
  47.                                   s_suffix(Monnam(mtmp)));
  48.              if (mon_reflects(
  49.                      mtmp, !useeit ? (char *) 0
  50.                                    : "The gaze is reflected away by %s %s!"))
  51.                  break;
  52.              if (!m_canseeu(mtmp)) { /* probably you're invisible */
  53.                  if (useeit)
  54.                      pline(
  55.                        "%s doesn't seem to notice that %s gaze was reflected.",
  56.                            Monnam(mtmp), mhis(mtmp));
  57.                  break;
  58.              }
  59.              if (useeit)
  60.                  pline("%s is turned to stone!", Monnam(mtmp));
  61.              stoned = TRUE;
  62.              killed(mtmp);
  63.  
  64.              if (mtmp->mhp > 0)
  65.                  break;
  66.              return 2;
  67.          }
  68.          if (canseemon(mtmp) && couldsee(mtmp->mx, mtmp->my)
  69.              && !Stone_resistance) {
  70.              You("meet %s gaze.", s_suffix(mon_nam(mtmp)));
  71.              stop_occupation();
  72.              if (poly_when_stoned(youmonst.data) && polymon(PM_STONE_GOLEM))
  73.                  break;
  74.              You("turn to stone...");
  75.              killer.format = KILLED_BY;
  76.              Strcpy(killer.name, mtmp->data->mname);
  77.              done(STONING);
  78.          }
  79.          break;
  80.      case AD_CONF:
  81.          if (canseemon(mtmp) && couldsee(mtmp->mx, mtmp->my) && mtmp->mcansee
  82.              && !mtmp->mspec_used && rn2(5)) {
  83.              if (cancelled) {
  84.                  react = 0; /* "confused" */
  85.                  already = (mtmp->mconf != 0);
  86.              } else {
  87.                  int conf = d(3, 4);
  88.  
  89.                  mtmp->mspec_used = mtmp->mspec_used + (conf + rn2(6));
  90.                  if (!Confusion)
  91.                      pline("%s gaze confuses you!", s_suffix(Monnam(mtmp)));
  92.                  else
  93.                      You("are getting more and more confused.");
  94.                  make_confused(HConfusion + conf, FALSE);
  95.                  stop_occupation();
  96.              }
  97.          }
  98.          break;
  99.      case AD_STUN:
  100.          if (canseemon(mtmp) && couldsee(mtmp->mx, mtmp->my) && mtmp->mcansee
  101.              && !mtmp->mspec_used && rn2(5)) {
  102.              if (cancelled) {
  103.                  react = 1; /* "stunned" */
  104.                  already = (mtmp->mstun != 0);
  105.              } else {
  106.                  int stun = d(2, 6);
  107.  
  108.                  mtmp->mspec_used = mtmp->mspec_used + (stun + rn2(6));
  109.                  pline("%s stares piercingly at you!", Monnam(mtmp));
  110.                  make_stunned((HStun & TIMEOUT) + (long) stun, TRUE);
  111.                  stop_occupation();
  112.              }
  113.          }
  114.          break;
  115.      case AD_BLND:
  116.          if (canseemon(mtmp) && !resists_blnd(&youmonst)
  117.              && distu(mtmp->mx, mtmp->my) <= BOLT_LIM * BOLT_LIM) {
  118.              if (cancelled) {
  119.                  react = rn1(2, 2); /* "puzzled" || "dazzled" */
  120.                  already = (mtmp->mcansee == 0);
  121.                  /* Archons gaze every round; we don't want cancelled ones
  122.                     giving the "seems puzzled/dazzled" message that often */
  123.                  if (mtmp->mcan && mtmp->data == &mons[PM_ARCHON] && rn2(5))
  124.                      react = -1;
  125.              } else {
  126.                  int blnd = d((int) mattk->damn, (int) mattk->damd);
  127.  
  128.                  You("are blinded by %s radiance!", s_suffix(mon_nam(mtmp)));
  129.                  make_blinded((long) blnd, FALSE);
  130.                  stop_occupation();
  131.                  /* not blind at this point implies you're wearing
  132.                     the Eyes of the Overworld; make them block this
  133.                     particular stun attack too */
  134.                  if (!Blind) {
  135.                      Your1(vision_clears);
  136.                  } else {
  137.                      long oldstun = (HStun & TIMEOUT), newstun = (long) rnd(3);
  138.  
  139.                      /* we don't want to increment stun duration every time
  140.                         or sighted hero will become incapacitated */
  141.                      make_stunned(max(oldstun, newstun), TRUE);
  142.                  }
  143.              }
  144.          }
  145.          break;
  146.      case AD_FIRE:
  147.          if (canseemon(mtmp) && couldsee(mtmp->mx, mtmp->my) && mtmp->mcansee
  148.              && !mtmp->mspec_used && rn2(5)) {
  149.              if (cancelled) {
  150.                  react = rn1(2, 4); /* "irritated" || "inflamed" */
  151.              } else {
  152.                  int dmg = d(2, 6), lev = (int) mtmp->m_lev;
  153.  
  154.                  pline("%s attacks you with a fiery gaze!", Monnam(mtmp));
  155.                  stop_occupation();
  156.                  if (Fire_resistance) {
  157.                      pline_The("fire doesn't feel hot!");
  158.                      dmg = 0;
  159.                  }
  160.                  burn_away_slime();
  161.                  if (lev > rn2(20))
  162.                      destroy_item(SCROLL_CLASS, AD_FIRE);
  163.                  if (lev > rn2(20))
  164.                      destroy_item(POTION_CLASS, AD_FIRE);
  165.                  if (lev > rn2(25))
  166.                      destroy_item(SPBOOK_CLASS, AD_FIRE);
  167.                  if (dmg)
  168.                      mdamageu(mtmp, dmg);
  169.              }
  170.          }
  171.          break;
  172.  #ifdef PM_BEHOLDER /* work in progress */
  173.      case AD_SLEE:
  174.          if (canseemon(mtmp) && couldsee(mtmp->mx, mtmp->my) && mtmp->mcansee
  175.              && multi >= 0 && !rn2(5) && !Sleep_resistance) {
  176.              if (cancelled) {
  177.                  react = 6;                      /* "tired" */
  178.                  already = (mtmp->mfrozen != 0); /* can't happen... */
  179.              } else {
  180.                  fall_asleep(-rnd(10), TRUE);
  181.                  pline("%s gaze makes you very sleepy...",
  182.                        s_suffix(Monnam(mtmp)));
  183.              }
  184.          }
  185.          break;
  186.      case AD_SLOW:
  187.          if (canseemon(mtmp) && couldsee(mtmp->mx, mtmp->my) && mtmp->mcansee
  188.              && (HFast & (INTRINSIC | TIMEOUT)) && !defends(AD_SLOW, uwep)
  189.              && !rn2(4)) {
  190.              if (cancelled) {
  191.                  react = 7; /* "dulled" */
  192.                  already = (mtmp->mspeed == MSLOW);
  193.              } else {
  194.                  u_slow_down();
  195.                  stop_occupation();
  196.              }
  197.          }
  198.          break;
  199.  #endif /* BEHOLDER */
  200.      default:
  201.          impossible("Gaze attack %d?", mattk->adtyp);
  202.          break;
  203.      }
  204.      if (react >= 0) {
  205.          if (Hallucination && rn2(3))
  206.              react = rn2(SIZE(reactions));
  207.          /* cancelled/hallucinatory feedback; monster might look "confused",
  208.             "stunned",&c but we don't actually set corresponding attribute */
  209.          pline("%s looks %s%s.", Monnam(mtmp),
  210.                !rn2(3) ? "" : already ? "quite "
  211.                                       : (!rn2(2) ? "a bit " : "somewhat "),
  212.                reactions[react]);
  213.      }
  214.      return 0;
  215.  }
  216.  

mdamageu

  1.  /* mtmp hits you for n points damage */
  2.  void
  3.  mdamageu(mtmp, n)
  4.  struct monst *mtmp;
  5.  int n;
  6.  {
  7.      context.botl = 1;
  8.      if (Upolyd) {
  9.          u.mh -= n;
  10.          if (u.mh < 1)
  11.              rehumanize();
  12.      } else {
  13.          u.uhp -= n;
  14.          if (u.uhp < 1)
  15.              done_in_by(mtmp, DIED);
  16.      }
  17.  }
  18.  

could_seduce

  1.  /* returns 0 if seduction impossible,
  2.   *         1 if fine,
  3.   *         2 if wrong gender for nymph
  4.   */
  5.  int
  6.  could_seduce(magr, mdef, mattk)
  7.  struct monst *magr, *mdef;
  8.  struct attack *mattk;
  9.  {
  10.      struct permonst *pagr;
  11.      boolean agrinvis, defperc;
  12.      xchar genagr, gendef;
  13.  
  14.      if (is_animal(magr->data))
  15.          return 0;
  16.      if (magr == &youmonst) {
  17.          pagr = youmonst.data;
  18.          agrinvis = (Invis != 0);
  19.          genagr = poly_gender();
  20.      } else {
  21.          pagr = magr->data;
  22.          agrinvis = magr->minvis;
  23.          genagr = gender(magr);
  24.      }
  25.      if (mdef == &youmonst) {
  26.          defperc = (See_invisible != 0);
  27.          gendef = poly_gender();
  28.      } else {
  29.          defperc = perceives(mdef->data);
  30.          gendef = gender(mdef);
  31.      }
  32.  
  33.      if (agrinvis && !defperc
  34.          && (!SYSOPT_SEDUCE || (mattk && mattk->adtyp != AD_SSEX)))
  35.          return 0;
  36.  
  37.      if (pagr->mlet != S_NYMPH
  38.          && ((pagr != &mons[PM_INCUBUS] && pagr != &mons[PM_SUCCUBUS])
  39.              || (SYSOPT_SEDUCE && mattk && mattk->adtyp != AD_SSEX)))
  40.          return 0;
  41.  
  42.      if (genagr == 1 - gendef)
  43.          return 1;
  44.      else
  45.          return (pagr->mlet == S_NYMPH) ? 2 : 0;
  46.  }
  47.  

doseduce

  1.  /* Returns 1 if monster teleported */
  2.  int
  3.  doseduce(mon)
  4.  struct monst *mon;
  5.  {
  6.      struct obj *ring, *nring;
  7.      boolean fem = (mon->data == &mons[PM_SUCCUBUS]); /* otherwise incubus */
  8.      int attr_tot, tried_gloves = 0;
  9.      char qbuf[QBUFSZ];
  10.  
  11.      if (mon->mcan || mon->mspec_used) {
  12.          pline("%s acts as though %s has got a %sheadache.", Monnam(mon),
  13.                mhe(mon), mon->mcan ? "severe " : "");
  14.          return 0;
  15.      }
  16.  
  17.      if (unconscious()) {
  18.          pline("%s seems dismayed at your lack of response.", Monnam(mon));
  19.          return 0;
  20.      }
  21.  
  22.      if (Blind)
  23.          pline("It caresses you...");
  24.      else
  25.          You_feel("very attracted to %s.", mon_nam(mon));
  26.      /* if in the process of putting armor on or taking armor off,
  27.         interrupt that activity now */
  28.      (void) stop_donning((struct obj *) 0);
  29.      /* don't try to take off gloves if cursed weapon blocks them */
  30.      if (welded(uwep))
  31.          tried_gloves = 1;
  32.  
  33.      for (ring = invent; ring; ring = nring) {
  34.          nring = ring->nobj;
  35.          if (ring->otyp != RIN_ADORNMENT)
  36.              continue;
  37.          if (fem) {
  38.              if (ring->owornmask && uarmg) {
  39.                  /* don't take off worn ring if gloves are in the way */
  40.                  if (!tried_gloves++)
  41.                      mayberem(uarmg, "gloves");
  42.                  if (uarmg)
  43.                      continue; /* next ring might not be worn */
  44.              }
  45.              if (rn2(20) < ACURR(A_CHA)) {
  46.                  (void) safe_qbuf(qbuf, "\"That ",
  47.                                   " looks pretty.  May I have it?\"", ring,
  48.                                   xname, simpleonames, "ring");
  49.                  makeknown(RIN_ADORNMENT);
  50.                  if (yn(qbuf) == 'n')
  51.                      continue;
  52.              } else
  53.                  pline("%s decides she'd like %s, and takes it.",
  54.                        Blind ? "She" : Monnam(mon), yname(ring));
  55.              makeknown(RIN_ADORNMENT);
  56.              if (ring == uleft || ring == uright)
  57.                  Ring_gone(ring);
  58.              if (ring == uwep)
  59.                  setuwep((struct obj *) 0);
  60.              if (ring == uswapwep)
  61.                  setuswapwep((struct obj *) 0);
  62.              if (ring == uquiver)
  63.                  setuqwep((struct obj *) 0);
  64.              freeinv(ring);
  65.              (void) mpickobj(mon, ring);
  66.          } else {
  67.              if (uleft && uright && uleft->otyp == RIN_ADORNMENT
  68.                  && uright->otyp == RIN_ADORNMENT)
  69.                  break;
  70.              if (ring == uleft || ring == uright)
  71.                  continue;
  72.              if (uarmg) {
  73.                  /* don't put on ring if gloves are in the way */
  74.                  if (!tried_gloves++)
  75.                      mayberem(uarmg, "gloves");
  76.                  if (uarmg)
  77.                      break; /* no point trying further rings */
  78.              }
  79.              if (rn2(20) < ACURR(A_CHA)) {
  80.                  (void) safe_qbuf(qbuf, "\"That ",
  81.                                  " looks pretty.  Would you wear it for me?\"",
  82.                                   ring, xname, simpleonames, "ring");
  83.                  makeknown(RIN_ADORNMENT);
  84.                  if (yn(qbuf) == 'n')
  85.                      continue;
  86.              } else {
  87.                  pline("%s decides you'd look prettier wearing %s,",
  88.                        Blind ? "He" : Monnam(mon), yname(ring));
  89.                  pline("and puts it on your finger.");
  90.              }
  91.              makeknown(RIN_ADORNMENT);
  92.              if (!uright) {
  93.                  pline("%s puts %s on your right %s.",
  94.                        Blind ? "He" : Monnam(mon), the(xname(ring)),
  95.                        body_part(HAND));
  96.                  setworn(ring, RIGHT_RING);
  97.              } else if (!uleft) {
  98.                  pline("%s puts %s on your left %s.",
  99.                        Blind ? "He" : Monnam(mon), the(xname(ring)),
  100.                        body_part(HAND));
  101.                  setworn(ring, LEFT_RING);
  102.              } else if (uright && uright->otyp != RIN_ADORNMENT) {
  103.                  pline("%s replaces %s with %s.", Blind ? "He" : Monnam(mon),
  104.                        yname(uright), yname(ring));
  105.                  Ring_gone(uright);
  106.                  setworn(ring, RIGHT_RING);
  107.              } else if (uleft && uleft->otyp != RIN_ADORNMENT) {
  108.                  pline("%s replaces %s with %s.", Blind ? "He" : Monnam(mon),
  109.                        yname(uleft), yname(ring));
  110.                  Ring_gone(uleft);
  111.                  setworn(ring, LEFT_RING);
  112.              } else
  113.                  impossible("ring replacement");
  114.              Ring_on(ring);
  115.              prinv((char *) 0, ring, 0L);
  116.          }
  117.      }
  118.  
  119.      if (!uarmc && !uarmf && !uarmg && !uarms && !uarmh && !uarmu)
  120.          pline("%s murmurs sweet nothings into your ear.",
  121.                Blind ? (fem ? "She" : "He") : Monnam(mon));
  122.      else
  123.          pline("%s murmurs in your ear, while helping you undress.",
  124.                Blind ? (fem ? "She" : "He") : Monnam(mon));
  125.      mayberem(uarmc, cloak_simple_name(uarmc));
  126.      if (!uarmc)
  127.          mayberem(uarm, "suit");
  128.      mayberem(uarmf, "boots");
  129.      if (!tried_gloves)
  130.          mayberem(uarmg, "gloves");
  131.      mayberem(uarms, "shield");
  132.      mayberem(uarmh, helm_simple_name(uarmh));
  133.      if (!uarmc && !uarm)
  134.          mayberem(uarmu, "shirt");
  135.  
  136.      if (uarm || uarmc) {
  137.          verbalize("You're such a %s; I wish...",
  138.                    flags.female ? "sweet lady" : "nice guy");
  139.          if (!tele_restrict(mon))
  140.              (void) rloc(mon, TRUE);
  141.          return 1;
  142.      }
  143.      if (u.ualign.type == A_CHAOTIC)
  144.          adjalign(1);
  145.  
  146.      /* by this point you have discovered mon's identity, blind or not... */
  147.      pline("Time stands still while you and %s lie in each other's arms...",
  148.            noit_mon_nam(mon));
  149.      /* 3.6.1: a combined total for charisma plus intelligence of 35-1
  150.         used to guarantee successful outcome; now total maxes out at 32
  151.         as far as deciding what will happen; chance for bad outcome when
  152.         Cha+Int is 32 or more is 2/35, a bit over 5.7% */
  153.      attr_tot = ACURR(A_CHA) + ACURR(A_INT);
  154.      if (rn2(35) > min(attr_tot, 32)) {
  155.          /* Don't bother with mspec_used here... it didn't get tired! */
  156.          pline("%s seems to have enjoyed it more than you...",
  157.                noit_Monnam(mon));
  158.          switch (rn2(5)) {
  159.          case 0:
  160.              You_feel("drained of energy.");
  161.              u.uen = 0;
  162.              u.uenmax -= rnd(Half_physical_damage ? 5 : 10);
  163.              exercise(A_CON, FALSE);
  164.              if (u.uenmax < 0)
  165.                  u.uenmax = 0;
  166.              break;
  167.          case 1:
  168.              You("are down in the dumps.");
  169.              (void) adjattrib(A_CON, -1, TRUE);
  170.              exercise(A_CON, FALSE);
  171.              context.botl = 1;
  172.              break;
  173.          case 2:
  174.              Your("senses are dulled.");
  175.              (void) adjattrib(A_WIS, -1, TRUE);
  176.              exercise(A_WIS, FALSE);
  177.              context.botl = 1;
  178.              break;
  179.          case 3:
  180.              if (!resists_drli(&youmonst)) {
  181.                  You_feel("out of shape.");
  182.                  losexp("overexertion");
  183.              } else {
  184.                  You("have a curious feeling...");
  185.              }
  186.              exercise(A_CON, FALSE);
  187.              exercise(A_DEX, FALSE);
  188.              exercise(A_WIS, FALSE);
  189.              break;
  190.          case 4: {
  191.              int tmp;
  192.  
  193.              You_feel("exhausted.");
  194.              exercise(A_STR, FALSE);
  195.              tmp = rn1(10, 6);
  196.              losehp(Maybe_Half_Phys(tmp), "exhaustion", KILLED_BY);
  197.              break;
  198.          } /* case 4 */
  199.          } /* switch */
  200.      } else {
  201.          mon->mspec_used = rnd(100); /* monster is worn out */
  202.          You("seem to have enjoyed it more than %s...", noit_mon_nam(mon));
  203.          switch (rn2(5)) {
  204.          case 0:
  205.              You_feel("raised to your full potential.");
  206.              exercise(A_CON, TRUE);
  207.              u.uen = (u.uenmax += rnd(5));
  208.              break;
  209.          case 1:
  210.              You_feel("good enough to do it again.");
  211.              (void) adjattrib(A_CON, 1, TRUE);
  212.              exercise(A_CON, TRUE);
  213.              context.botl = 1;
  214.              break;
  215.          case 2:
  216.              You("will always remember %s...", noit_mon_nam(mon));
  217.              (void) adjattrib(A_WIS, 1, TRUE);
  218.              exercise(A_WIS, TRUE);
  219.              context.botl = 1;
  220.              break;
  221.          case 3:
  222.              pline("That was a very educational experience.");
  223.              pluslvl(FALSE);
  224.              exercise(A_WIS, TRUE);
  225.              break;
  226.          case 4:
  227.              You_feel("restored to health!");
  228.              u.uhp = u.uhpmax;
  229.              if (Upolyd)
  230.                  u.mh = u.mhmax;
  231.              exercise(A_STR, TRUE);
  232.              context.botl = 1;
  233.              break;
  234.          }
  235.      }
  236.  
  237.      if (mon->mtame) { /* don't charge */
  238.          ;
  239.      } else if (rn2(20) < ACURR(A_CHA)) {
  240.          pline("%s demands that you pay %s, but you refuse...",
  241.                noit_Monnam(mon), Blind ? (fem ? "her" : "him") : mhim(mon));
  242.      } else if (u.umonnum == PM_LEPRECHAUN) {
  243.          pline("%s tries to take your money, but fails...", noit_Monnam(mon));
  244.      } else {
  245.          long cost;
  246.          long umoney = money_cnt(invent);
  247.  
  248.          if (umoney > (long) LARGEST_INT - 10L)
  249.              cost = (long) rnd(LARGEST_INT) + 500L;
  250.          else
  251.              cost = (long) rnd((int) umoney + 10) + 500L;
  252.          if (mon->mpeaceful) {
  253.              cost /= 5L;
  254.              if (!cost)
  255.                  cost = 1L;
  256.          }
  257.          if (cost > umoney)
  258.              cost = umoney;
  259.          if (!cost) {
  260.              verbalize("It's on the house!");
  261.          } else {
  262.              pline("%s takes %ld %s for services rendered!", noit_Monnam(mon),
  263.                    cost, currency(cost));
  264.              money2mon(mon, cost);
  265.              context.botl = 1;
  266.          }
  267.      }
  268.      if (!rn2(25))
  269.          mon->mcan = 1; /* monster is worn out */
  270.      if (!tele_restrict(mon))
  271.          (void) rloc(mon, TRUE);
  272.      return 1;
  273.  }
  274.  

mayberem

  1.  STATIC_OVL void
  2.  mayberem(obj, str)
  3.  struct obj *obj;
  4.  const char *str;
  5.  {
  6.      char qbuf[QBUFSZ];
  7.  
  8.      if (!obj || !obj->owornmask)
  9.          return;
  10.  
  11.      if (rn2(20) < ACURR(A_CHA)) {
  12.          Sprintf(qbuf, "\"Shall I remove your %s, %s?\"", str,
  13.                  (!rn2(2) ? "lover" : !rn2(2) ? "dear" : "sweetheart"));
  14.          if (yn(qbuf) == 'n')
  15.              return;
  16.      } else {
  17.          char hairbuf[BUFSZ];
  18.  
  19.          Sprintf(hairbuf, "let me run my fingers through your %s",
  20.                  body_part(HAIR));
  21.          verbalize("Take off your %s; %s.", str,
  22.                    (obj == uarm)
  23.                       ? "let's get a little closer"
  24.                       : (obj == uarmc || obj == uarms)
  25.                          ? "it's in the way"
  26.                          : (obj == uarmf)
  27.                             ? "let me rub your feet"
  28.                             : (obj == uarmg)
  29.                                ? "they're too clumsy"
  30.                                : (obj == uarmu)
  31.                                   ? "let me massage you"
  32.                                   /* obj == uarmh */
  33.                                   : hairbuf);
  34.      }
  35.      remove_worn_item(obj, TRUE);
  36.  }
  37.  
  38.  /* FIXME:
  39.   *  sequencing issue:  a monster's attack might cause poly'd hero
  40.   *  to revert to normal form.  The messages for passive counterattack
  41.   *  would look better if they came before reverting form, but we need
  42.   *  to know whether hero reverted in order to decide whether passive
  43.   *  damage applies.
  44.   */

passiveum

  1.  STATIC_OVL int
  2.  passiveum(olduasmon, mtmp, mattk)
  3.  struct permonst *olduasmon;
  4.  struct monst *mtmp;
  5.  struct attack *mattk;
  6.  {
  7.      int i, tmp;
  8.      struct attack *oldu_mattk = 0;
  9.  
  10.      /*
  11.       * mattk      == mtmp's attack that hit you;
  12.       * oldu_mattk == your passive counterattack (even if mtmp's attack
  13.       *               has already caused you to revert to normal form).
  14.       */
  15.      for (i = 0; !oldu_mattk; i++) {
  16.          if (i >= NATTK)
  17.              return 1;
  18.          if (olduasmon->mattk[i].aatyp == AT_NONE
  19.              || olduasmon->mattk[i].aatyp == AT_BOOM)
  20.              oldu_mattk = &olduasmon->mattk[i];
  21.      }
  22.      if (oldu_mattk->damn)
  23.          tmp = d((int) oldu_mattk->damn, (int) oldu_mattk->damd);
  24.      else if (oldu_mattk->damd)
  25.          tmp = d((int) olduasmon->mlevel + 1, (int) oldu_mattk->damd);
  26.      else
  27.          tmp = 0;
  28.  
  29.      /* These affect the enemy even if you were "killed" (rehumanized) */
  30.      switch (oldu_mattk->adtyp) {
  31.      case AD_ACID:
  32.          if (!rn2(2)) {
  33.              pline("%s is splashed by %s%s!", Monnam(mtmp),
  34.                    /* temporary? hack for sequencing issue:  "your acid"
  35.                       looks strange coming immediately after player has
  36.                       been told that hero has reverted to normal form */
  37.                    !Upolyd ? "" : "your ", hliquid("acid"));
  38.              if (resists_acid(mtmp)) {
  39.                  pline("%s is not affected.", Monnam(mtmp));
  40.                  tmp = 0;
  41.              }
  42.          } else
  43.              tmp = 0;
  44.          if (!rn2(30))
  45.              erode_armor(mtmp, ERODE_CORRODE);
  46.          if (!rn2(6))
  47.              acid_damage(MON_WEP(mtmp));
  48.          goto assess_dmg;
  49.      case AD_STON: /* cockatrice */
  50.      {
  51.          long protector = attk_protection((int) mattk->aatyp),
  52.               wornitems = mtmp->misc_worn_check;
  53.  
  54.          /* wielded weapon gives same protection as gloves here */
  55.          if (MON_WEP(mtmp) != 0)
  56.              wornitems |= W_ARMG;
  57.  
  58.          if (!resists_ston(mtmp)
  59.              && (protector == 0L
  60.                  || (protector != ~0L
  61.                      && (wornitems & protector) != protector))) {
  62.              if (poly_when_stoned(mtmp->data)) {
  63.                  mon_to_stone(mtmp);
  64.                  return 1;
  65.              }
  66.              pline("%s turns to stone!", Monnam(mtmp));
  67.              stoned = 1;
  68.              xkilled(mtmp, XKILL_NOMSG);
  69.              if (mtmp->mhp > 0)
  70.                  return 1;
  71.              return 2;
  72.          }
  73.          return 1;
  74.      }
  75.      case AD_ENCH: /* KMH -- remove enchantment (disenchanter) */
  76.          if (mon_currwep) {
  77.              /* by_you==True: passive counterattack to hero's action
  78.                 is hero's fault */
  79.              (void) drain_item(mon_currwep, TRUE);
  80.              /* No message */
  81.          }
  82.          return 1;
  83.      default:
  84.          break;
  85.      }
  86.      if (!Upolyd)
  87.          return 1;
  88.  
  89.      /* These affect the enemy only if you are still a monster */
  90.      if (rn2(3))
  91.          switch (oldu_mattk->adtyp) {
  92.          case AD_PHYS:
  93.              if (oldu_mattk->aatyp == AT_BOOM) {
  94.                  You("explode!");
  95.                  /* KMH, balance patch -- this is okay with unchanging */
  96.                  rehumanize();
  97.                  goto assess_dmg;
  98.              }
  99.              break;
  100.          case AD_PLYS: /* Floating eye */
  101.              if (tmp > 127)
  102.                  tmp = 127;
  103.              if (u.umonnum == PM_FLOATING_EYE) {
  104.                  if (!rn2(4))
  105.                      tmp = 127;
  106.                  if (mtmp->mcansee && haseyes(mtmp->data) && rn2(3)
  107.                      && (perceives(mtmp->data) || !Invis)) {
  108.                      if (Blind)
  109.                          pline("As a blind %s, you cannot defend yourself.",
  110.                                youmonst.data->mname);
  111.                      else {
  112.                          if (mon_reflects(mtmp,
  113.                                           "Your gaze is reflected by %s %s."))
  114.                              return 1;
  115.                          pline("%s is frozen by your gaze!", Monnam(mtmp));
  116.                          paralyze_monst(mtmp, tmp);
  117.                          return 3;
  118.                      }
  119.                  }
  120.              } else { /* gelatinous cube */
  121.                  pline("%s is frozen by you.", Monnam(mtmp));
  122.                  paralyze_monst(mtmp, tmp);
  123.                  return 3;
  124.              }
  125.              return 1;
  126.          case AD_COLD: /* Brown mold or blue jelly */
  127.              if (resists_cold(mtmp)) {
  128.                  shieldeff(mtmp->mx, mtmp->my);
  129.                  pline("%s is mildly chilly.", Monnam(mtmp));
  130.                  golemeffects(mtmp, AD_COLD, tmp);
  131.                  tmp = 0;
  132.                  break;
  133.              }
  134.              pline("%s is suddenly very cold!", Monnam(mtmp));
  135.              u.mh += tmp / 2;
  136.              if (u.mhmax < u.mh)
  137.                  u.mhmax = u.mh;
  138.              if (u.mhmax > ((youmonst.data->mlevel + 1) * 8))
  139.                  (void) split_mon(&youmonst, mtmp);
  140.              break;
  141.          case AD_STUN: /* Yellow mold */
  142.              if (!mtmp->mstun) {
  143.                  mtmp->mstun = 1;
  144.                  pline("%s %s.", Monnam(mtmp),
  145.                        makeplural(stagger(mtmp->data, "stagger")));
  146.              }
  147.              tmp = 0;
  148.              break;
  149.          case AD_FIRE: /* Red mold */
  150.              if (resists_fire(mtmp)) {
  151.                  shieldeff(mtmp->mx, mtmp->my);
  152.                  pline("%s is mildly warm.", Monnam(mtmp));
  153.                  golemeffects(mtmp, AD_FIRE, tmp);
  154.                  tmp = 0;
  155.                  break;
  156.              }
  157.              pline("%s is suddenly very hot!", Monnam(mtmp));
  158.              break;
  159.          case AD_ELEC:
  160.              if (resists_elec(mtmp)) {
  161.                  shieldeff(mtmp->mx, mtmp->my);
  162.                  pline("%s is slightly tingled.", Monnam(mtmp));
  163.                  golemeffects(mtmp, AD_ELEC, tmp);
  164.                  tmp = 0;
  165.                  break;
  166.              }
  167.              pline("%s is jolted with your electricity!", Monnam(mtmp));
  168.              break;
  169.          default:
  170.              tmp = 0;
  171.              break;
  172.          }
  173.      else
  174.          tmp = 0;
  175.  
  176.  assess_dmg:
  177.      if ((mtmp->mhp -= tmp) <= 0) {
  178.          pline("%s dies!", Monnam(mtmp));
  179.          xkilled(mtmp, XKILL_NOMSG);
  180.          if (mtmp->mhp > 0)
  181.              return 1;
  182.          return 2;
  183.      }
  184.      return 1;
  185.  }
  186.  

cloneu

  1.  struct monst *
  2.  cloneu()
  3.  {
  4.      struct monst *mon;
  5.      int mndx = monsndx(youmonst.data);
  6.  
  7.      if (u.mh <= 1)
  8.          return (struct monst *) 0;
  9.      if (mvitals[mndx].mvflags & G_EXTINCT)
  10.          return (struct monst *) 0;
  11.      mon = makemon(youmonst.data, u.ux, u.uy, NO_MINVENT | MM_EDOG);
  12.      if (!mon)
  13.          return NULL;
  14.      mon->mcloned = 1;
  15.      mon = christen_monst(mon, plname);
  16.      initedog(mon);
  17.      mon->m_lev = youmonst.data->mlevel;
  18.      mon->mhpmax = u.mhmax;
  19.      mon->mhp = u.mh / 2;
  20.      u.mh -= mon->mhp;
  21.      context.botl = 1;
  22.      return mon;
  23.  }
  24.  
  25.  /*mhitu.c*/