Source:NetHack 3.6.0/src/dokick.c

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

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

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.

Top of file

  1.  /* NetHack 3.6	dokick.c	$NHDT-Date: 1446955295 2015/11/08 04:01:35 $  $NHDT-Branch: master $:$NHDT-Revision: 1.104 $ */
  2.  /* Copyright (c) Izchak Miller, Mike Stephenson, Steve Linhart, 1989. */
  3.  /* NetHack may be freely redistributed.  See license for details. */
  4.  
  5.  #include "hack.h"
  6.  
  7.  #define is_bigfoot(x) ((x) == &mons[PM_SASQUATCH])
  8.  #define martial()                                 \
  9.      (martial_bonus() || is_bigfoot(youmonst.data) \
  10.       || (uarmf && uarmf->otyp == KICKING_BOOTS))
  11.  
  12.  static NEARDATA struct rm *maploc, nowhere;
  13.  static NEARDATA const char *gate_str;
  14.  
  15.  /* kickedobj (decl.c) tracks a kicked object until placed or destroyed */
  16.  
  17.  extern boolean notonhead; /* for long worms */
  18.  
  19.  STATIC_DCL void FDECL(kickdmg, (struct monst *, BOOLEAN_P));
  20.  STATIC_DCL boolean FDECL(maybe_kick_monster, (struct monst *,
  21.                                                XCHAR_P, XCHAR_P));
  22.  STATIC_DCL void FDECL(kick_monster, (struct monst *, XCHAR_P, XCHAR_P));
  23.  STATIC_DCL int FDECL(kick_object, (XCHAR_P, XCHAR_P));
  24.  STATIC_DCL int FDECL(really_kick_object, (XCHAR_P, XCHAR_P));
  25.  STATIC_DCL char *FDECL(kickstr, (char *));
  26.  STATIC_DCL void FDECL(otransit_msg, (struct obj *, BOOLEAN_P, long));
  27.  STATIC_DCL void FDECL(drop_to, (coord *, SCHAR_P));
  28.  
  29.  static const char kick_passes_thru[] = "kick passes harmlessly through";
  30.  

kickdmg

  1.  STATIC_OVL void
  2.  kickdmg(mon, clumsy)
  3.  register struct monst *mon;
  4.  register boolean clumsy;
  5.  {
  6.      register int mdx, mdy;
  7.      register int dmg = (ACURRSTR + ACURR(A_DEX) + ACURR(A_CON)) / 15;
  8.      int kick_skill = P_NONE;
  9.      int blessed_foot_damage = 0;
  10.      boolean trapkilled = FALSE;
  11.  
  12.      if (uarmf && uarmf->otyp == KICKING_BOOTS)
  13.          dmg += 5;
  14.  
  15.      /* excessive wt affects dex, so it affects dmg */
  16.      if (clumsy)
  17.          dmg /= 2;
  18.  
  19.      /* kicking a dragon or an elephant will not harm it */
  20.      if (thick_skinned(mon->data))
  21.          dmg = 0;
  22.  
  23.      /* attacking a shade is useless */
  24.      if (mon->data == &mons[PM_SHADE])
  25.          dmg = 0;
  26.  
  27.      if ((is_undead(mon->data) || is_demon(mon->data) || is_vampshifter(mon))
  28.          && uarmf && uarmf->blessed)
  29.          blessed_foot_damage = 1;
  30.  
  31.      if (mon->data == &mons[PM_SHADE] && !blessed_foot_damage) {
  32.          pline_The("%s.", kick_passes_thru);
  33.          /* doesn't exercise skill or abuse alignment or frighten pet,
  34.             and shades have no passive counterattack */
  35.          return;
  36.      }
  37.  
  38.      if (mon->m_ap_type)
  39.          seemimic(mon);
  40.  
  41.      check_caitiff(mon);
  42.  
  43.      /* squeeze some guilt feelings... */
  44.      if (mon->mtame) {
  45.          abuse_dog(mon);
  46.          if (mon->mtame)
  47.              monflee(mon, (dmg ? rnd(dmg) : 1), FALSE, FALSE);
  48.          else
  49.              mon->mflee = 0;
  50.      }
  51.  
  52.      if (dmg > 0) {
  53.          /* convert potential damage to actual damage */
  54.          dmg = rnd(dmg);
  55.          if (martial()) {
  56.              if (dmg > 1)
  57.                  kick_skill = P_MARTIAL_ARTS;
  58.              dmg += rn2(ACURR(A_DEX) / 2 + 1);
  59.          }
  60.          /* a good kick exercises your dex */
  61.          exercise(A_DEX, TRUE);
  62.      }
  63.      if (blessed_foot_damage)
  64.          dmg += rnd(4);
  65.      if (uarmf)
  66.          dmg += uarmf->spe;
  67.      dmg += u.udaminc; /* add ring(s) of increase damage */
  68.      if (dmg > 0)
  69.          mon->mhp -= dmg;
  70.      if (mon->mhp > 0 && martial() && !bigmonst(mon->data) && !rn2(3)
  71.          && mon->mcanmove && mon != u.ustuck && !mon->mtrapped) {
  72.          /* see if the monster has a place to move into */
  73.          mdx = mon->mx + u.dx;
  74.          mdy = mon->my + u.dy;
  75.          if (goodpos(mdx, mdy, mon, 0)) {
  76.              pline("%s reels from the blow.", Monnam(mon));
  77.              if (m_in_out_region(mon, mdx, mdy)) {
  78.                  remove_monster(mon->mx, mon->my);
  79.                  newsym(mon->mx, mon->my);
  80.                  place_monster(mon, mdx, mdy);
  81.                  newsym(mon->mx, mon->my);
  82.                  set_apparxy(mon);
  83.                  if (mintrap(mon) == 2)
  84.                      trapkilled = TRUE;
  85.              }
  86.          }
  87.      }
  88.  
  89.      (void) passive(mon, TRUE, mon->mhp > 0, AT_KICK, FALSE);
  90.      if (mon->mhp <= 0 && !trapkilled)
  91.          killed(mon);
  92.  
  93.      /* may bring up a dialog, so put this after all messages */
  94.      if (kick_skill != P_NONE) /* exercise proficiency */
  95.          use_skill(kick_skill, 1);
  96.  }
  97.  

maybe_kick_monster

  1.  STATIC_OVL boolean
  2.  maybe_kick_monster(mon, x, y)
  3.  struct monst *mon;
  4.  xchar x, y;
  5.  {
  6.      if (mon) {
  7.          boolean save_forcefight = context.forcefight;
  8.  
  9.          bhitpos.x = x;
  10.          bhitpos.y = y;
  11.          if (!mon->mpeaceful || !canspotmon(mon))
  12.              context.forcefight = TRUE; /* attack even if invisible */
  13.          /* kicking might be halted by discovery of hidden monster,
  14.             by player declining to attack peaceful monster,
  15.             or by passing out due to encumbrance */
  16.          if (attack_checks(mon, (struct obj *) 0) || overexertion())
  17.              mon = 0; /* don't kick after all */
  18.          context.forcefight = save_forcefight;
  19.      }
  20.      return (boolean) (mon != 0);
  21.  }
  22.  

