Source:NetHack 3.6.0/src/teleport.c

From NetHackWiki
Jump to: navigation, search

Below is the full text to teleport.c from the source code of NetHack 3.6.0. To link to a particular line, write [[Source:NetHack 3.6.0/src/teleport.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	teleport.c	$NHDT-Date: 1446887535 2015/11/07 09:12:15 $  $NHDT-Branch: master $:$NHDT-Revision: 1.62 $ */
  2.  /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
  3.  /* NetHack may be freely redistributed.  See license for details. */
  4.  
  5.  #include "hack.h"
  6.  
  7.  STATIC_DCL boolean FDECL(tele_jump_ok, (int, int, int, int));
  8.  STATIC_DCL boolean FDECL(teleok, (int, int, BOOLEAN_P));
  9.  STATIC_DCL void NDECL(vault_tele);
  10.  STATIC_DCL boolean FDECL(rloc_pos_ok, (int, int, struct monst *));
  11.  STATIC_DCL void FDECL(mvault_tele, (struct monst *));
  12.  
  13.  /* non-null when teleporting via having read this scroll */
  14.  STATIC_VAR struct obj *telescroll = 0;
  15.  

goodpos

  1.  /*
  2.   * Is (x,y) a good position of mtmp?  If mtmp is NULL, then is (x,y) good
  3.   * for an object?
  4.   *
  5.   * This function will only look at mtmp->mdat, so makemon, mplayer, etc can
  6.   * call it to generate new monster positions with fake monster structures.
  7.   */
  8.  boolean
  9.  goodpos(x, y, mtmp, gpflags)
  10.  int x, y;
  11.  struct monst *mtmp;
  12.  unsigned gpflags;
  13.  {
  14.      struct permonst *mdat = (struct permonst *) 0;
  15.      boolean ignorewater = ((gpflags & MM_IGNOREWATER) != 0);
  16.  
  17.      if (!isok(x, y))
  18.          return FALSE;
  19.  
  20.      /* in many cases, we're trying to create a new monster, which
  21.       * can't go on top of the player or any existing monster.
  22.       * however, occasionally we are relocating engravings or objects,
  23.       * which could be co-located and thus get restricted a bit too much.
  24.       * oh well.
  25.       */
  26.      if (mtmp != &youmonst && x == u.ux && y == u.uy
  27.          && (!u.usteed || mtmp != u.usteed))
  28.          return FALSE;
  29.  
  30.      if (mtmp) {
  31.          struct monst *mtmp2 = m_at(x, y);
  32.  
  33.          /* Be careful with long worms.  A monster may be placed back in
  34.           * its own location.  Normally, if m_at() returns the same monster
  35.           * that we're trying to place, the monster is being placed in its
  36.           * own location.  However, that is not correct for worm segments,
  37.           * because all the segments of the worm return the same m_at().
  38.           * Actually we overdo the check a little bit--a worm can't be placed
  39.           * in its own location, period.  If we just checked for mtmp->mx
  40.           * != x || mtmp->my != y, we'd miss the case where we're called
  41.           * to place the worm segment and the worm's head is at x,y.
  42.           */
  43.          if (mtmp2 && (mtmp2 != mtmp || mtmp->wormno))
  44.              return FALSE;
  45.  
  46.          mdat = mtmp->data;
  47.          if (is_pool(x, y) && !ignorewater) {
  48.              if (mtmp == &youmonst)
  49.                  return (Levitation || Flying || Wwalking || Swimming
  50.                          || Amphibious);
  51.              else
  52.                  return (is_floater(mdat) || is_flyer(mdat) || is_swimmer(mdat)
  53.                          || is_clinger(mdat));
  54.          } else if (mdat->mlet == S_EEL && rn2(13) && !ignorewater) {
  55.              return FALSE;
  56.          } else if (is_lava(x, y)) {
  57.              if (mtmp == &youmonst)
  58.                  return (Levitation || Flying
  59.                          || (Fire_resistance && Wwalking && uarmf
  60.                              && uarmf->oerodeproof)
  61.                          || (Upolyd && likes_lava(youmonst.data)));
  62.              else
  63.                  return (is_floater(mdat) || is_flyer(mdat)
  64.                          || likes_lava(mdat));
  65.          }
  66.          if (passes_walls(mdat) && may_passwall(x, y))
  67.              return TRUE;
  68.          if (amorphous(mdat) && closed_door(x, y))
  69.              return TRUE;
  70.      }
  71.      if (!accessible(x, y)) {
  72.          if (!(is_pool(x, y) && ignorewater))
  73.              return FALSE;
  74.      }
  75.  
  76.      if (sobj_at(BOULDER, x, y) && (!mdat || !throws_rocks(mdat)))
  77.          return FALSE;
  78.      return TRUE;
  79.  }
  80.  

enexto

  1.  /*
  2.   * "entity next to"
  3.   *
  4.   * Attempt to find a good place for the given monster type in the closest
  5.   * position to (xx,yy).  Do so in successive square rings around (xx,yy).
  6.   * If there is more than one valid position in the ring, choose one randomly.
  7.   * Return TRUE and the position chosen when successful, FALSE otherwise.
  8.   */
  9.  boolean
  10.  enexto(cc, xx, yy, mdat)
  11.  coord *cc;
  12.  register xchar xx, yy;
  13.  struct permonst *mdat;
  14.  {
  15.      return enexto_core(cc, xx, yy, mdat, 0);
  16.  }
  17.  

enexto_core

  1.  boolean
  2.  enexto_core(cc, xx, yy, mdat, entflags)
  3.  coord *cc;
  4.  register xchar xx, yy;
  5.  struct permonst *mdat;
  6.  unsigned entflags;
  7.  {
  8.  #define MAX_GOOD 15
  9.      coord good[MAX_GOOD], *good_ptr;
  10.      int x, y, range, i;
  11.      int xmin, xmax, ymin, ymax;
  12.      struct monst fakemon; /* dummy monster */
  13.  
  14.      if (!mdat) {
  15.          debugpline0("enexto() called with null mdat");
  16.          /* default to player's original monster type */
  17.          mdat = &mons[u.umonster];
  18.      }
  19.      fakemon.data = mdat; /* set up for goodpos */
  20.      good_ptr = good;
  21.      range = 1;
  22.      /*
  23.       * Walk around the border of the square with center (xx,yy) and
  24.       * radius range.  Stop when we find at least one valid position.
  25.       */
  26.      do {
  27.          xmin = max(1, xx - range);
  28.          xmax = min(COLNO - 1, xx + range);
  29.          ymin = max(0, yy - range);
  30.          ymax = min(ROWNO - 1, yy + range);
  31.  
  32.          for (x = xmin; x <= xmax; x++)
  33.              if (goodpos(x, ymin, &fakemon, entflags)) {
  34.                  good_ptr->x = x;
  35.                  good_ptr->y = ymin;
  36.                  /* beware of accessing beyond segment boundaries.. */
  37.                  if (good_ptr++ == &good[MAX_GOOD - 1])
  38.                      goto full;
  39.              }
  40.          for (x = xmin; x <= xmax; x++)
  41.              if (goodpos(x, ymax, &fakemon, entflags)) {
  42.                  good_ptr->x = x;
  43.                  good_ptr->y = ymax;
  44.                  /* beware of accessing beyond segment boundaries.. */
  45.                  if (good_ptr++ == &good[MAX_GOOD - 1])
  46.                      goto full;
  47.              }
  48.          for (y = ymin + 1; y < ymax; y++)
  49.              if (goodpos(xmin, y, &fakemon, entflags)) {
  50.                  good_ptr->x = xmin;
  51.                  good_ptr->y = y;
  52.                  /* beware of accessing beyond segment boundaries.. */
  53.                  if (good_ptr++ == &good[MAX_GOOD - 1])
  54.                      goto full;
  55.              }
  56.          for (y = ymin + 1; y < ymax; y++)
  57.              if (goodpos(xmax, y, &fakemon, entflags)) {
  58.                  good_ptr->x = xmax;
  59.                  good_ptr->y = y;
  60.                  /* beware of accessing beyond segment boundaries.. */
  61.                  if (good_ptr++ == &good[MAX_GOOD - 1])
  62.                      goto full;
  63.              }
  64.          range++;
  65.  
  66.          /* return if we've grown too big (nothing is valid) */
  67.          if (range > ROWNO && range > COLNO)
  68.              return FALSE;
  69.      } while (good_ptr == good);
  70.  
  71.  full:
  72.      i = rn2((int) (good_ptr - good));
  73.      cc->x = good[i].x;
  74.      cc->y = good[i].y;
  75.      return TRUE;
  76.  }
  77.  

tele_jump_ok

  1.  /*
  2.   * Check for restricted areas present in some special levels.  (This might
  3.   * need to be augmented to allow deliberate passage in wizard mode, but
  4.   * only for explicitly chosen destinations.)
  5.   */
  6.  STATIC_OVL boolean
  7.  tele_jump_ok(x1, y1, x2, y2)
  8.  int x1, y1, x2, y2;
  9.  {
  10.      if (dndest.nlx > 0) {
  11.          /* if inside a restricted region, can't teleport outside */
  12.          if (within_bounded_area(x1, y1, dndest.nlx, dndest.nly, dndest.nhx,
  13.                                  dndest.nhy)
  14.              && !within_bounded_area(x2, y2, dndest.nlx, dndest.nly,
  15.                                      dndest.nhx, dndest.nhy))
  16.              return FALSE;
  17.          /* and if outside, can't teleport inside */
  18.          if (!within_bounded_area(x1, y1, dndest.nlx, dndest.nly, dndest.nhx,
  19.                                   dndest.nhy)
  20.              && within_bounded_area(x2, y2, dndest.nlx, dndest.nly, dndest.nhx,
  21.                                     dndest.nhy))
  22.              return FALSE;
  23.      }
  24.      if (updest.nlx > 0) { /* ditto */
  25.          if (within_bounded_area(x1, y1, updest.nlx, updest.nly, updest.nhx,
  26.                                  updest.nhy)
  27.              && !within_bounded_area(x2, y2, updest.nlx, updest.nly,
  28.                                      updest.nhx, updest.nhy))
  29.              return FALSE;
  30.          if (!within_bounded_area(x1, y1, updest.nlx, updest.nly, updest.nhx,
  31.                                   updest.nhy)
  32.              && within_bounded_area(x2, y2, updest.nlx, updest.nly, updest.nhx,
  33.                                     updest.nhy))
  34.              return FALSE;
  35.      }
  36.      return TRUE;
  37.  }
  38.  

teleok

  1.  STATIC_OVL boolean
  2.  teleok(x, y, trapok)
  3.  register int x, y;
  4.  boolean trapok;
  5.  {
  6.      if (!trapok && t_at(x, y))
  7.          return FALSE;
  8.      if (!goodpos(x, y, &youmonst, 0))
  9.          return FALSE;
  10.      if (!tele_jump_ok(u.ux, u.uy, x, y))
  11.          return FALSE;
  12.      if (!in_out_region(x, y))
  13.          return FALSE;
  14.      return TRUE;
  15.  }
  16.  

teleds

  1.  void
  2.  teleds(nux, nuy, allow_drag)
  3.  register int nux, nuy;
  4.  boolean allow_drag;
  5.  {
  6.      boolean ball_active, ball_still_in_range;
  7.  
  8.      if (u.utraptype == TT_BURIEDBALL) {
  9.          /* unearth it */
  10.          buried_ball_to_punishment();
  11.      }
  12.      ball_active = (Punished && uball->where != OBJ_FREE),
  13.      ball_still_in_range = FALSE;
  14.  
  15.      /* If they have to move the ball, then drag if allow_drag is true;
  16.       * otherwise they are teleporting, so unplacebc().
  17.       * If they don't have to move the ball, then always "drag" whether or
  18.       * not allow_drag is true, because we are calling that function, not
  19.       * to drag, but to move the chain.  *However* there are some dumb
  20.       * special cases:
  21.       *    0                          0
  22.       *   _X  move east       ----->  X_
  23.       *    @                           @
  24.       * These are permissible if teleporting, but not if dragging.  As a
  25.       * result, drag_ball() needs to know about allow_drag and might end
  26.       * up dragging the ball anyway.  Also, drag_ball() might find that
  27.       * dragging the ball is completely impossible (ball in range but there's
  28.       * rock in the way), in which case it teleports the ball on its own.
  29.       */
  30.      if (ball_active) {
  31.          if (!carried(uball) && distmin(nux, nuy, uball->ox, uball->oy) <= 2)
  32.              ball_still_in_range = TRUE; /* don't have to move the ball */
  33.          else {
  34.              /* have to move the ball */
  35.              if (!allow_drag || distmin(u.ux, u.uy, nux, nuy) > 1) {
  36.                  /* we should not have dist > 1 and allow_drag at the same
  37.                   * time, but just in case, we must then revert to teleport.
  38.                   */
  39.                  allow_drag = FALSE;
  40.                  unplacebc();
  41.              }
  42.          }
  43.      }
  44.      u.utrap = 0;
  45.      u.ustuck = 0;
  46.      u.ux0 = u.ux;
  47.      u.uy0 = u.uy;
  48.  
  49.      if (!hideunder(&youmonst) && youmonst.data->mlet == S_MIMIC) {
  50.          /* mimics stop being unnoticed */
  51.          youmonst.m_ap_type = M_AP_NOTHING;
  52.      }
  53.  
  54.      if (u.uswallow) {
  55.          u.uswldtim = u.uswallow = 0;
  56.          if (Punished && !ball_active) {
  57.              /* ensure ball placement, like unstuck */
  58.              ball_active = TRUE;
  59.              allow_drag = FALSE;
  60.          }
  61.          docrt();
  62.      }
  63.      if (ball_active) {
  64.          if (ball_still_in_range || allow_drag) {
  65.              int bc_control;
  66.              xchar ballx, bally, chainx, chainy;
  67.              boolean cause_delay;
  68.  
  69.              if (drag_ball(nux, nuy, &bc_control, &ballx, &bally, &chainx,
  70.                            &chainy, &cause_delay, allow_drag))
  71.                  move_bc(0, bc_control, ballx, bally, chainx, chainy);
  72.          }
  73.      }
  74.      /* must set u.ux, u.uy after drag_ball(), which may need to know
  75.         the old position if allow_drag is true... */
  76.      u_on_newpos(nux, nuy); /* set u.<x,y>, usteed-><mx,my>; cliparound() */
  77.      fill_pit(u.ux0, u.uy0);
  78.      if (ball_active) {
  79.          if (!ball_still_in_range && !allow_drag)
  80.              placebc();
  81.      }
  82.      initrack(); /* teleports mess up tracking monsters without this */
  83.      update_player_regions();
  84.      /*
  85.       *  Make sure the hero disappears from the old location.  This will
  86.       *  not happen if she is teleported within sight of her previous
  87.       *  location.  Force a full vision recalculation because the hero
  88.       *  is now in a new location.
  89.       */
  90.      newsym(u.ux0, u.uy0);
  91.      see_monsters();
  92.      vision_full_recalc = 1;
  93.      nomul(0);
  94.      vision_recalc(0); /* vision before effects */
  95.      if (telescroll) {
  96.          /* when teleporting by scroll, we need to handle discovery
  97.             now before getting feedback about any objects at our
  98.             destination since we might land on another such scroll */
  99.          if (distu(u.ux0, u.uy0) >= 16 || !couldsee(u.ux0, u.uy0))
  100.              learnscroll(telescroll);
  101.          else
  102.              telescroll = 0; /* no discovery by scrolltele()'s caller */
  103.      }
  104.      spoteffects(TRUE);
  105.      invocation_message();
  106.  }
  107.  

safe_teleds

  1.  boolean
  2.  safe_teleds(allow_drag)
  3.  boolean allow_drag;
  4.  {
  5.      register int nux, nuy, tcnt = 0;
  6.  
  7.      do {
  8.          nux = rnd(COLNO - 1);
  9.          nuy = rn2(ROWNO);
  10.      } while (!teleok(nux, nuy, (boolean) (tcnt > 200)) && ++tcnt <= 400);
  11.  
  12.      if (tcnt <= 400) {
  13.          teleds(nux, nuy, allow_drag);
  14.          return TRUE;
  15.      } else
  16.          return FALSE;
  17.  }
  18.  

vault_tele

  1.  STATIC_OVL void
  2.  vault_tele()
  3.  {
  4.      register struct mkroom *croom = search_special(VAULT);
  5.      coord c;
  6.  
  7.      if (croom && somexy(croom, &c) && teleok(c.x, c.y, FALSE)) {
  8.          teleds(c.x, c.y, FALSE);
  9.          return;
  10.      }
  11.      tele();
  12.  }
  13.  

teleport_pet

  1.  boolean
  2.  teleport_pet(mtmp, force_it)
  3.  register struct monst *mtmp;
  4.  boolean force_it;
  5.  {
  6.      register struct obj *otmp;
  7.  
  8.      if (mtmp == u.usteed)
  9.          return FALSE;
  10.  
  11.      if (mtmp->mleashed) {
  12.          otmp = get_mleash(mtmp);
  13.          if (!otmp) {
  14.              impossible("%s is leashed, without a leash.", Monnam(mtmp));
  15.              goto release_it;
  16.          }
  17.          if (otmp->cursed && !force_it) {
  18.              yelp(mtmp);
  19.              return FALSE;
  20.          } else {
  21.              Your("leash goes slack.");
  22.          release_it:
  23.              m_unleash(mtmp, FALSE);
  24.              return TRUE;
  25.          }
  26.      }
  27.      return TRUE;
  28.  }
  29.  

tele

  1.  /* teleport the hero via some method other than scroll of teleport */
  2.  void
  3.  tele()
  4.  {
  5.      (void) scrolltele((struct obj *) 0);
  6.  }
  7.  

scrolltele

  1.  /* teleport the hero; return true if scroll of teleportation should become
  2.     discovered; teleds() will usually do the actual discovery, since the
  3.     outcome sometimes depends upon destination and discovery needs to be
  4.     performed before arrival, in case we land on another teleport scroll */
  5.  boolean
  6.  scrolltele(scroll)
  7.  struct obj *scroll;
  8.  {
  9.      coord cc;
  10.      boolean result = FALSE; /* don't learn scroll */
  11.  
  12.      /* Disable teleportation in stronghold && Vlad's Tower */
  13.      if (level.flags.noteleport) {
  14.          if (!wizard) {
  15.              pline("A mysterious force prevents you from teleporting!");
  16.              return TRUE;
  17.          }
  18.      }
  19.  
  20.      /* don't show trap if "Sorry..." */
  21.      if (!Blinded)
  22.          make_blinded(0L, FALSE);
  23.  
  24.      if ((u.uhave.amulet || On_W_tower_level(&u.uz)) && !rn2(3)) {
  25.          You_feel("disoriented for a moment.");
  26.          if (!wizard || yn("Override?") != 'y')
  27.              return FALSE;
  28.      }
  29.      if ((Teleport_control && !Stunned) || wizard) {
  30.          if (unconscious()) {
  31.              pline("Being unconscious, you cannot control your teleport.");
  32.          } else {
  33.              char whobuf[BUFSZ];
  34.  
  35.              Strcpy(whobuf, "you");
  36.              if (u.usteed)
  37.                  Sprintf(eos(whobuf), " and %s", mon_nam(u.usteed));
  38.              pline("To what position do %s want to be teleported?", whobuf);
  39.              cc.x = u.ux;
  40.              cc.y = u.uy;
  41.              if (getpos(&cc, TRUE, "the desired position") < 0)
  42.                  return TRUE; /* abort */
  43.              /* possible extensions: introduce a small error if
  44.                 magic power is low; allow transfer to solid rock */
  45.              if (teleok(cc.x, cc.y, FALSE)) {
  46.                  /* for scroll, discover it regardless of destination */
  47.                  if (scroll)
  48.                      learnscroll(scroll);
  49.                  teleds(cc.x, cc.y, FALSE);
  50.                  return TRUE;
  51.              }
  52.              pline("Sorry...");
  53.              result = TRUE;
  54.          }
  55.      } else if (scroll && scroll->blessed) {
  56.          /* (this used to be handled in seffects()) */
  57.          if (yn("Do you wish to teleport?") == 'n')
  58.              return TRUE;
  59.          result = TRUE;
  60.      }
  61.  
  62.      telescroll = scroll;
  63.      (void) safe_teleds(FALSE);
  64.      /* teleds() will leave telescroll intact iff random destination
  65.         is far enough away for scroll discovery to be warranted */
  66.      if (telescroll)
  67.          result = TRUE;
  68.      telescroll = 0; /* reset */
  69.      return result;
  70.  }
  71.  

dotele

  1.  int
  2.  dotele()
  3.  {
  4.      struct trap *trap;
  5.      boolean trap_once = FALSE;
  6.  
  7.      trap = t_at(u.ux, u.uy);
  8.      if (trap && (!trap->tseen || trap->ttyp != TELEP_TRAP))
  9.          trap = 0;
  10.  
  11.      if (trap) {
  12.          trap_once = trap->once; /* trap may get deleted, save this */
  13.          if (trap->once) {
  14.              pline("This is a vault teleport, usable once only.");
  15.              if (yn("Jump in?") == 'n')
  16.                  trap = 0;
  17.              else {
  18.                  deltrap(trap);
  19.                  newsym(u.ux, u.uy);
  20.              }
  21.          }
  22.          if (trap)
  23.              You("%s onto the teleportation trap.",
  24.                  locomotion(youmonst.data, "jump"));
  25.      }
  26.      if (!trap) {
  27.          boolean castit = FALSE;
  28.          register int sp_no = 0, energy = 0;
  29.  
  30.          if (!Teleportation || (u.ulevel < (Role_if(PM_WIZARD) ? 8 : 12)
  31.                                 && !can_teleport(youmonst.data))) {
  32.              /* Try to use teleport away spell. */
  33.              if (objects[SPE_TELEPORT_AWAY].oc_name_known && !Confusion)
  34.                  for (sp_no = 0; sp_no < MAXSPELL; sp_no++)
  35.                      if (spl_book[sp_no].sp_id == SPE_TELEPORT_AWAY) {
  36.                          castit = TRUE;
  37.                          break;
  38.                      }
  39.              if (!wizard) {
  40.                  if (!castit) {
  41.                      if (!Teleportation)
  42.                          You("don't know that spell.");
  43.                      else
  44.                          You("are not able to teleport at will.");
  45.                      return 0;
  46.                  }
  47.              }
  48.          }
  49.  
  50.          if (u.uhunger <= 100 || ACURR(A_STR) < 6) {
  51.              if (!wizard) {
  52.                  You("lack the strength %s.",
  53.                      castit ? "for a teleport spell" : "to teleport");
  54.                  return 1;
  55.              }
  56.          }
  57.  
  58.          energy = objects[SPE_TELEPORT_AWAY].oc_level * 7 / 2 - 2;
  59.          if (u.uen <= energy) {
  60.              if (wizard)
  61.                  energy = u.uen;
  62.              else {
  63.                  You("lack the energy %s.",
  64.                      castit ? "for a teleport spell" : "to teleport");
  65.                  return 1;
  66.              }
  67.          }
  68.  
  69.          if (check_capacity(
  70.                  "Your concentration falters from carrying so much."))
  71.              return 1;
  72.  
  73.          if (castit) {
  74.              exercise(A_WIS, TRUE);
  75.              if (spelleffects(sp_no, TRUE))
  76.                  return 1;
  77.              else if (!wizard)
  78.                  return 0;
  79.          } else {
  80.              u.uen -= energy;
  81.              context.botl = 1;
  82.          }
  83.      }
  84.  
  85.      if (next_to_u()) {
  86.          if (trap && trap_once)
  87.              vault_tele();
  88.          else
  89.              tele();
  90.          (void) next_to_u();
  91.      } else {
  92.          You1(shudder_for_moment);
  93.          return 0;
  94.      }
  95.      if (!trap)
  96.          morehungry(100);
  97.      return 1;
  98.  }
  99.  

level_tele

  1.  void
  2.  level_tele()
  3.  {
  4.      register int newlev;
  5.      d_level newlevel;
  6.      const char *escape_by_flying = 0; /* when surviving dest of -N */
  7.      char buf[BUFSZ];
  8.      boolean force_dest = FALSE;
  9.  
  10.      if ((u.uhave.amulet || In_endgame(&u.uz) || In_sokoban(&u.uz))
  11.          && !wizard) {
  12.          You_feel("very disoriented for a moment.");
  13.          return;
  14.      }
  15.      if ((Teleport_control && !Stunned) || wizard) {
  16.          char qbuf[BUFSZ];
  17.          int trycnt = 0;
  18.  
  19.          Strcpy(qbuf, "To what level do you want to teleport?");
  20.          do {
  21.              if (++trycnt == 2) {
  22.                  if (wizard)
  23.                      Strcat(qbuf, " [type a number or ? for a menu]");
  24.                  else
  25.                      Strcat(qbuf, " [type a number]");
  26.              }
  27.              getlin(qbuf, buf);
  28.              if (!strcmp(buf, "\033")) { /* cancelled */
  29.                  if (Confusion && rnl(5)) {
  30.                      pline("Oops...");
  31.                      goto random_levtport;
  32.                  }
  33.                  return;
  34.              } else if (!strcmp(buf, "*")) {
  35.                  goto random_levtport;
  36.              } else if (Confusion && rnl(5)) {
  37.                  pline("Oops...");
  38.                  goto random_levtport;
  39.              }
  40.              if (wizard && !strcmp(buf, "?")) {
  41.                  schar destlev = 0;
  42.                  xchar destdnum = 0;
  43.  
  44.                  newlev = (int) print_dungeon(TRUE, &destlev, &destdnum);
  45.                  if (!newlev)
  46.                      return;
  47.  
  48.                  newlevel.dnum = destdnum;
  49.                  newlevel.dlevel = destlev;
  50.                  if (In_endgame(&newlevel) && !In_endgame(&u.uz)) {
  51.                      struct obj *amu;
  52.  
  53.                      if (!u.uhave.amulet
  54.                          && (amu = mksobj(AMULET_OF_YENDOR, TRUE, FALSE))
  55.                                 != 0) {
  56.                          /* ordinarily we'd use hold_another_object()
  57.                             for something like this, but we don't want
  58.                             fumbling or already full pack to interfere */
  59.                          amu = addinv(amu);
  60.                          prinv("Endgame prerequisite:", amu, 0L);
  61.                      }
  62.                  }
  63.                  force_dest = TRUE;
  64.              } else if ((newlev = lev_by_name(buf)) == 0)
  65.                  newlev = atoi(buf);
  66.          } while (!newlev && !digit(buf[0])
  67.                   && (buf[0] != '-' || !digit(buf[1])) && trycnt < 10);
  68.  
  69.          /* no dungeon escape via this route */
  70.          if (newlev == 0) {
  71.              if (trycnt >= 10)
  72.                  goto random_levtport;
  73.              if (ynq("Go to Nowhere.  Are you sure?") != 'y')
  74.                  return;
  75.              You("%s in agony as your body begins to warp...",
  76.                  is_silent(youmonst.data) ? "writhe" : "scream");
  77.              display_nhwindow(WIN_MESSAGE, FALSE);
  78.              You("cease to exist.");
  79.              if (invent)
  80.                  Your("possessions land on the %s with a thud.",
  81.                       surface(u.ux, u.uy));
  82.              killer.format = NO_KILLER_PREFIX;
  83.              Strcpy(killer.name, "committed suicide");
  84.              done(DIED);
  85.              pline("An energized cloud of dust begins to coalesce.");
  86.              Your("body rematerializes%s.",
  87.                   invent ? ", and you gather up all your possessions" : "");
  88.              return;
  89.          }
  90.  
  91.          /* if in Knox and the requested level > 0, stay put.
  92.           * we let negative values requests fall into the "heaven" loop.
  93.           */
  94.          if (Is_knox(&u.uz) && newlev > 0 && !force_dest) {
  95.              You1(shudder_for_moment);
  96.              return;
  97.          }
  98.          /* if in Quest, the player sees "Home 1", etc., on the status
  99.           * line, instead of the logical depth of the level.  controlled
  100.           * level teleport request is likely to be relativized to the
  101.           * status line, and consequently it should be incremented to
  102.           * the value of the logical depth of the target level.
  103.           *
  104.           * we let negative values requests fall into the "heaven" loop.
  105.           */
  106.          if (In_quest(&u.uz) && newlev > 0)
  107.              newlev = newlev + dungeons[u.uz.dnum].depth_start - 1;
  108.      } else { /* involuntary level tele */
  109.      random_levtport:
  110.          newlev = random_teleport_level();
  111.          if (newlev == depth(&u.uz)) {
  112.              You1(shudder_for_moment);
  113.              return;
  114.          }
  115.      }
  116.  
  117.      if (u.utrap && u.utraptype == TT_BURIEDBALL)
  118.          buried_ball_to_punishment();
  119.  
  120.      if (!next_to_u() && !force_dest) {
  121.          You1(shudder_for_moment);
  122.          return;
  123.      }
  124.      if (In_endgame(&u.uz)) { /* must already be wizard */
  125.          int llimit = dunlevs_in_dungeon(&u.uz);
  126.  
  127.          if (newlev >= 0 || newlev <= -llimit) {
  128.              You_cant("get there from here.");
  129.              return;
  130.          }
  131.          newlevel.dnum = u.uz.dnum;
  132.          newlevel.dlevel = llimit + newlev;
  133.          schedule_goto(&newlevel, FALSE, FALSE, 0, (char *) 0, (char *) 0);
  134.          return;
  135.      }
  136.  
  137.      killer.name[0] = 0; /* still alive, so far... */
  138.  
  139.      if (newlev < 0 && !force_dest) {
  140.          if (*u.ushops0) {
  141.              /* take unpaid inventory items off of shop bills */
  142.              in_mklev = TRUE; /* suppress map update */
  143.              u_left_shop(u.ushops0, TRUE);
  144.              /* you're now effectively out of the shop */
  145.              *u.ushops0 = *u.ushops = '\0';
  146.              in_mklev = FALSE;
  147.          }
  148.          if (newlev <= -10) {
  149.              You("arrive in heaven.");
  150.              verbalize("Thou art early, but we'll admit thee.");
  151.              killer.format = NO_KILLER_PREFIX;
  152.              Strcpy(killer.name, "went to heaven prematurely");
  153.          } else if (newlev == -9) {
  154.              You_feel("deliriously happy. ");
  155.              pline("(In fact, you're on Cloud 9!) ");
  156.              display_nhwindow(WIN_MESSAGE, FALSE);
  157.          } else
  158.              You("are now high above the clouds...");
  159.  
  160.          if (killer.name[0]) {
  161.              ; /* arrival in heaven is pending */
  162.          } else if (Levitation) {
  163.              escape_by_flying = "float gently down to earth";
  164.          } else if (Flying) {
  165.              escape_by_flying = "fly down to the ground";
  166.          } else {
  167.              pline("Unfortunately, you don't know how to fly.");
  168.              You("plummet a few thousand feet to your death.");
  169.              Sprintf(killer.name,
  170.                      "teleported out of the dungeon and fell to %s death",
  171.                      uhis());
  172.              killer.format = NO_KILLER_PREFIX;
  173.          }
  174.      }
  175.  
  176.      if (killer.name[0]) { /* the chosen destination was not survivable */
  177.          d_level lsav;
  178.  
  179.          /* set specific death location; this also suppresses bones */
  180.          lsav = u.uz;   /* save current level, see below */
  181.          u.uz.dnum = 0; /* main dungeon */
  182.          u.uz.dlevel = (newlev <= -10) ? -10 : 0; /* heaven or surface */
  183.          done(DIED);
  184.          /* can only get here via life-saving (or declining to die in
  185.             explore|debug mode); the hero has now left the dungeon... */
  186.          escape_by_flying = "find yourself back on the surface";
  187.          u.uz = lsav; /* restore u.uz so escape code works */
  188.      }
  189.  
  190.      /* calls done(ESCAPED) if newlevel==0 */
  191.      if (escape_by_flying) {
  192.          You("%s.", escape_by_flying);
  193.          newlevel.dnum = 0;   /* specify main dungeon */
  194.          newlevel.dlevel = 0; /* escape the dungeon */
  195.          /* [dlevel used to be set to 1, but it doesn't make sense to
  196.              teleport out of the dungeon and float or fly down to the
  197.              surface but then actually arrive back inside the dungeon] */
  198.      } else if (u.uz.dnum == medusa_level.dnum
  199.                 && newlev >= dungeons[u.uz.dnum].depth_start
  200.                                  + dunlevs_in_dungeon(&u.uz)) {
  201.          if (!(wizard && force_dest))
  202.              find_hell(&newlevel);
  203.      } else {
  204.          /* if invocation did not yet occur, teleporting into
  205.           * the last level of Gehennom is forbidden.
  206.           */
  207.          if (!wizard && Inhell && !u.uevent.invoked
  208.              && newlev >= (dungeons[u.uz.dnum].depth_start
  209.                            + dunlevs_in_dungeon(&u.uz) - 1)) {
  210.              newlev = dungeons[u.uz.dnum].depth_start
  211.                       + dunlevs_in_dungeon(&u.uz) - 2;
  212.              pline("Sorry...");
  213.          }
  214.          /* no teleporting out of quest dungeon */
  215.          if (In_quest(&u.uz) && newlev < depth(&qstart_level))
  216.              newlev = depth(&qstart_level);
  217.          /* the player thinks of levels purely in logical terms, so
  218.           * we must translate newlev to a number relative to the
  219.           * current dungeon.
  220.           */
  221.          if (!(wizard && force_dest))
  222.              get_level(&newlevel, newlev);
  223.      }
  224.      schedule_goto(&newlevel, FALSE, FALSE, 0, (char *) 0, (char *) 0);
  225.      /* in case player just read a scroll and is about to be asked to
  226.         call it something, we can't defer until the end of the turn */
  227.      if (u.utotype && !context.mon_moving)
  228.          deferred_goto();
  229.  }
  230.  

domagicportal

  1.  void
  2.  domagicportal(ttmp)
  3.  register struct trap *ttmp;
  4.  {
  5.      struct d_level target_level;
  6.  
  7.      if (u.utrap && u.utraptype == TT_BURIEDBALL)
  8.          buried_ball_to_punishment();
  9.  
  10.      if (!next_to_u()) {
  11.          You1(shudder_for_moment);
  12.          return;
  13.      }
  14.  
  15.      /* if landed from another portal, do nothing */
  16.      /* problem: level teleport landing escapes the check */
  17.      if (!on_level(&u.uz, &u.uz0))
  18.          return;
  19.  
  20.      You("activated a magic portal!");
  21.  
  22.      /* prevent the poor shnook, whose amulet was stolen while in
  23.       * the endgame, from accidently triggering the portal to the
  24.       * next level, and thus losing the game
  25.       */
  26.      if (In_endgame(&u.uz) && !u.uhave.amulet) {
  27.          You_feel("dizzy for a moment, but nothing happens...");
  28.          return;
  29.      }
  30.  
  31.      target_level = ttmp->dst;
  32.      schedule_goto(&target_level, FALSE, FALSE, 1,
  33.                    "You feel dizzy for a moment, but the sensation passes.",
  34.                    (char *) 0);
  35.  }
  36.  

tele_trap

  1.  void
  2.  tele_trap(trap)
  3.  struct trap *trap;
  4.  {
  5.      if (In_endgame(&u.uz) || Antimagic) {
  6.          if (Antimagic)
  7.              shieldeff(u.ux, u.uy);
  8.          You_feel("a wrenching sensation.");
  9.      } else if (!next_to_u()) {
  10.          You1(shudder_for_moment);
  11.      } else if (trap->once) {
  12.          deltrap(trap);
  13.          newsym(u.ux, u.uy); /* get rid of trap symbol */
  14.          vault_tele();
  15.      } else
  16.          tele();
  17.  }
  18.  

level_tele_trap

  1.  void
  2.  level_tele_trap(trap)
  3.  struct trap *trap;
  4.  {
  5.      You("%s onto a level teleport trap!",
  6.          Levitation ? (const char *) "float"
  7.                     : locomotion(youmonst.data, "step"));
  8.      if (Antimagic) {
  9.          shieldeff(u.ux, u.uy);
  10.      }
  11.      if (Antimagic || In_endgame(&u.uz)) {
  12.          You_feel("a wrenching sensation.");
  13.          return;
  14.      }
  15.      if (!Blind)
  16.          You("are momentarily blinded by a flash of light.");
  17.      else
  18.          You("are momentarily disoriented.");
  19.      deltrap(trap);
  20.      newsym(u.ux, u.uy); /* get rid of trap symbol */
  21.      level_tele();
  22.  }
  23.  

rloc_pos_ok

  1.  /* check whether monster can arrive at location <x,y> via Tport (or fall) */
  2.  STATIC_OVL boolean
  3.  rloc_pos_ok(x, y, mtmp)
  4.  register int x, y; /* coordinates of candidate location */
  5.  struct monst *mtmp;
  6.  {
  7.      register int xx, yy;
  8.  
  9.      if (!goodpos(x, y, mtmp, 0))
  10.          return FALSE;
  11.      /*
  12.       * Check for restricted areas present in some special levels.
  13.       *
  14.       * `xx' is current column; if 0, then `yy' will contain flag bits
  15.       * rather than row:  bit #0 set => moving upwards; bit #1 set =>
  16.       * inside the Wizard's tower.
  17.       */
  18.      xx = mtmp->mx;
  19.      yy = mtmp->my;
  20.      if (!xx) {
  21.          /* no current location (migrating monster arrival) */
  22.          if (dndest.nlx && On_W_tower_level(&u.uz))
  23.              return (((yy & 2) != 0)
  24.                      /* inside xor not within */
  25.                      ^ !within_bounded_area(x, y, dndest.nlx, dndest.nly,
  26.                                             dndest.nhx, dndest.nhy));
  27.          if (updest.lx && (yy & 1) != 0) /* moving up */
  28.              return (within_bounded_area(x, y, updest.lx, updest.ly,
  29.                                          updest.hx, updest.hy)
  30.                      && (!updest.nlx
  31.                          || !within_bounded_area(x, y, updest.nlx, updest.nly,
  32.                                                  updest.nhx, updest.nhy)));
  33.          if (dndest.lx && (yy & 1) == 0) /* moving down */
  34.              return (within_bounded_area(x, y, dndest.lx, dndest.ly,
  35.                                          dndest.hx, dndest.hy)
  36.                      && (!dndest.nlx
  37.                          || !within_bounded_area(x, y, dndest.nlx, dndest.nly,
  38.                                                  dndest.nhx, dndest.nhy)));
  39.      } else {
  40.          /* [try to] prevent a shopkeeper or temple priest from being
  41.             sent out of his room (caller might resort to goodpos() if
  42.             we report failure here, so this isn't full prevention) */
  43.          if (mtmp->isshk && inhishop(mtmp)) {
  44.              if (levl[x][y].roomno != ESHK(mtmp)->shoproom)
  45.                  return FALSE;
  46.          } else if (mtmp->ispriest && inhistemple(mtmp)) {
  47.              if (levl[x][y].roomno != EPRI(mtmp)->shroom)
  48.                  return FALSE;
  49.          }
  50.          /* current location is <xx,yy> */
  51.          if (!tele_jump_ok(xx, yy, x, y))
  52.              return FALSE;
  53.      }
  54.      /* <x,y> is ok */
  55.      return TRUE;
  56.  }
  57.  

rloc_to

  1.  /*
  2.   * rloc_to()
  3.   *
  4.   * Pulls a monster from its current position and places a monster at
  5.   * a new x and y.  If oldx is 0, then the monster was not in the
  6.   * levels.monsters
  7.   * array.  However, if oldx is 0, oldy may still have a value because mtmp is
  8.   * a
  9.   * migrating_mon.  Worm tails are always placed randomly around the head of
  10.   * the worm.
  11.   */
  12.  void
  13.  rloc_to(mtmp, x, y)
  14.  struct monst *mtmp;
  15.  register int x, y;
  16.  {
  17.      register int oldx = mtmp->mx, oldy = mtmp->my;
  18.      boolean resident_shk = mtmp->isshk && inhishop(mtmp);
  19.  
  20.      if (x == mtmp->mx && y == mtmp->my) /* that was easy */
  21.          return;
  22.  
  23.      if (oldx) { /* "pick up" monster */
  24.          if (mtmp->wormno)
  25.              remove_worm(mtmp);
  26.          else {
  27.              remove_monster(oldx, oldy);
  28.              newsym(oldx, oldy); /* update old location */
  29.          }
  30.      }
  31.  
  32.      place_monster(mtmp, x, y); /* put monster down */
  33.      update_monster_region(mtmp);
  34.  
  35.      if (mtmp->wormno) /* now put down tail */
  36.          place_worm_tail_randomly(mtmp, x, y);
  37.  
  38.      if (u.ustuck == mtmp) {
  39.          if (u.uswallow) {
  40.              u.ux = x;
  41.              u.uy = y;
  42.              docrt();
  43.          } else
  44.              u.ustuck = 0;
  45.      }
  46.  
  47.      newsym(x, y);      /* update new location */
  48.      set_apparxy(mtmp); /* orient monster */
  49.  
  50.      /* shopkeepers will only teleport if you zap them with a wand of
  51.         teleportation or if they've been transformed into a jumpy monster;
  52.         the latter only happens if you've attacked them with polymorph */
  53.      if (resident_shk && !inhishop(mtmp))
  54.          make_angry_shk(mtmp, oldx, oldy);
  55.  }
  56.  

rloc

  1.  /* place a monster at a random location, typically due to teleport */
  2.  /* return TRUE if successful, FALSE if not */
  3.  boolean
  4.  rloc(mtmp, suppress_impossible)
  5.  struct monst *mtmp; /* mx==0 implies migrating monster arrival */
  6.  boolean suppress_impossible;
  7.  {
  8.      register int x, y, trycount;
  9.  
  10.      if (mtmp == u.usteed) {
  11.          tele();
  12.          return TRUE;
  13.      }
  14.  
  15.      if (mtmp->iswiz && mtmp->mx) { /* Wizard, not just arriving */
  16.          if (!In_W_tower(u.ux, u.uy, &u.uz))
  17.              x = xupstair, y = yupstair;
  18.          else if (!xdnladder) /* bottom level of tower */
  19.              x = xupladder, y = yupladder;
  20.          else
  21.              x = xdnladder, y = ydnladder;
  22.          /* if the wiz teleports away to heal, try the up staircase,
  23.             to block the player's escaping before he's healed
  24.             (deliberately use `goodpos' rather than `rloc_pos_ok' here) */
  25.          if (goodpos(x, y, mtmp, 0))
  26.              goto found_xy;
  27.      }
  28.  
  29.      trycount = 0;
  30.      do {
  31.          x = rn1(COLNO - 3, 2);
  32.          y = rn2(ROWNO);
  33.          if ((trycount < 500) ? rloc_pos_ok(x, y, mtmp)
  34.                               : goodpos(x, y, mtmp, 0))
  35.              goto found_xy;
  36.      } while (++trycount < 1000);
  37.  
  38.      /* last ditch attempt to find a good place */
  39.      for (x = 2; x < COLNO - 1; x++)
  40.          for (y = 0; y < ROWNO; y++)
  41.              if (goodpos(x, y, mtmp, 0))
  42.                  goto found_xy;
  43.  
  44.      /* level either full of monsters or somehow faulty */
  45.      if (!suppress_impossible)
  46.          impossible("rloc(): couldn't relocate monster");
  47.      return FALSE;
  48.  
  49.  found_xy:
  50.      rloc_to(mtmp, x, y);
  51.      return TRUE;
  52.  }
  53.  

mvault_tele

  1.  STATIC_OVL void
  2.  mvault_tele(mtmp)
  3.  struct monst *mtmp;
  4.  {
  5.      register struct mkroom *croom = search_special(VAULT);
  6.      coord c;
  7.  
  8.      if (croom && somexy(croom, &c) && goodpos(c.x, c.y, mtmp, 0)) {
  9.          rloc_to(mtmp, c.x, c.y);
  10.          return;
  11.      }
  12.      (void) rloc(mtmp, TRUE);
  13.  }
  14.  

tele_restrict

  1.  boolean
  2.  tele_restrict(mon)
  3.  struct monst *mon;
  4.  {
  5.      if (level.flags.noteleport) {
  6.          if (canseemon(mon))
  7.              pline("A mysterious force prevents %s from teleporting!",
  8.                    mon_nam(mon));
  9.          return TRUE;
  10.      }
  11.      return FALSE;
  12.  }
  13.  

mtele_trap

  1.  void
  2.  mtele_trap(mtmp, trap, in_sight)
  3.  struct monst *mtmp;
  4.  struct trap *trap;
  5.  int in_sight;
  6.  {
  7.      char *monname;
  8.  
  9.      if (tele_restrict(mtmp))
  10.          return;
  11.      if (teleport_pet(mtmp, FALSE)) {
  12.          /* save name with pre-movement visibility */
  13.          monname = Monnam(mtmp);
  14.  
  15.          /* Note: don't remove the trap if a vault.  Other-
  16.           * wise the monster will be stuck there, since
  17.           * the guard isn't going to come for it...
  18.           */
  19.          if (trap->once)
  20.              mvault_tele(mtmp);
  21.          else
  22.              (void) rloc(mtmp, TRUE);
  23.  
  24.          if (in_sight) {
  25.              if (canseemon(mtmp))
  26.                  pline("%s seems disoriented.", monname);
  27.              else
  28.                  pline("%s suddenly disappears!", monname);
  29.              seetrap(trap);
  30.          }
  31.      }
  32.  }
  33.  

mlevel_tele_trap

  1.  /* return 0 if still on level, 3 if not */
  2.  int
  3.  mlevel_tele_trap(mtmp, trap, force_it, in_sight)
  4.  struct monst *mtmp;
  5.  struct trap *trap;
  6.  boolean force_it;
  7.  int in_sight;
  8.  {
  9.      int tt = trap->ttyp;
  10.      struct permonst *mptr = mtmp->data;
  11.  
  12.      if (mtmp == u.ustuck) /* probably a vortex */
  13.          return 0;         /* temporary? kludge */
  14.      if (teleport_pet(mtmp, force_it)) {
  15.          d_level tolevel;
  16.          int migrate_typ = MIGR_RANDOM;
  17.  
  18.          if ((tt == HOLE || tt == TRAPDOOR)) {
  19.              if (Is_stronghold(&u.uz)) {
  20.                  assign_level(&tolevel, &valley_level);
  21.              } else if (Is_botlevel(&u.uz)) {
  22.                  if (in_sight && trap->tseen)
  23.                      pline("%s avoids the %s.", Monnam(mtmp),
  24.                            (tt == HOLE) ? "hole" : "trap");
  25.                  return 0;
  26.              } else {
  27.                  get_level(&tolevel, depth(&u.uz) + 1);
  28.              }
  29.          } else if (tt == MAGIC_PORTAL) {
  30.              if (In_endgame(&u.uz)
  31.                  && (mon_has_amulet(mtmp) || is_home_elemental(mptr))) {
  32.                  if (in_sight && mptr->mlet != S_ELEMENTAL) {
  33.                      pline("%s seems to shimmer for a moment.", Monnam(mtmp));
  34.                      seetrap(trap);
  35.                  }
  36.                  return 0;
  37.              } else {
  38.                  assign_level(&tolevel, &trap->dst);
  39.                  migrate_typ = MIGR_PORTAL;
  40.              }
  41.          } else { /* (tt == LEVEL_TELEP) */
  42.              int nlev;
  43.  
  44.              if (mon_has_amulet(mtmp) || In_endgame(&u.uz)) {
  45.                  if (in_sight)
  46.                      pline("%s seems very disoriented for a moment.",
  47.                            Monnam(mtmp));
  48.                  return 0;
  49.              }
  50.              nlev = random_teleport_level();
  51.              if (nlev == depth(&u.uz)) {
  52.                  if (in_sight)
  53.                      pline("%s shudders for a moment.", Monnam(mtmp));
  54.                  return 0;
  55.              }
  56.              get_level(&tolevel, nlev);
  57.          }
  58.  
  59.          if (in_sight) {
  60.              pline("Suddenly, %s disappears out of sight.", mon_nam(mtmp));
  61.              seetrap(trap);
  62.          }
  63.          migrate_to_level(mtmp, ledger_no(&tolevel), migrate_typ, (coord *) 0);
  64.          return 3; /* no longer on this level */
  65.      }
  66.      return 0;
  67.  }
  68.  

rloco

  1.  /* place object randomly, returns False if it's gone (eg broken) */
  2.  boolean
  3.  rloco(obj)
  4.  register struct obj *obj;
  5.  {
  6.      register xchar tx, ty, otx, oty;
  7.      boolean restricted_fall;
  8.      int try_limit = 4000;
  9.  
  10.      if (obj->otyp == CORPSE && is_rider(&mons[obj->corpsenm])) {
  11.          if (revive_corpse(obj))
  12.              return FALSE;
  13.      }
  14.  
  15.      obj_extract_self(obj);
  16.      otx = obj->ox;
  17.      oty = obj->oy;
  18.      restricted_fall = (otx == 0 && dndest.lx);
  19.      do {
  20.          tx = rn1(COLNO - 3, 2);
  21.          ty = rn2(ROWNO);
  22.          if (!--try_limit)
  23.              break;
  24.      } while (!goodpos(tx, ty, (struct monst *) 0, 0)
  25.               || (restricted_fall
  26.                   && (!within_bounded_area(tx, ty, dndest.lx, dndest.ly,
  27.                                            dndest.hx, dndest.hy)
  28.                       || (dndest.nlx
  29.                           && within_bounded_area(tx, ty,
  30.                                                  dndest.nlx, dndest.nly,
  31.                                                  dndest.nhx, dndest.nhy))))
  32.               /* on the Wizard Tower levels, objects inside should
  33.                  stay inside and objects outside should stay outside */
  34.               || (dndest.nlx && On_W_tower_level(&u.uz)
  35.                   && within_bounded_area(tx, ty, dndest.nlx, dndest.nly,
  36.                                          dndest.nhx, dndest.nhy)
  37.                      != within_bounded_area(otx, oty, dndest.nlx, dndest.nly,
  38.                                             dndest.nhx, dndest.nhy)));
  39.  
  40.      if (flooreffects(obj, tx, ty, "fall")) {
  41.          return FALSE;
  42.      } else if (otx == 0 && oty == 0) {
  43.          ; /* fell through a trap door; no update of old loc needed */
  44.      } else {
  45.          if (costly_spot(otx, oty)
  46.              && (!costly_spot(tx, ty)
  47.                  || !index(in_rooms(tx, ty, 0), *in_rooms(otx, oty, 0)))) {
  48.              if (costly_spot(u.ux, u.uy)
  49.                  && index(u.urooms, *in_rooms(otx, oty, 0)))
  50.                  addtobill(obj, FALSE, FALSE, FALSE);
  51.              else
  52.                  (void) stolen_value(obj, otx, oty, FALSE, FALSE);
  53.          }
  54.          newsym(otx, oty); /* update old location */
  55.      }
  56.      place_object(obj, tx, ty);
  57.      newsym(tx, ty);
  58.      return TRUE;
  59.  }
  60.  

random_teleport_level

  1.  /* Returns an absolute depth */
  2.  int
  3.  random_teleport_level()
  4.  {
  5.      int nlev, max_depth, min_depth, cur_depth = (int) depth(&u.uz);
  6.  
  7.      /* [the endgame case can only occur in wizard mode] */
  8.      if (!rn2(5) || Is_knox(&u.uz) || In_endgame(&u.uz))
  9.          return cur_depth;
  10.  
  11.      /* What I really want to do is as follows:
  12.       * -- If in a dungeon that goes down, the new level is to be restricted
  13.       *    to [top of parent, bottom of current dungeon]
  14.       * -- If in a dungeon that goes up, the new level is to be restricted
  15.       *    to [top of current dungeon, bottom of parent]
  16.       * -- If in a quest dungeon or similar dungeon entered by portals,
  17.       *    the new level is to be restricted to [top of current dungeon,
  18.       *    bottom of current dungeon]
  19.       * The current behavior is not as sophisticated as that ideal, but is
  20.       * still better what we used to do, which was like this for players
  21.       * but different for monsters for no obvious reason.  Currently, we
  22.       * must explicitly check for special dungeons.  We check for Knox
  23.       * above; endgame is handled in the caller due to its different
  24.       * message ("disoriented").
  25.       * --KAA
  26.       * 3.4.2: explicitly handle quest here too, to fix the problem of
  27.       * monsters sometimes level teleporting out of it into main dungeon.
  28.       * Also prevent monsters reaching the Sanctum prior to invocation.
  29.       */
  30.      if (In_quest(&u.uz)) {
  31.          int bottom = dunlevs_in_dungeon(&u.uz),
  32.              qlocate_depth = qlocate_level.dlevel;
  33.  
  34.          /* if hero hasn't reached the middle locate level yet,
  35.             no one can randomly teleport past it */
  36.          if (dunlev_reached(&u.uz) < qlocate_depth)
  37.              bottom = qlocate_depth;
  38.          min_depth = dungeons[u.uz.dnum].depth_start;
  39.          max_depth = bottom + (dungeons[u.uz.dnum].depth_start - 1);
  40.      } else {
  41.          min_depth = 1;
  42.          max_depth =
  43.              dunlevs_in_dungeon(&u.uz) + (dungeons[u.uz.dnum].depth_start - 1);
  44.          /* can't reach Sanctum if the invocation hasn't been performed */
  45.          if (Inhell && !u.uevent.invoked)
  46.              max_depth -= 1;
  47.      }
  48.  
  49.      /* Get a random value relative to the current dungeon */
  50.      /* Range is 1 to current+3, current not counting */
  51.      nlev = rn2(cur_depth + 3 - min_depth) + min_depth;
  52.      if (nlev >= cur_depth)
  53.          nlev++;
  54.  
  55.      if (nlev > max_depth) {
  56.          nlev = max_depth;
  57.          /* teleport up if already on bottom */
  58.          if (Is_botlevel(&u.uz))
  59.              nlev -= rnd(3);
  60.      }
  61.      if (nlev < min_depth) {
  62.          nlev = min_depth;
  63.          if (nlev == cur_depth) {
  64.              nlev += rnd(3);
  65.              if (nlev > max_depth)
  66.                  nlev = max_depth;
  67.          }
  68.      }
  69.      return nlev;
  70.  }
  71.  

u_teleport_mon

  1.  /* you teleport a monster (via wand, spell, or poly'd q.mechanic attack);
  2.     return false iff the attempt fails */
  3.  boolean
  4.  u_teleport_mon(mtmp, give_feedback)
  5.  struct monst *mtmp;
  6.  boolean give_feedback;
  7.  {
  8.      coord cc;
  9.  
  10.      if (mtmp->ispriest && *in_rooms(mtmp->mx, mtmp->my, TEMPLE)) {
  11.          if (give_feedback)
  12.              pline("%s resists your magic!", Monnam(mtmp));
  13.          return FALSE;
  14.      } else if (level.flags.noteleport && u.uswallow && mtmp == u.ustuck) {
  15.          if (give_feedback)
  16.              You("are no longer inside %s!", mon_nam(mtmp));
  17.          unstuck(mtmp);
  18.          (void) rloc(mtmp, TRUE);
  19.      } else if (is_rider(mtmp->data) && rn2(13)
  20.                 && enexto(&cc, u.ux, u.uy, mtmp->data))
  21.          rloc_to(mtmp, cc.x, cc.y);
  22.      else
  23.          (void) rloc(mtmp, TRUE);
  24.      return TRUE;
  25.  }
  26.  
  27.  /*teleport.c*/