1 /* aNetHack 0.0.1 teleport.c $ANH-Date: 1455140444 2016/02/10 21:40:44 $ $ANH-Branch: master $:$ANH-Revision: 1.66 $ */
2 /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
3 /* aNetHack 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
*));
13 /* non-null when teleporting via having read this scroll */
14 STATIC_VAR
struct obj
*telescroll
= 0;
17 * Is (x,y) a good position of mtmp? If mtmp is NULL, then is (x,y) good
20 * This function will only look at mtmp->mdat, so makemon, mplayer, etc can
21 * call it to generate new monster positions with fake monster structures.
24 goodpos(x
, y
, mtmp
, gpflags
)
29 struct permonst
*mdat
= (struct permonst
*) 0;
30 boolean ignorewater
= ((gpflags
& MM_IGNOREWATER
) != 0);
35 /* in many cases, we're trying to create a new monster, which
36 * can't go on top of the player or any existing monster.
37 * however, occasionally we are relocating engravings or objects,
38 * which could be co-located and thus get restricted a bit too much.
41 if (mtmp
!= &youmonst
&& x
== u
.ux
&& y
== u
.uy
42 && (!u
.usteed
|| mtmp
!= u
.usteed
))
46 struct monst
*mtmp2
= m_at(x
, y
);
48 /* Be careful with long worms. A monster may be placed back in
49 * its own location. Normally, if m_at() returns the same monster
50 * that we're trying to place, the monster is being placed in its
51 * own location. However, that is not correct for worm segments,
52 * because all the segments of the worm return the same m_at().
53 * Actually we overdo the check a little bit--a worm can't be placed
54 * in its own location, period. If we just checked for mtmp->mx
55 * != x || mtmp->my != y, we'd miss the case where we're called
56 * to place the worm segment and the worm's head is at x,y.
58 if (mtmp2
&& (mtmp2
!= mtmp
|| mtmp
->wormno
))
62 if (is_pool(x
, y
) && !ignorewater
) {
63 if (mtmp
== &youmonst
)
64 return (Levitation
|| Flying
|| Wwalking
|| Swimming
67 return (is_floater(mdat
) || is_flyer(mdat
) || is_swimmer(mdat
)
69 } else if (mdat
->mlet
== S_EEL
&& rn2(13) && !ignorewater
) {
71 } else if (is_lava(x
, y
)) {
72 if (mtmp
== &youmonst
)
73 return (Levitation
|| Flying
74 || (Fire_resistance
&& Wwalking
&& uarmf
75 && uarmf
->oerodeproof
)
76 || (Upolyd
&& likes_lava(youmonst
.data
)));
78 return (is_floater(mdat
) || is_flyer(mdat
)
81 if (passes_walls(mdat
) && may_passwall(x
, y
))
83 if (amorphous(mdat
) && closed_door(x
, y
))
86 if (!accessible(x
, y
)) {
87 if (!(is_pool(x
, y
) && ignorewater
))
91 if (sobj_at(BOULDER
, x
, y
) && (!mdat
|| !throws_rocks(mdat
)))
99 * Attempt to find a good place for the given monster type in the closest
100 * position to (xx,yy). Do so in successive square rings around (xx,yy).
101 * If there is more than one valid position in the ring, choose one randomly.
102 * Return TRUE and the position chosen when successful, FALSE otherwise.
105 enexto(cc
, xx
, yy
, mdat
)
107 register xchar xx
, yy
;
108 struct permonst
*mdat
;
110 return enexto_core(cc
, xx
, yy
, mdat
, 0);
114 enexto_core(cc
, xx
, yy
, mdat
, entflags
)
116 register xchar xx
, yy
;
117 struct permonst
*mdat
;
121 coord good
[MAX_GOOD
], *good_ptr
;
123 int xmin
, xmax
, ymin
, ymax
;
124 struct monst fakemon
; /* dummy monster */
127 debugpline0("enexto() called with null mdat");
128 /* default to player's original monster type */
129 mdat
= &mons
[u
.umonster
];
132 set_mon_data(&fakemon
, mdat
, -1); /* set up for goodpos */
137 * Walk around the border of the square with center (xx,yy) and
138 * radius range. Stop when we find at least one valid position.
141 xmin
= max(1, xx
- range
);
142 xmax
= min(COLNO
- 1, xx
+ range
);
143 ymin
= max(0, yy
- range
);
144 ymax
= min(ROWNO
- 1, yy
+ range
);
146 for (x
= xmin
; x
<= xmax
; x
++)
147 if (goodpos(x
, ymin
, &fakemon
, entflags
)) {
150 /* beware of accessing beyond segment boundaries.. */
151 if (good_ptr
++ == &good
[MAX_GOOD
- 1])
154 for (x
= xmin
; x
<= xmax
; x
++)
155 if (goodpos(x
, ymax
, &fakemon
, entflags
)) {
158 /* beware of accessing beyond segment boundaries.. */
159 if (good_ptr
++ == &good
[MAX_GOOD
- 1])
162 for (y
= ymin
+ 1; y
< ymax
; y
++)
163 if (goodpos(xmin
, y
, &fakemon
, entflags
)) {
166 /* beware of accessing beyond segment boundaries.. */
167 if (good_ptr
++ == &good
[MAX_GOOD
- 1])
170 for (y
= ymin
+ 1; y
< ymax
; y
++)
171 if (goodpos(xmax
, y
, &fakemon
, entflags
)) {
174 /* beware of accessing beyond segment boundaries.. */
175 if (good_ptr
++ == &good
[MAX_GOOD
- 1])
180 /* return if we've grown too big (nothing is valid) */
181 if (range
> ROWNO
&& range
> COLNO
)
183 } while (good_ptr
== good
);
186 i
= rn2((int) (good_ptr
- good
));
193 * Check for restricted areas present in some special levels. (This might
194 * need to be augmented to allow deliberate passage in wizard mode, but
195 * only for explicitly chosen destinations.)
198 tele_jump_ok(x1
, y1
, x2
, y2
)
201 if (dndest
.nlx
> 0) {
202 /* if inside a restricted region, can't teleport outside */
203 if (within_bounded_area(x1
, y1
, dndest
.nlx
, dndest
.nly
, dndest
.nhx
,
205 && !within_bounded_area(x2
, y2
, dndest
.nlx
, dndest
.nly
,
206 dndest
.nhx
, dndest
.nhy
))
208 /* and if outside, can't teleport inside */
209 if (!within_bounded_area(x1
, y1
, dndest
.nlx
, dndest
.nly
, dndest
.nhx
,
211 && within_bounded_area(x2
, y2
, dndest
.nlx
, dndest
.nly
, dndest
.nhx
,
215 if (updest
.nlx
> 0) { /* ditto */
216 if (within_bounded_area(x1
, y1
, updest
.nlx
, updest
.nly
, updest
.nhx
,
218 && !within_bounded_area(x2
, y2
, updest
.nlx
, updest
.nly
,
219 updest
.nhx
, updest
.nhy
))
221 if (!within_bounded_area(x1
, y1
, updest
.nlx
, updest
.nly
, updest
.nhx
,
223 && within_bounded_area(x2
, y2
, updest
.nlx
, updest
.nly
, updest
.nhx
,
235 if (!trapok
&& t_at(x
, y
))
237 if (!goodpos(x
, y
, &youmonst
, 0))
239 if (!tele_jump_ok(u
.ux
, u
.uy
, x
, y
))
241 if (!in_out_region(x
, y
))
247 teleds(nux
, nuy
, allow_drag
)
248 register int nux
, nuy
;
251 boolean ball_active
, ball_still_in_range
;
253 if (u
.utraptype
== TT_BURIEDBALL
) {
255 buried_ball_to_punishment();
257 ball_active
= (Punished
&& uball
->where
!= OBJ_FREE
);
258 ball_still_in_range
= FALSE
;
260 /* If they have to move the ball, then drag if allow_drag is true;
261 * otherwise they are teleporting, so unplacebc().
262 * If they don't have to move the ball, then always "drag" whether or
263 * not allow_drag is true, because we are calling that function, not
264 * to drag, but to move the chain. *However* there are some dumb
267 * _X move east -----> X_
269 * These are permissible if teleporting, but not if dragging. As a
270 * result, drag_ball() needs to know about allow_drag and might end
271 * up dragging the ball anyway. Also, drag_ball() might find that
272 * dragging the ball is completely impossible (ball in range but there's
273 * rock in the way), in which case it teleports the ball on its own.
276 if (!carried(uball
) && distmin(nux
, nuy
, uball
->ox
, uball
->oy
) <= 2)
277 ball_still_in_range
= TRUE
; /* don't have to move the ball */
279 /* have to move the ball */
280 if (!allow_drag
|| distmin(u
.ux
, u
.uy
, nux
, nuy
) > 1) {
281 /* we should not have dist > 1 and allow_drag at the same
282 * time, but just in case, we must then revert to teleport.
294 if (!hideunder(&youmonst
) && youmonst
.data
->mlet
== S_MIMIC
) {
295 /* mimics stop being unnoticed */
296 youmonst
.m_ap_type
= M_AP_NOTHING
;
300 u
.uswldtim
= u
.uswallow
= 0;
301 if (Punished
&& !ball_active
) {
302 /* ensure ball placement, like unstuck */
309 if (ball_still_in_range
|| allow_drag
) {
311 xchar ballx
, bally
, chainx
, chainy
;
314 if (drag_ball(nux
, nuy
, &bc_control
, &ballx
, &bally
, &chainx
,
315 &chainy
, &cause_delay
, allow_drag
))
316 move_bc(0, bc_control
, ballx
, bally
, chainx
, chainy
);
319 /* must set u.ux, u.uy after drag_ball(), which may need to know
320 the old position if allow_drag is true... */
321 u_on_newpos(nux
, nuy
); /* set u.<x,y>, usteed-><mx,my>; cliparound() */
322 fill_pit(u
.ux0
, u
.uy0
);
324 if (!ball_still_in_range
&& !allow_drag
)
327 initrack(); /* teleports mess up tracking monsters without this */
328 update_player_regions();
330 * Make sure the hero disappears from the old location. This will
331 * not happen if she is teleported within sight of her previous
332 * location. Force a full vision recalculation because the hero
333 * is now in a new location.
335 newsym(u
.ux0
, u
.uy0
);
337 vision_full_recalc
= 1;
339 vision_recalc(0); /* vision before effects */
341 /* when teleporting by scroll, we need to handle discovery
342 now before getting feedback about any objects at our
343 destination since we might land on another such scroll */
344 if (distu(u
.ux0
, u
.uy0
) >= 16 || !couldsee(u
.ux0
, u
.uy0
))
345 learnscroll(telescroll
);
347 telescroll
= 0; /* no discovery by scrolltele()'s caller */
350 invocation_message();
354 safe_teleds(allow_drag
)
357 register int nux
, nuy
, tcnt
= 0;
360 nux
= rnd(COLNO
- 1);
362 } while (!teleok(nux
, nuy
, (boolean
) (tcnt
> 200)) && ++tcnt
<= 400);
365 teleds(nux
, nuy
, allow_drag
);
374 register struct mkroom
*croom
= search_special(VAULT
);
377 if (croom
&& somexy(croom
, &c
) && teleok(c
.x
, c
.y
, FALSE
)) {
378 teleds(c
.x
, c
.y
, FALSE
);
385 teleport_pet(mtmp
, force_it
)
386 register struct monst
*mtmp
;
389 register struct obj
*otmp
;
391 if (mtmp
== u
.usteed
)
394 if (mtmp
->mleashed
) {
395 otmp
= get_mleash(mtmp
);
397 impossible("%s is leashed, without a leash.", Monnam(mtmp
));
400 if (otmp
->cursed
&& !force_it
) {
404 Your("leash goes slack.");
406 m_unleash(mtmp
, FALSE
);
413 /* teleport the hero via some method other than scroll of teleport */
417 (void) scrolltele((struct obj
*) 0);
420 /* teleport the hero; return true if scroll of teleportation should become
421 discovered; teleds() will usually do the actual discovery, since the
422 outcome sometimes depends upon destination and discovery needs to be
423 performed before arrival, in case we land on another teleport scroll */
429 boolean result
= FALSE
; /* don't learn scroll */
431 /* Disable teleportation in stronghold && Vlad's Tower */
432 if (level
.flags
.noteleport
) {
434 pline("A mysterious force prevents you from teleporting!");
439 /* don't show trap if "Sorry..." */
441 make_blinded(0L, FALSE
);
443 if ((u
.uhave
.amulet
|| On_W_tower_level(&u
.uz
)) && !rn2(3)) {
444 You_feel("disoriented for a moment.");
445 if (!wizard
|| yn("Override?") != 'y')
448 if ((Teleport_control
&& !Stunned
) || wizard
) {
450 pline("Being unconscious, you cannot control your teleport.");
454 Strcpy(whobuf
, "you");
456 Sprintf(eos(whobuf
), " and %s", mon_nam(u
.usteed
));
457 pline("To what position do %s want to be teleported?", whobuf
);
460 if (getpos(&cc
, TRUE
, "the desired position") < 0)
461 return TRUE
; /* abort */
462 /* possible extensions: introduce a small error if
463 magic power is low; allow transfer to solid rock */
464 if (teleok(cc
.x
, cc
.y
, FALSE
)) {
465 /* for scroll, discover it regardless of destination */
468 teleds(cc
.x
, cc
.y
, FALSE
);
474 } else if (scroll
&& scroll
->blessed
) {
475 /* (this used to be handled in seffects()) */
476 if (yn("Do you wish to teleport?") == 'n')
482 (void) safe_teleds(FALSE
);
483 /* teleds() will leave telescroll intact iff random destination
484 is far enough away for scroll discovery to be warranted */
487 telescroll
= 0; /* reset */
495 boolean trap_once
= FALSE
;
497 trap
= t_at(u
.ux
, u
.uy
);
498 if (trap
&& (!trap
->tseen
|| trap
->ttyp
!= TELEP_TRAP
))
502 trap_once
= trap
->once
; /* trap may get deleted, save this */
504 pline("This is a vault teleport, usable once only.");
505 if (yn("Jump in?") == 'n')
513 You("%s onto the teleportation trap.",
514 locomotion(youmonst
.data
, "jump"));
517 boolean castit
= FALSE
;
518 register int sp_no
= 0, energy
= 0;
520 if (!Teleportation
|| (u
.ulevel
< (Role_if(PM_WIZARD
) ? 8 : 12)
521 && !can_teleport(youmonst
.data
))) {
522 /* Try to use teleport away spell. */
523 if (objects
[SPE_TELEPORT_AWAY
].oc_name_known
&& !Confusion
)
524 for (sp_no
= 0; sp_no
< MAXSPELL
; sp_no
++)
525 if (spl_book
[sp_no
].sp_id
== SPE_TELEPORT_AWAY
) {
532 You("don't know that spell.");
534 You("are not able to teleport at will.");
540 if (u
.uhunger
<= 100 || ACURR(A_STR
) < 6) {
542 You("lack the strength %s.",
543 castit
? "for a teleport spell" : "to teleport");
548 energy
= objects
[SPE_TELEPORT_AWAY
].oc_level
* 7 / 2 - 2;
549 if (u
.uen
<= energy
) {
553 You("lack the energy %s.",
554 castit
? "for a teleport spell" : "to teleport");
560 "Your concentration falters from carrying so much."))
564 exercise(A_WIS
, TRUE
);
565 if (spelleffects(sp_no
, TRUE
))
576 if (trap
&& trap_once
)
582 You1(shudder_for_moment
);
595 const char *escape_by_flying
= 0; /* when surviving dest of -N */
597 boolean force_dest
= FALSE
;
599 if ((u
.uhave
.amulet
|| In_endgame(&u
.uz
) || In_sokoban(&u
.uz
))
601 You_feel("very disoriented for a moment.");
604 if ((Teleport_control
&& !Stunned
) || wizard
) {
608 Strcpy(qbuf
, "To what level do you want to teleport?");
612 Strcat(qbuf
, " [type a number, name, or ? for a menu]");
614 Strcat(qbuf
, " [type a number or name]");
617 if (!strcmp(buf
, "\033")) { /* cancelled */
618 if (Confusion
&& rnl(5)) {
620 goto random_levtport
;
623 } else if (!strcmp(buf
, "*")) {
624 goto random_levtport
;
625 } else if (Confusion
&& rnl(5)) {
627 goto random_levtport
;
629 if (wizard
&& !strcmp(buf
, "?")) {
633 newlev
= (int) print_dungeon(TRUE
, &destlev
, &destdnum
);
637 newlevel
.dnum
= destdnum
;
638 newlevel
.dlevel
= destlev
;
639 if (In_endgame(&newlevel
) && !In_endgame(&u
.uz
)) {
643 && (amu
= mksobj(AMULET_OF_YENDOR
, TRUE
, FALSE
))
645 /* ordinarily we'd use hold_another_object()
646 for something like this, but we don't want
647 fumbling or already full pack to interfere */
649 prinv("Endgame prerequisite:", amu
, 0L);
653 } else if ((newlev
= lev_by_name(buf
)) == 0)
655 } while (!newlev
&& !digit(buf
[0])
656 && (buf
[0] != '-' || !digit(buf
[1])) && trycnt
< 10);
658 /* no dungeon escape via this route */
661 goto random_levtport
;
662 if (ynq("Go to Nowhere. Are you sure?") != 'y')
664 You("%s in agony as your body begins to warp...",
665 is_silent(youmonst
.data
) ? "writhe" : "scream");
666 display_nhwindow(WIN_MESSAGE
, FALSE
);
667 You("cease to exist.");
669 Your("possessions land on the %s with a thud.",
670 surface(u
.ux
, u
.uy
));
671 killer
.format
= NO_KILLER_PREFIX
;
672 Strcpy(killer
.name
, "committed suicide");
674 pline("An energized cloud of dust begins to coalesce.");
675 Your("body rematerializes%s.",
676 invent
? ", and you gather up all your possessions" : "");
680 /* if in Knox and the requested level > 0, stay put.
681 * we let negative values requests fall into the "heaven" loop.
683 if (Is_knox(&u
.uz
) && newlev
> 0 && !force_dest
) {
684 You1(shudder_for_moment
);
687 /* if in Quest, the player sees "Home 1", etc., on the status
688 * line, instead of the logical depth of the level. controlled
689 * level teleport request is likely to be relativized to the
690 * status line, and consequently it should be incremented to
691 * the value of the logical depth of the target level.
693 * we let negative values requests fall into the "heaven" loop.
695 if (In_quest(&u
.uz
) && newlev
> 0)
696 newlev
= newlev
+ dungeons
[u
.uz
.dnum
].depth_start
- 1;
697 } else { /* involuntary level tele */
699 newlev
= random_teleport_level();
700 if (newlev
== depth(&u
.uz
)) {
701 You1(shudder_for_moment
);
706 if (u
.utrap
&& u
.utraptype
== TT_BURIEDBALL
)
707 buried_ball_to_punishment();
709 if (!next_to_u() && !force_dest
) {
710 You1(shudder_for_moment
);
713 if (In_endgame(&u
.uz
)) { /* must already be wizard */
714 int llimit
= dunlevs_in_dungeon(&u
.uz
);
716 if (newlev
>= 0 || newlev
<= -llimit
) {
717 You_cant("get there from here.");
720 newlevel
.dnum
= u
.uz
.dnum
;
721 newlevel
.dlevel
= llimit
+ newlev
;
722 schedule_goto(&newlevel
, FALSE
, FALSE
, 0, (char *) 0, (char *) 0);
726 killer
.name
[0] = 0; /* still alive, so far... */
728 if (newlev
< 0 && !force_dest
) {
730 /* take unpaid inventory items off of shop bills */
731 in_mklev
= TRUE
; /* suppress map update */
732 u_left_shop(u
.ushops0
, TRUE
);
733 /* you're now effectively out of the shop */
734 *u
.ushops0
= *u
.ushops
= '\0';
738 You("arrive in heaven.");
739 verbalize("Thou art early, but we'll admit thee.");
740 killer
.format
= NO_KILLER_PREFIX
;
741 Strcpy(killer
.name
, "went to heaven prematurely");
742 } else if (newlev
== -9) {
743 You_feel("deliriously happy. ");
744 pline("(In fact, you're on Cloud 9!) ");
745 display_nhwindow(WIN_MESSAGE
, FALSE
);
747 You("are now high above the clouds...");
749 if (killer
.name
[0]) {
750 ; /* arrival in heaven is pending */
751 } else if (Levitation
) {
752 escape_by_flying
= "float gently down to earth";
754 escape_by_flying
= "fly down to the ground";
756 pline("Unfortunately, you don't know how to fly.");
757 You("plummet a few thousand feet to your death.");
759 "teleported out of the dungeon and fell to %s death",
761 killer
.format
= NO_KILLER_PREFIX
;
765 if (killer
.name
[0]) { /* the chosen destination was not survivable */
768 /* set specific death location; this also suppresses bones */
769 lsav
= u
.uz
; /* save current level, see below */
770 u
.uz
.dnum
= 0; /* main dungeon */
771 u
.uz
.dlevel
= (newlev
<= -10) ? -10 : 0; /* heaven or surface */
773 /* can only get here via life-saving (or declining to die in
774 explore|debug mode); the hero has now left the dungeon... */
775 escape_by_flying
= "find yourself back on the surface";
776 u
.uz
= lsav
; /* restore u.uz so escape code works */
779 /* calls done(ESCAPED) if newlevel==0 */
780 if (escape_by_flying
) {
781 You("%s.", escape_by_flying
);
782 newlevel
.dnum
= 0; /* specify main dungeon */
783 newlevel
.dlevel
= 0; /* escape the dungeon */
784 /* [dlevel used to be set to 1, but it doesn't make sense to
785 teleport out of the dungeon and float or fly down to the
786 surface but then actually arrive back inside the dungeon] */
787 } else if (u
.uz
.dnum
== medusa_level
.dnum
788 && newlev
>= dungeons
[u
.uz
.dnum
].depth_start
789 + dunlevs_in_dungeon(&u
.uz
)) {
790 if (!(wizard
&& force_dest
))
791 find_hell(&newlevel
);
793 /* if invocation did not yet occur, teleporting into
794 * the last level of Gehennom is forbidden.
796 if (!wizard
&& Inhell
&& !u
.uevent
.invoked
797 && newlev
>= (dungeons
[u
.uz
.dnum
].depth_start
798 + dunlevs_in_dungeon(&u
.uz
) - 1)) {
799 newlev
= dungeons
[u
.uz
.dnum
].depth_start
800 + dunlevs_in_dungeon(&u
.uz
) - 2;
803 /* no teleporting out of quest dungeon */
804 if (In_quest(&u
.uz
) && newlev
< depth(&qstart_level
))
805 newlev
= depth(&qstart_level
);
806 /* the player thinks of levels purely in logical terms, so
807 * we must translate newlev to a number relative to the
810 if (!(wizard
&& force_dest
))
811 get_level(&newlevel
, newlev
);
813 schedule_goto(&newlevel
, FALSE
, FALSE
, 0, (char *) 0, (char *) 0);
814 /* in case player just read a scroll and is about to be asked to
815 call it something, we can't defer until the end of the turn */
816 if (u
.utotype
&& !context
.mon_moving
)
822 register struct trap
*ttmp
;
824 struct d_level target_level
;
826 if (u
.utrap
&& u
.utraptype
== TT_BURIEDBALL
)
827 buried_ball_to_punishment();
830 You1(shudder_for_moment
);
834 /* if landed from another portal, do nothing */
835 /* problem: level teleport landing escapes the check */
836 if (!on_level(&u
.uz
, &u
.uz0
))
839 You("activated a magic portal!");
841 /* prevent the poor shnook, whose amulet was stolen while in
842 * the endgame, from accidently triggering the portal to the
843 * next level, and thus losing the game
845 if (In_endgame(&u
.uz
) && !u
.uhave
.amulet
) {
846 You_feel("dizzy for a moment, but nothing happens...");
850 target_level
= ttmp
->dst
;
851 schedule_goto(&target_level
, FALSE
, FALSE
, 1,
852 "You feel dizzy for a moment, but the sensation passes.",
860 if (In_endgame(&u
.uz
) || Antimagic
) {
862 shieldeff(u
.ux
, u
.uy
);
863 You_feel("a wrenching sensation.");
864 } else if (!next_to_u()) {
865 You1(shudder_for_moment
);
866 } else if (trap
->once
) {
868 newsym(u
.ux
, u
.uy
); /* get rid of trap symbol */
875 level_tele_trap(trap
, trflags
)
881 if ((trflags
& VIASITTING
) != 0)
882 Strcpy(verbbuf
, "trigger"); /* follows "You sit down." */
884 Sprintf(verbbuf
, "%s onto",
885 Levitation
? (const char *) "float"
886 : locomotion(youmonst
.data
, "step"));
887 You("%s a level teleport trap!", verbbuf
);
890 shieldeff(u
.ux
, u
.uy
);
892 if (Antimagic
|| In_endgame(&u
.uz
)) {
893 You_feel("a wrenching sensation.");
897 You("are momentarily blinded by a flash of light.");
899 You("are momentarily disoriented.");
901 newsym(u
.ux
, u
.uy
); /* get rid of trap symbol */
905 /* check whether monster can arrive at location <x,y> via Tport (or fall) */
907 rloc_pos_ok(x
, y
, mtmp
)
908 register int x
, y
; /* coordinates of candidate location */
913 if (!goodpos(x
, y
, mtmp
, 0))
916 * Check for restricted areas present in some special levels.
918 * `xx' is current column; if 0, then `yy' will contain flag bits
919 * rather than row: bit #0 set => moving upwards; bit #1 set =>
920 * inside the Wizard's tower.
925 /* no current location (migrating monster arrival) */
926 if (dndest
.nlx
&& On_W_tower_level(&u
.uz
))
927 return (((yy
& 2) != 0)
928 /* inside xor not within */
929 ^ !within_bounded_area(x
, y
, dndest
.nlx
, dndest
.nly
,
930 dndest
.nhx
, dndest
.nhy
));
931 if (updest
.lx
&& (yy
& 1) != 0) /* moving up */
932 return (within_bounded_area(x
, y
, updest
.lx
, updest
.ly
,
933 updest
.hx
, updest
.hy
)
935 || !within_bounded_area(x
, y
, updest
.nlx
, updest
.nly
,
936 updest
.nhx
, updest
.nhy
)));
937 if (dndest
.lx
&& (yy
& 1) == 0) /* moving down */
938 return (within_bounded_area(x
, y
, dndest
.lx
, dndest
.ly
,
939 dndest
.hx
, dndest
.hy
)
941 || !within_bounded_area(x
, y
, dndest
.nlx
, dndest
.nly
,
942 dndest
.nhx
, dndest
.nhy
)));
944 /* [try to] prevent a shopkeeper or temple priest from being
945 sent out of his room (caller might resort to goodpos() if
946 we report failure here, so this isn't full prevention) */
947 if (mtmp
->isshk
&& inhishop(mtmp
)) {
948 if (levl
[x
][y
].roomno
!= ESHK(mtmp
)->shoproom
)
950 } else if (mtmp
->ispriest
&& inhistemple(mtmp
)) {
951 if (levl
[x
][y
].roomno
!= EPRI(mtmp
)->shroom
)
954 /* current location is <xx,yy> */
955 if (!tele_jump_ok(xx
, yy
, x
, y
))
965 * Pulls a monster from its current position and places a monster at
966 * a new x and y. If oldx is 0, then the monster was not in the
967 * levels.monsters array. However, if oldx is 0, oldy may still have
968 * a value because mtmp is a migrating_mon. Worm tails are always
969 * placed randomly around the head of the worm.
976 register int oldx
= mtmp
->mx
, oldy
= mtmp
->my
;
977 boolean resident_shk
= mtmp
->isshk
&& inhishop(mtmp
);
979 if (x
== mtmp
->mx
&& y
== mtmp
->my
) /* that was easy */
982 if (oldx
) { /* "pick up" monster */
986 remove_monster(oldx
, oldy
);
987 newsym(oldx
, oldy
); /* update old location */
991 memset(mtmp
->mtrack
, 0, sizeof mtmp
->mtrack
);
992 place_monster(mtmp
, x
, y
); /* put monster down */
993 update_monster_region(mtmp
);
995 if (mtmp
->wormno
) /* now put down tail */
996 place_worm_tail_randomly(mtmp
, x
, y
);
998 if (u
.ustuck
== mtmp
) {
1007 newsym(x
, y
); /* update new location */
1008 set_apparxy(mtmp
); /* orient monster */
1010 /* shopkeepers will only teleport if you zap them with a wand of
1011 teleportation or if they've been transformed into a jumpy monster;
1012 the latter only happens if you've attacked them with polymorph */
1013 if (resident_shk
&& !inhishop(mtmp
))
1014 make_angry_shk(mtmp
, oldx
, oldy
);
1017 /* place a monster at a random location, typically due to teleport */
1018 /* return TRUE if successful, FALSE if not */
1020 rloc(mtmp
, suppress_impossible
)
1021 struct monst
*mtmp
; /* mx==0 implies migrating monster arrival */
1022 boolean suppress_impossible
;
1024 register int x
, y
, trycount
;
1026 if (mtmp
== u
.usteed
) {
1031 if (mtmp
->iswiz
&& mtmp
->mx
) { /* Wizard, not just arriving */
1032 if (!In_W_tower(u
.ux
, u
.uy
, &u
.uz
))
1033 x
= xupstair
, y
= yupstair
;
1034 else if (!xdnladder
) /* bottom level of tower */
1035 x
= xupladder
, y
= yupladder
;
1037 x
= xdnladder
, y
= ydnladder
;
1038 /* if the wiz teleports away to heal, try the up staircase,
1039 to block the player's escaping before he's healed
1040 (deliberately use `goodpos' rather than `rloc_pos_ok' here) */
1041 if (goodpos(x
, y
, mtmp
, 0))
1047 x
= rn1(COLNO
- 3, 2);
1049 if ((trycount
< 500) ? rloc_pos_ok(x
, y
, mtmp
)
1050 : goodpos(x
, y
, mtmp
, 0))
1052 } while (++trycount
< 1000);
1054 /* last ditch attempt to find a good place */
1055 for (x
= 2; x
< COLNO
- 1; x
++)
1056 for (y
= 0; y
< ROWNO
; y
++)
1057 if (goodpos(x
, y
, mtmp
, 0))
1060 /* level either full of monsters or somehow faulty */
1061 if (!suppress_impossible
)
1062 impossible("rloc(): couldn't relocate monster");
1066 rloc_to(mtmp
, x
, y
);
1074 register struct mkroom
*croom
= search_special(VAULT
);
1077 if (croom
&& somexy(croom
, &c
) && goodpos(c
.x
, c
.y
, mtmp
, 0)) {
1078 rloc_to(mtmp
, c
.x
, c
.y
);
1081 (void) rloc(mtmp
, TRUE
);
1088 if (level
.flags
.noteleport
) {
1090 pline("A mysterious force prevents %s from teleporting!",
1098 mtele_trap(mtmp
, trap
, in_sight
)
1105 if (tele_restrict(mtmp
))
1107 if (teleport_pet(mtmp
, FALSE
)) {
1108 /* save name with pre-movement visibility */
1109 monname
= Monnam(mtmp
);
1111 /* Note: don't remove the trap if a vault. Other-
1112 * wise the monster will be stuck there, since
1113 * the guard isn't going to come for it...
1118 (void) rloc(mtmp
, TRUE
);
1121 if (canseemon(mtmp
))
1122 pline("%s seems disoriented.", monname
);
1124 pline("%s suddenly disappears!", monname
);
1130 /* return 0 if still on level, 3 if not */
1132 mlevel_tele_trap(mtmp
, trap
, force_it
, in_sight
)
1138 int tt
= trap
->ttyp
;
1139 struct permonst
*mptr
= mtmp
->data
;
1141 if (mtmp
== u
.ustuck
) /* probably a vortex */
1142 return 0; /* temporary? kludge */
1143 if (teleport_pet(mtmp
, force_it
)) {
1145 int migrate_typ
= MIGR_RANDOM
;
1147 if ((tt
== HOLE
|| tt
== TRAPDOOR
)) {
1148 if (Is_stronghold(&u
.uz
)) {
1149 assign_level(&tolevel
, &valley_level
);
1150 } else if (Is_botlevel(&u
.uz
)) {
1151 if (in_sight
&& trap
->tseen
)
1152 pline("%s avoids the %s.", Monnam(mtmp
),
1153 (tt
== HOLE
) ? "hole" : "trap");
1156 get_level(&tolevel
, depth(&u
.uz
) + 1);
1158 } else if (tt
== MAGIC_PORTAL
) {
1159 if (In_endgame(&u
.uz
)
1160 && (mon_has_amulet(mtmp
) || is_home_elemental(mptr
))) {
1161 if (in_sight
&& mptr
->mlet
!= S_ELEMENTAL
) {
1162 pline("%s seems to shimmer for a moment.", Monnam(mtmp
));
1167 assign_level(&tolevel
, &trap
->dst
);
1168 migrate_typ
= MIGR_PORTAL
;
1170 } else { /* (tt == LEVEL_TELEP) */
1173 if (mon_has_amulet(mtmp
) || In_endgame(&u
.uz
)) {
1175 pline("%s seems very disoriented for a moment.",
1179 nlev
= random_teleport_level();
1180 if (nlev
== depth(&u
.uz
)) {
1182 pline("%s shudders for a moment.", Monnam(mtmp
));
1185 get_level(&tolevel
, nlev
);
1189 pline("Suddenly, %s disappears out of sight.", mon_nam(mtmp
));
1192 migrate_to_level(mtmp
, ledger_no(&tolevel
), migrate_typ
, (coord
*) 0);
1193 return 3; /* no longer on this level */
1198 /* place object randomly, returns False if it's gone (eg broken) */
1201 register struct obj
*obj
;
1203 register xchar tx
, ty
, otx
, oty
;
1204 boolean restricted_fall
;
1205 int try_limit
= 4000;
1207 if (obj
->otyp
== CORPSE
&& is_rider(&mons
[obj
->corpsenm
])) {
1208 if (revive_corpse(obj
))
1212 obj_extract_self(obj
);
1215 restricted_fall
= (otx
== 0 && dndest
.lx
);
1217 tx
= rn1(COLNO
- 3, 2);
1221 } while (!goodpos(tx
, ty
, (struct monst
*) 0, 0)
1223 && (!within_bounded_area(tx
, ty
, dndest
.lx
, dndest
.ly
,
1224 dndest
.hx
, dndest
.hy
)
1226 && within_bounded_area(tx
, ty
,
1227 dndest
.nlx
, dndest
.nly
,
1228 dndest
.nhx
, dndest
.nhy
))))
1229 /* on the Wizard Tower levels, objects inside should
1230 stay inside and objects outside should stay outside */
1231 || (dndest
.nlx
&& On_W_tower_level(&u
.uz
)
1232 && within_bounded_area(tx
, ty
, dndest
.nlx
, dndest
.nly
,
1233 dndest
.nhx
, dndest
.nhy
)
1234 != within_bounded_area(otx
, oty
, dndest
.nlx
, dndest
.nly
,
1235 dndest
.nhx
, dndest
.nhy
)));
1237 if (flooreffects(obj
, tx
, ty
, "fall")) {
1239 } else if (otx
== 0 && oty
== 0) {
1240 ; /* fell through a trap door; no update of old loc needed */
1242 if (costly_spot(otx
, oty
)
1243 && (!costly_spot(tx
, ty
)
1244 || !index(in_rooms(tx
, ty
, 0), *in_rooms(otx
, oty
, 0)))) {
1245 if (costly_spot(u
.ux
, u
.uy
)
1246 && index(u
.urooms
, *in_rooms(otx
, oty
, 0)))
1247 addtobill(obj
, FALSE
, FALSE
, FALSE
);
1249 (void) stolen_value(obj
, otx
, oty
, FALSE
, FALSE
);
1251 newsym(otx
, oty
); /* update old location */
1253 place_object(obj
, tx
, ty
);
1258 /* Returns an absolute depth */
1260 random_teleport_level()
1262 int nlev
, max_depth
, min_depth
, cur_depth
= (int) depth(&u
.uz
);
1264 /* [the endgame case can only occur in wizard mode] */
1265 if (!rn2(5) || Is_knox(&u
.uz
) || In_endgame(&u
.uz
))
1268 /* What I really want to do is as follows:
1269 * -- If in a dungeon that goes down, the new level is to be restricted
1270 * to [top of parent, bottom of current dungeon]
1271 * -- If in a dungeon that goes up, the new level is to be restricted
1272 * to [top of current dungeon, bottom of parent]
1273 * -- If in a quest dungeon or similar dungeon entered by portals,
1274 * the new level is to be restricted to [top of current dungeon,
1275 * bottom of current dungeon]
1276 * The current behavior is not as sophisticated as that ideal, but is
1277 * still better what we used to do, which was like this for players
1278 * but different for monsters for no obvious reason. Currently, we
1279 * must explicitly check for special dungeons. We check for Knox
1280 * above; endgame is handled in the caller due to its different
1281 * message ("disoriented").
1283 * 3.4.2: explicitly handle quest here too, to fix the problem of
1284 * monsters sometimes level teleporting out of it into main dungeon.
1285 * Also prevent monsters reaching the Sanctum prior to invocation.
1287 if (In_quest(&u
.uz
)) {
1288 int bottom
= dunlevs_in_dungeon(&u
.uz
),
1289 qlocate_depth
= qlocate_level
.dlevel
;
1291 /* if hero hasn't reached the middle locate level yet,
1292 no one can randomly teleport past it */
1293 if (dunlev_reached(&u
.uz
) < qlocate_depth
)
1294 bottom
= qlocate_depth
;
1295 min_depth
= dungeons
[u
.uz
.dnum
].depth_start
;
1296 max_depth
= bottom
+ (dungeons
[u
.uz
.dnum
].depth_start
- 1);
1300 dunlevs_in_dungeon(&u
.uz
) + (dungeons
[u
.uz
.dnum
].depth_start
- 1);
1301 /* can't reach Sanctum if the invocation hasn't been performed */
1302 if (Inhell
&& !u
.uevent
.invoked
)
1306 /* Get a random value relative to the current dungeon */
1307 /* Range is 1 to current+3, current not counting */
1308 nlev
= rn2(cur_depth
+ 3 - min_depth
) + min_depth
;
1309 if (nlev
>= cur_depth
)
1312 if (nlev
> max_depth
) {
1314 /* teleport up if already on bottom */
1315 if (Is_botlevel(&u
.uz
))
1318 if (nlev
< min_depth
) {
1320 if (nlev
== cur_depth
) {
1322 if (nlev
> max_depth
)
1329 /* you teleport a monster (via wand, spell, or poly'd q.mechanic attack);
1330 return false iff the attempt fails */
1332 u_teleport_mon(mtmp
, give_feedback
)
1334 boolean give_feedback
;
1338 if (mtmp
->ispriest
&& *in_rooms(mtmp
->mx
, mtmp
->my
, TEMPLE
)) {
1340 pline("%s resists your magic!", Monnam(mtmp
));
1342 } else if (level
.flags
.noteleport
&& u
.uswallow
&& mtmp
== u
.ustuck
) {
1344 You("are no longer inside %s!", mon_nam(mtmp
));
1346 (void) rloc(mtmp
, TRUE
);
1347 } else if (is_rider(mtmp
->data
) && rn2(13)
1348 && enexto(&cc
, u
.ux
, u
.uy
, mtmp
->data
))
1349 rloc_to(mtmp
, cc
.x
, cc
.y
);
1351 (void) rloc(mtmp
, TRUE
);