kick_monster

  1.  STATIC_OVL void
  2.  kick_monster(mon, x, y)
  3.  struct monst *mon;
  4.  xchar x, y;
  5.  {
  6.      boolean clumsy = FALSE;
  7.      int i, j;
  8.  
  9.      /* anger target even if wild miss will occur */
  10.      setmangry(mon);
  11.  
  12.      if (Levitation && !rn2(3) && verysmall(mon->data)
  13.          && !is_flyer(mon->data)) {
  14.          pline("Floating in the air, you miss wildly!");
  15.          exercise(A_DEX, FALSE);
  16.          (void) passive(mon, FALSE, 1, AT_KICK, FALSE);
  17.          return;
  18.      }
  19.  
  20.      /* reveal hidden target even if kick ends up missing (note: being
  21.         hidden doesn't affect chance to hit so neither does this reveal) */
  22.      if (mon->mundetected
  23.          || (mon->m_ap_type && mon->m_ap_type != M_AP_MONSTER)) {
  24.          if (mon->m_ap_type)
  25.              seemimic(mon);
  26.          mon->mundetected = 0;
  27.          if (!canspotmon(mon))
  28.              map_invisible(x, y);
  29.          else
  30.              newsym(x, y);
  31.          There("is %s here.",
  32.                canspotmon(mon) ? a_monnam(mon) : "something hidden");
  33.      }
  34.  
  35.      /* Kick attacks by kicking monsters are normal attacks, not special.
  36.       * This is almost always worthless, since you can either take one turn
  37.       * and do all your kicks, or else take one turn and attack the monster
  38.       * normally, getting all your attacks _including_ all your kicks.
  39.       * If you have >1 kick attack, you get all of them.
  40.       */
  41.      if (Upolyd && attacktype(youmonst.data, AT_KICK)) {
  42.          struct attack *uattk;
  43.          int sum, kickdieroll, armorpenalty,
  44.              attknum = 0,
  45.              tmp = find_roll_to_hit(mon, AT_KICK, (struct obj *) 0, &attknum,
  46.                                     &armorpenalty);
  47.  
  48.          for (i = 0; i < NATTK; i++) {
  49.              /* first of two kicks might have provoked counterattack
  50.                 that has incapacitated the hero (ie, floating eye) */
  51.              if (multi < 0)
  52.                  break;
  53.  
  54.              uattk = &youmonst.data->mattk[i];
  55.              /* we only care about kicking attacks here */
  56.              if (uattk->aatyp != AT_KICK)
  57.                  continue;
  58.  
  59.              if (mon->data == &mons[PM_SHADE] && (!uarmf || !uarmf->blessed)) {
  60.                  /* doesn't matter whether it would have hit or missed,
  61.                     and shades have no passive counterattack */
  62.                  Your("%s %s.", kick_passes_thru, mon_nam(mon));
  63.                  break; /* skip any additional kicks */
  64.              } else if (tmp > (kickdieroll = rnd(20))) {
  65.                  You("kick %s.", mon_nam(mon));
  66.                  sum = damageum(mon, uattk);
  67.                  (void) passive(mon, (boolean) (sum > 0), (sum != 2), AT_KICK,
  68.                                 FALSE);
  69.                  if (sum == 2)
  70.                      break; /* Defender died */
  71.              } else {
  72.                  missum(mon, uattk, (tmp + armorpenalty > kickdieroll));
  73.                  (void) passive(mon, FALSE, 1, AT_KICK, FALSE);
  74.              }
  75.          }
  76.          return;
  77.      }
  78.  
  79.      i = -inv_weight();
  80.      j = weight_cap();
  81.  
  82.      if (i < (j * 3) / 10) {
  83.          if (!rn2((i < j / 10) ? 2 : (i < j / 5) ? 3 : 4)) {
  84.              if (martial() && !rn2(2))
  85.                  goto doit;
  86.              Your("clumsy kick does no damage.");
  87.              (void) passive(mon, FALSE, 1, AT_KICK, FALSE);
  88.              return;
  89.          }
  90.          if (i < j / 10)
  91.              clumsy = TRUE;
  92.          else if (!rn2((i < j / 5) ? 2 : 3))
  93.              clumsy = TRUE;
  94.      }
  95.  
  96.      if (Fumbling)
  97.          clumsy = TRUE;
  98.  
  99.      else if (uarm && objects[uarm->otyp].oc_bulky && ACURR(A_DEX) < rnd(25))
  100.          clumsy = TRUE;
  101.  doit:
  102.      You("kick %s.", mon_nam(mon));
  103.      if (!rn2(clumsy ? 3 : 4) && (clumsy || !bigmonst(mon->data))
  104.          && mon->mcansee && !mon->mtrapped && !thick_skinned(mon->data)
  105.          && mon->data->mlet != S_EEL && haseyes(mon->data) && mon->mcanmove
  106.          && !mon->mstun && !mon->mconf && !mon->msleeping
  107.          && mon->data->mmove >= 12) {
  108.          if (!nohands(mon->data) && !rn2(martial() ? 5 : 3)) {
  109.              pline("%s blocks your %skick.", Monnam(mon),
  110.                    clumsy ? "clumsy " : "");
  111.              (void) passive(mon, FALSE, 1, AT_KICK, FALSE);
  112.              return;
  113.          } else {
  114.              maybe_mnexto(mon);
  115.              if (mon->mx != x || mon->my != y) {
  116.                  if (glyph_is_invisible(levl[x][y].glyph)) {
  117.                      unmap_object(x, y);
  118.                      newsym(x, y);
  119.                  }
  120.                  pline("%s %s, %s evading your %skick.", Monnam(mon),
  121.                        (!level.flags.noteleport && can_teleport(mon->data))
  122.                            ? "teleports"
  123.                            : is_floater(mon->data)
  124.                                  ? "floats"
  125.                                  : is_flyer(mon->data) ? "swoops"
  126.                                                        : (nolimbs(mon->data)
  127.                                                           || slithy(mon->data))
  128.                                                              ? "slides"
  129.                                                              : "jumps",
  130.                        clumsy ? "easily" : "nimbly", clumsy ? "clumsy " : "");
  131.                  (void) passive(mon, FALSE, 1, AT_KICK, FALSE);
  132.                  return;
  133.              }
  134.          }
  135.      }
  136.      kickdmg(mon, clumsy);
  137.  }
  138.  

ghitm

  1.  /*
  2.   *  Return TRUE if caught (the gold taken care of), FALSE otherwise.
  3.   *  The gold object is *not* attached to the fobj chain!
  4.   */
  5.  boolean
  6.  ghitm(mtmp, gold)
  7.  register struct monst *mtmp;
  8.  register struct obj *gold;
  9.  {
  10.      boolean msg_given = FALSE;
  11.  
  12.      if (!likes_gold(mtmp->data) && !mtmp->isshk && !mtmp->ispriest
  13.          && !mtmp->isgd && !is_mercenary(mtmp->data)) {
  14.          wakeup(mtmp);
  15.      } else if (!mtmp->mcanmove) {
  16.          /* too light to do real damage */
  17.          if (canseemon(mtmp)) {
  18.              pline_The("%s harmlessly %s %s.", xname(gold),
  19.                        otense(gold, "hit"), mon_nam(mtmp));
  20.              msg_given = TRUE;
  21.          }
  22.      } else {
  23.          long umoney, value = gold->quan * objects[gold->otyp].oc_cost;
  24.  
  25.          mtmp->msleeping = 0;
  26.          finish_meating(mtmp);
  27.          if (!mtmp->isgd && !rn2(4)) /* not always pleasing */
  28.              setmangry(mtmp);
  29.          /* greedy monsters catch gold */
  30.          if (cansee(mtmp->mx, mtmp->my))
  31.              pline("%s catches the gold.", Monnam(mtmp));
  32.          (void) mpickobj(mtmp, gold);
  33.          gold = (struct obj *) 0; /* obj has been freed */
  34.          if (mtmp->isshk) {
  35.              long robbed = ESHK(mtmp)->robbed;
  36.  
  37.              if (robbed) {
  38.                  robbed -= value;
  39.                  if (robbed < 0L)
  40.                      robbed = 0L;
  41.                  pline_The("amount %scovers %s recent losses.",
  42.                            !robbed ? "" : "partially ", mhis(mtmp));
  43.                  ESHK(mtmp)->robbed = robbed;
  44.                  if (!robbed)
  45.                      make_happy_shk(mtmp, FALSE);
  46.              } else {
  47.                  if (mtmp->mpeaceful) {
  48.                      ESHK(mtmp)->credit += value;
  49.                      You("have %ld %s in credit.", ESHK(mtmp)->credit,
  50.                          currency(ESHK(mtmp)->credit));
  51.                  } else
  52.                      verbalize("Thanks, scum!");
  53.              }
  54.          } else if (mtmp->ispriest) {
  55.              if (mtmp->mpeaceful)
  56.                  verbalize("Thank you for your contribution.");
  57.              else
  58.                  verbalize("Thanks, scum!");
  59.          } else if (mtmp->isgd) {
  60.              umoney = money_cnt(invent);
  61.              /* Some of these are iffy, because a hostile guard
  62.                 won't become peaceful and resume leading hero
  63.                 out of the vault.  If he did do that, player
  64.                 could try fighting, then weasle out of being
  65.                 killed by throwing his/her gold when losing. */
  66.              verbalize(
  67.                  umoney
  68.                      ? "Drop the rest and follow me."
  69.                      : hidden_gold()
  70.                            ? "You still have hidden gold.  Drop it now."
  71.                            : mtmp->mpeaceful
  72.                                  ? "I'll take care of that; please move along."
  73.                                  : "I'll take that; now get moving.");
  74.          } else if (is_mercenary(mtmp->data)) {
  75.              long goldreqd = 0L;
  76.  
  77.              if (rn2(3)) {
  78.                  if (mtmp->data == &mons[PM_SOLDIER])
  79.                      goldreqd = 100L;
  80.                  else if (mtmp->data == &mons[PM_SERGEANT])
  81.                      goldreqd = 250L;
  82.                  else if (mtmp->data == &mons[PM_LIEUTENANT])
  83.                      goldreqd = 500L;
  84.                  else if (mtmp->data == &mons[PM_CAPTAIN])
  85.                      goldreqd = 750L;
  86.  
  87.                  if (goldreqd) {
  88.                      umoney = money_cnt(invent);
  89.                      if (value
  90.                          > goldreqd
  91.                                + (umoney + u.ulevel * rn2(5)) / ACURR(A_CHA))
  92.                          mtmp->mpeaceful = TRUE;
  93.                  }
  94.              }
  95.              if (mtmp->mpeaceful)
  96.                  verbalize("That should do.  Now beat it!");
  97.              else
  98.                  verbalize("That's not enough, coward!");
  99.          }
  100.          return TRUE;
  101.      }
  102.  
  103.      if (!msg_given)
  104.          miss(xname(gold), mtmp);
  105.      return FALSE;
  106.  }
  107.  

