Source:NetHack 3.6.1/src/mthrowu.c

From NetHackWiki
(Redirected from Source:Mthrowu.c)
Jump to: navigation, search

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

Top of file

  1.  /* NetHack 3.6	mthrowu.c	$NHDT-Date: 1514152830 2017/12/24 22:00:30 $  $NHDT-Branch: NetHack-3.6.0 $:$NHDT-Revision: 1.73 $ */
  2.  /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
  3.  /*-Copyright (c) Pasi Kallinen, 2016. */
  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.  
  4.  STATIC_DCL int FDECL(monmulti, (struct monst *, struct obj *, struct obj *));
  5.  STATIC_DCL void FDECL(monshoot, (struct monst *, struct obj *, struct obj *));
  6.  STATIC_DCL int FDECL(drop_throw, (struct obj *, BOOLEAN_P, int, int));
  7.  STATIC_DCL boolean FDECL(m_lined_up, (struct monst *, struct monst *));
  8.  
  9.  #define URETREATING(x, y) \
  10.      (distmin(u.ux, u.uy, x, y) > distmin(u.ux0, u.uy0, x, y))
  11.  
  12.  #define POLE_LIM 5 /* How far monsters can use pole-weapons */
  13.  
  14.  #define PET_MISSILE_RANGE2 36 /* Square of distance within which pets shoot */
  15.  
  16.  /*
  17.   * Keep consistent with breath weapons in zap.c, and AD_* in monattk.h.
  18.   */
  19.  STATIC_OVL NEARDATA const char *breathwep[] = {
  20.      "fragments", "fire", "frost", "sleep gas", "a disintegration blast",
  21.      "lightning", "poison gas", "acid", "strange breath #8",
  22.      "strange breath #9"
  23.  };
  24.  
  25.  extern boolean notonhead; /* for long worms */
  26.  STATIC_VAR int mesg_given; /* for m_throw()/thitu() 'miss' message */
  27.  

thitu

  1.  /* hero is hit by something other than a monster */
  2.  int
  3.  thitu(tlev, dam, objp, name)
  4.  int tlev, dam;
  5.  struct obj **objp;
  6.  const char *name; /* if null, then format `*objp' */
  7.  {
  8.      struct obj *obj = objp ? *objp : 0;
  9.      const char *onm, *knm;
  10.      boolean is_acid;
  11.      int kprefix = KILLED_BY_AN, dieroll;
  12.      char onmbuf[BUFSZ], knmbuf[BUFSZ];
  13.  
  14.      if (!name) {
  15.          if (!obj)
  16.              panic("thitu: name & obj both null?");
  17.          name = strcpy(onmbuf,
  18.                        (obj->quan > 1L) ? doname(obj) : mshot_xname(obj));
  19.          knm = strcpy(knmbuf, killer_xname(obj));
  20.          kprefix = KILLED_BY; /* killer_name supplies "an" if warranted */
  21.      } else {
  22.          knm = name;
  23.          /* [perhaps ought to check for plural here to] */
  24.          if (!strncmpi(name, "the ", 4) || !strncmpi(name, "an ", 3)
  25.              || !strncmpi(name, "a ", 2))
  26.              kprefix = KILLED_BY;
  27.      }
  28.      onm = (obj && obj_is_pname(obj)) ? the(name)
  29.            : (obj && obj->quan > 1L) ? name
  30.              : an(name);
  31.      is_acid = (obj && obj->otyp == ACID_VENOM);
  32.  
  33.      if (u.uac + tlev <= (dieroll = rnd(20))) {
  34.          ++mesg_given;
  35.          if (Blind || !flags.verbose) {
  36.              pline("It misses.");
  37.          } else if (u.uac + tlev <= dieroll - 2) {
  38.              if (onm != onmbuf)
  39.                  Strcpy(onmbuf, onm); /* [modifiable buffer for upstart()] */
  40.              pline("%s %s you.", upstart(onmbuf), vtense(onmbuf, "miss"));
  41.          } else
  42.              You("are almost hit by %s.", onm);
  43.          return 0;
  44.      } else {
  45.          if (Blind || !flags.verbose)
  46.              You("are hit%s", exclam(dam));
  47.          else
  48.              You("are hit by %s%s", onm, exclam(dam));
  49.  
  50.          if (is_acid && Acid_resistance) {
  51.              pline("It doesn't seem to hurt you.");
  52.          } else if (obj && obj->oclass == POTION_CLASS) {
  53.              /* an explosion which scatters objects might hit hero with one
  54.                 (potions deliberately thrown at hero are handled by m_throw) */
  55.              potionhit(&youmonst, obj, POTHIT_OTHER_THROW);
  56.              *objp = obj = 0; /* potionhit() uses up the potion */
  57.          } else {
  58.              if (obj && objects[obj->otyp].oc_material == SILVER
  59.                  && Hate_silver) {
  60.                  /* extra damage already applied by dmgval() */
  61.                  pline_The("silver sears your flesh!");
  62.                  exercise(A_CON, FALSE);
  63.              }
  64.              if (is_acid)
  65.                  pline("It burns!");
  66.              losehp(dam, knm, kprefix); /* acid damage */
  67.              exercise(A_STR, FALSE);
  68.          }
  69.          return 1;
  70.      }
  71.  }
  72.  

drop_throw

  1.  /* Be sure this corresponds with what happens to player-thrown objects in
  2.   * dothrow.c (for consistency). --KAA
  3.   * Returns 0 if object still exists (not destroyed).
  4.   */
  5.  STATIC_OVL int
  6.  drop_throw(obj, ohit, x, y)
  7.  register struct obj *obj;
  8.  boolean ohit;
  9.  int x, y;
  10.  {
  11.      int retvalu = 1;
  12.      int create;
  13.      struct monst *mtmp;
  14.      struct trap *t;
  15.  
  16.      if (obj->otyp == CREAM_PIE || obj->oclass == VENOM_CLASS
  17.          || (ohit && obj->otyp == EGG))
  18.          create = 0;
  19.      else if (ohit && (is_multigen(obj) || obj->otyp == ROCK))
  20.          create = !rn2(3);
  21.      else
  22.          create = 1;
  23.  
  24.      if (create && !((mtmp = m_at(x, y)) != 0 && mtmp->mtrapped
  25.                      && (t = t_at(x, y)) != 0
  26.                      && (t->ttyp == PIT || t->ttyp == SPIKED_PIT))) {
  27.          int objgone = 0;
  28.  
  29.          if (down_gate(x, y) != -1)
  30.              objgone = ship_object(obj, x, y, FALSE);
  31.          if (!objgone) {
  32.              if (!flooreffects(obj, x, y, "fall")) {
  33.                  place_object(obj, x, y);
  34.                  if (!mtmp && x == u.ux && y == u.uy)
  35.                      mtmp = &youmonst;
  36.                  if (mtmp && ohit)
  37.                      passive_obj(mtmp, obj, (struct attack *) 0);
  38.                  stackobj(obj);
  39.                  retvalu = 0;
  40.              }
  41.          }
  42.      } else
  43.          obfree(obj, (struct obj *) 0);
  44.      return retvalu;
  45.  }
  46.  
  47.  /* The monster that's being shot at when one monster shoots at another */
  48.  STATIC_OVL struct monst *target = 0;
  49.  /* The monster that's doing the shooting/throwing */
  50.  STATIC_OVL struct monst *archer = 0;
  51.  

