Source:NetHack 3.6.0/src/do.c

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

Below is the full text to do.c from the source code of NetHack 3.6.0. To link to a particular line, write [[Source:NetHack 3.6.0/src/do.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	do.c	$NHDT-Date: 1446975464 2015/11/08 09:37:44 $  $NHDT-Branch: master $:$NHDT-Revision: 1.149 $ */
  2.  /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
  3.  /* NetHack may be freely redistributed.  See license for details. */
  4.  
  5.  /* Contains code for 'd', 'D' (drop), '>', '<' (up, down) */
  6.  
  7.  #include "hack.h"
  8.  #include "lev.h"
  9.  
  10.  STATIC_DCL void FDECL(trycall, (struct obj *));
  11.  STATIC_DCL void NDECL(polymorph_sink);
  12.  STATIC_DCL boolean NDECL(teleport_sink);
  13.  STATIC_DCL void FDECL(dosinkring, (struct obj *));
  14.  STATIC_PTR int FDECL(drop, (struct obj *));
  15.  STATIC_PTR int NDECL(wipeoff);
  16.  STATIC_DCL int FDECL(menu_drop, (int));
  17.  STATIC_DCL int NDECL(currentlevel_rewrite);
  18.  STATIC_DCL void NDECL(final_level);
  19.  /* static boolean FDECL(badspot, (XCHAR_P,XCHAR_P)); */
  20.  
  21.  extern int n_dgns; /* number of dungeons, from dungeon.c */
  22.  
  23.  static NEARDATA const char drop_types[] = { ALLOW_COUNT, COIN_CLASS,
  24.                                              ALL_CLASSES, 0 };
  25.  

dodrop

  1.  /* 'd' command: drop one inventory item */
  2.  int
  3.  dodrop()
  4.  {
  5.      int result, i = (invent) ? 0 : (SIZE(drop_types) - 1);
  6.  
  7.      if (*u.ushops)
  8.          sellobj_state(SELL_DELIBERATE);
  9.      result = drop(getobj(&drop_types[i], "drop"));
  10.      if (*u.ushops)
  11.          sellobj_state(SELL_NORMAL);
  12.      reset_occupations();
  13.  
  14.      return result;
  15.  }
  16.  

boulder_hits_pool

  1.  /* Called when a boulder is dropped, thrown, or pushed.  If it ends up
  2.   * in a pool, it either fills the pool up or sinks away.  In either case,
  3.   * it's gone for good...  If the destination is not a pool, returns FALSE.
  4.   */
  5.  boolean
  6.  boulder_hits_pool(otmp, rx, ry, pushing)
  7.  struct obj *otmp;
  8.  register int rx, ry;
  9.  boolean pushing;
  10.  {
  11.      if (!otmp || otmp->otyp != BOULDER) {
  12.          impossible("Not a boulder?");
  13.      } else if (!Is_waterlevel(&u.uz) && is_pool_or_lava(rx, ry)) {
  14.          boolean lava = is_lava(rx, ry), fills_up;
  15.          const char *what = waterbody_name(rx, ry);
  16.          schar ltyp = levl[rx][ry].typ;
  17.          int chance = rn2(10); /* water: 90%; lava: 10% */
  18.          fills_up = lava ? chance == 0 : chance != 0;
  19.  
  20.          if (fills_up) {
  21.              struct trap *ttmp = t_at(rx, ry);
  22.  
  23.              if (ltyp == DRAWBRIDGE_UP) {
  24.                  levl[rx][ry].drawbridgemask &= ~DB_UNDER; /* clear lava */
  25.                  levl[rx][ry].drawbridgemask |= DB_FLOOR;
  26.              } else
  27.                  levl[rx][ry].typ = ROOM;
  28.  
  29.              if (ttmp)
  30.                  (void) delfloortrap(ttmp);
  31.              bury_objs(rx, ry);
  32.  
  33.              newsym(rx, ry);
  34.              if (pushing) {
  35.                  char whobuf[BUFSZ];
  36.  
  37.                  Strcpy(whobuf, "you");
  38.                  if (u.usteed)
  39.                      Strcpy(whobuf, y_monnam(u.usteed));
  40.                  pline("%s %s %s into the %s.", upstart(whobuf),
  41.                        vtense(whobuf, "push"), the(xname(otmp)), what);
  42.                  if (flags.verbose && !Blind)
  43.                      pline("Now you can cross it!");
  44.                  /* no splashing in this case */
  45.              }
  46.          }
  47.          if (!fills_up || !pushing) { /* splashing occurs */
  48.              if (!u.uinwater) {
  49.                  if (pushing ? !Blind : cansee(rx, ry)) {
  50.                      There("is a large splash as %s %s the %s.",
  51.                            the(xname(otmp)), fills_up ? "fills" : "falls into",
  52.                            what);
  53.                  } else if (!Deaf)
  54.                      You_hear("a%s splash.", lava ? " sizzling" : "");
  55.                  wake_nearto(rx, ry, 40);
  56.              }
  57.  
  58.              if (fills_up && u.uinwater && distu(rx, ry) == 0) {
  59.                  u.uinwater = 0;
  60.                  docrt();
  61.                  vision_full_recalc = 1;
  62.                  You("find yourself on dry land again!");
  63.              } else if (lava && distu(rx, ry) <= 2) {
  64.                  int dmg;
  65.                  You("are hit by molten lava%c", Fire_resistance ? '.' : '!');
  66.                  burn_away_slime();
  67.                  dmg = d((Fire_resistance ? 1 : 3), 6);
  68.                  losehp(Maybe_Half_Phys(dmg), /* lava damage */
  69.                         "molten lava", KILLED_BY);
  70.              } else if (!fills_up && flags.verbose
  71.                         && (pushing ? !Blind : cansee(rx, ry)))
  72.                  pline("It sinks without a trace!");
  73.          }
  74.  
  75.          /* boulder is now gone */
  76.          if (pushing)
  77.              delobj(otmp);
  78.          else
  79.              obfree(otmp, (struct obj *) 0);
  80.          return TRUE;
  81.      }
  82.      return FALSE;
  83.  }
  84.  

flooreffects

  1.  /* Used for objects which sometimes do special things when dropped; must be
  2.   * called with the object not in any chain.  Returns TRUE if the object goes
  3.   * away.
  4.   */
  5.  boolean
  6.  flooreffects(obj, x, y, verb)
  7.  struct obj *obj;
  8.  int x, y;
  9.  const char *verb;
  10.  {
  11.      struct trap *t;
  12.      struct monst *mtmp;
  13.      struct obj *otmp;
  14.  
  15.      if (obj->where != OBJ_FREE)
  16.          panic("flooreffects: obj not free");
  17.  
  18.      /* make sure things like water_damage() have no pointers to follow */
  19.      obj->nobj = obj->nexthere = (struct obj *) 0;
  20.  
  21.      if (obj->otyp == BOULDER && boulder_hits_pool(obj, x, y, FALSE)) {
  22.          return TRUE;
  23.      } else if (obj->otyp == BOULDER && (t = t_at(x, y)) != 0
  24.               && (t->ttyp == PIT || t->ttyp == SPIKED_PIT
  25.                   || t->ttyp == TRAPDOOR || t->ttyp == HOLE)) {
  26.          if (((mtmp = m_at(x, y)) && mtmp->mtrapped)
  27.              || (u.utrap && u.ux == x && u.uy == y)) {
  28.              if (*verb)
  29.                  pline_The("boulder %s into the pit%s.",
  30.                            vtense((const char *) 0, verb),
  31.                            (mtmp) ? "" : " with you");
  32.              if (mtmp) {
  33.                  if (!passes_walls(mtmp->data) && !throws_rocks(mtmp->data)) {
  34.                      if (hmon(mtmp, obj, TRUE) && !is_whirly(mtmp->data))
  35.                          return FALSE; /* still alive */
  36.                  }
  37.                  mtmp->mtrapped = 0;
  38.              } else {
  39.                  if (!Passes_walls && !throws_rocks(youmonst.data)) {
  40.                      losehp(Maybe_Half_Phys(rnd(15)),
  41.                             "squished under a boulder", NO_KILLER_PREFIX);
  42.                      return FALSE; /* player remains trapped */
  43.                  } else
  44.                      u.utrap = 0;
  45.              }
  46.          }
  47.          if (*verb) {
  48.              if (Blind && (x == u.ux) && (y == u.uy)) {
  49.                  You_hear("a CRASH! beneath you.");
  50.              } else if (!Blind && cansee(x, y)) {
  51.                  pline_The("boulder %s%s.", t->tseen ? "" : "triggers and ",
  52.                            t->ttyp == TRAPDOOR
  53.                                ? "plugs a trap door"
  54.                                : t->ttyp == HOLE ? "plugs a hole"
  55.                                                  : "fills a pit");
  56.              } else {
  57.                  You_hear("a boulder %s.", verb);
  58.              }
  59.          }
  60.          deltrap(t);
  61.          useupf(obj, 1L);
  62.          bury_objs(x, y);
  63.          newsym(x, y);
  64.          return TRUE;
  65.      } else if (is_lava(x, y)) {
  66.          return fire_damage(obj, FALSE, x, y);
  67.      } else if (is_pool(x, y)) {
  68.          /* Reasonably bulky objects (arbitrary) splash when dropped.
  69.           * If you're floating above the water even small things make
  70.           * noise.  Stuff dropped near fountains always misses */
  71.          if ((Blind || (Levitation || Flying)) && !Deaf
  72.              && ((x == u.ux) && (y == u.uy))) {
  73.              if (!Underwater) {
  74.                  if (weight(obj) > 9) {
  75.                      pline("Splash!");
  76.                  } else if (Levitation || Flying) {
  77.                      pline("Plop!");
  78.                  }
  79.              }
  80.              map_background(x, y, 0);
  81.              newsym(x, y);
  82.          }
  83.          return water_damage(obj, NULL, FALSE) == ER_DESTROYED;
  84.      } else if (u.ux == x && u.uy == y && (t = t_at(x, y)) != 0
  85.                 && uteetering_at_seen_pit(t)) {
  86.          if (Blind && !Deaf)
  87.              You_hear("%s tumble downwards.", the(xname(obj)));
  88.          else
  89.              pline("%s %s into %s pit.", The(xname(obj)),
  90.                    otense(obj, "tumble"), the_your[t->madeby_u]);
  91.      } else if (obj->globby) {
  92.          /* Globby things like puddings might stick together */
  93.          while (obj
  94.                 && (otmp = obj_nexto_xy(obj->otyp, x, y, obj->o_id))
  95.                        != (struct obj *) 0) {
  96.              pudding_merge_message(obj, otmp);
  97.              /* intentionally not getting the melded object; obj_meld may set
  98.               * obj to null. */
  99.              (void) obj_meld(&obj, &otmp);
  100.          }
  101.          return (boolean) (obj == NULL);
  102.      }
  103.      return FALSE;
  104.  }
  105.  

doaltarobj

  1.  /* obj is an object dropped on an altar */
  2.  void
  3.  doaltarobj(obj)
  4.  register struct obj *obj;
  5.  {
  6.      if (Blind)
  7.          return;
  8.  
  9.      if (obj->oclass != COIN_CLASS) {
  10.          /* KMH, conduct */
  11.          u.uconduct.gnostic++;
  12.      } else {
  13.          /* coins don't have bless/curse status */
  14.          obj->blessed = obj->cursed = 0;
  15.      }
  16.  
  17.      if (obj->blessed || obj->cursed) {
  18.          There("is %s flash as %s %s the altar.",
  19.                an(hcolor(obj->blessed ? NH_AMBER : NH_BLACK)), doname(obj),
  20.                otense(obj, "hit"));
  21.          if (!Hallucination)
  22.              obj->bknown = 1;
  23.      } else {
  24.          pline("%s %s on the altar.", Doname2(obj), otense(obj, "land"));
  25.          if (obj->oclass != COIN_CLASS)
  26.              obj->bknown = 1;
  27.      }
  28.  }
  29.  

trycall

  1.  STATIC_OVL void
  2.  trycall(obj)
  3.  register struct obj *obj;
  4.  {
  5.      if (!objects[obj->otyp].oc_name_known && !objects[obj->otyp].oc_uname)
  6.          docall(obj);
  7.  }
  8.  

polymorph_sink

  1.  /* Transforms the sink at the player's position into
  2.     a fountain, throne, altar or grave. */
  3.  STATIC_DCL void
  4.  polymorph_sink()
  5.  {
  6.      if (levl[u.ux][u.uy].typ != SINK)
  7.          return;
  8.  
  9.      level.flags.nsinks--;
  10.      levl[u.ux][u.uy].doormask = 0;
  11.      switch (rn2(4)) {
  12.      default:
  13.      case 0:
  14.          levl[u.ux][u.uy].typ = FOUNTAIN;
  15.          level.flags.nfountains++;
  16.          break;
  17.      case 1:
  18.          levl[u.ux][u.uy].typ = THRONE;
  19.          break;
  20.      case 2:
  21.          levl[u.ux][u.uy].typ = ALTAR;
  22.          levl[u.ux][u.uy].altarmask = Align2amask(rn2((int) A_LAWFUL + 2) - 1);
  23.          break;
  24.      case 3:
  25.          levl[u.ux][u.uy].typ = ROOM;
  26.          make_grave(u.ux, u.uy, (char *) 0);
  27.          break;
  28.      }
  29.      pline_The("sink transforms into %s!", (levl[u.ux][u.uy].typ == THRONE)
  30.                                                ? "a throne"
  31.                                                : an(surface(u.ux, u.uy)));
  32.      newsym(u.ux, u.uy);
  33.  }
  34.  

teleport_sink

  1.  /* Teleports the sink at the player's position;
  2.     return True if sink teleported. */
  3.  STATIC_DCL boolean
  4.  teleport_sink()
  5.  {
  6.      int cx, cy;
  7.      int cnt = 0;
  8.      struct trap *trp;
  9.      struct engr *eng;
  10.  
  11.      do {
  12.          cx = rnd(COLNO - 1);
  13.          cy = rn2(ROWNO);
  14.          trp = t_at(cx, cy);
  15.          eng = engr_at(cx, cy);
  16.      } while ((levl[cx][cy].typ != ROOM || trp || eng || cansee(cx, cy))
  17.               && cnt++ < 200);
  18.  
  19.      if (levl[cx][cy].typ == ROOM && !trp && !eng) {
  20.          /* create sink at new position */
  21.          levl[cx][cy].typ = SINK;
  22.          levl[cx][cy].looted = levl[u.ux][u.uy].looted;
  23.          newsym(cx, cy);
  24.          /* remove old sink */
  25.          levl[u.ux][u.uy].typ = ROOM;
  26.          levl[u.ux][u.uy].looted = 0;
  27.          newsym(u.ux, u.uy);
  28.          return TRUE;
  29.      }
  30.      return FALSE;
  31.  }
  32.  

dosinkring

  1.  /* obj is a ring being dropped over a kitchen sink */
  2.  STATIC_OVL void
  3.  dosinkring(obj)
  4.  register struct obj *obj;
  5.  {
  6.      struct obj *otmp, *otmp2;
  7.      boolean ideed = TRUE;
  8.      boolean nosink = FALSE;
  9.  
  10.      You("drop %s down the drain.", doname(obj));
  11.      obj->in_use = TRUE;  /* block free identification via interrupt */
  12.      switch (obj->otyp) { /* effects that can be noticed without eyes */
  13.      case RIN_SEARCHING:
  14.          You("thought %s got lost in the sink, but there it is!", yname(obj));
  15.          goto giveback;
  16.      case RIN_SLOW_DIGESTION:
  17.          pline_The("ring is regurgitated!");
  18.      giveback:
  19.          obj->in_use = FALSE;
  20.          dropx(obj);
  21.          trycall(obj);
  22.          return;
  23.      case RIN_LEVITATION:
  24.          pline_The("sink quivers upward for a moment.");
  25.          break;
  26.      case RIN_POISON_RESISTANCE:
  27.          You("smell rotten %s.", makeplural(fruitname(FALSE)));
  28.          break;
  29.      case RIN_AGGRAVATE_MONSTER:
  30.          pline("Several %s buzz angrily around the sink.",
  31.                Hallucination ? makeplural(rndmonnam(NULL)) : "flies");
  32.          break;
  33.      case RIN_SHOCK_RESISTANCE:
  34.          pline("Static electricity surrounds the sink.");
  35.          break;
  36.      case RIN_CONFLICT:
  37.          You_hear("loud noises coming from the drain.");
  38.          break;
  39.      case RIN_SUSTAIN_ABILITY: /* KMH */
  40.          pline_The("water flow seems fixed.");
  41.          break;
  42.      case RIN_GAIN_STRENGTH:
  43.          pline_The("water flow seems %ser now.",
  44.                    (obj->spe < 0) ? "weak" : "strong");
  45.          break;
  46.      case RIN_GAIN_CONSTITUTION:
  47.          pline_The("water flow seems %ser now.",
  48.                    (obj->spe < 0) ? "less" : "great");
  49.          break;
  50.      case RIN_INCREASE_ACCURACY: /* KMH */
  51.          pline_The("water flow %s the drain.",
  52.                    (obj->spe < 0) ? "misses" : "hits");
  53.          break;
  54.      case RIN_INCREASE_DAMAGE:
  55.          pline_The("water's force seems %ser now.",
  56.                    (obj->spe < 0) ? "small" : "great");
  57.          break;
  58.      case RIN_HUNGER:
  59.          ideed = FALSE;
  60.          for (otmp = level.objects[u.ux][u.uy]; otmp; otmp = otmp2) {
  61.              otmp2 = otmp->nexthere;
  62.              if (otmp != uball && otmp != uchain
  63.                  && !obj_resists(otmp, 1, 99)) {
  64.                  if (!Blind) {
  65.                      pline("Suddenly, %s %s from the sink!", doname(otmp),
  66.                            otense(otmp, "vanish"));
  67.                      ideed = TRUE;
  68.                  }
  69.                  delobj(otmp);
  70.              }
  71.          }
  72.          break;
  73.      case MEAT_RING:
  74.          /* Not the same as aggravate monster; besides, it's obvious. */
  75.          pline("Several flies buzz around the sink.");
  76.          break;
  77.      default:
  78.          ideed = FALSE;
  79.          break;
  80.      }
  81.      if (!Blind && !ideed && obj->otyp != RIN_HUNGER) {
  82.          ideed = TRUE;
  83.          switch (obj->otyp) { /* effects that need eyes */
  84.          case RIN_ADORNMENT:
  85.              pline_The("faucets flash brightly for a moment.");
  86.              break;
  87.          case RIN_REGENERATION:
  88.              pline_The("sink looks as good as new.");
  89.              break;
  90.          case RIN_INVISIBILITY:
  91.              You("don't see anything happen to the sink.");
  92.              break;
  93.          case RIN_FREE_ACTION:
  94.              You_see("the ring slide right down the drain!");
  95.              break;
  96.          case RIN_SEE_INVISIBLE:
  97.              You_see("some %s in the sink.",
  98.                      Hallucination ? "oxygen molecules" : "air");
  99.              break;
  100.          case RIN_STEALTH:
  101.              pline_The("sink seems to blend into the floor for a moment.");
  102.              break;
  103.          case RIN_FIRE_RESISTANCE:
  104.              pline_The("hot water faucet flashes brightly for a moment.");
  105.              break;
  106.          case RIN_COLD_RESISTANCE:
  107.              pline_The("cold water faucet flashes brightly for a moment.");
  108.              break;
  109.          case RIN_PROTECTION_FROM_SHAPE_CHAN:
  110.              pline_The("sink looks nothing like a fountain.");
  111.              break;
  112.          case RIN_PROTECTION:
  113.              pline_The("sink glows %s for a moment.",
  114.                        hcolor((obj->spe < 0) ? NH_BLACK : NH_SILVER));
  115.              break;
  116.          case RIN_WARNING:
  117.              pline_The("sink glows %s for a moment.", hcolor(NH_WHITE));
  118.              break;
  119.          case RIN_TELEPORTATION:
  120.              nosink = teleport_sink();
  121.              pline_The("sink %svanishes.", nosink ? "" : "momentarily ");
  122.              break;
  123.          case RIN_TELEPORT_CONTROL:
  124.              pline_The("sink looks like it is being beamed aboard somewhere.");
  125.              break;
  126.          case RIN_POLYMORPH:
  127.              polymorph_sink();
  128.              nosink = TRUE;
  129.              break;
  130.          case RIN_POLYMORPH_CONTROL:
  131.              pline_The(
  132.                  "sink momentarily looks like a regularly erupting geyser.");
  133.              break;
  134.          }
  135.      }
  136.      if (ideed)
  137.          trycall(obj);
  138.      else if (!nosink)
  139.          You_hear("the ring bouncing down the drainpipe.");
  140.  
  141.      if (!rn2(20) && !nosink) {
  142.          pline_The("sink backs up, leaving %s.", doname(obj));
  143.          obj->in_use = FALSE;
  144.          dropx(obj);
  145.      } else
  146.          useup(obj);
  147.  }
  148.  

canletgo

  1.  /* some common tests when trying to drop or throw items */
  2.  boolean
  3.  canletgo(obj, word)
  4.  struct obj *obj;
  5.  const char *word;
  6.  {
  7.      if (obj->owornmask & (W_ARMOR | W_ACCESSORY)) {
  8.          if (*word)
  9.              Norep("You cannot %s %s you are wearing.", word, something);
  10.          return FALSE;
  11.      }
  12.      if (obj->otyp == LOADSTONE && obj->cursed) {
  13.          /* getobj() kludge sets corpsenm to user's specified count
  14.             when refusing to split a stack of cursed loadstones */
  15.          if (*word) {
  16.              /* getobj() ignores a count for throwing since that is
  17.                 implicitly forced to be 1; replicate its kludge... */
  18.              if (!strcmp(word, "throw") && obj->quan > 1L)
  19.                  obj->corpsenm = 1;
  20.              pline("For some reason, you cannot %s%s the stone%s!", word,
  21.                    obj->corpsenm ? " any of" : "", plur(obj->quan));
  22.          }
  23.          obj->corpsenm = 0; /* reset */
  24.          obj->bknown = 1;
  25.          return FALSE;
  26.      }
  27.      if (obj->otyp == LEASH && obj->leashmon != 0) {
  28.          if (*word)
  29.              pline_The("leash is tied around your %s.", body_part(HAND));
  30.          return FALSE;
  31.      }
  32.      if (obj->owornmask & W_SADDLE) {
  33.          if (*word)
  34.              You("cannot %s %s you are sitting on.", word, something);
  35.          return FALSE;
  36.      }
  37.      return TRUE;
  38.  }
  39.  

drop

  1.  STATIC_PTR int
  2.  drop(obj)
  3.  register struct obj *obj;
  4.  {
  5.      if (!obj)
  6.          return 0;
  7.      if (!canletgo(obj, "drop"))
  8.          return 0;
  9.      if (obj == uwep) {
  10.          if (welded(uwep)) {
  11.              weldmsg(obj);
  12.              return 0;
  13.          }
  14.          setuwep((struct obj *) 0);
  15.      }
  16.      if (obj == uquiver) {
  17.          setuqwep((struct obj *) 0);
  18.      }
  19.      if (obj == uswapwep) {
  20.          setuswapwep((struct obj *) 0);
  21.      }
  22.  
  23.      if (u.uswallow) {
  24.          /* barrier between you and the floor */
  25.          if (flags.verbose) {
  26.              char buf[BUFSZ];
  27.  
  28.              /* doname can call s_suffix, reusing its buffer */
  29.              Strcpy(buf, s_suffix(mon_nam(u.ustuck)));
  30.              You("drop %s into %s %s.", doname(obj), buf,
  31.                  mbodypart(u.ustuck, STOMACH));
  32.          }
  33.      } else {
  34.          if ((obj->oclass == RING_CLASS || obj->otyp == MEAT_RING)
  35.              && IS_SINK(levl[u.ux][u.uy].typ)) {
  36.              dosinkring(obj);
  37.              return 1;
  38.          }
  39.          if (!can_reach_floor(TRUE)) {
  40.              /* we might be levitating due to #invoke Heart of Ahriman;
  41.                 if so, levitation would end during call to freeinv()
  42.                 and we want hitfloor() to happen before float_down() */
  43.              boolean levhack = finesse_ahriman(obj);
  44.  
  45.              if (levhack)
  46.                  ELevitation = W_ART; /* other than W_ARTI */
  47.              if (flags.verbose)
  48.                  You("drop %s.", doname(obj));
  49.              /* Ensure update when we drop gold objects */
  50.              if (obj->oclass == COIN_CLASS)
  51.                  context.botl = 1;
  52.              freeinv(obj);
  53.              hitfloor(obj);
  54.              if (levhack)
  55.                  float_down(I_SPECIAL | TIMEOUT, W_ARTI | W_ART);
  56.              return 1;
  57.          }
  58.          if (!IS_ALTAR(levl[u.ux][u.uy].typ) && flags.verbose)
  59.              You("drop %s.", doname(obj));
  60.      }
  61.      dropx(obj);
  62.      return 1;
  63.  }
  64.  

dropx

  1.  /* dropx - take dropped item out of inventory;
  2.     called in several places - may produce output
  3.     (eg ship_object() and dropy() -> sellobj() both produce output) */
  4.  void
  5.  dropx(obj)
  6.  register struct obj *obj;
  7.  {
  8.      /* Ensure update when we drop gold objects */
  9.      if (obj->oclass == COIN_CLASS)
  10.          context.botl = 1;
  11.      freeinv(obj);
  12.      if (!u.uswallow) {
  13.          if (ship_object(obj, u.ux, u.uy, FALSE))
  14.              return;
  15.          if (IS_ALTAR(levl[u.ux][u.uy].typ))
  16.              doaltarobj(obj); /* set bknown */
  17.      }
  18.      dropy(obj);
  19.  }
  20.  

dropy

  1.  /* dropy - put dropped object at destination; called from lots of places */
  2.  void
  3.  dropy(obj)
  4.  struct obj *obj;
  5.  {
  6.      dropz(obj, FALSE);
  7.  }
  8.  

dropz

  1.  /* dropz - really put dropped object at its destination... */
  2.  void
  3.  dropz(obj, with_impact)
  4.  struct obj *obj;
  5.  boolean with_impact;
  6.  {
  7.      if (obj == uwep)
  8.          setuwep((struct obj *) 0);
  9.      if (obj == uquiver)
  10.          setuqwep((struct obj *) 0);
  11.      if (obj == uswapwep)
  12.          setuswapwep((struct obj *) 0);
  13.  
  14.      if (!u.uswallow && flooreffects(obj, u.ux, u.uy, "drop"))
  15.          return;
  16.      /* uswallow check done by GAN 01/29/87 */
  17.      if (u.uswallow) {
  18.          boolean could_petrify = FALSE;
  19.          boolean could_poly = FALSE;
  20.          boolean could_slime = FALSE;
  21.          boolean could_grow = FALSE;
  22.          boolean could_heal = FALSE;
  23.  
  24.          if (obj != uball) { /* mon doesn't pick up ball */
  25.              if (obj->otyp == CORPSE) {
  26.                  could_petrify = touch_petrifies(&mons[obj->corpsenm]);
  27.                  could_poly = polyfodder(obj);
  28.                  could_slime = (obj->corpsenm == PM_GREEN_SLIME);
  29.                  could_grow = (obj->corpsenm == PM_WRAITH);
  30.                  could_heal = (obj->corpsenm == PM_NURSE);
  31.              }
  32.              (void) mpickobj(u.ustuck, obj);
  33.              if (is_animal(u.ustuck->data)) {
  34.                  if (could_poly || could_slime) {
  35.                      (void) newcham(u.ustuck,
  36.                                     could_poly ? (struct permonst *) 0
  37.                                                : &mons[PM_GREEN_SLIME],
  38.                                     FALSE, could_slime);
  39.                      delobj(obj); /* corpse is digested */
  40.                  } else if (could_petrify) {
  41.                      minstapetrify(u.ustuck, TRUE);
  42.                      /* Don't leave a cockatrice corpse in a statue */
  43.                      if (!u.uswallow)
  44.                          delobj(obj);
  45.                  } else if (could_grow) {
  46.                      (void) grow_up(u.ustuck, (struct monst *) 0);
  47.                      delobj(obj); /* corpse is digested */
  48.                  } else if (could_heal) {
  49.                      u.ustuck->mhp = u.ustuck->mhpmax;
  50.                      delobj(obj); /* corpse is digested */
  51.                  }
  52.              }
  53.          }
  54.      } else {
  55.          place_object(obj, u.ux, u.uy);
  56.          if (with_impact)
  57.              container_impact_dmg(obj, u.ux, u.uy);
  58.          if (obj == uball)
  59.              drop_ball(u.ux, u.uy);
  60.          else if (level.flags.has_shop)
  61.              sellobj(obj, u.ux, u.uy);
  62.          stackobj(obj);
  63.          if (Blind && Levitation)
  64.              map_object(obj, 0);
  65.          newsym(u.ux, u.uy); /* remap location under self */
  66.      }
  67.  }
  68.  

obj_no_longer_held

  1.  /* things that must change when not held; recurse into containers.
  2.     Called for both player and monsters */
  3.  void
  4.  obj_no_longer_held(obj)
  5.  struct obj *obj;
  6.  {
  7.      if (!obj) {
  8.          return;
  9.      } else if (Has_contents(obj)) {
  10.          struct obj *contents;
  11.  
  12.          for (contents = obj->cobj; contents; contents = contents->nobj)
  13.              obj_no_longer_held(contents);
  14.      }
  15.      switch (obj->otyp) {
  16.      case CRYSKNIFE:
  17.          /* Normal crysknife reverts to worm tooth when not held by hero
  18.           * or monster; fixed crysknife has only 10% chance of reverting.
  19.           * When a stack of the latter is involved, it could be worthwhile
  20.           * to give each individual crysknife its own separate 10% chance,
  21.           * but we aren't in any position to handle stack splitting here.
  22.           */
  23.          if (!obj->oerodeproof || !rn2(10)) {
  24.              /* if monsters aren't moving, assume player is responsible */
  25.              if (!context.mon_moving && !program_state.gameover)
  26.                  costly_alteration(obj, COST_DEGRD);
  27.              obj->otyp = WORM_TOOTH;
  28.              obj->oerodeproof = 0;
  29.          }
  30.          break;
  31.      }
  32.  }
  33.  

doddrop

  1.  /* 'D' command: drop several things */
  2.  int
  3.  doddrop()
  4.  {
  5.      int result = 0;
  6.  
  7.      add_valid_menu_class(0); /* clear any classes already there */
  8.      if (*u.ushops)
  9.          sellobj_state(SELL_DELIBERATE);
  10.      if (flags.menu_style != MENU_TRADITIONAL
  11.          || (result = ggetobj("drop", drop, 0, FALSE, (unsigned *) 0)) < -1)
  12.          result = menu_drop(result);
  13.      if (*u.ushops)
  14.          sellobj_state(SELL_NORMAL);
  15.      reset_occupations();
  16.  
  17.      return result;
  18.  }
  19.  

menu_drop

  1.  /* Drop things from the hero's inventory, using a menu. */
  2.  STATIC_OVL int
  3.  menu_drop(retry)
  4.  int retry;
  5.  {
  6.      int n, i, n_dropped = 0;
  7.      long cnt;
  8.      struct obj *otmp, *otmp2;
  9.      menu_item *pick_list;
  10.      boolean all_categories = TRUE;
  11.      boolean drop_everything = FALSE;
  12.  
  13.      if (retry) {
  14.          all_categories = (retry == -2);
  15.      } else if (flags.menu_style == MENU_FULL) {
  16.          all_categories = FALSE;
  17.          n = query_category("Drop what type of items?", invent,
  18.                             UNPAID_TYPES | ALL_TYPES | CHOOSE_ALL | BUC_BLESSED
  19.                                 | BUC_CURSED | BUC_UNCURSED | BUC_UNKNOWN,
  20.                             &pick_list, PICK_ANY);
  21.          if (!n)
  22.              goto drop_done;
  23.          for (i = 0; i < n; i++) {
  24.              if (pick_list[i].item.a_int == ALL_TYPES_SELECTED)
  25.                  all_categories = TRUE;
  26.              else if (pick_list[i].item.a_int == 'A')
  27.                  drop_everything = TRUE;
  28.              else
  29.                  add_valid_menu_class(pick_list[i].item.a_int);
  30.          }
  31.          free((genericptr_t) pick_list);
  32.      } else if (flags.menu_style == MENU_COMBINATION) {
  33.          unsigned ggoresults = 0;
  34.          all_categories = FALSE;
  35.          /* Gather valid classes via traditional NetHack method */
  36.          i = ggetobj("drop", drop, 0, TRUE, &ggoresults);
  37.          if (i == -2)
  38.              all_categories = TRUE;
  39.          if (ggoresults & ALL_FINISHED) {
  40.              n_dropped = i;
  41.              goto drop_done;
  42.          }
  43.      }
  44.  
  45.      if (drop_everything) {
  46.          /*
  47.           * Dropping a burning potion of oil while levitating can cause
  48.           * an explosion which might destroy some of hero's inventory,
  49.           * so the old code
  50.           *      for (otmp = invent; otmp; otmp = otmp2) {
  51.           *          otmp2 = otmp->nobj;
  52.           *          n_dropped += drop(otmp);
  53.           *      }
  54.           * was unreliable and could lead to an "object lost" panic.
  55.           *
  56.           * Use the bypass bit to mark items already processed (hence
  57.           * not droppable) and rescan inventory until no unbypassed
  58.           * items remain.
  59.           */
  60.          bypass_objlist(invent, FALSE); /* clear bypass bit for invent */
  61.          while ((otmp = nxt_unbypassed_obj(invent)) != 0)
  62.              n_dropped += drop(otmp);
  63.          /* we might not have dropped everything (worn armor, welded weapon,
  64.             cursed loadstones), so reset any remaining inventory to normal */
  65.          bypass_objlist(invent, FALSE);
  66.      } else {
  67.          /* should coordinate with perm invent, maybe not show worn items */
  68.          n = query_objlist("What would you like to drop?", invent,
  69.                            USE_INVLET | INVORDER_SORT, &pick_list, PICK_ANY,
  70.                            all_categories ? allow_all : allow_category);
  71.          if (n > 0) {
  72.              /*
  73.               * picklist[] contains a set of pointers into inventory, but
  74.               * as soon as something gets dropped, they might become stale
  75.               * (see the drop_everything code above for an explanation).
  76.               * Just checking to see whether one is still in the invent
  77.               * chain is not sufficient validation since destroyed items
  78.               * will be freed and items we've split here might have already
  79.               * reused that memory and put the same pointer value back into
  80.               * invent.  Ditto for using invlet to validate.  So we start
  81.               * by setting bypass on all of invent, then check each pointer
  82.               * to verify that it is in invent and has that bit set.
  83.               */
  84.              bypass_objlist(invent, TRUE);
  85.              for (i = 0; i < n; i++) {
  86.                  otmp = pick_list[i].item.a_obj;
  87.                  for (otmp2 = invent; otmp2; otmp2 = otmp2->nobj)
  88.                      if (otmp2 == otmp)
  89.                          break;
  90.                  if (!otmp2 || !otmp2->bypass)
  91.                      continue;
  92.                  /* found next selected invent item */
  93.                  cnt = pick_list[i].count;
  94.                  if (cnt < otmp->quan) {
  95.                      if (welded(otmp)) {
  96.                          ; /* don't split */
  97.                      } else if (otmp->otyp == LOADSTONE && otmp->cursed) {
  98.                          /* same kludge as getobj(), for canletgo()'s use */
  99.                          otmp->corpsenm = (int) cnt; /* don't split */
  100.                      } else {
  101.                          otmp = splitobj(otmp, cnt);
  102.                      }
  103.                  }
  104.                  n_dropped += drop(otmp);
  105.              }
  106.              bypass_objlist(invent, FALSE); /* reset invent to normal */
  107.              free((genericptr_t) pick_list);
  108.          }
  109.      }
  110.  
  111.  drop_done:
  112.      return n_dropped;
  113.  }
  114.  

dodown

  1.  /* on a ladder, used in goto_level */
  2.  static NEARDATA boolean at_ladder = FALSE;
  3.  
  4.  /* the '>' command */
  5.  int
  6.  dodown()
  7.  {
  8.      struct trap *trap = 0;
  9.      boolean stairs_down = ((u.ux == xdnstair && u.uy == ydnstair)
  10.                             || (u.ux == sstairs.sx && u.uy == sstairs.sy
  11.                                 && !sstairs.up)),
  12.              ladder_down = (u.ux == xdnladder && u.uy == ydnladder);
  13.  
  14.      if (u_rooted())
  15.          return 1;
  16.  
  17.      if (stucksteed(TRUE)) {
  18.          return 0;
  19.      }
  20.      /* Levitation might be blocked, but player can still use '>' to
  21.         turn off controlled levitation */
  22.      if (HLevitation || ELevitation) {
  23.          if ((HLevitation & I_SPECIAL) || (ELevitation & W_ARTI)) {
  24.              /* end controlled levitation */
  25.              if (ELevitation & W_ARTI) {
  26.                  struct obj *obj;
  27.  
  28.                  for (obj = invent; obj; obj = obj->nobj) {
  29.                      if (obj->oartifact
  30.                          && artifact_has_invprop(obj, LEVITATION)) {
  31.                          if (obj->age < monstermoves)
  32.                              obj->age = monstermoves;
  33.                          obj->age += rnz(100);
  34.                      }
  35.                  }
  36.              }
  37.              if (float_down(I_SPECIAL | TIMEOUT, W_ARTI)) {
  38.                  return 1; /* came down, so moved */
  39.              } else if (!HLevitation && !ELevitation) {
  40.                  Your("latent levitation ceases.");
  41.                  return 1; /* did something, effectively moved */
  42.              }
  43.          }
  44.          if (BLevitation) {
  45.              ; /* weren't actually floating after all */
  46.          } else if (Blind) {
  47.              /* Avoid alerting player to an unknown stair or ladder.
  48.               * Changes the message for a covered, known staircase
  49.               * too; staircase knowledge is not stored anywhere.
  50.               */
  51.              if (stairs_down)
  52.                  stairs_down =
  53.                      (glyph_to_cmap(levl[u.ux][u.uy].glyph) == S_dnstair);
  54.              else if (ladder_down)
  55.                  ladder_down =
  56.                      (glyph_to_cmap(levl[u.ux][u.uy].glyph) == S_dnladder);
  57.          }
  58.          floating_above(stairs_down ? "stairs" : ladder_down
  59.                                                      ? "ladder"
  60.                                                      : surface(u.ux, u.uy));
  61.          return 0; /* didn't move */
  62.      }
  63.      if (!stairs_down && !ladder_down) {
  64.          trap = t_at(u.ux, u.uy);
  65.          if (trap && uteetering_at_seen_pit(trap)) {
  66.              dotrap(trap, TOOKPLUNGE);
  67.              return 1;
  68.          } else if (!trap || (trap->ttyp != TRAPDOOR && trap->ttyp != HOLE)
  69.                     || !Can_fall_thru(&u.uz) || !trap->tseen) {
  70.              if (flags.autodig && !context.nopick && uwep && is_pick(uwep)) {
  71.                  return use_pick_axe2(uwep);
  72.              } else {
  73.                  You_cant("go down here.");
  74.                  return 0;
  75.              }
  76.          }
  77.      }
  78.      if (u.ustuck) {
  79.          You("are %s, and cannot go down.",
  80.              !u.uswallow ? "being held" : is_animal(u.ustuck->data)
  81.                                               ? "swallowed"
  82.                                               : "engulfed");
  83.          return 1;
  84.      }
  85.      if (on_level(&valley_level, &u.uz) && !u.uevent.gehennom_entered) {
  86.          You("are standing at the gate to Gehennom.");
  87.          pline("Unspeakable cruelty and harm lurk down there.");
  88.          if (yn("Are you sure you want to enter?") != 'y')
  89.              return 0;
  90.          else
  91.              pline("So be it.");
  92.          u.uevent.gehennom_entered = 1; /* don't ask again */
  93.      }
  94.  
  95.      if (!next_to_u()) {
  96.          You("are held back by your pet!");
  97.          return 0;
  98.      }
  99.  
  100.      if (trap)
  101.          You("%s %s.", Flying ? "fly" : locomotion(youmonst.data, "jump"),
  102.              trap->ttyp == HOLE ? "down the hole" : "through the trap door");
  103.  
  104.      if (trap && Is_stronghold(&u.uz)) {
  105.          goto_hell(FALSE, TRUE);
  106.      } else {
  107.          at_ladder = (boolean) (levl[u.ux][u.uy].typ == LADDER);
  108.          next_level(!trap);
  109.          at_ladder = FALSE;
  110.      }
  111.      return 1;
  112.  }
  113.  

doup

  1.  /* the '<' command */
  2.  int
  3.  doup()
  4.  {
  5.      if (u_rooted())
  6.          return 1;
  7.  
  8.      /* "up" to get out of a pit... */
  9.      if (u.utrap && u.utraptype == TT_PIT) {
  10.          climb_pit();
  11.          return 1;
  12.      }
  13.  
  14.      if ((u.ux != xupstair || u.uy != yupstair)
  15.          && (!xupladder || u.ux != xupladder || u.uy != yupladder)
  16.          && (!sstairs.sx || u.ux != sstairs.sx || u.uy != sstairs.sy
  17.              || !sstairs.up)) {
  18.          You_cant("go up here.");
  19.          return 0;
  20.      }
  21.      if (stucksteed(TRUE)) {
  22.          return 0;
  23.      }
  24.      if (u.ustuck) {
  25.          You("are %s, and cannot go up.",
  26.              !u.uswallow ? "being held" : is_animal(u.ustuck->data)
  27.                                               ? "swallowed"
  28.                                               : "engulfed");
  29.          return 1;
  30.      }
  31.      if (near_capacity() > SLT_ENCUMBER) {
  32.          /* No levitation check; inv_weight() already allows for it */
  33.          Your("load is too heavy to climb the %s.",
  34.               levl[u.ux][u.uy].typ == STAIRS ? "stairs" : "ladder");
  35.          return 1;
  36.      }
  37.      if (ledger_no(&u.uz) == 1) {
  38.          if (yn("Beware, there will be no return! Still climb?") != 'y')
  39.              return 0;
  40.      }
  41.      if (!next_to_u()) {
  42.          You("are held back by your pet!");
  43.          return 0;
  44.      }
  45.      at_ladder = (boolean) (levl[u.ux][u.uy].typ == LADDER);
  46.      prev_level(TRUE);
  47.      at_ladder = FALSE;
  48.      return 1;
  49.  }
  50.  

currentlevel_rewrite

  1.  d_level save_dlevel = { 0, 0 };
  2.  
  3.  /* check that we can write out the current level */
  4.  STATIC_OVL int
  5.  currentlevel_rewrite()
  6.  {
  7.      register int fd;
  8.      char whynot[BUFSZ];
  9.  
  10.      /* since level change might be a bit slow, flush any buffered screen
  11.       *  output (like "you fall through a trap door") */
  12.      mark_synch();
  13.  
  14.      fd = create_levelfile(ledger_no(&u.uz), whynot);
  15.      if (fd < 0) {
  16.          /*
  17.           * This is not quite impossible: e.g., we may have
  18.           * exceeded our quota. If that is the case then we
  19.           * cannot leave this level, and cannot save either.
  20.           * Another possibility is that the directory was not
  21.           * writable.
  22.           */
  23.          pline1(whynot);
  24.          return -1;
  25.      }
  26.  
  27.  #ifdef MFLOPPY
  28.      if (!savelev(fd, ledger_no(&u.uz), COUNT_SAVE)) {
  29.          (void) nhclose(fd);
  30.          delete_levelfile(ledger_no(&u.uz));
  31.          pline("NetHack is out of disk space for making levels!");
  32.          You("can save, quit, or continue playing.");
  33.          return -1;
  34.      }
  35.  #endif
  36.      return fd;
  37.  }
  38.  

save_currentstate

  1.  #ifdef INSURANCE
  2.  void
  3.  save_currentstate()
  4.  {
  5.      int fd;
  6.  
  7.      if (flags.ins_chkpt) {
  8.          /* write out just-attained level, with pets and everything */
  9.          fd = currentlevel_rewrite();
  10.          if (fd < 0)
  11.              return;
  12.          bufon(fd);
  13.          savelev(fd, ledger_no(&u.uz), WRITE_SAVE);
  14.          bclose(fd);
  15.      }
  16.  
  17.      /* write out non-level state */
  18.      savestateinlock();
  19.  }
  20.  #endif
  21.  
  22.  /*
  23.  static boolean
  24.  badspot(x, y)
  25.  register xchar x, y;
  26.  {
  27.      return (boolean) ((levl[x][y].typ != ROOM
  28.                         && levl[x][y].typ != AIR
  29.                         && levl[x][y].typ != CORR)
  30.                        || MON_AT(x, y));
  31.  }
  32.  */
  33.  

goto_level

  1.  void
  2.  goto_level(newlevel, at_stairs, falling, portal)
  3.  d_level *newlevel;
  4.  boolean at_stairs, falling, portal;
  5.  {
  6.      int fd, l_idx;
  7.      xchar new_ledger;
  8.      boolean cant_go_back, up = (depth(newlevel) < depth(&u.uz)),
  9.                            newdungeon = (u.uz.dnum != newlevel->dnum),
  10.                            was_in_W_tower = In_W_tower(u.ux, u.uy, &u.uz),
  11.                            familiar = FALSE;
  12.      boolean new = FALSE; /* made a new level? */
  13.      struct monst *mtmp;
  14.      char whynot[BUFSZ];
  15.      char *annotation;
  16.  
  17.      if (dunlev(newlevel) > dunlevs_in_dungeon(newlevel))
  18.          newlevel->dlevel = dunlevs_in_dungeon(newlevel);
  19.      if (newdungeon && In_endgame(newlevel)) { /* 1st Endgame Level !!! */
  20.          if (!u.uhave.amulet)
  21.              return;  /* must have the Amulet */
  22.          if (!wizard) /* wizard ^V can bypass Earth level */
  23.              assign_level(newlevel, &earth_level); /* (redundant) */
  24.      }
  25.      new_ledger = ledger_no(newlevel);
  26.      if (new_ledger <= 0)
  27.          done(ESCAPED); /* in fact < 0 is impossible */
  28.  
  29.      /* If you have the amulet and are trying to get out of Gehennom,
  30.       * going up a set of stairs sometimes does some very strange things!
  31.       * Biased against law and towards chaos.  (The chance to be sent
  32.       * down multiple levels when attempting to go up are significantly
  33.       * less than the corresponding comment in older versions indicated
  34.       * due to overlooking the effect of the call to assign_rnd_lvl().)
  35.       *
  36.       * Odds for making it to the next level up, or of being sent down:
  37.       *  "up"    L      N      C
  38.       *   +1   75.0   75.0   75.0
  39.       *    0    6.25   8.33  12.5
  40.       *   -1   11.46  12.50  12.5
  41.       *   -2    5.21   4.17   0.0
  42.       *   -3    2.08   0.0    0.0
  43.       */
  44.      if (Inhell && up && u.uhave.amulet && !newdungeon && !portal
  45.          && (dunlev(&u.uz) < dunlevs_in_dungeon(&u.uz) - 3)) {
  46.          if (!rn2(4)) {
  47.              int odds = 3 + (int) u.ualign.type,   /* 2..4 */
  48.                  diff = odds <= 1 ? 0 : rn2(odds); /* paranoia */
  49.  
  50.              if (diff != 0) {
  51.                  assign_rnd_level(newlevel, &u.uz, diff);
  52.                  /* if inside the tower, stay inside */
  53.                  if (was_in_W_tower && !On_W_tower_level(newlevel))
  54.                      diff = 0;
  55.              }
  56.              if (diff == 0)
  57.                  assign_level(newlevel, &u.uz);
  58.  
  59.              new_ledger = ledger_no(newlevel);
  60.  
  61.              pline("A mysterious force momentarily surrounds you...");
  62.              if (on_level(newlevel, &u.uz)) {
  63.                  (void) safe_teleds(FALSE);
  64.                  (void) next_to_u();
  65.                  return;
  66.              } else
  67.                  at_stairs = at_ladder = FALSE;
  68.          }
  69.      }
  70.  
  71.      /* Prevent the player from going past the first quest level unless
  72.       * (s)he has been given the go-ahead by the leader.
  73.       */
  74.      if (on_level(&u.uz, &qstart_level) && !newdungeon && !ok_to_quest()) {
  75.          pline("A mysterious force prevents you from descending.");
  76.          return;
  77.      }
  78.  
  79.      if (on_level(newlevel, &u.uz))
  80.          return; /* this can happen */
  81.  
  82.      /* tethered movement makes level change while trapped feasible */
  83.      if (u.utrap && u.utraptype == TT_BURIEDBALL)
  84.          buried_ball_to_punishment(); /* (before we save/leave old level) */
  85.  
  86.      fd = currentlevel_rewrite();
  87.      if (fd < 0)
  88.          return;
  89.  
  90.      if (falling) /* assuming this is only trap door or hole */
  91.          impact_drop((struct obj *) 0, u.ux, u.uy, newlevel->dlevel);
  92.  
  93.      check_special_room(TRUE); /* probably was a trap door */
  94.      if (Punished)
  95.          unplacebc();
  96.      u.utrap = 0; /* needed in level_tele */
  97.      fill_pit(u.ux, u.uy);
  98.      u.ustuck = 0; /* idem */
  99.      u.uinwater = 0;
  100.      u.uundetected = 0; /* not hidden, even if means are available */
  101.      keepdogs(FALSE);
  102.      if (u.uswallow) /* idem */
  103.          u.uswldtim = u.uswallow = 0;
  104.      recalc_mapseen(); /* recalculate map overview before we leave the level */
  105.      /*
  106.       *  We no longer see anything on the level.  Make sure that this
  107.       *  follows u.uswallow set to null since uswallow overrides all
  108.       *  normal vision.
  109.       */
  110.      vision_recalc(2);
  111.  
  112.      /*
  113.       * Save the level we're leaving.  If we're entering the endgame,
  114.       * we can get rid of all existing levels because they cannot be
  115.       * reached any more.  We still need to use savelev()'s cleanup
  116.       * for the level being left, to recover dynamic memory in use and
  117.       * to avoid dangling timers and light sources.
  118.       */
  119.      cant_go_back = (newdungeon && In_endgame(newlevel));
  120.      if (!cant_go_back) {
  121.          update_mlstmv(); /* current monsters are becoming inactive */
  122.          bufon(fd);       /* use buffered output */
  123.      }
  124.      savelev(fd, ledger_no(&u.uz),
  125.              cant_go_back ? FREE_SAVE : (WRITE_SAVE | FREE_SAVE));
  126.      bclose(fd);
  127.      if (cant_go_back) {
  128.          /* discard unreachable levels; keep #0 */
  129.          for (l_idx = maxledgerno(); l_idx > 0; --l_idx)
  130.              delete_levelfile(l_idx);
  131.          /* mark #overview data for all dungeon branches as uninteresting */
  132.          for (l_idx = 0; l_idx < n_dgns; ++l_idx)
  133.              remdun_mapseen(l_idx);
  134.      }
  135.  
  136.      if (Is_rogue_level(newlevel) || Is_rogue_level(&u.uz))
  137.          assign_graphics(Is_rogue_level(newlevel) ? ROGUESET : PRIMARY);
  138.  #ifdef USE_TILES
  139.      substitute_tiles(newlevel);
  140.  #endif
  141.      /* record this level transition as a potential seen branch unless using
  142.       * some non-standard means of transportation (level teleport).
  143.       */
  144.      if ((at_stairs || falling || portal) && (u.uz.dnum != newlevel->dnum))
  145.          recbranch_mapseen(&u.uz, newlevel);
  146.      assign_level(&u.uz0, &u.uz);
  147.      assign_level(&u.uz, newlevel);
  148.      assign_level(&u.utolev, newlevel);
  149.      u.utotype = 0;
  150.      if (!builds_up(&u.uz)) { /* usual case */
  151.          if (dunlev(&u.uz) > dunlev_reached(&u.uz))
  152.              dunlev_reached(&u.uz) = dunlev(&u.uz);
  153.      } else {
  154.          if (dunlev_reached(&u.uz) == 0
  155.              || dunlev(&u.uz) < dunlev_reached(&u.uz))
  156.              dunlev_reached(&u.uz) = dunlev(&u.uz);
  157.      }
  158.      reset_rndmonst(NON_PM); /* u.uz change affects monster generation */
  159.  
  160.      /* set default level change destination areas */
  161.      /* the special level code may override these */
  162.      (void) memset((genericptr_t) &updest, 0, sizeof updest);
  163.      (void) memset((genericptr_t) &dndest, 0, sizeof dndest);
  164.  
  165.      if (!(level_info[new_ledger].flags & LFILE_EXISTS)) {
  166.          /* entering this level for first time; make it now */
  167.          if (level_info[new_ledger].flags & (FORGOTTEN | VISITED)) {
  168.              impossible("goto_level: returning to discarded level?");
  169.              level_info[new_ledger].flags &= ~(FORGOTTEN | VISITED);
  170.          }
  171.          mklev();
  172.          new = TRUE; /* made the level */
  173.      } else {
  174.          /* returning to previously visited level; reload it */
  175.          fd = open_levelfile(new_ledger, whynot);
  176.          if (tricked_fileremoved(fd, whynot)) {
  177.              /* we'll reach here if running in wizard mode */
  178.              error("Cannot continue this game.");
  179.          }
  180.          minit(); /* ZEROCOMP */
  181.          getlev(fd, hackpid, new_ledger, FALSE);
  182.          (void) nhclose(fd);
  183.          oinit(); /* reassign level dependent obj probabilities */
  184.      }
  185.      reglyph_darkroom();
  186.      /* do this prior to level-change pline messages */
  187.      vision_reset();         /* clear old level's line-of-sight */
  188.      vision_full_recalc = 0; /* don't let that reenable vision yet */
  189.      flush_screen(-1);       /* ensure all map flushes are postponed */
  190.  
  191.      if (portal && !In_endgame(&u.uz)) {
  192.          /* find the portal on the new level */
  193.          register struct trap *ttrap;
  194.  
  195.          for (ttrap = ftrap; ttrap; ttrap = ttrap->ntrap)
  196.              if (ttrap->ttyp == MAGIC_PORTAL)
  197.                  break;
  198.  
  199.          if (!ttrap)
  200.              panic("goto_level: no corresponding portal!");
  201.          seetrap(ttrap);
  202.          u_on_newpos(ttrap->tx, ttrap->ty);
  203.      } else if (at_stairs && !In_endgame(&u.uz)) {
  204.          if (up) {
  205.              if (at_ladder)
  206.                  u_on_newpos(xdnladder, ydnladder);
  207.              else if (newdungeon)
  208.                  u_on_sstairs(1);
  209.              else
  210.                  u_on_dnstairs();
  211.              /* you climb up the {stairs|ladder};
  212.                 fly up the stairs; fly up along the ladder */
  213.              pline("%s %s up%s the %s.",
  214.                    (Punished && !Levitation) ? "With great effort you" : "You",
  215.                    Flying ? "fly" : "climb",
  216.                    (Flying && at_ladder) ? " along" : "",
  217.                    at_ladder ? "ladder" : "stairs");
  218.          } else { /* down */
  219.              if (at_ladder)
  220.                  u_on_newpos(xupladder, yupladder);
  221.              else if (newdungeon)
  222.                  u_on_sstairs(0);
  223.              else
  224.                  u_on_upstairs();
  225.              if (!u.dz) {
  226.                  ; /* stayed on same level? (no transit effects) */
  227.              } else if (Flying) {
  228.                  if (flags.verbose)
  229.                      You("fly down %s.",
  230.                          at_ladder ? "along the ladder" : "the stairs");
  231.              } else if (near_capacity() > UNENCUMBERED || Punished
  232.                         || Fumbling) {
  233.                  You("fall down the %s.", at_ladder ? "ladder" : "stairs");
  234.                  if (Punished) {
  235.                      drag_down();
  236.                      ballrelease(FALSE);
  237.                  }
  238.                  /* falling off steed has its own losehp() call */
  239.                  if (u.usteed)
  240.                      dismount_steed(DISMOUNT_FELL);
  241.                  else
  242.                      losehp(Maybe_Half_Phys(rnd(3)),
  243.                             at_ladder ? "falling off a ladder"
  244.                                       : "tumbling down a flight of stairs",
  245.                             KILLED_BY);
  246.                  selftouch("Falling, you");
  247.              } else { /* ordinary descent */
  248.                  if (flags.verbose)
  249.                      You("%s.", at_ladder ? "climb down the ladder"
  250.                                           : "descend the stairs");
  251.              }
  252.          }
  253.      } else { /* trap door or level_tele or In_endgame */
  254.          u_on_rndspot((up ? 1 : 0) | (was_in_W_tower ? 2 : 0));
  255.          if (falling) {
  256.              if (Punished)
  257.                  ballfall();
  258.              selftouch("Falling, you");
  259.          }
  260.      }
  261.  
  262.      if (Punished)
  263.          placebc();
  264.      obj_delivery(FALSE);
  265.      losedogs();
  266.      kill_genocided_monsters(); /* for those wiped out while in limbo */
  267.      /*
  268.       * Expire all timers that have gone off while away.  Must be
  269.       * after migrating monsters and objects are delivered
  270.       * (losedogs and obj_delivery).
  271.       */
  272.      run_timers();
  273.  
  274.      initrack();
  275.  
  276.      if ((mtmp = m_at(u.ux, u.uy)) != 0 && mtmp != u.usteed) {
  277.          /* There's a monster at your target destination; it might be one
  278.             which accompanied you--see mon_arrive(dogmove.c)--or perhaps
  279.             it was already here.  Randomly move you to an adjacent spot
  280.             or else the monster to any nearby location.  Prior to 3.3.0
  281.             the latter was done unconditionally. */
  282.          coord cc;
  283.  
  284.          if (!rn2(2) && enexto(&cc, u.ux, u.uy, youmonst.data)
  285.              && distu(cc.x, cc.y) <= 2)
  286.              u_on_newpos(cc.x, cc.y); /*[maybe give message here?]*/
  287.          else
  288.              mnexto(mtmp);
  289.  
  290.          if ((mtmp = m_at(u.ux, u.uy)) != 0) {
  291.              /* there was an unconditional impossible("mnearto failed")
  292.                 here, but it's not impossible and we're prepared to cope
  293.                 with the situation, so only say something when debugging */
  294.              if (wizard)
  295.                  pline("(monster in hero's way)");
  296.              if (!rloc(mtmp, TRUE))
  297.                  /* no room to move it; send it away, to return later */
  298.                  migrate_to_level(mtmp, ledger_no(&u.uz), MIGR_RANDOM,
  299.                                   (coord *) 0);
  300.          }
  301.      }
  302.  
  303.      /* initial movement of bubbles just before vision_recalc */
  304.      if (Is_waterlevel(&u.uz) || Is_airlevel(&u.uz))
  305.          movebubbles();
  306.      else if (Is_firelevel(&u.uz))
  307.          fumaroles();
  308.  
  309.      if (level_info[new_ledger].flags & FORGOTTEN) {
  310.          forget_map(ALL_MAP); /* forget the map */
  311.          forget_traps();      /* forget all traps too */
  312.          familiar = TRUE;
  313.          level_info[new_ledger].flags &= ~FORGOTTEN;
  314.      }
  315.  
  316.      /* Reset the screen. */
  317.      vision_reset(); /* reset the blockages */
  318.      docrt();        /* does a full vision recalc */
  319.      flush_screen(-1);
  320.  
  321.      /*
  322.       *  Move all plines beyond the screen reset.
  323.       */
  324.  
  325.      /* special levels can have a custom arrival message */
  326.      deliver_splev_message();
  327.  
  328.      /* give room entrance message, if any */
  329.      check_special_room(FALSE);
  330.  
  331.      /* deliver objects traveling with player */
  332.      obj_delivery(TRUE);
  333.  
  334.      /* Check whether we just entered Gehennom. */
  335.      if (!In_hell(&u.uz0) && Inhell) {
  336.          if (Is_valley(&u.uz)) {
  337.              You("arrive at the Valley of the Dead...");
  338.              pline_The("odor of burnt flesh and decay pervades the air.");
  339.  #ifdef MICRO
  340.              display_nhwindow(WIN_MESSAGE, FALSE);
  341.  #endif
  342.              You_hear("groans and moans everywhere.");
  343.          } else
  344.              pline("It is hot here.  You smell smoke...");
  345.          u.uachieve.enter_gehennom = 1;
  346.      }
  347.      /* in case we've managed to bypass the Valley's stairway down */
  348.      if (Inhell && !Is_valley(&u.uz))
  349.          u.uevent.gehennom_entered = 1;
  350.  
  351.      if (familiar) {
  352.          static const char *const fam_msgs[4] = {
  353.              "You have a sense of deja vu.",
  354.              "You feel like you've been here before.",
  355.              "This place %s familiar...", 0 /* no message */
  356.          };
  357.          static const char *const halu_fam_msgs[4] = {
  358.              "Whoa!  Everything %s different.",
  359.              "You are surrounded by twisty little passages, all alike.",
  360.              "Gee, this %s like uncle Conan's place...", 0 /* no message */
  361.          };
  362.          const char *mesg;
  363.          char buf[BUFSZ];
  364.          int which = rn2(4);
  365.  
  366.          if (Hallucination)
  367.              mesg = halu_fam_msgs[which];
  368.          else
  369.              mesg = fam_msgs[which];
  370.          if (mesg && index(mesg, '%')) {
  371.              Sprintf(buf, mesg, !Blind ? "looks" : "seems");
  372.              mesg = buf;
  373.          }
  374.          if (mesg)
  375.              pline1(mesg);
  376.      }
  377.  
  378.      /* special location arrival messages/events */
  379.      if (In_endgame(&u.uz)) {
  380.          if (new &&on_level(&u.uz, &astral_level))
  381.              final_level(); /* guardian angel,&c */
  382.          else if (newdungeon && u.uhave.amulet)
  383.              resurrect(); /* force confrontation with Wizard */
  384.      } else if (In_quest(&u.uz)) {
  385.          onquest(); /* might be reaching locate|goal level */
  386.      } else if (In_V_tower(&u.uz)) {
  387.          if (newdungeon && In_hell(&u.uz0))
  388.              pline_The("heat and smoke are gone.");
  389.      } else if (Is_knox(&u.uz)) {
  390.          /* alarm stops working once Croesus has died */
  391.          if (new || !mvitals[PM_CROESUS].died) {
  392.              You("have penetrated a high security area!");
  393.              pline("An alarm sounds!");
  394.              for (mtmp = fmon; mtmp; mtmp = mtmp->nmon) {
  395.                  if (DEADMONSTER(mtmp))
  396.                      continue;
  397.                  mtmp->msleeping = 0;
  398.              }
  399.          }
  400.      } else {
  401.          if (new && Is_rogue_level(&u.uz))
  402.              You("enter what seems to be an older, more primitive world.");
  403.          /* main dungeon message from your quest leader */
  404.          if (!In_quest(&u.uz0) && at_dgn_entrance("The Quest")
  405.              && !(u.uevent.qcompleted || u.uevent.qexpelled
  406.                   || quest_status.leader_is_dead)) {
  407.              if (!u.uevent.qcalled) {
  408.                  u.uevent.qcalled = 1;
  409.                  com_pager(2); /* main "leader needs help" message */
  410.              } else {          /* reminder message */
  411.                  com_pager(Role_if(PM_ROGUE) ? 4 : 3);
  412.              }
  413.          }
  414.      }
  415.  
  416.      assign_level(&u.uz0, &u.uz); /* reset u.uz0 */
  417.  #ifdef INSURANCE
  418.      save_currentstate();
  419.  #endif
  420.  
  421.      if ((annotation = get_annotation(&u.uz)))
  422.          You("remember this level as %s.", annotation);
  423.  
  424.      /* assume this will always return TRUE when changing level */
  425.      (void) in_out_region(u.ux, u.uy);
  426.      (void) pickup(1);
  427.      context.polearm.hitmon = NULL;
  428.  }
  429.  

final_level

  1.  STATIC_OVL void
  2.  final_level()
  3.  {
  4.      struct monst *mtmp;
  5.  
  6.      /* reset monster hostility relative to player */
  7.      for (mtmp = fmon; mtmp; mtmp = mtmp->nmon) {
  8.          if (DEADMONSTER(mtmp))
  9.              continue;
  10.          reset_hostility(mtmp);
  11.      }
  12.  
  13.      /* create some player-monsters */
  14.      create_mplayers(rn1(4, 3), TRUE);
  15.  
  16.      /* create a guardian angel next to player, if worthy */
  17.      gain_guardian_angel();
  18.  }
  19.  

schedule_goto

  1.  static char *dfr_pre_msg = 0,  /* pline() before level change */
  2.              *dfr_post_msg = 0; /* pline() after level change */
  3.  
  4.  /* change levels at the end of this turn, after monsters finish moving */
  5.  void
  6.  schedule_goto(tolev, at_stairs, falling, portal_flag, pre_msg, post_msg)
  7.  d_level *tolev;
  8.  boolean at_stairs, falling;
  9.  int portal_flag;
  10.  const char *pre_msg, *post_msg;
  11.  {
  12.      int typmask = 0100; /* non-zero triggers `deferred_goto' */
  13.  
  14.      /* destination flags (`goto_level' args) */
  15.      if (at_stairs)
  16.          typmask |= 1;
  17.      if (falling)
  18.          typmask |= 2;
  19.      if (portal_flag)
  20.          typmask |= 4;
  21.      if (portal_flag < 0)
  22.          typmask |= 0200; /* flag for portal removal */
  23.      u.utotype = typmask;
  24.      /* destination level */
  25.      assign_level(&u.utolev, tolev);
  26.  
  27.      if (pre_msg)
  28.          dfr_pre_msg = dupstr(pre_msg);
  29.      if (post_msg)
  30.          dfr_post_msg = dupstr(post_msg);
  31.  }
  32.  

deferred_goto

  1.  /* handle something like portal ejection */
  2.  void
  3.  deferred_goto()
  4.  {
  5.      if (!on_level(&u.uz, &u.utolev)) {
  6.          d_level dest;
  7.          int typmask = u.utotype; /* save it; goto_level zeroes u.utotype */
  8.  
  9.          assign_level(&dest, &u.utolev);
  10.          if (dfr_pre_msg)
  11.              pline1(dfr_pre_msg);
  12.          goto_level(&dest, !!(typmask & 1), !!(typmask & 2), !!(typmask & 4));
  13.          if (typmask & 0200) { /* remove portal */
  14.              struct trap *t = t_at(u.ux, u.uy);
  15.  
  16.              if (t) {
  17.                  deltrap(t);
  18.                  newsym(u.ux, u.uy);
  19.              }
  20.          }
  21.          if (dfr_post_msg)
  22.              pline1(dfr_post_msg);
  23.      }
  24.      u.utotype = 0; /* our caller keys off of this */
  25.      if (dfr_pre_msg)
  26.          free((genericptr_t) dfr_pre_msg), dfr_pre_msg = 0;
  27.      if (dfr_post_msg)
  28.          free((genericptr_t) dfr_post_msg), dfr_post_msg = 0;
  29.  }
  30.  

revive_corpse

  1.  /*
  2.   * Return TRUE if we created a monster for the corpse.  If successful, the
  3.   * corpse is gone.
  4.   */
  5.  boolean
  6.  revive_corpse(corpse)
  7.  struct obj *corpse;
  8.  {
  9.      struct monst *mtmp, *mcarry;
  10.      boolean is_uwep, chewed;
  11.      xchar where;
  12.      char cname[BUFSZ];
  13.      struct obj *container = (struct obj *) 0;
  14.      int container_where = 0;
  15.  
  16.      where = corpse->where;
  17.      is_uwep = (corpse == uwep);
  18.      chewed = (corpse->oeaten != 0);
  19.      Strcpy(cname,
  20.             corpse_xname(corpse, chewed ? "bite-covered" : (const char *) 0,
  21.                          CXN_SINGULAR));
  22.      mcarry = (where == OBJ_MINVENT) ? corpse->ocarry : 0;
  23.  
  24.      if (where == OBJ_CONTAINED) {
  25.          struct monst *mtmp2;
  26.  
  27.          container = corpse->ocontainer;
  28.          mtmp2 =
  29.              get_container_location(container, &container_where, (int *) 0);
  30.          /* container_where is the outermost container's location even if
  31.           * nested */
  32.          if (container_where == OBJ_MINVENT && mtmp2)
  33.              mcarry = mtmp2;
  34.      }
  35.      mtmp = revive(corpse, FALSE); /* corpse is gone if successful */
  36.  
  37.      if (mtmp) {
  38.          switch (where) {
  39.          case OBJ_INVENT:
  40.              if (is_uwep)
  41.                  pline_The("%s writhes out of your grasp!", cname);
  42.              else
  43.                  You_feel("squirming in your backpack!");
  44.              break;
  45.  
  46.          case OBJ_FLOOR:
  47.              if (cansee(mtmp->mx, mtmp->my))
  48.                  pline("%s rises from the dead!",
  49.                        chewed ? Adjmonnam(mtmp, "bite-covered")
  50.                               : Monnam(mtmp));
  51.              break;
  52.  
  53.          case OBJ_MINVENT: /* probably a nymph's */
  54.              if (cansee(mtmp->mx, mtmp->my)) {
  55.                  if (canseemon(mcarry))
  56.                      pline("Startled, %s drops %s as it revives!",
  57.                            mon_nam(mcarry), an(cname));
  58.                  else
  59.                      pline("%s suddenly appears!",
  60.                            chewed ? Adjmonnam(mtmp, "bite-covered")
  61.                                   : Monnam(mtmp));
  62.              }
  63.              break;
  64.          case OBJ_CONTAINED: {
  65.              char sackname[BUFSZ];
  66.  
  67.              if (container_where == OBJ_MINVENT && cansee(mtmp->mx, mtmp->my)
  68.                  && mcarry && canseemon(mcarry) && container) {
  69.                  pline("%s writhes out of %s!", Amonnam(mtmp),
  70.                        yname(container));
  71.              } else if (container_where == OBJ_INVENT && container) {
  72.                  Strcpy(sackname, an(xname(container)));
  73.                  pline("%s %s out of %s in your pack!",
  74.                        Blind ? Something : Amonnam(mtmp),
  75.                        locomotion(mtmp->data, "writhes"), sackname);
  76.              } else if (container_where == OBJ_FLOOR && container
  77.                         && cansee(mtmp->mx, mtmp->my)) {
  78.                  Strcpy(sackname, an(xname(container)));
  79.                  pline("%s escapes from %s!", Amonnam(mtmp), sackname);
  80.              }
  81.              break;
  82.          }
  83.          default:
  84.              /* we should be able to handle the other cases... */
  85.              impossible("revive_corpse: lost corpse @ %d", where);
  86.              break;
  87.          }
  88.          return TRUE;
  89.      }
  90.      return FALSE;
  91.  }
  92.  

revive_mon

  1.  /* Revive the corpse via a timeout. */
  2.  /*ARGSUSED*/
  3.  void
  4.  revive_mon(arg, timeout)
  5.  anything *arg;
  6.  long timeout UNUSED;
  7.  {
  8.      struct obj *body = arg->a_obj;
  9.      struct permonst *mptr = &mons[body->corpsenm];
  10.      struct monst *mtmp;
  11.      xchar x, y;
  12.  
  13.      /* corpse will revive somewhere else if there is a monster in the way;
  14.         Riders get a chance to try to bump the obstacle out of their way */
  15.      if ((mptr->mflags3 & M3_DISPLACES) != 0 && body->where == OBJ_FLOOR
  16.          && get_obj_location(body, &x, &y, 0) && (mtmp = m_at(x, y)) != 0) {
  17.          boolean notice_it = canseemon(mtmp); /* before rloc() */
  18.          char *monname = Monnam(mtmp);
  19.  
  20.          if (rloc(mtmp, TRUE)) {
  21.              if (notice_it && !canseemon(mtmp))
  22.                  pline("%s vanishes.", monname);
  23.              else if (!notice_it && canseemon(mtmp))
  24.                  pline("%s appears.", Monnam(mtmp)); /* not pre-rloc monname */
  25.              else if (notice_it && dist2(mtmp->mx, mtmp->my, x, y) > 2)
  26.                  pline("%s teleports.", monname); /* saw it and still see it */
  27.          }
  28.      }
  29.  
  30.      /* if we succeed, the corpse is gone */
  31.      if (!revive_corpse(body)) {
  32.          long when;
  33.          int action;
  34.  
  35.          if (is_rider(mptr) && rn2(99)) { /* Rider usually tries again */
  36.              action = REVIVE_MON;
  37.              for (when = 3L; when < 67L; when++)
  38.                  if (!rn2(3))
  39.                      break;
  40.          } else { /* rot this corpse away */
  41.              You_feel("%sless hassled.", is_rider(mptr) ? "much " : "");
  42.              action = ROT_CORPSE;
  43.              when = 250L - (monstermoves - body->age);
  44.              if (when < 1L)
  45.                  when = 1L;
  46.          }
  47.          (void) start_timer(when, TIMER_OBJECT, action, arg);
  48.      }
  49.  }
  50.  

donull

  1.  int
  2.  donull()
  3.  {
  4.      return 1; /* Do nothing, but let other things happen */
  5.  }
  6.  

wipeoff

  1.  STATIC_PTR int
  2.  wipeoff(VOID_ARGS)
  3.  {
  4.      if (u.ucreamed < 4)
  5.          u.ucreamed = 0;
  6.      else
  7.          u.ucreamed -= 4;
  8.      if (Blinded < 4)
  9.          Blinded = 0;
  10.      else
  11.          Blinded -= 4;
  12.      if (!Blinded) {
  13.          pline("You've got the glop off.");
  14.          u.ucreamed = 0;
  15.          if (!gulp_blnd_check()) {
  16.              Blinded = 1;
  17.              make_blinded(0L, TRUE);
  18.          }
  19.          return 0;
  20.      } else if (!u.ucreamed) {
  21.          Your("%s feels clean now.", body_part(FACE));
  22.          return 0;
  23.      }
  24.      return 1; /* still busy */
  25.  }
  26.  

dowipe

  1.  int
  2.  dowipe()
  3.  {
  4.      if (u.ucreamed) {
  5.          static NEARDATA char buf[39];
  6.  
  7.          Sprintf(buf, "wiping off your %s", body_part(FACE));
  8.          set_occupation(wipeoff, buf, 0);
  9.          /* Not totally correct; what if they change back after now
  10.           * but before they're finished wiping?
  11.           */
  12.          return 1;
  13.      }
  14.      Your("%s is already clean.", body_part(FACE));
  15.      return 1;
  16.  }
  17.  

set_wounded_legs

  1.  void
  2.  set_wounded_legs(side, timex)
  3.  register long side;
  4.  register int timex;
  5.  {
  6.      /* KMH -- STEED
  7.       * If you are riding, your steed gets the wounded legs instead.
  8.       * You still call this function, but don't lose hp.
  9.       * Caller is also responsible for adjusting messages.
  10.       */
  11.  
  12.      if (!Wounded_legs) {
  13.          ATEMP(A_DEX)--;
  14.          context.botl = 1;
  15.      }
  16.  
  17.      if (!Wounded_legs || (HWounded_legs & TIMEOUT))
  18.          HWounded_legs = timex;
  19.      EWounded_legs = side;
  20.      (void) encumber_msg();
  21.  }
  22.  

heal_legs

  1.  void
  2.  heal_legs()
  3.  {
  4.      if (Wounded_legs) {
  5.          if (ATEMP(A_DEX) < 0) {
  6.              ATEMP(A_DEX)++;
  7.              context.botl = 1;
  8.          }
  9.  
  10.          if (!u.usteed) {
  11.              const char *legs = body_part(LEG);
  12.  
  13.              if ((EWounded_legs & BOTH_SIDES) == BOTH_SIDES)
  14.                  legs = makeplural(legs);
  15.              /* this used to say "somewhat better" but that was
  16.                 misleading since legs are being fully healed */
  17.              Your("%s %s better.", legs, vtense(legs, "feel"));
  18.          }
  19.  
  20.          HWounded_legs = EWounded_legs = 0;
  21.  
  22.          /* Wounded_legs reduces carrying capacity, so we want
  23.             an encumbrance check when they're healed.  However,
  24.             while dismounting, first steed's legs get healed,
  25.             then hero is dropped to floor and a new encumbrance
  26.             check is made [in dismount_steed()].  So don't give
  27.             encumbrance feedback during the dismount stage
  28.             because it could seem to be shown out of order and
  29.             it might be immediately contradicted [able to carry
  30.             more when steed becomes healthy, then possible floor
  31.             feedback, then able to carry less when back on foot]. */
  32.          if (!in_steed_dismounting)
  33.              (void) encumber_msg();
  34.      }
  35.  }
  36.  
  37.  /*do.c*/