container_impact_dmg

  1.  /* container is kicked, dropped, thrown or otherwise impacted by player.
  2.   * Assumes container is on floor.  Checks contents for possible damage. */
  3.  void
  4.  container_impact_dmg(obj, x, y)
  5.  struct obj *obj;
  6.  xchar x, y; /* coordinates where object was before the impact, not after */
  7.  {
  8.      struct monst *shkp;
  9.      struct obj *otmp, *otmp2;
  10.      long loss = 0L;
  11.      boolean costly, insider, frominv;
  12.  
  13.      /* only consider normal containers */
  14.      if (!Is_container(obj) || !Has_contents(obj) || Is_mbag(obj))
  15.          return;
  16.  
  17.      costly = ((shkp = shop_keeper(*in_rooms(x, y, SHOPBASE)))
  18.                && costly_spot(x, y));
  19.      insider = (*u.ushops && inside_shop(u.ux, u.uy)
  20.                 && *in_rooms(x, y, SHOPBASE) == *u.ushops);
  21.      /* if dropped or thrown, shop ownership flags are set on this obj */
  22.      frominv = (obj != kickedobj);
  23.  
  24.      for (otmp = obj->cobj; otmp; otmp = otmp2) {
  25.          const char *result = (char *) 0;
  26.  
  27.          otmp2 = otmp->nobj;
  28.          if (objects[otmp->otyp].oc_material == GLASS
  29.              && otmp->oclass != GEM_CLASS && !obj_resists(otmp, 33, 100)) {
  30.              result = "shatter";
  31.          } else if (otmp->otyp == EGG && !rn2(3)) {
  32.              result = "cracking";
  33.          }
  34.          if (result) {
  35.              if (otmp->otyp == MIRROR)
  36.                  change_luck(-2);
  37.  
  38.              /* eggs laid by you.  penalty is -1 per egg, max 5,
  39.               * but it's always exactly 1 that breaks */
  40.              if (otmp->otyp == EGG && otmp->spe && otmp->corpsenm >= LOW_PM)
  41.                  change_luck(-1);
  42.              You_hear("a muffled %s.", result);
  43.              if (costly) {
  44.                  if (frominv && !otmp->unpaid)
  45.                      otmp->no_charge = 1;
  46.                  loss +=
  47.                      stolen_value(otmp, x, y, (boolean) shkp->mpeaceful, TRUE);
  48.              }
  49.              if (otmp->quan > 1L) {
  50.                  useup(otmp);
  51.              } else {
  52.                  obj_extract_self(otmp);
  53.                  obfree(otmp, (struct obj *) 0);
  54.              }
  55.              /* contents of this container are no longer known */
  56.              obj->cknown = 0;
  57.          }
  58.      }
  59.      if (costly && loss) {
  60.          if (!insider) {
  61.              You("caused %ld %s worth of damage!", loss, currency(loss));
  62.              make_angry_shk(shkp, x, y);
  63.          } else {
  64.              You("owe %s %ld %s for objects destroyed.", mon_nam(shkp), loss,
  65.                  currency(loss));
  66.          }
  67.      }
  68.  }
  69.  

kick_object

  1.  /* jacket around really_kick_object */
  2.  STATIC_OVL int
  3.  kick_object(x, y)
  4.  xchar x, y;
  5.  {
  6.      int res = 0;
  7.  
  8.      /* if a pile, the "top" object gets kicked */
  9.      kickedobj = level.objects[x][y];
  10.      if (kickedobj) {
  11.          /* kick object; if doing is fatal, done() will clean up kickedobj */
  12.          res = really_kick_object(x, y);
  13.          kickedobj = (struct obj *) 0;
  14.      }
  15.      return res;
  16.  }
  17.  

really_kick_object

  1.  /* guts of kick_object */
  2.  STATIC_OVL int
  3.  really_kick_object(x, y)
  4.  xchar x, y;
  5.  {
  6.      int range;
  7.      struct monst *mon, *shkp = 0;
  8.      struct trap *trap;
  9.      char bhitroom;
  10.      boolean costly, isgold, slide = FALSE;
  11.  
  12.      /* kickedobj should always be set due to conditions of call */
  13.      if (!kickedobj || kickedobj->otyp == BOULDER || kickedobj == uball
  14.          || kickedobj == uchain)
  15.          return 0;
  16.  
  17.      if ((trap = t_at(x, y)) != 0
  18.          && (((trap->ttyp == PIT || trap->ttyp == SPIKED_PIT) && !Passes_walls)
  19.              || trap->ttyp == WEB)) {
  20.          if (!trap->tseen)
  21.              find_trap(trap);
  22.          You_cant("kick %s that's in a %s!", something,
  23.                   Hallucination ? "tizzy" : (trap->ttyp == WEB) ? "web"
  24.                                                                 : "pit");
  25.          return 1;
  26.      }
  27.  
  28.      if (Fumbling && !rn2(3)) {
  29.          Your("clumsy kick missed.");
  30.          return 1;
  31.      }
  32.  
  33.      if (!uarmf && kickedobj->otyp == CORPSE
  34.          && touch_petrifies(&mons[kickedobj->corpsenm]) && !Stone_resistance) {
  35.          You("kick %s with your bare %s.",
  36.              corpse_xname(kickedobj, (const char *) 0, CXN_PFX_THE),
  37.              makeplural(body_part(FOOT)));
  38.          if (poly_when_stoned(youmonst.data) && polymon(PM_STONE_GOLEM)) {
  39.              ; /* hero has been transformed but kick continues */
  40.          } else {
  41.              /* normalize body shape here; foot, not body_part(FOOT) */
  42.              Sprintf(killer.name, "kicking %s barefoot",
  43.                      killer_xname(kickedobj));
  44.              instapetrify(killer.name);
  45.          }
  46.      }
  47.  
  48.      /* range < 2 means the object will not move.  */
  49.      /* maybe dexterity should also figure here.   */
  50.      range = (int) ((ACURRSTR) / 2 - kickedobj->owt / 40);
  51.  
  52.      if (martial())
  53.          range += rnd(3);
  54.  
  55.      if (is_pool(x, y)) {
  56.          /* you're in the water too; significantly reduce range */
  57.          range = range / 3 + 1; /* {1,2}=>1, {3,4,5}=>2, {6,7,8}=>3 */
  58.      } else if (Is_airlevel(&u.uz) || Is_waterlevel(&u.uz)) {
  59.          /* you're in air, since is_pool did not match */
  60.          range += rnd(3);
  61.      } else {
  62.          if (is_ice(x, y))
  63.              range += rnd(3), slide = TRUE;
  64.          if (kickedobj->greased)
  65.              range += rnd(3), slide = TRUE;
  66.      }
  67.  
  68.      /* Mjollnir is magically too heavy to kick */
  69.      if (kickedobj->oartifact == ART_MJOLLNIR)
  70.          range = 1;
  71.  
  72.      /* see if the object has a place to move into */
  73.      if (!ZAP_POS(levl[x + u.dx][y + u.dy].typ)
  74.          || closed_door(x + u.dx, y + u.dy))
  75.          range = 1;
  76.  
  77.      costly = (!(kickedobj->no_charge && !Has_contents(kickedobj))
  78.                && (shkp = shop_keeper(*in_rooms(x, y, SHOPBASE))) != 0
  79.                && costly_spot(x, y));
  80.      isgold = (kickedobj->oclass == COIN_CLASS);
  81.  
  82.      if (IS_ROCK(levl[x][y].typ) || closed_door(x, y)) {
  83.          if ((!martial() && rn2(20) > ACURR(A_DEX))
  84.              || IS_ROCK(levl[u.ux][u.uy].typ) || closed_door(u.ux, u.uy)) {
  85.              if (Blind)
  86.                  pline("It doesn't come loose.");
  87.              else
  88.                  pline("%s %sn't come loose.",
  89.                        The(distant_name(kickedobj, xname)),
  90.                        otense(kickedobj, "do"));
  91.              return (!rn2(3) || martial());
  92.          }
  93.          if (Blind)
  94.              pline("It comes loose.");
  95.          else
  96.              pline("%s %s loose.", The(distant_name(kickedobj, xname)),
  97.                    otense(kickedobj, "come"));
  98.          obj_extract_self(kickedobj);
  99.          newsym(x, y);
  100.          if (costly && (!costly_spot(u.ux, u.uy)
  101.                         || !index(u.urooms, *in_rooms(x, y, SHOPBASE))))
  102.              addtobill(kickedobj, FALSE, FALSE, FALSE);
  103.          if (!flooreffects(kickedobj, u.ux, u.uy, "fall")) {
  104.              place_object(kickedobj, u.ux, u.uy);
  105.              stackobj(kickedobj);
  106.              newsym(u.ux, u.uy);
  107.          }
  108.          return 1;
  109.      }
  110.  
  111.      /* a box gets a chance of breaking open here */
  112.      if (Is_box(kickedobj)) {
  113.          boolean otrp = kickedobj->otrapped;
  114.  
  115.          if (range < 2)
  116.              pline("THUD!");
  117.          container_impact_dmg(kickedobj, x, y);
  118.          if (kickedobj->olocked) {
  119.              if (!rn2(5) || (martial() && !rn2(2))) {
  120.                  You("break open the lock!");
  121.                  breakchestlock(kickedobj, FALSE);
  122.                  if (otrp)
  123.                      (void) chest_trap(kickedobj, LEG, FALSE);
  124.                  return 1;
  125.              }
  126.          } else {
  127.              if (!rn2(3) || (martial() && !rn2(2))) {
  128.                  pline_The("lid slams open, then falls shut.");
  129.                  kickedobj->lknown = 1;
  130.                  if (otrp)
  131.                      (void) chest_trap(kickedobj, LEG, FALSE);
  132.                  return 1;
  133.              }
  134.          }
  135.          if (range < 2)
  136.              return 1;
  137.          /* else let it fall through to the next cases... */
  138.      }
  139.  
  140.      /* fragile objects should not be kicked */
  141.      if (hero_breaks(kickedobj, kickedobj->ox, kickedobj->oy, FALSE))
  142.          return 1;
  143.  
  144.      /* too heavy to move.  range is calculated as potential distance from
  145.       * player, so range == 2 means the object may move up to one square
  146.       * from its current position
  147.       */
  148.      if (range < 2) {
  149.          if (!Is_box(kickedobj))
  150.              pline("Thump!");
  151.          return (!rn2(3) || martial());
  152.      }
  153.  
  154.      if (kickedobj->quan > 1L) {
  155.          if (!isgold) {
  156.              kickedobj = splitobj(kickedobj, 1L);
  157.          } else {
  158.              if (rn2(20)) {
  159.                  static NEARDATA const char *const flyingcoinmsg[] = {
  160.                      "scatter the coins", "knock coins all over the place",
  161.                      "send coins flying in all directions",
  162.                  };
  163.  
  164.                  pline("Thwwpingg!");
  165.                  You("%s!", flyingcoinmsg[rn2(SIZE(flyingcoinmsg))]);
  166.                  (void) scatter(x, y, rn2(3) + 1, VIS_EFFECTS | MAY_HIT,
  167.                                 kickedobj);
  168.                  newsym(x, y);
  169.                  return 1;
  170.              }
  171.              if (kickedobj->quan > 300L) {
  172.                  pline("Thump!");
  173.                  return (!rn2(3) || martial());
  174.              }
  175.          }
  176.      }
  177.  
  178.      if (slide && !Blind)
  179.          pline("Whee!  %s %s across the %s.", Doname2(kickedobj),
  180.                otense(kickedobj, "slide"), surface(x, y));
  181.  
  182.      if (costly && !isgold)
  183.          addtobill(kickedobj, FALSE, FALSE, TRUE);
  184.      obj_extract_self(kickedobj);
  185.      (void) snuff_candle(kickedobj);
  186.      newsym(x, y);
  187.      mon = bhit(u.dx, u.dy, range, KICKED_WEAPON,
  188.                 (int FDECL((*), (MONST_P, OBJ_P))) 0,
  189.                 (int FDECL((*), (OBJ_P, OBJ_P))) 0, &kickedobj);
  190.      if (!kickedobj)
  191.          return 1; /* object broken */
  192.  
  193.      if (mon) {
  194.          if (mon->isshk && kickedobj->where == OBJ_MINVENT
  195.              && kickedobj->ocarry == mon)
  196.              return 1; /* alert shk caught it */
  197.          notonhead = (mon->mx != bhitpos.x || mon->my != bhitpos.y);
  198.          if (isgold ? ghitm(mon, kickedobj)      /* caught? */
  199.                     : thitmonst(mon, kickedobj)) /* hit && used up? */
  200.              return 1;
  201.      }
  202.  
  203.      /* the object might have fallen down a hole;
  204.         ship_object() will have taken care of shop billing */
  205.      if (kickedobj->where == OBJ_MIGRATING)
  206.          return 1;
  207.  
  208.      bhitroom = *in_rooms(bhitpos.x, bhitpos.y, SHOPBASE);
  209.      if (costly && (!costly_spot(bhitpos.x, bhitpos.y)
  210.                     || *in_rooms(x, y, SHOPBASE) != bhitroom)) {
  211.          if (isgold)
  212.              costly_gold(x, y, kickedobj->quan);
  213.          else
  214.              (void) stolen_value(kickedobj, x, y, (boolean) shkp->mpeaceful,
  215.                                  FALSE);
  216.      }
  217.  
  218.      if (flooreffects(kickedobj, bhitpos.x, bhitpos.y, "fall"))
  219.          return 1;
  220.      if (kickedobj->unpaid)
  221.          subfrombill(kickedobj, shkp);
  222.      place_object(kickedobj, bhitpos.x, bhitpos.y);
  223.      stackobj(kickedobj);
  224.      newsym(kickedobj->ox, kickedobj->oy);
  225.      return 1;
  226.  }
  227.  