monmulti

  1.  /* calculate multishot volley count for mtmp throwing otmp (if not ammo) or
  2.     shooting otmp with mwep (if otmp is ammo and mwep appropriate launcher) */
  3.  STATIC_OVL int
  4.  monmulti(mtmp, otmp, mwep)
  5.  struct monst *mtmp;
  6.  struct obj *otmp, *mwep;
  7.  {
  8.      int skill = (int) objects[otmp->otyp].oc_skill;
  9.      int multishot = 1;
  10.  
  11.      if (otmp->quan > 1L /* no point checking if there's only 1 */
  12.          /* ammo requires corresponding launcher be wielded */
  13.          && (is_ammo(otmp)
  14.                 ? matching_launcher(otmp, mwep)
  15.                 /* otherwise any stackable (non-ammo) weapon */
  16.                 : otmp->oclass == WEAPON_CLASS)
  17.          && !mtmp->mconf) {
  18.          /* Assumes lords are skilled, princes are expert */
  19.          if (is_prince(mtmp->data))
  20.              multishot += 2;
  21.          else if (is_lord(mtmp->data))
  22.              multishot++;
  23.          /* fake players treated as skilled (regardless of role limits) */
  24.          else if (is_mplayer(mtmp->data))
  25.              multishot++;
  26.  
  27.          /* this portion is different from hero multishot; from slash'em?
  28.           */
  29.          /* Elven Craftsmanship makes for light, quick bows */
  30.          if (otmp->otyp == ELVEN_ARROW && !otmp->cursed)
  31.              multishot++;
  32.          if (ammo_and_launcher(otmp, uwep) && mwep->otyp == ELVEN_BOW
  33.              && !mwep->cursed)
  34.              multishot++;
  35.          /* 1/3 of launcher enchantment */
  36.          if (ammo_and_launcher(otmp, mwep) && mwep->spe > 1)
  37.              multishot += (long) rounddiv(mwep->spe, 3);
  38.          /* Some randomness */
  39.          multishot = (long) rnd((int) multishot);
  40.  
  41.          /* class bonus */
  42.          switch (monsndx(mtmp->data)) {
  43.          case PM_CAVEMAN: /* give bonus for low-tech gear */
  44.              if (skill == -P_SLING || skill == P_SPEAR)
  45.                  multishot++;
  46.              break;
  47.          case PM_MONK: /* allow higher volley count */
  48.              if (skill == -P_SHURIKEN)
  49.                  multishot++;
  50.              break;
  51.          case PM_RANGER:
  52.              if (skill != P_DAGGER)
  53.                  multishot++;
  54.              break;
  55.          case PM_ROGUE:
  56.              if (skill == P_DAGGER)
  57.                  multishot++;
  58.              break;
  59.          case PM_NINJA:
  60.              if (skill == -P_SHURIKEN || skill == -P_DART)
  61.                  multishot++;
  62.              /*FALLTHRU*/
  63.          case PM_SAMURAI:
  64.              if (otmp->otyp == YA && mwep->otyp == YUMI)
  65.                  multishot++;
  66.              break;
  67.          default:
  68.              break;
  69.          }
  70.          /* racial bonus */
  71.          if ((is_elf(mtmp->data) && otmp->otyp == ELVEN_ARROW
  72.              && mwep->otyp == ELVEN_BOW)
  73.              || (is_orc(mtmp->data) && otmp->otyp == ORCISH_ARROW
  74.                  && mwep->otyp == ORCISH_BOW)
  75.              || (is_gnome(mtmp->data) && otmp->otyp == CROSSBOW_BOLT
  76.                  && mwep->otyp == CROSSBOW))
  77.              multishot++;
  78.      }
  79.  
  80.      if (otmp->quan < multishot)
  81.          multishot = (int) otmp->quan;
  82.      if (multishot < 1)
  83.          multishot = 1;
  84.      return multishot;
  85.  }
  86.  

monshoot

  1.  /* mtmp throws otmp, or shoots otmp with mwep, at hero or at monster mtarg */
  2.  STATIC_OVL void
  3.  monshoot(mtmp, otmp, mwep)
  4.  struct monst *mtmp;
  5.  struct obj *otmp, *mwep;
  6.  {
  7.      struct monst *mtarg = target;
  8.      int dm = distmin(mtmp->mx, mtmp->my,
  9.                       mtarg ? mtarg->mx : mtmp->mux,
  10.                       mtarg ? mtarg->my : mtmp->muy),
  11.          multishot = monmulti(mtmp, otmp, mwep);
  12.          /*
  13.           * Caller must have called linedup() to set up tbx, tby.
  14.           */
  15.  
  16.      if (canseemon(mtmp)) {
  17.          const char *onm;
  18.          char onmbuf[BUFSZ], trgbuf[BUFSZ];
  19.  
  20.          if (multishot > 1) {
  21.              /* "N arrows"; multishot > 1 implies otmp->quan > 1, so
  22.                 xname()'s result will already be pluralized */
  23.              Sprintf(onmbuf, "%d %s", multishot, xname(otmp));
  24.              onm = onmbuf;
  25.          } else {
  26.              /* "an arrow" */
  27.              onm = singular(otmp, xname);
  28.              onm = obj_is_pname(otmp) ? the(onm) : an(onm);
  29.          }
  30.          m_shot.s = ammo_and_launcher(otmp, mwep) ? TRUE : FALSE;
  31.          Strcpy(trgbuf, mtarg ? mon_nam(mtarg) : "");
  32.          if (!strcmp(trgbuf, "it"))
  33.              Strcpy(trgbuf, humanoid(mtmp->data) ? "someone" : something);
  34.          pline("%s %s %s%s%s!", Monnam(mtmp),
  35.                m_shot.s ? "shoots" : "throws", onm,
  36.                mtarg ? " at " : "", trgbuf);
  37.          m_shot.o = otmp->otyp;
  38.      } else {
  39.          m_shot.o = STRANGE_OBJECT; /* don't give multishot feedback */
  40.      }
  41.      m_shot.n = multishot;
  42.      for (m_shot.i = 1; m_shot.i <= m_shot.n; m_shot.i++) {
  43.          m_throw(mtmp, mtmp->mx, mtmp->my, sgn(tbx), sgn(tby), dm, otmp);
  44.          /* conceptually all N missiles are in flight at once, but
  45.             if mtmp gets killed (shot kills adjacent gas spore and
  46.             triggers explosion, perhaps), inventory will be dropped
  47.             and otmp might go away via merging into another stack */
  48.          if (mtmp->mhp <= 0 && m_shot.i < m_shot.n)
  49.              /* cancel pending shots (perhaps ought to give a message here
  50.                 since we gave one above about throwing/shooting N missiles) */
  51.              break; /* endmultishot(FALSE); */
  52.      }
  53.      /* reset 'm_shot' */
  54.      m_shot.n = m_shot.i = 0;
  55.      m_shot.o = STRANGE_OBJECT;
  56.      m_shot.s = FALSE;
  57.  }
  58.  

