1 /* SCCS Id: @(#)teleport.c 3.4 2003/08/11 */
2 /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
3 /* NetHack may be freely redistributed. See license for details. */
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 *));
14 * Is (x,y) a good position of mtmp? If mtmp is NULL, then is (x,y) good
17 * This function will only look at mtmp->mdat, so makemon, mplayer, etc can
18 * call it to generate new monster positions with fake monster structures.
21 goodpos(x, y, mtmp, gpflags)
26 struct permonst *mdat = NULL;
27 boolean ignorewater = ((gpflags & MM_IGNOREWATER) != 0);
29 if (!isok(x, y)) return FALSE;
31 /* in many cases, we're trying to create a new monster, which
32 * can't go on top of the player or any existing monster.
33 * however, occasionally we are relocating engravings or objects,
34 * which could be co-located and thus get restricted a bit too much.
37 if (mtmp != &youmonst && x == u.ux && y == u.uy
39 && (!u.usteed || mtmp != u.usteed)
45 struct monst *mtmp2 = m_at(x,y);
47 /* Be careful with long worms. A monster may be placed back in
48 * its own location. Normally, if m_at() returns the same monster
49 * that we're trying to place, the monster is being placed in its
50 * own location. However, that is not correct for worm segments,
51 * because all the segments of the worm return the same m_at().
52 * Actually we overdo the check a little bit--a worm can't be placed
53 * in its own location, period. If we just checked for mtmp->mx
54 * != x || mtmp->my != y, we'd miss the case where we're called
55 * to place the worm segment and the worm's head is at x,y.
57 if (mtmp2 && (mtmp2 != mtmp || mtmp->wormno))
61 if (is_pool(x,y) && !ignorewater) {
62 if (mtmp == &youmonst)
63 return !!(HLevitation || Flying || Wwalking ||
64 Swimming || Amphibious);
65 else return (is_flyer(mdat) || is_swimmer(mdat) ||
67 } else if (mdat->mlet == S_EEL && rn2(13) && !ignorewater) {
69 } else if (is_lava(x,y)) {
70 if (mtmp == &youmonst)
73 return (is_flyer(mdat) || likes_lava(mdat));
75 if (passes_walls(mdat) && may_passwall(x,y)) return TRUE;
77 if (!ACCESSIBLE(levl[x][y].typ)) {
78 if (!(is_pool(x,y) && ignorewater)) return FALSE;
81 if (closed_door(x, y) && (!mdat || !amorphous(mdat)))
83 if (sobj_at(BOULDER, x, y) && (!mdat || !throws_rocks(mdat)))
91 * Attempt to find a good place for the given monster type in the closest
92 * position to (xx,yy). Do so in successive square rings around (xx,yy).
93 * If there is more than one valid positon in the ring, choose one randomly.
94 * Return TRUE and the position chosen when successful, FALSE otherwise.
97 enexto(cc, xx, yy, mdat)
99 register xchar xx, yy;
100 struct permonst *mdat;
102 return enexto_core(cc, xx, yy, mdat, 0);
106 enexto_core(cc, xx, yy, mdat, entflags)
108 register xchar xx, yy;
109 struct permonst *mdat;
113 coord good[MAX_GOOD], *good_ptr;
115 int xmin, xmax, ymin, ymax;
116 struct monst fakemon; /* dummy monster */
120 pline("enexto() called with mdat==0");
122 /* default to player's original monster type */
123 mdat = &mons[u.umonster];
125 fakemon.data = mdat; /* set up for goodpos */
129 * Walk around the border of the square with center (xx,yy) and
130 * radius range. Stop when we find at least one valid position.
133 xmin = max(1, xx-range);
134 xmax = min(COLNO-1, xx+range);
135 ymin = max(0, yy-range);
136 ymax = min(ROWNO-1, yy+range);
138 for (x = xmin; x <= xmax; x++)
139 if (goodpos(x, ymin, &fakemon, entflags)) {
142 /* beware of accessing beyond segment boundaries.. */
143 if (good_ptr++ == &good[MAX_GOOD-1]) goto full;
145 for (x = xmin; x <= xmax; x++)
146 if (goodpos(x, ymax, &fakemon, entflags)) {
149 /* beware of accessing beyond segment boundaries.. */
150 if (good_ptr++ == &good[MAX_GOOD-1]) goto full;
152 for (y = ymin+1; y < ymax; y++)
153 if (goodpos(xmin, y, &fakemon, entflags)) {
156 /* beware of accessing beyond segment boundaries.. */
157 if (good_ptr++ == &good[MAX_GOOD-1]) goto full;
159 for (y = ymin+1; y < ymax; y++)
160 if (goodpos(xmax, y, &fakemon, entflags)) {
163 /* beware of accessing beyond segment boundaries.. */
164 if (good_ptr++ == &good[MAX_GOOD-1]) goto full;
168 /* return if we've grown too big (nothing is valid) */
169 if (range > ROWNO && range > COLNO) return FALSE;
170 } while (good_ptr == good);
173 i = rn2((int)(good_ptr - good));
180 * Check for restricted areas present in some special levels. (This might
181 * need to be augmented to allow deliberate passage in wizard mode, but
182 * only for explicitly chosen destinations.)
185 tele_jump_ok(x1, y1, x2, y2)
188 if (dndest.nlx > 0) {
189 /* if inside a restricted region, can't teleport outside */
190 if (within_bounded_area(x1, y1, dndest.nlx, dndest.nly,
191 dndest.nhx, dndest.nhy) &&
192 !within_bounded_area(x2, y2, dndest.nlx, dndest.nly,
193 dndest.nhx, dndest.nhy))
195 /* and if outside, can't teleport inside */
196 if (!within_bounded_area(x1, y1, dndest.nlx, dndest.nly,
197 dndest.nhx, dndest.nhy) &&
198 within_bounded_area(x2, y2, dndest.nlx, dndest.nly,
199 dndest.nhx, dndest.nhy))
202 if (updest.nlx > 0) { /* ditto */
203 if (within_bounded_area(x1, y1, updest.nlx, updest.nly,
204 updest.nhx, updest.nhy) &&
205 !within_bounded_area(x2, y2, updest.nlx, updest.nly,
206 updest.nhx, updest.nhy))
208 if (!within_bounded_area(x1, y1, updest.nlx, updest.nly,
209 updest.nhx, updest.nhy) &&
210 within_bounded_area(x2, y2, updest.nlx, updest.nly,
211 updest.nhx, updest.nhy))
222 if (!trapok && t_at(x, y)) return FALSE;
223 if (!goodpos(x, y, &youmonst, 0)) return FALSE;
224 if (!tele_jump_ok(u.ux, u.uy, x, y)) return FALSE;
225 if (!in_out_region(x, y)) return FALSE;
230 teleds(nux, nuy, allow_drag)
231 register int nux,nuy;
234 boolean ball_active = (Punished && uball->where != OBJ_FREE),
235 ball_still_in_range = FALSE;
237 /* If they have to move the ball, then drag if allow_drag is true;
238 * otherwise they are teleporting, so unplacebc().
239 * If they don't have to move the ball, then always "drag" whether or
240 * not allow_drag is true, because we are calling that function, not
241 * to drag, but to move the chain. *However* there are some dumb
244 * _X move east -----> X_
246 * These are permissible if teleporting, but not if dragging. As a
247 * result, drag_ball() needs to know about allow_drag and might end
248 * up dragging the ball anyway. Also, drag_ball() might find that
249 * dragging the ball is completely impossible (ball in range but there's
250 * rock in the way), in which case it teleports the ball on its own.
253 if (!carried(uball) && distmin(nux, nuy, uball->ox, uball->oy) <= 2)
254 ball_still_in_range = TRUE; /* don't have to move the ball */
256 /* have to move the ball */
257 if (!allow_drag || distmin(u.ux, u.uy, nux, nuy) > 1) {
258 /* we should not have dist > 1 and allow_drag at the same
259 * time, but just in case, we must then revert to teleport.
271 if (hides_under(youmonst.data))
272 u.uundetected = OBJ_AT(nux, nuy);
273 else if (youmonst.data->mlet == S_EEL)
274 u.uundetected = is_pool(nux, nuy);
277 /* mimics stop being unnoticed */
278 if (youmonst.data->mlet == S_MIMIC)
279 youmonst.m_ap_type = M_AP_NOTHING;
283 u.uswldtim = u.uswallow = 0;
284 if (Punished && !ball_active) {
285 /* ensure ball placement, like unstuck */
292 if (ball_still_in_range || allow_drag) {
294 xchar ballx, bally, chainx, chainy;
297 if (drag_ball(nux, nuy, &bc_control, &ballx, &bally,
298 &chainx, &chainy, &cause_delay, allow_drag))
299 move_bc(0, bc_control, ballx, bally, chainx, chainy);
302 /* must set u.ux, u.uy after drag_ball(), which may need to know
303 the old position if allow_drag is true... */
306 fill_pit(u.ux0, u.uy0);
308 if (!ball_still_in_range && !allow_drag)
311 initrack(); /* teleports mess up tracking monsters without this */
312 update_player_regions();
314 /* Move your steed, too */
321 * Make sure the hero disappears from the old location. This will
322 * not happen if she is teleported within sight of her previous
323 * location. Force a full vision recalculation because the hero
324 * is now in a new location.
328 vision_full_recalc = 1;
330 vision_recalc(0); /* vision before effects */
332 invocation_message();
336 safe_teleds(allow_drag)
339 register int nux, nuy, tcnt = 0;
344 } while (!teleok(nux, nuy, (boolean)(tcnt > 200)) && ++tcnt <= 400);
347 teleds(nux, nuy, allow_drag);
356 register struct mkroom *croom = search_special(VAULT);
359 if (croom && somexy(croom, &c) && teleok(c.x,c.y,FALSE)) {
360 teleds(c.x,c.y,FALSE);
367 teleport_pet(mtmp, force_it)
368 register struct monst *mtmp;
371 register struct obj *otmp;
374 if (mtmp == u.usteed)
378 if (mtmp->mleashed) {
379 otmp = get_mleash(mtmp);
381 impossible("%s is leashed, without a leash.", Monnam(mtmp));
384 if (otmp->cursed && !force_it) {
388 Your("leash goes slack.");
390 m_unleash(mtmp, FALSE);
402 /* Disable teleportation in stronghold && Vlad's Tower */
403 if (level.flags.noteleport) {
407 pline("A mysterious force prevents you from teleporting!");
414 /* don't show trap if "Sorry..." */
415 if (!Blinded) make_blinded(0L,FALSE);
417 if ((u.uhave.amulet || On_W_tower_level(&u.uz)) && !rn2(3)) {
418 You_feel("disoriented for a moment.");
421 if ((Teleport_control && !Stunned)
427 pline("Being unconscious, you cannot control your teleport.");
431 if (u.usteed) Sprintf(buf," and %s", mon_nam(u.usteed));
433 pline("To what position do you%s want to be teleported?",
440 if (getpos(&cc, TRUE, "the desired position") < 0)
442 /* possible extensions: introduce a small error if
443 magic power is low; allow transfer to solid rock */
444 if (teleok(cc.x, cc.y, FALSE)) {
445 teleds(cc.x, cc.y, FALSE);
452 (void) safe_teleds(FALSE);
460 trap = t_at(u.ux, u.uy);
461 if (trap && (!trap->tseen || trap->ttyp != TELEP_TRAP))
466 pline("This is a vault teleport, usable once only.");
467 if (yn("Jump in?") == 'n')
475 You("%s onto the teleportation trap.",
476 locomotion(youmonst.data, "jump"));
479 boolean castit = FALSE;
480 register int sp_no = 0, energy = 0;
482 if (!Teleportation || (u.ulevel < (Role_if(PM_WIZARD) ? 8 : 12)
483 && !can_teleport(youmonst.data))) {
484 /* Try to use teleport away spell. */
485 if (objects[SPE_TELEPORT_AWAY].oc_name_known && !Confusion)
486 for (sp_no = 0; sp_no < MAXSPELL; sp_no++)
487 if (spl_book[sp_no].sp_id == SPE_TELEPORT_AWAY) {
496 You("don't know that spell.");
497 else You("are not able to teleport at will.");
505 if (u.uhunger <= 100 || ACURR(A_STR) < 6) {
509 You("lack the strength %s.",
510 castit ? "for a teleport spell" : "to teleport");
517 energy = objects[SPE_TELEPORT_AWAY].oc_level * 7 / 2 - 2;
518 if (u.uen <= energy) {
525 You("lack the energy %s.",
526 castit ? "for a teleport spell" : "to teleport");
532 "Your concentration falters from carrying so much."))
536 exercise(A_WIS, TRUE);
537 if (spelleffects(sp_no, TRUE))
551 if (trap && trap->once) vault_tele();
555 You(shudder_for_moment);
558 if (!trap) morehungry(100);
568 const char *escape_by_flying = 0; /* when surviving dest of -N */
570 boolean force_dest = FALSE;
572 if ((u.uhave.amulet || In_endgame(&u.uz) || In_sokoban(&u.uz))
577 You_feel("very disoriented for a moment.");
580 if ((Teleport_control && !Stunned)
588 Strcpy(qbuf, "To what level do you want to teleport?");
592 if (wizard) Strcat(qbuf, " [type a number or ? for a menu]");
595 Strcat(qbuf, " [type a number]");
598 if (!strcmp(buf,"\033")) { /* cancelled */
599 if (Confusion && rnl(5)) {
601 goto random_levtport;
604 } else if (!strcmp(buf,"*")) {
605 goto random_levtport;
606 } else if (Confusion && rnl(5)) {
608 goto random_levtport;
611 if (wizard && !strcmp(buf,"?")) {
615 if ((newlev = (int)print_dungeon(TRUE, &destlev, &destdnum))) {
616 newlevel.dnum = destdnum;
617 newlevel.dlevel = destlev;
618 if (In_endgame(&newlevel) && !In_endgame(&u.uz)) {
620 "Destination is earth level");
621 if (!u.uhave.amulet) {
623 obj = mksobj(AMULET_OF_YENDOR,
627 Strcat(buf, " with the amulet");
630 assign_level(&newlevel, &earth_level);
637 if ((newlev = lev_by_name(buf)) == 0) newlev = atoi(buf);
638 } while (!newlev && !digit(buf[0]) &&
639 (buf[0] != '-' || !digit(buf[1])) &&
642 /* no dungeon escape via this route */
645 goto random_levtport;
646 if (ynq("Go to Nowhere. Are you sure?") != 'y') return;
647 You("%s in agony as your body begins to warp...",
648 is_silent(youmonst.data) ? "writhe" : "scream");
649 display_nhwindow(WIN_MESSAGE, FALSE);
650 You("cease to exist.");
651 if (invent) Your("possessions land on the %s with a thud.",
652 surface(u.ux, u.uy));
653 killer_format = NO_KILLER_PREFIX;
654 killer = "committed suicide";
656 pline("An energized cloud of dust begins to coalesce.");
657 Your("body rematerializes%s.", invent ?
658 ", and you gather up all your possessions" : "");
662 /* if in Knox and the requested level > 0, stay put.
663 * we let negative values requests fall into the "heaven" loop.
665 if (Is_knox(&u.uz) && newlev > 0) {
666 You(shudder_for_moment);
669 /* if in Quest, the player sees "Home 1", etc., on the status
670 * line, instead of the logical depth of the level. controlled
671 * level teleport request is likely to be relativized to the
672 * status line, and consequently it should be incremented to
673 * the value of the logical depth of the target level.
675 * we let negative values requests fall into the "heaven" loop.
677 if (In_quest(&u.uz) && newlev > 0)
678 newlev = newlev + dungeons[u.uz.dnum].depth_start - 1;
679 } else { /* involuntary level tele */
681 newlev = random_teleport_level();
682 if (newlev == depth(&u.uz)) {
683 You(shudder_for_moment);
689 You(shudder_for_moment);
693 if (In_endgame(&u.uz)) { /* must already be wizard */
694 int llimit = dunlevs_in_dungeon(&u.uz);
696 if (newlev >= 0 || newlev <= -llimit) {
697 You_cant("get there from here.");
700 newlevel.dnum = u.uz.dnum;
701 newlevel.dlevel = llimit + newlev;
702 schedule_goto(&newlevel, FALSE, FALSE, 0, (char *)0, (char *)0);
707 killer = 0; /* still alive, so far... */
709 if (newlev < 0 && !force_dest) {
711 /* take unpaid inventory items off of shop bills */
712 in_mklev = TRUE; /* suppress map update */
713 u_left_shop(u.ushops0, TRUE);
714 /* you're now effectively out of the shop */
715 *u.ushops0 = *u.ushops = '\0';
719 You("arrive in heaven.");
720 verbalize("Thou art early, but we'll admit thee.");
721 killer_format = NO_KILLER_PREFIX;
722 killer = "went to heaven prematurely";
723 } else if (newlev == -9) {
724 You_feel("deliriously happy. ");
725 pline("(In fact, you're on Cloud 9!) ");
726 display_nhwindow(WIN_MESSAGE, FALSE);
728 You("are now high above the clouds...");
731 ; /* arrival in heaven is pending */
732 } else if (Levitation) {
733 escape_by_flying = "float gently down to earth";
735 escape_by_flying = "fly down to the ground";
737 pline("Unfortunately, you don't know how to fly.");
738 You("plummet a few thousand feet to your death.");
740 "teleported out of the dungeon and fell to %s death",
743 killer_format = NO_KILLER_PREFIX;
747 if (killer) { /* the chosen destination was not survivable */
750 /* set specific death location; this also suppresses bones */
751 lsav = u.uz; /* save current level, see below */
752 u.uz.dnum = 0; /* main dungeon */
753 u.uz.dlevel = (newlev <= -10) ? -10 : 0; /* heaven or surface */
755 /* can only get here via life-saving (or declining to die in
756 explore|debug mode); the hero has now left the dungeon... */
757 escape_by_flying = "find yourself back on the surface";
758 u.uz = lsav; /* restore u.uz so escape code works */
761 /* calls done(ESCAPED) if newlevel==0 */
762 if (escape_by_flying) {
763 You("%s.", escape_by_flying);
764 newlevel.dnum = 0; /* specify main dungeon */
765 newlevel.dlevel = 0; /* escape the dungeon */
766 /* [dlevel used to be set to 1, but it doesn't make sense to
767 teleport out of the dungeon and float or fly down to the
768 surface but then actually arrive back inside the dungeon] */
769 } else if (u.uz.dnum == medusa_level.dnum &&
770 newlev >= dungeons[u.uz.dnum].depth_start +
771 dunlevs_in_dungeon(&u.uz)) {
773 if (!(wizard && force_dest))
775 find_hell(&newlevel);
777 /* if invocation did not yet occur, teleporting into
778 * the last level of Gehennom is forbidden.
783 if (Inhell && !u.uevent.invoked &&
784 newlev >= (dungeons[u.uz.dnum].depth_start +
785 dunlevs_in_dungeon(&u.uz) - 1)) {
786 newlev = dungeons[u.uz.dnum].depth_start +
787 dunlevs_in_dungeon(&u.uz) - 2;
790 /* no teleporting out of quest dungeon */
791 if (In_quest(&u.uz) && newlev < depth(&qstart_level))
792 newlev = depth(&qstart_level);
793 /* the player thinks of levels purely in logical terms, so
794 * we must translate newlev to a number relative to the
798 if (!(wizard && force_dest))
800 get_level(&newlevel, newlev);
802 schedule_goto(&newlevel, FALSE, FALSE, 0, (char *)0, (char *)0);
803 /* in case player just read a scroll and is about to be asked to
804 call it something, we can't defer until the end of the turn */
805 if (u.utotype && !flags.mon_moving) deferred_goto();
810 register struct trap *ttmp;
812 struct d_level target_level;
815 You(shudder_for_moment);
819 /* if landed from another portal, do nothing */
820 /* problem: level teleport landing escapes the check */
821 if (!on_level(&u.uz, &u.uz0)) return;
823 You("activated a magic portal!");
825 /* prevent the poor shnook, whose amulet was stolen while in
826 * the endgame, from accidently triggering the portal to the
827 * next level, and thus losing the game
829 if (In_endgame(&u.uz) && !u.uhave.amulet) {
830 You_feel("dizzy for a moment, but nothing happens...");
834 target_level = ttmp->dst;
835 schedule_goto(&target_level, FALSE, FALSE, 1,
836 "You feel dizzy for a moment, but the sensation passes.",
844 if (In_endgame(&u.uz) || Antimagic) {
846 shieldeff(u.ux, u.uy);
847 You_feel("a wrenching sensation.");
848 } else if (!next_to_u()) {
849 You(shudder_for_moment);
850 } else if (trap->once) {
852 newsym(u.ux,u.uy); /* get rid of trap symbol */
859 level_tele_trap(trap)
862 You("%s onto a level teleport trap!",
863 Levitation ? (const char *)"float" :
864 locomotion(youmonst.data, "step"));
866 shieldeff(u.ux, u.uy);
868 if (Antimagic || In_endgame(&u.uz)) {
869 You_feel("a wrenching sensation.");
873 You("are momentarily blinded by a flash of light.");
875 You("are momentarily disoriented.");
877 newsym(u.ux,u.uy); /* get rid of trap symbol */
881 /* check whether monster can arrive at location <x,y> via Tport (or fall) */
883 rloc_pos_ok(x, y, mtmp)
884 register int x, y; /* coordinates of candidate location */
889 if (!goodpos(x, y, mtmp, 0)) return FALSE;
891 * Check for restricted areas present in some special levels.
893 * `xx' is current column; if 0, then `yy' will contain flag bits
894 * rather than row: bit #0 set => moving upwards; bit #1 set =>
895 * inside the Wizard's tower.
900 /* no current location (migrating monster arrival) */
901 if (dndest.nlx && On_W_tower_level(&u.uz))
902 return ((yy & 2) != 0) ^ /* inside xor not within */
903 !within_bounded_area(x, y, dndest.nlx, dndest.nly,
904 dndest.nhx, dndest.nhy);
905 if (updest.lx && (yy & 1) != 0) /* moving up */
906 return (within_bounded_area(x, y, updest.lx, updest.ly,
907 updest.hx, updest.hy) &&
909 !within_bounded_area(x, y, updest.nlx, updest.nly,
910 updest.nhx, updest.nhy)));
911 if (dndest.lx && (yy & 1) == 0) /* moving down */
912 return (within_bounded_area(x, y, dndest.lx, dndest.ly,
913 dndest.hx, dndest.hy) &&
915 !within_bounded_area(x, y, dndest.nlx, dndest.nly,
916 dndest.nhx, dndest.nhy)));
918 /* current location is <xx,yy> */
919 if (!tele_jump_ok(xx, yy, x, y)) return FALSE;
928 * Pulls a monster from its current position and places a monster at
929 * a new x and y. If oldx is 0, then the monster was not in the levels.monsters
930 * array. However, if oldx is 0, oldy may still have a value because mtmp is a
931 * migrating_mon. Worm tails are always placed randomly around the head of
939 register int oldx = mtmp->mx, oldy = mtmp->my;
940 boolean resident_shk = mtmp->isshk && inhishop(mtmp);
942 if (x == mtmp->mx && y == mtmp->my) /* that was easy */
945 if (oldx) { /* "pick up" monster */
949 remove_monster(oldx, oldy);
950 newsym(oldx, oldy); /* update old location */
954 place_monster(mtmp, x, y); /* put monster down */
955 update_monster_region(mtmp);
957 if (mtmp->wormno) /* now put down tail */
958 place_worm_tail_randomly(mtmp, x, y);
960 if (u.ustuck == mtmp) {
968 newsym(x, y); /* update new location */
969 set_apparxy(mtmp); /* orient monster */
971 /* shopkeepers will only teleport if you zap them with a wand of
972 teleportation or if they've been transformed into a jumpy monster;
973 the latter only happens if you've attacked them with polymorph */
974 if (resident_shk && !inhishop(mtmp)) make_angry_shk(mtmp, oldx, oldy);
977 /* place a monster at a random location, typically due to teleport */
978 /* return TRUE if successful, FALSE if not */
980 rloc(mtmp, suppress_impossible)
981 struct monst *mtmp; /* mx==0 implies migrating monster arrival */
982 boolean suppress_impossible;
984 register int x, y, trycount;
987 if (mtmp == u.usteed) {
993 if (mtmp->iswiz && mtmp->mx) { /* Wizard, not just arriving */
994 if (!In_W_tower(u.ux, u.uy, &u.uz))
995 x = xupstair, y = yupstair;
996 else if (!xdnladder) /* bottom level of tower */
997 x = xupladder, y = yupladder;
999 x = xdnladder, y = ydnladder;
1000 /* if the wiz teleports away to heal, try the up staircase,
1001 to block the player's escaping before he's healed
1002 (deliberately use `goodpos' rather than `rloc_pos_ok' here) */
1003 if (goodpos(x, y, mtmp, 0))
1011 if ((trycount < 500) ? rloc_pos_ok(x, y, mtmp)
1012 : goodpos(x, y, mtmp, 0))
1014 } while (++trycount < 1000);
1016 /* last ditch attempt to find a good place */
1017 for (x = 2; x < COLNO - 1; x++)
1018 for (y = 0; y < ROWNO; y++)
1019 if (goodpos(x, y, mtmp, 0))
1022 /* level either full of monsters or somehow faulty */
1023 if (!suppress_impossible)
1024 impossible("rloc(): couldn't relocate monster");
1028 rloc_to(mtmp, x, y);
1036 register struct mkroom *croom = search_special(VAULT);
1039 if (croom && somexy(croom, &c) &&
1040 goodpos(c.x, c.y, mtmp, 0)) {
1041 rloc_to(mtmp, c.x, c.y);
1044 (void) rloc(mtmp, FALSE);
1051 if (level.flags.noteleport) {
1053 pline("A mysterious force prevents %s from teleporting!",
1061 mtele_trap(mtmp, trap, in_sight)
1068 if (tele_restrict(mtmp)) return;
1069 if (teleport_pet(mtmp, FALSE)) {
1070 /* save name with pre-movement visibility */
1071 monname = Monnam(mtmp);
1073 /* Note: don't remove the trap if a vault. Other-
1074 * wise the monster will be stuck there, since
1075 * the guard isn't going to come for it...
1077 if (trap->once) mvault_tele(mtmp);
1078 else (void) rloc(mtmp, FALSE);
1081 if (canseemon(mtmp))
1082 pline("%s seems disoriented.", monname);
1084 pline("%s suddenly disappears!", monname);
1090 /* return 0 if still on level, 3 if not */
1092 mlevel_tele_trap(mtmp, trap, force_it, in_sight)
1098 int tt = trap->ttyp;
1099 struct permonst *mptr = mtmp->data;
1101 if (mtmp == u.ustuck) /* probably a vortex */
1102 return 0; /* temporary? kludge */
1103 if (teleport_pet(mtmp, force_it)) {
1105 int migrate_typ = MIGR_RANDOM;
1107 if ((tt == HOLE || tt == TRAPDOOR)) {
1108 if (Is_stronghold(&u.uz)) {
1109 assign_level(&tolevel, &valley_level);
1110 } else if (Is_botlevel(&u.uz)) {
1111 if (in_sight && trap->tseen)
1112 pline("%s avoids the %s.", Monnam(mtmp),
1113 (tt == HOLE) ? "hole" : "trap");
1116 get_level(&tolevel, depth(&u.uz) + 1);
1118 } else if (tt == MAGIC_PORTAL) {
1119 if (In_endgame(&u.uz) &&
1120 (mon_has_amulet(mtmp) || is_home_elemental(mptr))) {
1121 if (in_sight && mptr->mlet != S_ELEMENTAL) {
1122 pline("%s seems to shimmer for a moment.",
1128 assign_level(&tolevel, &trap->dst);
1129 migrate_typ = MIGR_PORTAL;
1131 } else { /* (tt == LEVEL_TELEP) */
1134 if (mon_has_amulet(mtmp) || In_endgame(&u.uz)) {
1136 pline("%s seems very disoriented for a moment.",
1140 nlev = random_teleport_level();
1141 if (nlev == depth(&u.uz)) {
1143 pline("%s shudders for a moment.", Monnam(mtmp));
1146 get_level(&tolevel, nlev);
1150 pline("Suddenly, %s disappears out of sight.", mon_nam(mtmp));
1153 migrate_to_level(mtmp, ledger_no(&tolevel),
1154 migrate_typ, (coord *)0);
1155 return 3; /* no longer on this level */
1163 register struct obj *obj;
1165 register xchar tx, ty, otx, oty;
1166 boolean restricted_fall;
1167 int try_limit = 4000;
1169 if (obj->otyp == CORPSE && is_rider(&mons[obj->corpsenm])) {
1170 if (revive_corpse(obj)) return;
1173 obj_extract_self(obj);
1176 restricted_fall = (otx == 0 && dndest.lx);
1178 tx = rn1(COLNO-3,2);
1180 if (!--try_limit) break;
1181 } while (!goodpos(tx, ty, (struct monst *)0, 0) ||
1182 /* bug: this lacks provision for handling the Wizard's tower */
1184 (!within_bounded_area(tx, ty, dndest.lx, dndest.ly,
1185 dndest.hx, dndest.hy) ||
1187 within_bounded_area(tx, ty, dndest.nlx, dndest.nly,
1188 dndest.nhx, dndest.nhy)))));
1190 if (flooreffects(obj, tx, ty, "fall")) {
1192 } else if (otx == 0 && oty == 0) {
1193 ; /* fell through a trap door; no update of old loc needed */
1195 if (costly_spot(otx, oty)
1196 && (!costly_spot(tx, ty) ||
1197 !index(in_rooms(tx, ty, 0), *in_rooms(otx, oty, 0)))) {
1198 if (costly_spot(u.ux, u.uy) &&
1199 index(u.urooms, *in_rooms(otx, oty, 0)))
1200 addtobill(obj, FALSE, FALSE, FALSE);
1201 else (void)stolen_value(obj, otx, oty, FALSE, FALSE);
1203 newsym(otx, oty); /* update old location */
1205 place_object(obj, tx, ty);
1209 /* Returns an absolute depth */
1211 random_teleport_level()
1213 int nlev, max_depth, min_depth,
1214 cur_depth = (int)depth(&u.uz);
1216 if (!rn2(5) || Is_knox(&u.uz))
1219 /* What I really want to do is as follows:
1220 * -- If in a dungeon that goes down, the new level is to be restricted
1221 * to [top of parent, bottom of current dungeon]
1222 * -- If in a dungeon that goes up, the new level is to be restricted
1223 * to [top of current dungeon, bottom of parent]
1224 * -- If in a quest dungeon or similar dungeon entered by portals,
1225 * the new level is to be restricted to [top of current dungeon,
1226 * bottom of current dungeon]
1227 * The current behavior is not as sophisticated as that ideal, but is
1228 * still better what we used to do, which was like this for players
1229 * but different for monsters for no obvious reason. Currently, we
1230 * must explicitly check for special dungeons. We check for Knox
1231 * above; endgame is handled in the caller due to its different
1232 * message ("disoriented").
1234 * 3.4.2: explicitly handle quest here too, to fix the problem of
1235 * monsters sometimes level teleporting out of it into main dungeon.
1236 * Also prevent monsters reaching the Sanctum prior to invocation.
1238 min_depth = In_quest(&u.uz) ? dungeons[u.uz.dnum].depth_start : 1;
1239 max_depth = dunlevs_in_dungeon(&u.uz) +
1240 (dungeons[u.uz.dnum].depth_start - 1);
1241 /* can't reach the Sanctum if the invocation hasn't been performed */
1242 if (Inhell && !u.uevent.invoked) max_depth -= 1;
1244 /* Get a random value relative to the current dungeon */
1245 /* Range is 1 to current+3, current not counting */
1246 nlev = rn2(cur_depth + 3 - min_depth) + min_depth;
1247 if (nlev >= cur_depth) nlev++;
1249 if (nlev > max_depth) {
1251 /* teleport up if already on bottom */
1252 if (Is_botlevel(&u.uz)) nlev -= rnd(3);
1254 if (nlev < min_depth) {
1256 if (nlev == cur_depth) {
1258 if (nlev > max_depth)
1265 /* you teleport a monster (via wand, spell, or poly'd q.mechanic attack);
1266 return false iff the attempt fails */
1268 u_teleport_mon(mtmp, give_feedback)
1270 boolean give_feedback;
1274 if (mtmp->ispriest && *in_rooms(mtmp->mx, mtmp->my, TEMPLE)) {
1276 pline("%s resists your magic!", Monnam(mtmp));
1278 } else if (level.flags.noteleport && u.uswallow && mtmp == u.ustuck) {
1280 You("are no longer inside %s!", mon_nam(mtmp));
1282 (void) rloc(mtmp, FALSE);
1283 } else if (is_rider(mtmp->data) && rn2(13) &&
1284 enexto(&cc, u.ux, u.uy, mtmp->data))
1285 rloc_to(mtmp, cc.x, cc.y);
1287 (void) rloc(mtmp, FALSE);