kickstr

  1.  /* cause of death if kicking kills kicker */
  2.  STATIC_OVL char *
  3.  kickstr(buf)
  4.  char *buf;
  5.  {
  6.      const char *what;
  7.  
  8.      if (kickedobj)
  9.          what = killer_xname(kickedobj);
  10.      else if (maploc == &nowhere)
  11.          what = "nothing";
  12.      else if (IS_DOOR(maploc->typ))
  13.          what = "a door";
  14.      else if (IS_TREE(maploc->typ))
  15.          what = "a tree";
  16.      else if (IS_STWALL(maploc->typ))
  17.          what = "a wall";
  18.      else if (IS_ROCK(maploc->typ))
  19.          what = "a rock";
  20.      else if (IS_THRONE(maploc->typ))
  21.          what = "a throne";
  22.      else if (IS_FOUNTAIN(maploc->typ))
  23.          what = "a fountain";
  24.      else if (IS_GRAVE(maploc->typ))
  25.          what = "a headstone";
  26.      else if (IS_SINK(maploc->typ))
  27.          what = "a sink";
  28.      else if (IS_ALTAR(maploc->typ))
  29.          what = "an altar";
  30.      else if (IS_DRAWBRIDGE(maploc->typ))
  31.          what = "a drawbridge";
  32.      else if (maploc->typ == STAIRS)
  33.          what = "the stairs";
  34.      else if (maploc->typ == LADDER)
  35.          what = "a ladder";
  36.      else if (maploc->typ == IRONBARS)
  37.          what = "an iron bar";
  38.      else
  39.          what = "something weird";
  40.      return strcat(strcpy(buf, "kicking "), what);
  41.  }
  42.  