ohitmon

  1.  /* an object launched by someone/thing other than player attacks a monster;
  2.     return 1 if the object has stopped moving (hit or its range used up) */
  3.  int
  4.  ohitmon(mtmp, otmp, range, verbose)
  5.  struct monst *mtmp; /* accidental target, located at <bhitpos.x,.y> */
  6.  struct obj *otmp;   /* missile; might be destroyed by drop_throw */
  7.  int range;          /* how much farther will object travel if it misses;
  8.                         use -1 to signify to keep going even after hit,
  9.                         unless it's gone (used for rolling_boulder_traps) */
  10.  boolean verbose;    /* give message(s) even when you can't see what happened */
  11.  {
  12.      int damage, tmp;
  13.      boolean vis, ismimic;
  14.      int objgone = 1;
  15.      struct obj *mon_launcher = archer ? MON_WEP(archer) : NULL;
  16.  
  17.      notonhead = (bhitpos.x != mtmp->mx || bhitpos.y != mtmp->my);
  18.      ismimic = mtmp->m_ap_type && mtmp->m_ap_type != M_AP_MONSTER;
  19.      vis = cansee(bhitpos.x, bhitpos.y);
  20.  
  21.      tmp = 5 + find_mac(mtmp) + omon_adj(mtmp, otmp, FALSE);
  22.      /* High level monsters will be more likely to hit */
  23.      /* This check applies only if this monster is the target
  24.       * the archer was aiming at. */
  25.      if (archer && target == mtmp) {
  26.          if (archer->m_lev > 5)
  27.              tmp += archer->m_lev - 5;
  28.          if (mon_launcher && mon_launcher->oartifact)
  29.              tmp += spec_abon(mon_launcher, mtmp);
  30.      }
  31.      if (tmp < rnd(20)) {
  32.          if (!ismimic) {
  33.              if (vis)
  34.                  miss(distant_name(otmp, mshot_xname), mtmp);
  35.              else if (verbose && !target)
  36.                  pline("It is missed.");
  37.          }
  38.          if (!range) { /* Last position; object drops */
  39.              (void) drop_throw(otmp, 0, mtmp->mx, mtmp->my);
  40.              return 1;
  41.          }
  42.      } else if (otmp->oclass == POTION_CLASS) {
  43.          if (ismimic)
  44.              seemimic(mtmp);
  45.          mtmp->msleeping = 0;
  46.          if (vis)
  47.              otmp->dknown = 1;
  48.          /* probably thrown by a monster rather than 'other', but the
  49.             distinction only matters when hitting the hero */
  50.          potionhit(mtmp, otmp, POTHIT_OTHER_THROW);
  51.          return 1;
  52.      } else {
  53.          damage = dmgval(otmp, mtmp);
  54.          if (otmp->otyp == ACID_VENOM && resists_acid(mtmp))
  55.              damage = 0;
  56.          if (ismimic)
  57.              seemimic(mtmp);
  58.          mtmp->msleeping = 0;
  59.          if (vis) {
  60.              if (otmp->otyp == EGG)
  61.                  pline("Splat! %s is hit with %s egg!", Monnam(mtmp),
  62.                        otmp->known ? an(mons[otmp->corpsenm].mname) : "an");
  63.              else
  64.                  hit(distant_name(otmp, mshot_xname), mtmp, exclam(damage));
  65.          } else if (verbose && !target)
  66.              pline("%s%s is hit%s", (otmp->otyp == EGG) ? "Splat! " : "",
  67.                    Monnam(mtmp), exclam(damage));
  68.  
  69.          if (otmp->opoisoned && is_poisonable(otmp)) {
  70.              if (resists_poison(mtmp)) {
  71.                  if (vis)
  72.                      pline_The("poison doesn't seem to affect %s.",
  73.                                mon_nam(mtmp));
  74.              } else {
  75.                  if (rn2(30)) {
  76.                      damage += rnd(6);
  77.                  } else {
  78.                      if (vis)
  79.                          pline_The("poison was deadly...");
  80.                      damage = mtmp->mhp;
  81.                  }
  82.              }
  83.          }
  84.          if (objects[otmp->otyp].oc_material == SILVER
  85.              && mon_hates_silver(mtmp)) {
  86.              if (vis)
  87.                  pline_The("silver sears %s flesh!", s_suffix(mon_nam(mtmp)));
  88.              else if (verbose && !target)
  89.                  pline("Its flesh is seared!");
  90.          }
  91.          if (otmp->otyp == ACID_VENOM && cansee(mtmp->mx, mtmp->my)) {
  92.              if (resists_acid(mtmp)) {
  93.                  if (vis || (verbose && !target))
  94.                      pline("%s is unaffected.", Monnam(mtmp));
  95.              } else {
  96.                  if (vis)
  97.                      pline_The("%s burns %s!", hliquid("acid"), mon_nam(mtmp));
  98.                  else if (verbose && !target)
  99.                      pline("It is burned!");
  100.              }
  101.          }
  102.          if (otmp->otyp == EGG && touch_petrifies(&mons[otmp->corpsenm])) {
  103.              if (!munstone(mtmp, TRUE))
  104.                  minstapetrify(mtmp, TRUE);
  105.              if (resists_ston(mtmp))
  106.                  damage = 0;
  107.          }
  108.  
  109.          if (mtmp->mhp > 0) { /* might already be dead (if petrified) */
  110.              mtmp->mhp -= damage;
  111.              if (mtmp->mhp < 1) {
  112.                  if (vis || (verbose && !target))
  113.                      pline("%s is %s!", Monnam(mtmp),
  114.                            (nonliving(mtmp->data) || is_vampshifter(mtmp)
  115.                             || !canspotmon(mtmp)) ? "destroyed" : "killed");
  116.                  /* don't blame hero for unknown rolling boulder trap */
  117.                  if (!context.mon_moving && (otmp->otyp != BOULDER
  118.                                              || range >= 0 || otmp->otrapped))
  119.                      xkilled(mtmp, XKILL_NOMSG);
  120.                  else
  121.                      mondied(mtmp);
  122.              }
  123.          }
  124.  
  125.          /* blinding venom and cream pie do 0 damage, but verify
  126.             that the target is still alive anyway */
  127.          if (mtmp->mhp > 0
  128.              && can_blnd((struct monst *) 0, mtmp,
  129.                          (uchar) ((otmp->otyp == BLINDING_VENOM) ? AT_SPIT
  130.                                                                  : AT_WEAP),
  131.                          otmp)) {
  132.              if (vis && mtmp->mcansee)
  133.                  pline("%s is blinded by %s.", Monnam(mtmp), the(xname(otmp)));
  134.              mtmp->mcansee = 0;
  135.              tmp = (int) mtmp->mblinded + rnd(25) + 20;
  136.              if (tmp > 127)
  137.                  tmp = 127;
  138.              mtmp->mblinded = tmp;
  139.          }
  140.  
  141.          objgone = drop_throw(otmp, 1, bhitpos.x, bhitpos.y);
  142.          if (!objgone && range == -1) { /* special case */
  143.              obj_extract_self(otmp);    /* free it for motion again */
  144.              return 0;
  145.          }
  146.          return 1;
  147.      }
  148.      return 0;
  149.  }
  150.  
  151.  #define MT_FLIGHTCHECK(pre)                                             \
  152.      (/* missile hits edge of screen */                                  \
  153.       !isok(bhitpos.x + dx, bhitpos.y + dy)                              \
  154.       /* missile hits the wall */                                        \
  155.       || IS_ROCK(levl[bhitpos.x + dx][bhitpos.y + dy].typ)               \
  156.       /* missile hit closed door */                                      \
  157.       || closed_door(bhitpos.x + dx, bhitpos.y + dy)                     \
  158.       /* missile might hit iron bars */                                  \
  159.       /* the random chance for small objects hitting bars is */          \
  160.       /* skipped when reaching them at point blank range */              \
  161.       || (levl[bhitpos.x + dx][bhitpos.y + dy].typ == IRONBARS           \
  162.           && hits_bars(&singleobj,                                       \
  163.                        bhitpos.x, bhitpos.y,                             \
  164.                        bhitpos.x + dx, bhitpos.y + dy,                   \
  165.                        ((pre) ? 0 : !rn2(5)), 0))                        \
  166.       /* Thrown objects "sink" */                                        \
  167.       || (!(pre) && IS_SINK(levl[bhitpos.x][bhitpos.y].typ)))
  168.  

m_throw

  1.  void
  2.  m_throw(mon, x, y, dx, dy, range, obj)
  3.  struct monst *mon;       /* launching monster */
  4.  int x, y, dx, dy, range; /* launch point, direction, and range */
  5.  struct obj *obj;         /* missile (or stack providing it) */
  6.  {
  7.      struct monst *mtmp;
  8.      struct obj *singleobj;
  9.      char sym = obj->oclass;
  10.      int hitu = 0, oldumort, blindinc = 0;
  11.  
  12.      bhitpos.x = x;
  13.      bhitpos.y = y;
  14.      notonhead = FALSE; /* reset potentially stale value */
  15.  
  16.      if (obj->quan == 1L) {
  17.          /*
  18.           * Remove object from minvent.  This cannot be done later on;
  19.           * what if the player dies before then, leaving the monster
  20.           * with 0 daggers?  (This caused the infamous 2^32-1 orcish
  21.           * dagger bug).
  22.           *
  23.           * VENOM is not in minvent - it should already be OBJ_FREE.
  24.           * The extract below does nothing.
  25.           */
  26.  
  27.          /* not possibly_unwield, which checks the object's */
  28.          /* location, not its existence */
  29.          if (MON_WEP(mon) == obj)
  30.              setmnotwielded(mon, obj);
  31.          obj_extract_self(obj);
  32.          singleobj = obj;
  33.          obj = (struct obj *) 0;
  34.      } else {
  35.          singleobj = splitobj(obj, 1L);
  36.          obj_extract_self(singleobj);
  37.      }
  38.  
  39.      singleobj->owornmask = 0; /* threw one of multiple weapons in hand? */
  40.  
  41.      if ((singleobj->cursed || singleobj->greased) && (dx || dy) && !rn2(7)) {
  42.          if (canseemon(mon) && flags.verbose) {
  43.              if (is_ammo(singleobj))
  44.                  pline("%s misfires!", Monnam(mon));
  45.              else
  46.                  pline("%s as %s throws it!", Tobjnam(singleobj, "slip"),
  47.                        mon_nam(mon));
  48.          }
  49.          dx = rn2(3) - 1;
  50.          dy = rn2(3) - 1;
  51.          /* check validity of new direction */
  52.          if (!dx && !dy) {
  53.              (void) drop_throw(singleobj, 0, bhitpos.x, bhitpos.y);
  54.              return;
  55.          }
  56.      }
  57.  
  58.      if (MT_FLIGHTCHECK(TRUE)) {
  59.          (void) drop_throw(singleobj, 0, bhitpos.x, bhitpos.y);
  60.          return;
  61.      }
  62.      mesg_given = 0; /* a 'missile misses' message has not yet been shown */
  63.  
  64.      /* Note: drop_throw may destroy singleobj.  Since obj must be destroyed
  65.       * early to avoid the dagger bug, anyone who modifies this code should
  66.       * be careful not to use either one after it's been freed.
  67.       */
  68.      if (sym)
  69.          tmp_at(DISP_FLASH, obj_to_glyph(singleobj));
  70.      while (range-- > 0) { /* Actually the loop is always exited by break */
  71.          bhitpos.x += dx;
  72.          bhitpos.y += dy;
  73.          if ((mtmp = m_at(bhitpos.x, bhitpos.y)) != 0) {
  74.              if (ohitmon(mtmp, singleobj, range, TRUE))
  75.                  break;
  76.          } else if (bhitpos.x == u.ux && bhitpos.y == u.uy) {
  77.              if (multi)
  78.                  nomul(0);
  79.  
  80.              if (singleobj->oclass == GEM_CLASS
  81.                  && singleobj->otyp <= LAST_GEM + 9 /* 9 glass colors */
  82.                  && is_unicorn(youmonst.data)) {
  83.                  if (singleobj->otyp > LAST_GEM) {
  84.                      You("catch the %s.", xname(singleobj));
  85.                      You("are not interested in %s junk.",
  86.                          s_suffix(mon_nam(mon)));
  87.                      makeknown(singleobj->otyp);
  88.                      dropy(singleobj);
  89.                  } else {
  90.                      You(
  91.                       "accept %s gift in the spirit in which it was intended.",
  92.                          s_suffix(mon_nam(mon)));
  93.                      (void) hold_another_object(singleobj,
  94.                                                 "You catch, but drop, %s.",
  95.                                                 xname(singleobj),
  96.                                                 "You catch:");
  97.                  }
  98.                  break;
  99.              }
  100.              if (singleobj->oclass == POTION_CLASS) {
  101.                  if (!Blind)
  102.                      singleobj->dknown = 1;
  103.                  potionhit(&youmonst, singleobj, POTHIT_MONST_THROW);
  104.                  break;
  105.              }
  106.              oldumort = u.umortality;
  107.              switch (singleobj->otyp) {
  108.                  int dam, hitv;
  109.              case EGG:
  110.                  if (!touch_petrifies(&mons[singleobj->corpsenm])) {
  111.                      impossible("monster throwing egg type %d",
  112.                                 singleobj->corpsenm);
  113.                      hitu = 0;
  114.                      break;
  115.                  }
  116.              /* fall through */
  117.              case CREAM_PIE:
  118.              case BLINDING_VENOM:
  119.                  hitu = thitu(8, 0, &singleobj, (char *) 0);
  120.                  break;
  121.              default:
  122.                  dam = dmgval(singleobj, &youmonst);
  123.                  hitv = 3 - distmin(u.ux, u.uy, mon->mx, mon->my);
  124.                  if (hitv < -4)
  125.                      hitv = -4;
  126.                  if (is_elf(mon->data)
  127.                      && objects[singleobj->otyp].oc_skill == P_BOW) {
  128.                      hitv++;
  129.                      if (MON_WEP(mon) && MON_WEP(mon)->otyp == ELVEN_BOW)
  130.                          hitv++;
  131.                      if (singleobj->otyp == ELVEN_ARROW)
  132.                          dam++;
  133.                  }
  134.                  if (bigmonst(youmonst.data))
  135.                      hitv++;
  136.                  hitv += 8 + singleobj->spe;
  137.                  if (dam < 1)
  138.                      dam = 1;
  139.                  hitu = thitu(hitv, dam, &singleobj, (char *) 0);
  140.              }
  141.              if (hitu && singleobj->opoisoned && is_poisonable(singleobj)) {
  142.                  char onmbuf[BUFSZ], knmbuf[BUFSZ];
  143.  
  144.                  Strcpy(onmbuf, xname(singleobj));
  145.                  Strcpy(knmbuf, killer_xname(singleobj));
  146.                  poisoned(onmbuf, A_STR, knmbuf,
  147.                           /* if damage triggered life-saving,
  148.                              poison is limited to attrib loss */
  149.                           (u.umortality > oldumort) ? 0 : 10, TRUE);
  150.              }
  151.              if (hitu && can_blnd((struct monst *) 0, &youmonst,
  152.                                   (uchar) ((singleobj->otyp == BLINDING_VENOM)
  153.                                               ? AT_SPIT
  154.                                               : AT_WEAP),
  155.                                   singleobj)) {
  156.                  blindinc = rnd(25);
  157.                  if (singleobj->otyp == CREAM_PIE) {
  158.                      if (!Blind)
  159.                          pline("Yecch!  You've been creamed.");
  160.                      else
  161.                          pline("There's %s sticky all over your %s.",
  162.                                something, body_part(FACE));
  163.                  } else if (singleobj->otyp == BLINDING_VENOM) {
  164.                      const char *eyes = body_part(EYE);
  165.  
  166.                      if (eyecount(youmonst.data) != 1)
  167.                          eyes = makeplural(eyes);
  168.                      /* venom in the eyes */
  169.                      if (!Blind)
  170.                          pline_The("venom blinds you.");
  171.                      else
  172.                          Your("%s %s.", eyes, vtense(eyes, "sting"));
  173.                  }
  174.              }
  175.              if (hitu && singleobj->otyp == EGG) {
  176.                  if (!Stoned && !Stone_resistance
  177.                      && !(poly_when_stoned(youmonst.data)
  178.                           && polymon(PM_STONE_GOLEM))) {
  179.                      make_stoned(5L, (char *) 0, KILLED_BY, "");
  180.                  }
  181.              }
  182.              stop_occupation();
  183.              if (hitu) {
  184.                  (void) drop_throw(singleobj, hitu, u.ux, u.uy);
  185.                  break;
  186.              }
  187.          }
  188.          if (!range /* reached end of path */
  189.              || MT_FLIGHTCHECK(FALSE)) {
  190.              if (singleobj) { /* hits_bars might have destroyed it */
  191.                  if (m_shot.n > 1
  192.                      && (!mesg_given || bhitpos.x != u.ux || bhitpos.y != u.uy)
  193.                      && (cansee(bhitpos.x, bhitpos.y)
  194.                          || (archer && canseemon(archer))))
  195.                      pline("%s misses.", The(mshot_xname(singleobj)));
  196.                  (void) drop_throw(singleobj, 0, bhitpos.x, bhitpos.y);
  197.              }
  198.              break;
  199.          }
  200.          tmp_at(bhitpos.x, bhitpos.y);
  201.          delay_output();
  202.      }
  203.      tmp_at(bhitpos.x, bhitpos.y);
  204.      delay_output();
  205.      tmp_at(DISP_END, 0);
  206.      mesg_given = 0; /* reset */
  207.  
  208.      if (blindinc) {
  209.          u.ucreamed += blindinc;
  210.          make_blinded(Blinded + (long) blindinc, FALSE);
  211.          if (!Blind)
  212.              Your1(vision_clears);
  213.      }
  214.  }
  215.  
  216.  #undef MT_FLIGHTCHECK
  217.  