dokick

  1.  int
  2.  dokick()
  3.  {
  4.      int x, y;
  5.      int avrg_attrib;
  6.      int dmg = 0, glyph, oldglyph = -1;
  7.      register struct monst *mtmp;
  8.      boolean no_kick = FALSE;
  9.      char buf[BUFSZ];
  10.  
  11.      if (nolimbs(youmonst.data) || slithy(youmonst.data)) {
  12.          You("have no legs to kick with.");
  13.          no_kick = TRUE;
  14.      } else if (verysmall(youmonst.data)) {
  15.          You("are too small to do any kicking.");
  16.          no_kick = TRUE;
  17.      } else if (u.usteed) {
  18.          if (yn_function("Kick your steed?", ynchars, 'y') == 'y') {
  19.              You("kick %s.", mon_nam(u.usteed));
  20.              kick_steed();
  21.              return 1;
  22.          } else {
  23.              return 0;
  24.          }
  25.      } else if (Wounded_legs) {
  26.          /* note: jump() has similar code */
  27.          long wl = (EWounded_legs & BOTH_SIDES);
  28.          const char *bp = body_part(LEG);
  29.  
  30.          if (wl == BOTH_SIDES)
  31.              bp = makeplural(bp);
  32.          Your("%s%s %s in no shape for kicking.",
  33.               (wl == LEFT_SIDE) ? "left " : (wl == RIGHT_SIDE) ? "right " : "",
  34.               bp, (wl == BOTH_SIDES) ? "are" : "is");
  35.          no_kick = TRUE;
  36.      } else if (near_capacity() > SLT_ENCUMBER) {
  37.          Your("load is too heavy to balance yourself for a kick.");
  38.          no_kick = TRUE;
  39.      } else if (youmonst.data->mlet == S_LIZARD) {
  40.          Your("legs cannot kick effectively.");
  41.          no_kick = TRUE;
  42.      } else if (u.uinwater && !rn2(2)) {
  43.          Your("slow motion kick doesn't hit anything.");
  44.          no_kick = TRUE;
  45.      } else if (u.utrap) {
  46.          no_kick = TRUE;
  47.          switch (u.utraptype) {
  48.          case TT_PIT:
  49.              if (!Passes_walls)
  50.                  pline("There's not enough room to kick down here.");
  51.              else
  52.                  no_kick = FALSE;
  53.              break;
  54.          case TT_WEB:
  55.          case TT_BEARTRAP:
  56.              You_cant("move your %s!", body_part(LEG));
  57.              break;
  58.          default:
  59.              break;
  60.          }
  61.      }
  62.  
  63.      if (no_kick) {
  64.          /* ignore direction typed before player notices kick failed */
  65.          display_nhwindow(WIN_MESSAGE, TRUE); /* --More-- */
  66.          return 0;
  67.      }
  68.  
  69.      if (!getdir((char *) 0))
  70.          return 0;
  71.      if (!u.dx && !u.dy)
  72.          return 0;
  73.  
  74.      x = u.ux + u.dx;
  75.      y = u.uy + u.dy;
  76.  
  77.      /* KMH -- Kicking boots always succeed */
  78.      if (uarmf && uarmf->otyp == KICKING_BOOTS)
  79.          avrg_attrib = 99;
  80.      else
  81.          avrg_attrib = (ACURRSTR + ACURR(A_DEX) + ACURR(A_CON)) / 3;
  82.  
  83.      if (u.uswallow) {
  84.          switch (rn2(3)) {
  85.          case 0:
  86.              You_cant("move your %s!", body_part(LEG));
  87.              break;
  88.          case 1:
  89.              if (is_animal(u.ustuck->data)) {
  90.                  pline("%s burps loudly.", Monnam(u.ustuck));
  91.                  break;
  92.              }
  93.          default:
  94.              Your("feeble kick has no effect.");
  95.              break;
  96.          }
  97.          return 1;
  98.      } else if (u.utrap && u.utraptype == TT_PIT) {
  99.          /* must be Passes_walls */
  100.          You("kick at the side of the pit.");
  101.          return 1;
  102.      }
  103.      if (Levitation) {
  104.          int xx, yy;
  105.  
  106.          xx = u.ux - u.dx;
  107.          yy = u.uy - u.dy;
  108.          /* doors can be opened while levitating, so they must be
  109.           * reachable for bracing purposes
  110.           * Possible extension: allow bracing against stuff on the side?
  111.           */
  112.          if (isok(xx, yy) && !IS_ROCK(levl[xx][yy].typ)
  113.              && !IS_DOOR(levl[xx][yy].typ)
  114.              && (!Is_airlevel(&u.uz) || !OBJ_AT(xx, yy))) {
  115.              You("have nothing to brace yourself against.");
  116.              return 0;
  117.          }
  118.      }
  119.  
  120.      mtmp = isok(x, y) ? m_at(x, y) : 0;
  121.      /* might not kick monster if it is hidden and becomes revealed,
  122.         if it is peaceful and player declines to attack, or if the
  123.         hero passes out due to encumbrance with low hp; context.move
  124.         will be 1 unless player declines to kick peaceful monster */
  125.      if (mtmp) {
  126.          oldglyph = glyph_at(x, y);
  127.          if (!maybe_kick_monster(mtmp, x, y))
  128.              return context.move;
  129.      }
  130.  
  131.      wake_nearby();
  132.      u_wipe_engr(2);
  133.  
  134.      if (!isok(x, y)) {
  135.          maploc = &nowhere;
  136.          goto ouch;
  137.      }
  138.      maploc = &levl[x][y];
  139.  
  140.      /*
  141.       * The next five tests should stay in their present order:
  142.       * monsters, pools, objects, non-doors, doors.
  143.       *
  144.       * [FIXME:  Monsters who are hidden underneath objects or
  145.       * in pools should lead to hero kicking the concealment
  146.       * rather than the monster, probably exposing the hidden
  147.       * monster in the process.  And monsters who are hidden on
  148.       * ceiling shouldn't be kickable (unless hero is flying?);
  149.       * kicking toward them should just target whatever is on
  150.       * the floor at that spot.]
  151.       */
  152.  
  153.      if (mtmp) {
  154.          /* save mtmp->data (for recoil) in case mtmp gets killed */
  155.          struct permonst *mdat = mtmp->data;
  156.  
  157.          kick_monster(mtmp, x, y);
  158.          glyph = glyph_at(x, y);
  159.          /* see comment in attack_checks() */
  160.          if (mtmp->mhp <= 0) { /* DEADMONSTER() */
  161.              /* if we mapped an invisible monster and immediately
  162.                 killed it, we don't want to forget what we thought
  163.                 was there before the kick */
  164.              if (glyph != oldglyph && glyph_is_invisible(glyph))
  165.                  show_glyph(x, y, oldglyph);
  166.          } else if (!canspotmon(mtmp)
  167.                     /* check <x,y>; monster that evades kick by jumping
  168.                        to an unseen square doesn't leave an I behind */
  169.                     && mtmp->mx == x && mtmp->my == y
  170.                     && !glyph_is_invisible(glyph)
  171.                     && !(u.uswallow && mtmp == u.ustuck)) {
  172.              map_invisible(x, y);
  173.          }
  174.          /* recoil if floating */
  175.          if ((Is_airlevel(&u.uz) || Levitation) && context.move) {
  176.              int range;
  177.  
  178.              range =
  179.                  ((int) youmonst.data->cwt + (weight_cap() + inv_weight()));
  180.              if (range < 1)
  181.                  range = 1; /* divide by zero avoidance */
  182.              range = (3 * (int) mdat->cwt) / range;
  183.  
  184.              if (range < 1)
  185.                  range = 1;
  186.              hurtle(-u.dx, -u.dy, range, TRUE);
  187.          }
  188.          return 1;
  189.      }
  190.      if (glyph_is_invisible(levl[x][y].glyph)) {
  191.          unmap_object(x, y);
  192.          newsym(x, y);
  193.      }
  194.      if (is_pool(x, y) ^ !!u.uinwater) {
  195.          /* objects normally can't be removed from water by kicking */
  196.          You("splash some water around.");
  197.          return 1;
  198.      }
  199.  
  200.      if (OBJ_AT(x, y) && (!Levitation || Is_airlevel(&u.uz)
  201.                           || Is_waterlevel(&u.uz) || sobj_at(BOULDER, x, y))) {
  202.          if (kick_object(x, y)) {
  203.              if (Is_airlevel(&u.uz))
  204.                  hurtle(-u.dx, -u.dy, 1, TRUE); /* assume it's light */
  205.              return 1;
  206.          }
  207.          goto ouch;
  208.      }
  209.  
  210.      if (!IS_DOOR(maploc->typ)) {
  211.          if (maploc->typ == SDOOR) {
  212.              if (!Levitation && rn2(30) < avrg_attrib) {
  213.                  cvt_sdoor_to_door(maploc); /* ->typ = DOOR */
  214.                  pline("Crash!  %s a secret door!",
  215.                        /* don't "kick open" when it's locked
  216.                           unless it also happens to be trapped */
  217.                        (maploc->doormask & (D_LOCKED | D_TRAPPED)) == D_LOCKED
  218.                            ? "Your kick uncovers"
  219.                            : "You kick open");
  220.                  exercise(A_DEX, TRUE);
  221.                  if (maploc->doormask & D_TRAPPED) {
  222.                      maploc->doormask = D_NODOOR;
  223.                      b_trapped("door", FOOT);
  224.                  } else if (maploc->doormask != D_NODOOR
  225.                             && !(maploc->doormask & D_LOCKED))
  226.                      maploc->doormask = D_ISOPEN;
  227.                  feel_newsym(x, y); /* we know it's gone */
  228.                  if (maploc->doormask == D_ISOPEN
  229.                      || maploc->doormask == D_NODOOR)
  230.                      unblock_point(x, y); /* vision */
  231.                  return 1;
  232.              } else
  233.                  goto ouch;
  234.          }
  235.          if (maploc->typ == SCORR) {
  236.              if (!Levitation && rn2(30) < avrg_attrib) {
  237.                  pline("Crash!  You kick open a secret passage!");
  238.                  exercise(A_DEX, TRUE);
  239.                  maploc->typ = CORR;
  240.                  feel_newsym(x, y); /* we know it's gone */
  241.                  unblock_point(x, y); /* vision */
  242.                  return 1;
  243.              } else
  244.                  goto ouch;
  245.          }
  246.          if (IS_THRONE(maploc->typ)) {
  247.              register int i;
  248.              if (Levitation)
  249.                  goto dumb;
  250.              if ((Luck < 0 || maploc->doormask) && !rn2(3)) {
  251.                  maploc->typ = ROOM;
  252.                  maploc->doormask = 0; /* don't leave loose ends.. */
  253.                  (void) mkgold((long) rnd(200), x, y);
  254.                  if (Blind)
  255.                      pline("CRASH!  You destroy it.");
  256.                  else {
  257.                      pline("CRASH!  You destroy the throne.");
  258.                      newsym(x, y);
  259.                  }
  260.                  exercise(A_DEX, TRUE);
  261.                  return 1;
  262.              } else if (Luck > 0 && !rn2(3) && !maploc->looted) {
  263.                  (void) mkgold((long) rn1(201, 300), x, y);
  264.                  i = Luck + 1;
  265.                  if (i > 6)
  266.                      i = 6;
  267.                  while (i--)
  268.                      (void) mksobj_at(
  269.                          rnd_class(DILITHIUM_CRYSTAL, LUCKSTONE - 1), x, y,
  270.                          FALSE, TRUE);
  271.                  if (Blind)
  272.                      You("kick %s loose!", something);
  273.                  else {
  274.                      You("kick loose some ornamental coins and gems!");
  275.                      newsym(x, y);
  276.                  }
  277.                  /* prevent endless milking */
  278.                  maploc->looted = T_LOOTED;
  279.                  return 1;
  280.              } else if (!rn2(4)) {
  281.                  if (dunlev(&u.uz) < dunlevs_in_dungeon(&u.uz)) {
  282.                      fall_through(FALSE);
  283.                      return 1;
  284.                  } else
  285.                      goto ouch;
  286.              }
  287.              goto ouch;
  288.          }
  289.          if (IS_ALTAR(maploc->typ)) {
  290.              if (Levitation)
  291.                  goto dumb;
  292.              You("kick %s.", (Blind ? something : "the altar"));
  293.              if (!rn2(3))
  294.                  goto ouch;
  295.              altar_wrath(x, y);
  296.              exercise(A_DEX, TRUE);
  297.              return 1;
  298.          }
  299.          if (IS_FOUNTAIN(maploc->typ)) {
  300.              if (Levitation)
  301.                  goto dumb;
  302.              You("kick %s.", (Blind ? something : "the fountain"));
  303.              if (!rn2(3))
  304.                  goto ouch;
  305.              /* make metal boots rust */
  306.              if (uarmf && rn2(3))
  307.                  if (water_damage(uarmf, "metal boots", TRUE) == ER_NOTHING) {
  308.                      Your("boots get wet.");
  309.                      /* could cause short-lived fumbling here */
  310.                  }
  311.              exercise(A_DEX, TRUE);
  312.              return 1;
  313.          }
  314.          if (IS_GRAVE(maploc->typ)) {
  315.              if (Levitation)
  316.                  goto dumb;
  317.              if (rn2(4))
  318.                  goto ouch;
  319.              exercise(A_WIS, FALSE);
  320.              if (Role_if(PM_ARCHEOLOGIST) || Role_if(PM_SAMURAI)
  321.                  || ((u.ualign.type == A_LAWFUL) && (u.ualign.record > -10))) {
  322.                  adjalign(-sgn(u.ualign.type));
  323.              }
  324.              maploc->typ = ROOM;
  325.              maploc->doormask = 0;
  326.              (void) mksobj_at(ROCK, x, y, TRUE, FALSE);
  327.              del_engr_at(x, y);
  328.              if (Blind)
  329.                  pline("Crack!  %s broke!", Something);
  330.              else {
  331.                  pline_The("headstone topples over and breaks!");
  332.                  newsym(x, y);
  333.              }
  334.              return 1;
  335.          }
  336.          if (maploc->typ == IRONBARS)
  337.              goto ouch;
  338.          if (IS_TREE(maploc->typ)) {
  339.              struct obj *treefruit;
  340.              /* nothing, fruit or trouble? 75:23.5:1.5% */
  341.              if (rn2(3)) {
  342.                  if (!rn2(6) && !(mvitals[PM_KILLER_BEE].mvflags & G_GONE))
  343.                      You_hear("a low buzzing."); /* a warning */
  344.                  goto ouch;
  345.              }
  346.              if (rn2(15) && !(maploc->looted & TREE_LOOTED)
  347.                  && (treefruit = rnd_treefruit_at(x, y))) {
  348.                  long nfruit = 8L - rnl(7), nfall;
  349.                  short frtype = treefruit->otyp;
  350.                  treefruit->quan = nfruit;
  351.                  if (is_plural(treefruit))
  352.                      pline("Some %s fall from the tree!", xname(treefruit));
  353.                  else
  354.                      pline("%s falls from the tree!", An(xname(treefruit)));
  355.                  nfall = scatter(x, y, 2, MAY_HIT, treefruit);
  356.                  if (nfall != nfruit) {
  357.                      /* scatter left some in the tree, but treefruit
  358.                       * may not refer to the correct object */
  359.                      treefruit = mksobj(frtype, TRUE, FALSE);
  360.                      treefruit->quan = nfruit - nfall;
  361.                      pline("%ld %s got caught in the branches.",
  362.                            nfruit - nfall, xname(treefruit));
  363.                      dealloc_obj(treefruit);
  364.                  }
  365.                  exercise(A_DEX, TRUE);
  366.                  exercise(A_WIS, TRUE); /* discovered a new food source! */
  367.                  newsym(x, y);
  368.                  maploc->looted |= TREE_LOOTED;
  369.                  return 1;
  370.              } else if (!(maploc->looted & TREE_SWARM)) {
  371.                  int cnt = rnl(4) + 2;
  372.                  int made = 0;
  373.                  coord mm;
  374.                  mm.x = x;
  375.                  mm.y = y;
  376.                  while (cnt--) {
  377.                      if (enexto(&mm, mm.x, mm.y, &mons[PM_KILLER_BEE])
  378.                          && makemon(&mons[PM_KILLER_BEE], mm.x, mm.y,
  379.                                     MM_ANGRY))
  380.                          made++;
  381.                  }
  382.                  if (made)
  383.                      pline("You've attracted the tree's former occupants!");
  384.                  else
  385.                      You("smell stale honey.");
  386.                  maploc->looted |= TREE_SWARM;
  387.                  return 1;
  388.              }
  389.              goto ouch;
  390.          }
  391.          if (IS_SINK(maploc->typ)) {
  392.              int gend = poly_gender();
  393.              short washerndx = (gend == 1 || (gend == 2 && rn2(2)))
  394.                                    ? PM_INCUBUS
  395.                                    : PM_SUCCUBUS;
  396.  
  397.              if (Levitation)
  398.                  goto dumb;
  399.              if (rn2(5)) {
  400.                  if (!Deaf)
  401.                      pline("Klunk!  The pipes vibrate noisily.");
  402.                  else
  403.                      pline("Klunk!");
  404.                  exercise(A_DEX, TRUE);
  405.                  return 1;
  406.              } else if (!(maploc->looted & S_LPUDDING) && !rn2(3)
  407.                         && !(mvitals[PM_BLACK_PUDDING].mvflags & G_GONE)) {
  408.                  if (Blind)
  409.                      You_hear("a gushing sound.");
  410.                  else
  411.                      pline("A %s ooze gushes up from the drain!",
  412.                            hcolor(NH_BLACK));
  413.                  (void) makemon(&mons[PM_BLACK_PUDDING], x, y, NO_MM_FLAGS);
  414.                  exercise(A_DEX, TRUE);
  415.                  newsym(x, y);
  416.                  maploc->looted |= S_LPUDDING;
  417.                  return 1;
  418.              } else if (!(maploc->looted & S_LDWASHER) && !rn2(3)
  419.                         && !(mvitals[washerndx].mvflags & G_GONE)) {
  420.                  /* can't resist... */
  421.                  pline("%s returns!", (Blind ? Something : "The dish washer"));
  422.                  if (makemon(&mons[washerndx], x, y, NO_MM_FLAGS))
  423.                      newsym(x, y);
  424.                  maploc->looted |= S_LDWASHER;
  425.                  exercise(A_DEX, TRUE);
  426.                  return 1;
  427.              } else if (!rn2(3)) {
  428.                  pline("Flupp!  %s.",
  429.                        (Blind ? "You hear a sloshing sound"
  430.                               : "Muddy waste pops up from the drain"));
  431.                  if (!(maploc->looted & S_LRING)) { /* once per sink */
  432.                      if (!Blind)
  433.                          You_see("a ring shining in its midst.");
  434.                      (void) mkobj_at(RING_CLASS, x, y, TRUE);
  435.                      newsym(x, y);
  436.                      exercise(A_DEX, TRUE);
  437.                      exercise(A_WIS, TRUE); /* a discovery! */
  438.                      maploc->looted |= S_LRING;
  439.                  }
  440.                  return 1;
  441.              }
  442.              goto ouch;
  443.          }
  444.          if (maploc->typ == STAIRS || maploc->typ == LADDER
  445.              || IS_STWALL(maploc->typ)) {
  446.              if (!IS_STWALL(maploc->typ) && maploc->ladder == LA_DOWN)
  447.                  goto dumb;
  448.          ouch:
  449.              pline("Ouch!  That hurts!");
  450.              exercise(A_DEX, FALSE);
  451.              exercise(A_STR, FALSE);
  452.              if (isok(x, y)) {
  453.                  if (Blind)
  454.                      feel_location(x, y); /* we know we hit it */
  455.                  if (is_drawbridge_wall(x, y) >= 0) {
  456.                      pline_The("drawbridge is unaffected.");
  457.                      /* update maploc to refer to the drawbridge */
  458.                      (void) find_drawbridge(&x, &y);
  459.                      maploc = &levl[x][y];
  460.                  }
  461.              }
  462.              if (!rn2(3))
  463.                  set_wounded_legs(RIGHT_SIDE, 5 + rnd(5));
  464.              dmg = rnd(ACURR(A_CON) > 15 ? 3 : 5);
  465.              losehp(Maybe_Half_Phys(dmg), kickstr(buf), KILLED_BY);
  466.              if (Is_airlevel(&u.uz) || Levitation)
  467.                  hurtle(-u.dx, -u.dy, rn1(2, 4), TRUE); /* assume it's heavy */
  468.              return 1;
  469.          }
  470.          goto dumb;
  471.      }
  472.  
  473.      if (maploc->doormask == D_ISOPEN || maploc->doormask == D_BROKEN
  474.          || maploc->doormask == D_NODOOR) {
  475.      dumb:
  476.          exercise(A_DEX, FALSE);
  477.          if (martial() || ACURR(A_DEX) >= 16 || rn2(3)) {
  478.              You("kick at empty space.");
  479.              if (Blind)
  480.                  feel_location(x, y);
  481.          } else {
  482.              pline("Dumb move!  You strain a muscle.");
  483.              exercise(A_STR, FALSE);
  484.              set_wounded_legs(RIGHT_SIDE, 5 + rnd(5));
  485.          }
  486.          if ((Is_airlevel(&u.uz) || Levitation) && rn2(2))
  487.              hurtle(-u.dx, -u.dy, 1, TRUE);
  488.          return 1; /* uses a turn */
  489.      }
  490.  
  491.      /* not enough leverage to kick open doors while levitating */
  492.      if (Levitation)
  493.          goto ouch;
  494.  
  495.      exercise(A_DEX, TRUE);
  496.      /* door is known to be CLOSED or LOCKED */
  497.      if (rnl(35) < avrg_attrib + (!martial() ? 0 : ACURR(A_DEX))) {
  498.          boolean shopdoor = *in_rooms(x, y, SHOPBASE) ? TRUE : FALSE;
  499.          /* break the door */
  500.          if (maploc->doormask & D_TRAPPED) {
  501.              if (flags.verbose)
  502.                  You("kick the door.");
  503.              exercise(A_STR, FALSE);
  504.              maploc->doormask = D_NODOOR;
  505.              b_trapped("door", FOOT);
  506.          } else if (ACURR(A_STR) > 18 && !rn2(5) && !shopdoor) {
  507.              pline("As you kick the door, it shatters to pieces!");
  508.              exercise(A_STR, TRUE);
  509.              maploc->doormask = D_NODOOR;
  510.          } else {
  511.              pline("As you kick the door, it crashes open!");
  512.              exercise(A_STR, TRUE);
  513.              maploc->doormask = D_BROKEN;
  514.          }
  515.          feel_newsym(x, y); /* we know we broke it */
  516.          unblock_point(x, y); /* vision */
  517.          if (shopdoor) {
  518.              add_damage(x, y, 400L);
  519.              pay_for_damage("break", FALSE);
  520.          }
  521.          if (in_town(x, y))
  522.              for (mtmp = fmon; mtmp; mtmp = mtmp->nmon) {
  523.                  if (DEADMONSTER(mtmp))
  524.                      continue;
  525.                  if (is_watch(mtmp->data) && couldsee(mtmp->mx, mtmp->my)
  526.                      && mtmp->mpeaceful) {
  527.                      mon_yells(mtmp, "Halt, thief!  You're under arrest!");
  528.                      (void) angry_guards(FALSE);
  529.                      break;
  530.                  }
  531.              }
  532.      } else {
  533.          if (Blind)
  534.              feel_location(x, y); /* we know we hit it */
  535.          exercise(A_STR, TRUE);
  536.          pline("WHAMMM!!!");
  537.          if (in_town(x, y))
  538.              for (mtmp = fmon; mtmp; mtmp = mtmp->nmon) {
  539.                  if (DEADMONSTER(mtmp))
  540.                      continue;
  541.                  if (is_watch(mtmp->data) && mtmp->mpeaceful
  542.                      && couldsee(mtmp->mx, mtmp->my)) {
  543.                      if (levl[x][y].looted & D_WARNED) {
  544.                          mon_yells(mtmp,
  545.                                    "Halt, vandal!  You're under arrest!");
  546.                          (void) angry_guards(FALSE);
  547.                      } else {
  548.                          mon_yells(mtmp, "Hey, stop damaging that door!");
  549.                          levl[x][y].looted |= D_WARNED;
  550.                      }
  551.                      break;
  552.                  }
  553.              }
  554.      }
  555.      return 1;
  556.  }
  557.  