thrwmm

  1.  /* Monster throws item at another monster */
  2.  int
  3.  thrwmm(mtmp, mtarg)
  4.  struct monst *mtmp, *mtarg;
  5.  {
  6.      struct obj *otmp, *mwep;
  7.      register xchar x, y;
  8.      boolean ispole;
  9.  
  10.      /* Polearms won't be applied by monsters against other monsters */
  11.      if (mtmp->weapon_check == NEED_WEAPON || !MON_WEP(mtmp)) {
  12.          mtmp->weapon_check = NEED_RANGED_WEAPON;
  13.          /* mon_wield_item resets weapon_check as appropriate */
  14.          if (mon_wield_item(mtmp) != 0)
  15.              return 0;
  16.      }
  17.  
  18.      /* Pick a weapon */
  19.      otmp = select_rwep(mtmp);
  20.      if (!otmp)
  21.          return 0;
  22.      ispole = is_pole(otmp);
  23.  
  24.      x = mtmp->mx;
  25.      y = mtmp->my;
  26.  
  27.      mwep = MON_WEP(mtmp); /* wielded weapon */
  28.  
  29.      if (!ispole && m_lined_up(mtarg, mtmp)) {
  30.          int chance = max(BOLT_LIM - distmin(x, y, mtarg->mx, mtarg->my), 1);
  31.  
  32.          if (!mtarg->mflee || !rn2(chance)) {
  33.              if (ammo_and_launcher(otmp, mwep)
  34.                  && dist2(mtmp->mx, mtmp->my, mtarg->mx, mtarg->my)
  35.                     > PET_MISSILE_RANGE2)
  36.                  return 0; /* Out of range */
  37.              /* Set target monster */
  38.              target = mtarg;
  39.              archer = mtmp;
  40.              monshoot(mtmp, otmp, mwep); /* multishot shooting or throwing */
  41.              archer = target = (struct monst *) 0;
  42.              nomul(0);
  43.              return 1;
  44.          }
  45.      }
  46.      return 0;
  47.  }
  48.  