drop_to

  1.  STATIC_OVL void
  2.  drop_to(cc, loc)
  3.  coord *cc;
  4.  schar loc;
  5.  {
  6.      /* cover all the MIGR_xxx choices generated by down_gate() */
  7.      switch (loc) {
  8.      case MIGR_RANDOM: /* trap door or hole */
  9.          if (Is_stronghold(&u.uz)) {
  10.              cc->x = valley_level.dnum;
  11.              cc->y = valley_level.dlevel;
  12.              break;
  13.          } else if (In_endgame(&u.uz) || Is_botlevel(&u.uz)) {
  14.              cc->y = cc->x = 0;
  15.              break;
  16.          } /* else fall to the next cases */
  17.      case MIGR_STAIRS_UP:
  18.      case MIGR_LADDER_UP:
  19.          cc->x = u.uz.dnum;
  20.          cc->y = u.uz.dlevel + 1;
  21.          break;
  22.      case MIGR_SSTAIRS:
  23.          cc->x = sstairs.tolev.dnum;
  24.          cc->y = sstairs.tolev.dlevel;
  25.          break;
  26.      default:
  27.      case MIGR_NOWHERE:
  28.          /* y==0 means "nowhere", in which case x doesn't matter */
  29.          cc->y = cc->x = 0;
  30.          break;
  31.      }
  32.  }
  33.  