spitmm

  1.  /* monster spits substance at monster */
  2.  int
  3.  spitmm(mtmp, mattk, mtarg)
  4.  struct monst *mtmp, *mtarg;
  5.  struct attack *mattk;
  6.  {
  7.      struct obj *otmp;
  8.  
  9.      if (mtmp->mcan) {
  10.          if (!Deaf)
  11.              pline("A dry rattle comes from %s throat.",
  12.                    s_suffix(mon_nam(mtmp)));
  13.          return 0;
  14.      }
  15.      if (m_lined_up(mtarg, mtmp)) {
  16.          switch (mattk->adtyp) {
  17.          case AD_BLND:
  18.          case AD_DRST:
  19.              otmp = mksobj(BLINDING_VENOM, TRUE, FALSE);
  20.              break;
  21.          default:
  22.              impossible("bad attack type in spitmu");
  23.              /* fall through */
  24.          case AD_ACID:
  25.              otmp = mksobj(ACID_VENOM, TRUE, FALSE);
  26.              break;
  27.          }
  28.          if (!rn2(BOLT_LIM-distmin(mtmp->mx,mtmp->my,mtarg->mx,mtarg->my))) {
  29.              if (canseemon(mtmp))
  30.                  pline("%s spits venom!", Monnam(mtmp));
  31.              target = mtarg;
  32.              m_throw(mtmp, mtmp->mx, mtmp->my, sgn(tbx), sgn(tby),
  33.                      distmin(mtmp->mx,mtmp->my,mtarg->mx,mtarg->my), otmp);
  34.              target = (struct monst *)0;
  35.              nomul(0);
  36.  
  37.              /* If this is a pet, it'll get hungry. Minions and
  38.               * spell beings won't hunger */
  39.              if (mtmp->mtame && !mtmp->isminion) {
  40.                  struct edog *dog = EDOG(mtmp);
  41.  
  42.                  /* Hunger effects will catch up next move */
  43.                  if (dog->hungrytime > 1)
  44.                      dog->hungrytime -= 5;
  45.              }
  46.  
  47.              return 1;
  48.          }
  49.      }
  50.      return 0;
  51.  }
  52.  

breamm

  1.  /* monster breathes at monster (ranged) */
  2.  int
  3.  breamm(mtmp, mattk, mtarg)
  4.  struct monst *mtmp, *mtarg;
  5.  struct attack  *mattk;
  6.  {
  7.      /* if new breath types are added, change AD_ACID to max type */
  8.      int typ = (mattk->adtyp == AD_RBRE) ? rnd(AD_ACID) : mattk->adtyp ;
  9.  
  10.      if (m_lined_up(mtarg, mtmp)) {
  11.          if (mtmp->mcan) {
  12.              if (!Deaf) {
  13.                  if (canseemon(mtmp))
  14.                      pline("%s coughs.", Monnam(mtmp));
  15.                  else
  16.                      You_hear("a cough.");
  17.              }
  18.              return 0;
  19.          }
  20.          if (!mtmp->mspec_used && rn2(3)) {
  21.              if ((typ >= AD_MAGM) && (typ <= AD_ACID)) {
  22.                  if (canseemon(mtmp))
  23.                      pline("%s breathes %s!", Monnam(mtmp), breathwep[typ - 1]);
  24.                  dobuzz((int) (-20 - (typ - 1)), (int)mattk->damn,
  25.                         mtmp->mx, mtmp->my, sgn(tbx), sgn(tby), FALSE);
  26.                  nomul(0);
  27.                  /* breath runs out sometimes. Also, give monster some
  28.                   * cunning; don't breath if the target fell asleep.
  29.                   */
  30.                  mtmp->mspec_used = 6 + rn2(18);
  31.  
  32.                  /* If this is a pet, it'll get hungry. Minions and
  33.                   * spell beings won't hunger */
  34.                  if (mtmp->mtame && !mtmp->isminion) {
  35.                      struct edog *dog = EDOG(mtmp);
  36.  
  37.                      /* Hunger effects will catch up next move */
  38.                      if (dog->hungrytime >= 10)
  39.                          dog->hungrytime -= 10;
  40.                  }
  41.              } else impossible("Breath weapon %d used", typ-1);
  42.          } else
  43.              return 0;
  44.      }
  45.      return 1;
  46.  }
  47.  
  48.  
  49.  

m_useupall

  1.  /* remove an entire item from a monster's inventory; destroy that item */
  2.  void
  3.  m_useupall(mon, obj)
  4.  struct monst *mon;
  5.  struct obj *obj;
  6.  {
  7.      obj_extract_self(obj);
  8.      if (obj->owornmask) {
  9.          if (obj == MON_WEP(mon))
  10.              mwepgone(mon);
  11.          mon->misc_worn_check &= ~obj->owornmask;
  12.          update_mon_intrinsics(mon, obj, FALSE, FALSE);
  13.          obj->owornmask = 0L;
  14.      }
  15.      obfree(obj, (struct obj *) 0);
  16.  }
  17.  

m_useup

  1.  /* remove one instance of an item from a monster's inventory */
  2.  void
  3.  m_useup(mon, obj)
  4.  struct monst *mon;
  5.  struct obj *obj;
  6.  {
  7.      if (obj->quan > 1L) {
  8.          obj->quan--;
  9.          obj->owt = weight(obj);
  10.      } else {
  11.          m_useupall(mon, obj);
  12.      }
  13.  }
  14.  

thrwmu

  1.  /* monster attempts ranged weapon attack against player */
  2.  void
  3.  thrwmu(mtmp)
  4.  struct monst *mtmp;
  5.  {
  6.      struct obj *otmp, *mwep;
  7.      xchar x, y;
  8.      const char *onm;
  9.  
  10.      /* Rearranged beginning so monsters can use polearms not in a line */
  11.      if (mtmp->weapon_check == NEED_WEAPON || !MON_WEP(mtmp)) {
  12.          mtmp->weapon_check = NEED_RANGED_WEAPON;
  13.          /* mon_wield_item resets weapon_check as appropriate */
  14.          if (mon_wield_item(mtmp) != 0)
  15.              return;
  16.      }
  17.  
  18.      /* Pick a weapon */
  19.      otmp = select_rwep(mtmp);
  20.      if (!otmp)
  21.          return;
  22.  
  23.      if (is_pole(otmp)) {
  24.          int dam, hitv;
  25.  
  26.          if (otmp != MON_WEP(mtmp))
  27.              return; /* polearm must be wielded */
  28.          if (dist2(mtmp->mx, mtmp->my, mtmp->mux, mtmp->muy) > POLE_LIM
  29.              || !couldsee(mtmp->mx, mtmp->my))
  30.              return; /* Out of range, or intervening wall */
  31.  
  32.          if (canseemon(mtmp)) {
  33.              onm = xname(otmp);
  34.              pline("%s thrusts %s.", Monnam(mtmp),
  35.                    obj_is_pname(otmp) ? the(onm) : an(onm));
  36.          }
  37.  
  38.          dam = dmgval(otmp, &youmonst);
  39.          hitv = 3 - distmin(u.ux, u.uy, mtmp->mx, mtmp->my);
  40.          if (hitv < -4)
  41.              hitv = -4;
  42.          if (bigmonst(youmonst.data))
  43.              hitv++;
  44.          hitv += 8 + otmp->spe;
  45.          if (dam < 1)
  46.              dam = 1;
  47.  
  48.          (void) thitu(hitv, dam, &otmp, (char *) 0);
  49.          stop_occupation();
  50.          return;
  51.      }
  52.  
  53.      x = mtmp->mx;
  54.      y = mtmp->my;
  55.      /* If you are coming toward the monster, the monster
  56.       * should try to soften you up with missiles.  If you are
  57.       * going away, you are probably hurt or running.  Give
  58.       * chase, but if you are getting too far away, throw.
  59.       */
  60.      if (!lined_up(mtmp)
  61.          || (URETREATING(x, y)
  62.              && rn2(BOLT_LIM - distmin(x, y, mtmp->mux, mtmp->muy))))
  63.          return;
  64.  
  65.      mwep = MON_WEP(mtmp); /* wielded weapon */
  66.      monshoot(mtmp, otmp, mwep); /* multishot shooting or throwing */
  67.      nomul(0);
  68.  }
  69.  

spitmu

  1.  /* monster spits substance at you */
  2.  int
  3.  spitmu(mtmp, mattk)
  4.  struct monst *mtmp;
  5.  struct attack *mattk;
  6.  {
  7.      struct obj *otmp;
  8.  
  9.      if (mtmp->mcan) {
  10.          if (!Deaf)
  11.              pline("A dry rattle comes from %s throat.",
  12.                    s_suffix(mon_nam(mtmp)));
  13.          return 0;
  14.      }
  15.      if (lined_up(mtmp)) {
  16.          switch (mattk->adtyp) {
  17.          case AD_BLND:
  18.          case AD_DRST:
  19.              otmp = mksobj(BLINDING_VENOM, TRUE, FALSE);
  20.              break;
  21.          default:
  22.              impossible("bad attack type in spitmu");
  23.          /* fall through */
  24.          case AD_ACID:
  25.              otmp = mksobj(ACID_VENOM, TRUE, FALSE);
  26.              break;
  27.          }
  28.          if (!rn2(BOLT_LIM
  29.                   - distmin(mtmp->mx, mtmp->my, mtmp->mux, mtmp->muy))) {
  30.              if (canseemon(mtmp))
  31.                  pline("%s spits venom!", Monnam(mtmp));
  32.              m_throw(mtmp, mtmp->mx, mtmp->my, sgn(tbx), sgn(tby),
  33.                      distmin(mtmp->mx, mtmp->my, mtmp->mux, mtmp->muy), otmp);
  34.              nomul(0);
  35.              return 0;
  36.          } else {
  37.              obj_extract_self(otmp);
  38.              obfree(otmp, (struct obj *) 0);
  39.          }
  40.      }
  41.      return 0;
  42.  }
  43.  

breamu

  1.  /* monster breathes at you (ranged) */
  2.  int
  3.  breamu(mtmp, mattk)
  4.  struct monst *mtmp;
  5.  struct attack *mattk;
  6.  {
  7.      /* if new breath types are added, change AD_ACID to max type */
  8.      int typ = (mattk->adtyp == AD_RBRE) ? rnd(AD_ACID) : mattk->adtyp;
  9.  
  10.      if (lined_up(mtmp)) {
  11.          if (mtmp->mcan) {
  12.              if (!Deaf) {
  13.                  if (canseemon(mtmp))
  14.                      pline("%s coughs.", Monnam(mtmp));
  15.                  else
  16.                      You_hear("a cough.");
  17.              }
  18.              return 0;
  19.          }
  20.          if (!mtmp->mspec_used && rn2(3)) {
  21.              if ((typ >= AD_MAGM) && (typ <= AD_ACID)) {
  22.                  if (canseemon(mtmp))
  23.                      pline("%s breathes %s!", Monnam(mtmp),
  24.                            breathwep[typ - 1]);
  25.                  buzz((int) (-20 - (typ - 1)), (int) mattk->damn, mtmp->mx,
  26.                       mtmp->my, sgn(tbx), sgn(tby));
  27.                  nomul(0);
  28.                  /* breath runs out sometimes. Also, give monster some
  29.                   * cunning; don't breath if the player fell asleep.
  30.                   */
  31.                  if (!rn2(3))
  32.                      mtmp->mspec_used = 10 + rn2(20);
  33.                  if (typ == AD_SLEE && !Sleep_resistance)
  34.                      mtmp->mspec_used += rnd(20);
  35.              } else
  36.                  impossible("Breath weapon %d used", typ - 1);
  37.          }
  38.      }
  39.      return 1;
  40.  }
  41.  

linedup

  1.  boolean
  2.  linedup(ax, ay, bx, by, boulderhandling)
  3.  register xchar ax, ay, bx, by;
  4.  int boulderhandling; /* 0=block, 1=ignore, 2=conditionally block */
  5.  {
  6.      int dx, dy, boulderspots;
  7.  
  8.      /* These two values are set for use after successful return. */
  9.      tbx = ax - bx;
  10.      tby = ay - by;
  11.  
  12.      /* sometimes displacement makes a monster think that you're at its
  13.         own location; prevent it from throwing and zapping in that case */
  14.      if (!tbx && !tby)
  15.          return FALSE;
  16.  
  17.      if ((!tbx || !tby || abs(tbx) == abs(tby)) /* straight line or diagonal */
  18.          && distmin(tbx, tby, 0, 0) < BOLT_LIM) {
  19.          if ((ax == u.ux && ay == u.uy) ? (boolean) couldsee(bx, by)
  20.                                         : clear_path(ax, ay, bx, by))
  21.              return TRUE;
  22.          /* don't have line of sight, but might still be lined up
  23.             if that lack of sight is due solely to boulders */
  24.          if (boulderhandling == 0)
  25.              return FALSE;
  26.          dx = sgn(ax - bx), dy = sgn(ay - by);
  27.          boulderspots = 0;
  28.          do {
  29.              /* <bx,by> is guaranteed to eventually converge with <ax,ay> */
  30.              bx += dx, by += dy;
  31.              if (IS_ROCK(levl[bx][by].typ) || closed_door(bx, by))
  32.                  return FALSE;
  33.              if (sobj_at(BOULDER, bx, by))
  34.                  ++boulderspots;
  35.          } while (bx != ax || by != ay);
  36.          /* reached target position without encountering obstacle */
  37.          if (boulderhandling == 1 || rn2(2 + boulderspots) < 2)
  38.              return TRUE;
  39.      }
  40.      return FALSE;
  41.  }
  42.  