impact_drop

  1.  /* player or missile impacts location, causing objects to fall down */
  2.  void
  3.  impact_drop(missile, x, y, dlev)
  4.  struct obj *missile; /* caused impact, won't drop itself */
  5.  xchar x, y;          /* location affected */
  6.  xchar dlev;          /* if !0 send to dlev near player */
  7.  {
  8.      schar toloc;
  9.      register struct obj *obj, *obj2;
  10.      register struct monst *shkp;
  11.      long oct, dct, price, debit, robbed;
  12.      boolean angry, costly, isrock;
  13.      coord cc;
  14.  
  15.      if (!OBJ_AT(x, y))
  16.          return;
  17.  
  18.      toloc = down_gate(x, y);
  19.      drop_to(&cc, toloc);
  20.      if (!cc.y)
  21.          return;
  22.  
  23.      if (dlev) {
  24.          /* send objects next to player falling through trap door.
  25.           * checked in obj_delivery().
  26.           */
  27.          toloc = MIGR_WITH_HERO;
  28.          cc.y = dlev;
  29.      }
  30.  
  31.      costly = costly_spot(x, y);
  32.      price = debit = robbed = 0L;
  33.      angry = FALSE;
  34.      shkp = (struct monst *) 0;
  35.      /* if 'costly', we must keep a record of ESHK(shkp) before
  36.       * it undergoes changes through the calls to stolen_value.
  37.       * the angry bit must be reset, if needed, in this fn, since
  38.       * stolen_value is called under the 'silent' flag to avoid
  39.       * unsavory pline repetitions.
  40.       */
  41.      if (costly) {
  42.          if ((shkp = shop_keeper(*in_rooms(x, y, SHOPBASE))) != 0) {
  43.              debit = ESHK(shkp)->debit;
  44.              robbed = ESHK(shkp)->robbed;
  45.              angry = !shkp->mpeaceful;
  46.          }
  47.      }
  48.  
  49.      isrock = (missile && missile->otyp == ROCK);
  50.      oct = dct = 0L;
  51.      for (obj = level.objects[x][y]; obj; obj = obj2) {
  52.          obj2 = obj->nexthere;
  53.          if (obj == missile)
  54.              continue;
  55.          /* number of objects in the pile */
  56.          oct += obj->quan;
  57.          if (obj == uball || obj == uchain)
  58.              continue;
  59.          /* boulders can fall too, but rarely & never due to rocks */
  60.          if ((isrock && obj->otyp == BOULDER)
  61.              || rn2(obj->otyp == BOULDER ? 30 : 3))
  62.              continue;
  63.          obj_extract_self(obj);
  64.  
  65.          if (costly) {
  66.              price += stolen_value(
  67.                  obj, x, y, (costly_spot(u.ux, u.uy)
  68.                              && index(u.urooms, *in_rooms(x, y, SHOPBASE))),
  69.                  TRUE);
  70.              /* set obj->no_charge to 0 */
  71.              if (Has_contents(obj))
  72.                  picked_container(obj); /* does the right thing */
  73.              if (obj->oclass != COIN_CLASS)
  74.                  obj->no_charge = 0;
  75.          }
  76.  
  77.          add_to_migration(obj);
  78.          obj->ox = cc.x;
  79.          obj->oy = cc.y;
  80.          obj->owornmask = (long) toloc;
  81.  
  82.          /* number of fallen objects */
  83.          dct += obj->quan;
  84.      }
  85.  
  86.      if (dct && cansee(x, y)) { /* at least one object fell */
  87.          const char *what = (dct == 1L ? "object falls" : "objects fall");
  88.  
  89.          if (missile)
  90.              pline("From the impact, %sother %s.",
  91.                    dct == oct ? "the " : dct == 1L ? "an" : "", what);
  92.          else if (oct == dct)
  93.              pline("%s adjacent %s %s.", dct == 1L ? "The" : "All the", what,
  94.                    gate_str);
  95.          else
  96.              pline("%s adjacent %s %s.",
  97.                    dct == 1L ? "One of the" : "Some of the",
  98.                    dct == 1L ? "objects falls" : what, gate_str);
  99.      }
  100.  
  101.      if (costly && shkp && price) {
  102.          if (ESHK(shkp)->robbed > robbed) {
  103.              You("removed %ld %s worth of goods!", price, currency(price));
  104.              if (cansee(shkp->mx, shkp->my)) {
  105.                  if (ESHK(shkp)->customer[0] == 0)
  106.                      (void) strncpy(ESHK(shkp)->customer, plname, PL_NSIZ);
  107.                  if (angry)
  108.                      pline("%s is infuriated!", Monnam(shkp));
  109.                  else
  110.                      pline("\"%s, you are a thief!\"", plname);
  111.              } else
  112.                  You_hear("a scream, \"Thief!\"");
  113.              hot_pursuit(shkp);
  114.              (void) angry_guards(FALSE);
  115.              return;
  116.          }
  117.          if (ESHK(shkp)->debit > debit) {
  118.              long amt = (ESHK(shkp)->debit - debit);
  119.              You("owe %s %ld %s for goods lost.", Monnam(shkp), amt,
  120.                  currency(amt));
  121.          }
  122.      }
  123.  }
  124.  