m_lined_up

  1.  STATIC_OVL boolean
  2.  m_lined_up(mtarg, mtmp)
  3.  struct monst *mtarg, *mtmp;
  4.  {
  5.      return (linedup(mtarg->mx, mtarg->my, mtmp->mx, mtmp->my, 0));
  6.  }
  7.  
  8.  

lined_up

  1.  /* is mtmp in position to use ranged attack? */
  2.  boolean
  3.  lined_up(mtmp)
  4.  register struct monst *mtmp;
  5.  {
  6.      boolean ignore_boulders;
  7.  
  8.      /* hero concealment usually trumps monst awareness of being lined up */
  9.      if (Upolyd && rn2(25)
  10.          && (u.uundetected || (youmonst.m_ap_type != M_AP_NOTHING
  11.                                && youmonst.m_ap_type != M_AP_MONSTER)))
  12.          return FALSE;
  13.  
  14.      ignore_boulders = (throws_rocks(mtmp->data)
  15.                         || m_carrying(mtmp, WAN_STRIKING));
  16.      return linedup(mtmp->mux, mtmp->muy, mtmp->mx, mtmp->my,
  17.                     ignore_boulders ? 1 : 2);
  18.  }
  19.  

m_carrying

  1.  /* check if a monster is carrying a particular item */
  2.  struct obj *
  3.  m_carrying(mtmp, type)
  4.  struct monst *mtmp;
  5.  int type;
  6.  {
  7.      register struct obj *otmp;
  8.  
  9.      for (otmp = mtmp->minvent; otmp; otmp = otmp->nobj)
  10.          if (otmp->otyp == type)
  11.              return otmp;
  12.      return (struct obj *) 0;
  13.  }
  14.  

hit_bars

  1.  void
  2.  hit_bars(objp, objx, objy, barsx, barsy, your_fault, from_invent)
  3.  struct obj **objp;      /* *objp will be set to NULL if object breaks */
  4.  int objx, objy, barsx, barsy;
  5.  boolean your_fault, from_invent;
  6.  {
  7.      struct obj *otmp = *objp;
  8.      int obj_type = otmp->otyp;
  9.      boolean unbreakable = (levl[barsx][barsy].wall_info & W_NONDIGGABLE) != 0;
  10.  
  11.      if (your_fault
  12.          ? hero_breaks(otmp, objx, objy, from_invent)
  13.          : breaks(otmp, objx, objy)) {
  14.          *objp = 0; /* object is now gone */
  15.          /* breakage makes its own noises */
  16.          if (obj_type == POT_ACID) {
  17.              if (cansee(barsx, barsy) && !unbreakable)
  18.                  pline_The("iron bars are dissolved!");
  19.              else
  20.                  You_hear(Hallucination ? "angry snakes!" : "a hissing noise.");
  21.              if (!unbreakable)
  22.                  dissolve_bars(barsx, barsy);
  23.          }
  24.      }
  25.      else if (obj_type == BOULDER || obj_type == HEAVY_IRON_BALL)
  26.          pline("Whang!");
  27.      else if (otmp->oclass == COIN_CLASS
  28.               || objects[obj_type].oc_material == GOLD
  29.               || objects[obj_type].oc_material == SILVER)
  30.          pline("Clink!");
  31.      else
  32.          pline("Clonk!");
  33.  }
  34.  

hits_bars

  1.  /* TRUE iff thrown/kicked/rolled object doesn't pass through iron bars */
  2.  boolean
  3.  hits_bars(obj_p, x, y, barsx, barsy, always_hit, whodidit)
  4.  struct obj **obj_p; /* *obj_p will be set to NULL if object breaks */
  5.  int x, y, barsx, barsy;
  6.  int always_hit; /* caller can force a hit for items which would fit through */
  7.  int whodidit;   /* 1==hero, 0=other, -1==just check whether it'll pass thru */
  8.  {
  9.      struct obj *otmp = *obj_p;
  10.      int obj_type = otmp->otyp;
  11.      boolean hits = always_hit;
  12.  
  13.      if (!hits)
  14.          switch (otmp->oclass) {
  15.          case WEAPON_CLASS: {
  16.              int oskill = objects[obj_type].oc_skill;
  17.  
  18.              hits = (oskill != -P_BOW && oskill != -P_CROSSBOW
  19.                      && oskill != -P_DART && oskill != -P_SHURIKEN
  20.                      && oskill != P_SPEAR
  21.                      && oskill != P_KNIFE); /* but not dagger */
  22.              break;
  23.          }
  24.          case ARMOR_CLASS:
  25.              hits = (objects[obj_type].oc_armcat != ARM_GLOVES);
  26.              break;
  27.          case TOOL_CLASS:
  28.              hits = (obj_type != SKELETON_KEY && obj_type != LOCK_PICK
  29.                      && obj_type != CREDIT_CARD && obj_type != TALLOW_CANDLE
  30.                      && obj_type != WAX_CANDLE && obj_type != LENSES
  31.                      && obj_type != TIN_WHISTLE && obj_type != MAGIC_WHISTLE);
  32.              break;
  33.          case ROCK_CLASS: /* includes boulder */
  34.              if (obj_type != STATUE || mons[otmp->corpsenm].msize > MZ_TINY)
  35.                  hits = TRUE;
  36.              break;
  37.          case FOOD_CLASS:
  38.              if (obj_type == CORPSE && mons[otmp->corpsenm].msize > MZ_TINY)
  39.                  hits = TRUE;
  40.              else
  41.                  hits = (obj_type == MEAT_STICK
  42.                          || obj_type == HUGE_CHUNK_OF_MEAT);
  43.              break;
  44.          case SPBOOK_CLASS:
  45.          case WAND_CLASS:
  46.          case BALL_CLASS:
  47.          case CHAIN_CLASS:
  48.              hits = TRUE;
  49.              break;
  50.          default:
  51.              break;
  52.          }
  53.  
  54.      if (hits && whodidit != -1) {
  55.          hit_bars(obj_p, x,y, barsx,barsy, whodidit, FALSE);
  56.      }
  57.  
  58.      return hits;
  59.  }
  60.  
  61.  /*mthrowu.c*/