ship_object

  1.  /* NOTE: ship_object assumes otmp was FREED from fobj or invent.
  2.   * <x,y> is the point of drop.  otmp is _not_ an <x,y> resident:
  3.   * otmp is either a kicked, dropped, or thrown object.
  4.   */
  5.  boolean
  6.  ship_object(otmp, x, y, shop_floor_obj)
  7.  xchar x, y;
  8.  struct obj *otmp;
  9.  boolean shop_floor_obj;
  10.  {
  11.      schar toloc;
  12.      xchar ox, oy;
  13.      coord cc;
  14.      struct obj *obj;
  15.      struct trap *t;
  16.      boolean nodrop, unpaid, container, impact = FALSE;
  17.      long n = 0L;
  18.  
  19.      if (!otmp)
  20.          return FALSE;
  21.      if ((toloc = down_gate(x, y)) == MIGR_NOWHERE)
  22.          return FALSE;
  23.      drop_to(&cc, toloc);
  24.      if (!cc.y)
  25.          return FALSE;
  26.  
  27.      /* objects other than attached iron ball always fall down ladder,
  28.         but have a chance of staying otherwise */
  29.      nodrop = (otmp == uball) || (otmp == uchain)
  30.               || (toloc != MIGR_LADDER_UP && rn2(3));
  31.  
  32.      container = Has_contents(otmp);
  33.      unpaid = is_unpaid(otmp);
  34.  
  35.      if (OBJ_AT(x, y)) {
  36.          for (obj = level.objects[x][y]; obj; obj = obj->nexthere)
  37.              if (obj != otmp)
  38.                  n += obj->quan;
  39.          if (n)
  40.              impact = TRUE;
  41.      }
  42.      /* boulders never fall through trap doors, but they might knock
  43.         other things down before plugging the hole */
  44.      if (otmp->otyp == BOULDER && ((t = t_at(x, y)) != 0)
  45.          && (t->ttyp == TRAPDOOR || t->ttyp == HOLE)) {
  46.          if (impact)
  47.              impact_drop(otmp, x, y, 0);
  48.          return FALSE; /* let caller finish the drop */
  49.      }
  50.  
  51.      if (cansee(x, y))
  52.          otransit_msg(otmp, nodrop, n);
  53.  
  54.      if (nodrop) {
  55.          if (impact)
  56.              impact_drop(otmp, x, y, 0);
  57.          return FALSE;
  58.      }
  59.  
  60.      if (unpaid || shop_floor_obj) {
  61.          if (unpaid) {
  62.              (void) stolen_value(otmp, u.ux, u.uy, TRUE, FALSE);
  63.          } else {
  64.              ox = otmp->ox;
  65.              oy = otmp->oy;
  66.              (void) stolen_value(
  67.                  otmp, ox, oy,
  68.                  (costly_spot(u.ux, u.uy)
  69.                   && index(u.urooms, *in_rooms(ox, oy, SHOPBASE))),
  70.                  FALSE);
  71.          }
  72.          /* set otmp->no_charge to 0 */
  73.          if (container)
  74.              picked_container(otmp); /* happens to do the right thing */
  75.          if (otmp->oclass != COIN_CLASS)
  76.              otmp->no_charge = 0;
  77.      }
  78.  
  79.      if (otmp->owornmask)
  80.          remove_worn_item(otmp, TRUE);
  81.  
  82.      /* some things break rather than ship */
  83.      if (breaktest(otmp)) {
  84.          const char *result;
  85.  
  86.          if (objects[otmp->otyp].oc_material == GLASS
  87.              || otmp->otyp == EXPENSIVE_CAMERA) {
  88.              if (otmp->otyp == MIRROR)
  89.                  change_luck(-2);
  90.              result = "crash";
  91.          } else {
  92.              /* penalty for breaking eggs laid by you */
  93.              if (otmp->otyp == EGG && otmp->spe && otmp->corpsenm >= LOW_PM)
  94.                  change_luck((schar) -min(otmp->quan, 5L));
  95.              result = "splat";
  96.          }
  97.          You_hear("a muffled %s.", result);
  98.          obj_extract_self(otmp);
  99.          obfree(otmp, (struct obj *) 0);
  100.          return TRUE;
  101.      }
  102.  
  103.      add_to_migration(otmp);
  104.      otmp->ox = cc.x;
  105.      otmp->oy = cc.y;
  106.      otmp->owornmask = (long) toloc;
  107.      /* boulder from rolling boulder trap, no longer part of the trap */
  108.      if (otmp->otyp == BOULDER)
  109.          otmp->otrapped = 0;
  110.  
  111.      if (impact) {
  112.          /* the objs impacted may be in a shop other than
  113.           * the one in which the hero is located.  another
  114.           * check for a shk is made in impact_drop.  it is, e.g.,
  115.           * possible to kick/throw an object belonging to one
  116.           * shop into another shop through a gap in the wall,
  117.           * and cause objects belonging to the other shop to
  118.           * fall down a trap door--thereby getting two shopkeepers
  119.           * angry at the hero in one shot.
  120.           */
  121.          impact_drop(otmp, x, y, 0);
  122.          newsym(x, y);
  123.      }
  124.      return TRUE;
  125.  }
  126.  

obj_delivery

  1.  void
  2.  obj_delivery(near_hero)
  3.  boolean near_hero;
  4.  {
  5.      register struct obj *otmp, *otmp2;
  6.      register int nx, ny;
  7.      int where;
  8.      boolean nobreak, noscatter;
  9.  
  10.      for (otmp = migrating_objs; otmp; otmp = otmp2) {
  11.          otmp2 = otmp->nobj;
  12.          if (otmp->ox != u.uz.dnum || otmp->oy != u.uz.dlevel)
  13.              continue;
  14.  
  15.          where = (int) (otmp->owornmask & 0x7fffL); /* destination code */
  16.          nobreak = (where & MIGR_NOBREAK) != 0;
  17.          noscatter = (where & MIGR_WITH_HERO) != 0;
  18.          where &= ~(MIGR_NOBREAK | MIGR_NOSCATTER);
  19.  
  20.          if (!near_hero ^ (where == MIGR_WITH_HERO))
  21.              continue;
  22.  
  23.          obj_extract_self(otmp);
  24.          otmp->owornmask = 0L;
  25.  
  26.          switch (where) {
  27.          case MIGR_STAIRS_UP:
  28.              nx = xupstair, ny = yupstair;
  29.              break;
  30.          case MIGR_LADDER_UP:
  31.              nx = xupladder, ny = yupladder;
  32.              break;
  33.          case MIGR_SSTAIRS:
  34.              nx = sstairs.sx, ny = sstairs.sy;
  35.              break;
  36.          case MIGR_WITH_HERO:
  37.              nx = u.ux, ny = u.uy;
  38.              break;
  39.          default:
  40.          case MIGR_RANDOM:
  41.              nx = ny = 0;
  42.              break;
  43.          }
  44.          if (nx > 0) {
  45.              place_object(otmp, nx, ny);
  46.              if (!nobreak && !IS_SOFT(levl[nx][ny].typ)) {
  47.                  if (where == MIGR_WITH_HERO) {
  48.                      if (breaks(otmp, nx, ny))
  49.                          continue;
  50.                  } else if (breaktest(otmp)) {
  51.                      /* assume it broke before player arrived, no messages */
  52.                      delobj(otmp);
  53.                      continue;
  54.                  }
  55.              }
  56.              stackobj(otmp);
  57.              if (!noscatter)
  58.                  (void) scatter(nx, ny, rnd(2), 0, otmp);
  59.          } else { /* random location */
  60.              /* set dummy coordinates because there's no
  61.                 current position for rloco() to update */
  62.              otmp->ox = otmp->oy = 0;
  63.              if (rloco(otmp) && !nobreak && breaktest(otmp)) {
  64.                  /* assume it broke before player arrived, no messages */
  65.                  delobj(otmp);
  66.              }
  67.          }
  68.      }
  69.  }
  70.  

otransit_msg

  1.  STATIC_OVL void
  2.  otransit_msg(otmp, nodrop, num)
  3.  register struct obj *otmp;
  4.  register boolean nodrop;
  5.  long num;
  6.  {
  7.      char obuf[BUFSZ];
  8.  
  9.      Sprintf(obuf, "%s%s",
  10.              (otmp->otyp == CORPSE && type_is_pname(&mons[otmp->corpsenm]))
  11.                  ? ""
  12.                  : "The ",
  13.              cxname(otmp));
  14.  
  15.      if (num) { /* means: other objects are impacted */
  16.          Sprintf(eos(obuf), " %s %s object%s", otense(otmp, "hit"),
  17.                  num == 1L ? "another" : "other", num > 1L ? "s" : "");
  18.          if (nodrop)
  19.              Sprintf(eos(obuf), ".");
  20.          else
  21.              Sprintf(eos(obuf), " and %s %s.", otense(otmp, "fall"), gate_str);
  22.          pline1(obuf);
  23.      } else if (!nodrop)
  24.          pline("%s %s %s.", obuf, otense(otmp, "fall"), gate_str);
  25.  }
  26.  

down_gate

  1.  /* migration destination for objects which fall down to next level */
  2.  schar
  3.  down_gate(x, y)
  4.  xchar x, y;
  5.  {
  6.      struct trap *ttmp;
  7.  
  8.      gate_str = 0;
  9.      /* this matches the player restriction in goto_level() */
  10.      if (on_level(&u.uz, &qstart_level) && !ok_to_quest())
  11.          return MIGR_NOWHERE;
  12.  
  13.      if ((xdnstair == x && ydnstair == y)
  14.          || (sstairs.sx == x && sstairs.sy == y && !sstairs.up)) {
  15.          gate_str = "down the stairs";
  16.          return (xdnstair == x && ydnstair == y) ? MIGR_STAIRS_UP
  17.                                                  : MIGR_SSTAIRS;
  18.      }
  19.      if (xdnladder == x && ydnladder == y) {
  20.          gate_str = "down the ladder";
  21.          return MIGR_LADDER_UP;
  22.      }
  23.  
  24.      if (((ttmp = t_at(x, y)) != 0 && ttmp->tseen)
  25.          && (ttmp->ttyp == TRAPDOOR || ttmp->ttyp == HOLE)) {
  26.          gate_str = (ttmp->ttyp == TRAPDOOR) ? "through the trap door"
  27.                                              : "through the hole";
  28.          return MIGR_RANDOM;
  29.      }
  30.      return MIGR_NOWHERE;
  31.  }
  32.  
  33.  /*dokick.c*/