1 /*	SCCS Id: @(#)teleport.c	3.3	2000/03/03	*/
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 /*
14  * Is (x,y) a good position of mtmp?  If mtmp is NULL, then is (x,y) good
15  * for an object?
16  *
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.
19  */
20 boolean
goodpos(x,y,mtmp)21 goodpos(x, y, mtmp)
22 int x,y;
23 struct monst *mtmp;
24 {
25 	struct permonst *mdat = NULL;
26 
27 	if (!isok(x, y)) return FALSE;
28 
29 	/* in many cases, we're trying to create a new monster, which
30 	 * can't go on top of the player or any existing monster.
31 	 * however, occasionally we are relocating engravings or objects,
32 	 * which could be co-located and thus get restricted a bit too much.
33 	 * oh well.
34 	 */
35 	if (mtmp != &youmonst && x == u.ux && y == u.uy
36 #ifdef STEED
37 			&& (!u.usteed || mtmp != u.usteed)
38 #endif
39 			)
40 		return FALSE;
41 
42 	if (mtmp) {
43 	    struct monst *mtmp2 = m_at(x,y);
44 
45 	    if (mtmp2 && mtmp2 != mtmp)
46 		return FALSE;
47 
48 	    mdat = mtmp->data;
49 	    if (is_pool(x,y)) {
50 		if (mtmp == &youmonst)
51 			return !!(HLevitation || Flying || Wwalking ||
52 					Swimming || Amphibious);
53 		else	return (is_flyer(mdat) || is_swimmer(mdat) ||
54 							is_clinger(mdat));
55 	    } else if (mdat->mlet == S_EEL && rn2(13)) {
56 		return FALSE;
57 	    } else if (is_lava(x,y)) {
58 		if (mtmp == &youmonst)
59 		    return !!HLevitation;
60 		else
61 		    return (is_flyer(mdat) || likes_lava(mdat));
62 	    }
63 	    if (passes_walls(mdat) && may_passwall(x,y)) return TRUE;
64 	}
65 	if (!ACCESSIBLE(levl[x][y].typ)) return FALSE;
66 	if (closed_door(x, y) && (!mdat || !amorphous(mdat)))
67 		return FALSE;
68 	if (sobj_at(BOULDER, x, y) && (!mdat || !throws_rocks(mdat)))
69 		return FALSE;
70 	return TRUE;
71 }
72 
73 /*
74  * "entity next to"
75  *
76  * Attempt to find a good place for the given monster type in the closest
77  * position to (xx,yy).  Do so in successive square rings around (xx,yy).
78  * If there is more than one valid positon in the ring, choose one randomly.
79  * Return TRUE and the position chosen when successful, FALSE otherwise.
80  */
81 boolean
enexto(cc,xx,yy,mdat)82 enexto(cc, xx, yy, mdat)
83 coord *cc;
84 register xchar xx, yy;
85 struct permonst *mdat;
86 {
87 #define MAX_GOOD 15
88     coord good[MAX_GOOD], *good_ptr;
89     int x, y, range, i;
90     int xmin, xmax, ymin, ymax;
91     struct monst fakemon;	/* dummy monster */
92 
93     if (!mdat) {
94 #ifdef DEBUG
95 	pline("enexto() called with mdat==0");
96 #endif
97 	/* default to player's original monster type */
98 	mdat = &mons[u.umonster];
99     }
100     fakemon.data = mdat;	/* set up for goodpos */
101     good_ptr = good;
102     range = 1;
103     /*
104      * Walk around the border of the square with center (xx,yy) and
105      * radius range.  Stop when we find at least one valid position.
106      */
107     do {
108 	xmin = max(1, xx-range);
109 	xmax = min(COLNO-1, xx+range);
110 	ymin = max(0, yy-range);
111 	ymax = min(ROWNO-1, yy+range);
112 
113 	for (x = xmin; x <= xmax; x++)
114 	    if (goodpos(x, ymin, &fakemon)) {
115 		good_ptr->x = x;
116 		good_ptr->y = ymin ;
117 		/* beware of accessing beyond segment boundaries.. */
118 		if (good_ptr++ == &good[MAX_GOOD-1]) goto full;
119 	    }
120 	for (x = xmin; x <= xmax; x++)
121 	    if (goodpos(x, ymax, &fakemon)) {
122 		good_ptr->x = x;
123 		good_ptr->y = ymax ;
124 		/* beware of accessing beyond segment boundaries.. */
125 		if (good_ptr++ == &good[MAX_GOOD-1]) goto full;
126 	    }
127 	for (y = ymin+1; y < ymax; y++)
128 	    if (goodpos(xmin, y, &fakemon)) {
129 		good_ptr->x = xmin;
130 		good_ptr-> y = y ;
131 		/* beware of accessing beyond segment boundaries.. */
132 		if (good_ptr++ == &good[MAX_GOOD-1]) goto full;
133 	    }
134 	for (y = ymin+1; y < ymax; y++)
135 	    if (goodpos(xmax, y, &fakemon)) {
136 		good_ptr->x = xmax;
137 		good_ptr->y = y ;
138 		/* beware of accessing beyond segment boundaries.. */
139 		if (good_ptr++ == &good[MAX_GOOD-1]) goto full;
140 	    }
141 	range++;
142 
143 	/* return if we've grown too big (nothing is valid) */
144 	if (range > ROWNO && range > COLNO) return FALSE;
145     } while (good_ptr == good);
146 
147 full:
148     i = rn2((int)(good_ptr - good));
149     cc->x = good[i].x;
150     cc->y = good[i].y;
151     return TRUE;
152 }
153 
154 /*
155  * Check for restricted areas present in some special levels.  (This might
156  * need to be augmented to allow deliberate passage in wizard mode, but
157  * only for explicitly chosen destinations.)
158  */
159 STATIC_OVL boolean
tele_jump_ok(x1,y1,x2,y2)160 tele_jump_ok(x1, y1, x2, y2)
161 int x1, y1, x2, y2;
162 {
163 	if (dndest.nlx > 0) {
164 	    /* if inside a restricted region, can't teleport outside */
165 	    if (within_bounded_area(x1, y1, dndest.nlx, dndest.nly,
166 						dndest.nhx, dndest.nhy) &&
167 		!within_bounded_area(x2, y2, dndest.nlx, dndest.nly,
168 						dndest.nhx, dndest.nhy))
169 		return FALSE;
170 	    /* and if outside, can't teleport inside */
171 	    if (!within_bounded_area(x1, y1, dndest.nlx, dndest.nly,
172 						dndest.nhx, dndest.nhy) &&
173 		within_bounded_area(x2, y2, dndest.nlx, dndest.nly,
174 						dndest.nhx, dndest.nhy))
175 		return FALSE;
176 	}
177 	if (updest.nlx > 0) {		/* ditto */
178 	    if (within_bounded_area(x1, y1, updest.nlx, updest.nly,
179 						updest.nhx, updest.nhy) &&
180 		!within_bounded_area(x2, y2, updest.nlx, updest.nly,
181 						updest.nhx, updest.nhy))
182 		return FALSE;
183 	    if (!within_bounded_area(x1, y1, updest.nlx, updest.nly,
184 						updest.nhx, updest.nhy) &&
185 		within_bounded_area(x2, y2, updest.nlx, updest.nly,
186 						updest.nhx, updest.nhy))
187 		return FALSE;
188 	}
189 	return TRUE;
190 }
191 
192 STATIC_OVL boolean
teleok(x,y,trapok)193 teleok(x, y, trapok)
194 register int x, y;
195 boolean trapok;
196 {
197 	if (!trapok && t_at(x, y)) return FALSE;
198 	if (!goodpos(x, y, &youmonst)) return FALSE;
199 	if (!tele_jump_ok(u.ux, u.uy, x, y)) return FALSE;
200 	return TRUE;
201 }
202 
203 void
teleds(nux,nuy)204 teleds(nux, nuy)
205 register int nux,nuy;
206 {
207 	if (Punished) unplacebc();
208 	u.utrap = 0;
209 	u.ustuck = 0;
210 	u.ux0 = u.ux;
211 	u.uy0 = u.uy;
212 	u.ux = nux;
213 	u.uy = nuy;
214 	fill_pit(u.ux0, u.uy0); /* do this now so that cansee() is correct */
215 
216 	if (hides_under(youmonst.data))
217 		u.uundetected = OBJ_AT(nux, nuy);
218 	else if (youmonst.data->mlet == S_EEL)
219 		u.uundetected = is_pool(u.ux, u.uy);
220 	else {
221 		u.uundetected = 0;
222 		/* mimics stop being unnoticed */
223 		if (youmonst.data->mlet == S_MIMIC)
224 		    youmonst.m_ap_type = M_AP_NOTHING;
225 	}
226 
227 	if (u.uswallow) {
228 		u.uswldtim = u.uswallow = 0;
229 		docrt();
230 	}
231 	if (Punished) placebc();
232 	initrack(); /* teleports mess up tracking monsters without this */
233 	update_player_regions();
234 #ifdef STEED
235 	/* Move your steed, too */
236 	if (u.usteed) {
237 		u.usteed->mx = nux;
238 		u.usteed->my = nuy;
239 	}
240 #endif
241 	/*
242 	 *  Make sure the hero disappears from the old location.  This will
243 	 *  not happen if she is teleported within sight of her previous
244 	 *  location.  Force a full vision recalculation because the hero
245 	 *  is now in a new location.
246 	 */
247 	newsym(u.ux0,u.uy0);
248 	see_monsters();
249 	vision_full_recalc = 1;
250 	nomul(0);
251 	spoteffects(TRUE);
252 	invocation_message();
253 }
254 
255 boolean
safe_teleds()256 safe_teleds()
257 {
258 	register int nux, nuy, tcnt = 0;
259 
260 	do {
261 		nux = rnd(COLNO-1);
262 		nuy = rn2(ROWNO);
263 	} while (!teleok(nux, nuy, (boolean)(tcnt > 200)) && ++tcnt <= 400);
264 
265 	if (tcnt <= 400) {
266 		teleds(nux, nuy);
267 		return TRUE;
268 	} else
269 		return FALSE;
270 }
271 
272 STATIC_OVL void
vault_tele()273 vault_tele()
274 {
275 	register struct mkroom *croom = search_special(VAULT);
276 	coord c;
277 
278 	if (croom && somexy(croom, &c) && teleok(c.x,c.y,FALSE)) {
279 		teleds(c.x,c.y);
280 		return;
281 	}
282 	tele();
283 }
284 
285 boolean
teleport_pet(mtmp,force_it)286 teleport_pet(mtmp, force_it)
287 register struct monst *mtmp;
288 boolean force_it;
289 {
290 	register struct obj *otmp;
291 
292 #ifdef STEED
293 	if (mtmp == u.usteed)
294 		return (FALSE);
295 #endif
296 
297 	if (mtmp->mleashed) {
298 	    otmp = get_mleash(mtmp);
299 	    if (!otmp) {
300 		impossible("%s is leashed, without a leash.", Monnam(mtmp));
301 		goto release_it;
302 	    }
303 	    if (otmp->cursed && !force_it) {
304 		yelp(mtmp);
305 		return FALSE;
306 	    } else {
307 		Your("leash goes slack.");
308  release_it:
309 		m_unleash(mtmp);
310 		return TRUE;
311 	    }
312 	}
313 	return TRUE;
314 }
315 
316 void
tele()317 tele()
318 {
319 	coord cc;
320 
321 	/* Disable teleportation in stronghold && Vlad's Tower */
322 	if (level.flags.noteleport) {
323 #ifdef WIZARD
324 		if (!wizard) {
325 #endif
326 		    pline("A mysterious force prevents you from teleporting!");
327 		    return;
328 #ifdef WIZARD
329 		}
330 #endif
331 	}
332 
333 	/* don't show trap if "Sorry..." */
334 	if (!Blinded) make_blinded(0L,FALSE);
335 
336 	if ((u.uhave.amulet || On_W_tower_level(&u.uz)) && !rn2(3)) {
337 	    You_feel("disoriented for a moment.");
338 	    return;
339 	}
340 	if (Teleport_control
341 #ifdef WIZARD
342 			    || wizard
343 #endif
344 					) {
345 	    if (unconscious()) {
346 		pline("Being unconscious, you cannot control your teleport.");
347 	    } else {
348 #ifdef STEED
349 		    char buf[BUFSZ];
350 		    if (u.usteed) Sprintf(buf," and %s", mon_nam(u.usteed));
351 #endif
352 		    pline("To what position do you%s want to be teleported?",
353 #ifdef STEED
354 				u.usteed ? buf :
355 #endif
356 			   "");
357 		    cc.x = u.ux;
358 		    cc.y = u.uy;
359 		    if (getpos(&cc, TRUE, "the desired position") < 0)
360 			return;	/* abort */
361 		    /* possible extensions: introduce a small error if
362 		       magic power is low; allow transfer to solid rock */
363 		    if (teleok(cc.x, cc.y, FALSE)) {
364 			teleds(cc.x, cc.y);
365 			return;
366 		    }
367 		    pline("Sorry...");
368 		}
369 	}
370 
371 	(void) safe_teleds();
372 }
373 
374 int
dotele()375 dotele()
376 {
377 	struct trap *trap;
378 
379 	trap = t_at(u.ux, u.uy);
380 	if (trap && (!trap->tseen || trap->ttyp != TELEP_TRAP))
381 		trap = 0;
382 
383 	if (trap) {
384 		if (trap->once) {
385 			pline("This is a vault teleport, usable once only.");
386 			if (yn("Jump in?") == 'n')
387 				trap = 0;
388 			else {
389 				deltrap(trap);
390 				newsym(u.ux, u.uy);
391 			}
392 		}
393 		if (trap)
394 			You("%s onto the teleportation trap.",
395 			    locomotion(youmonst.data, "jump"));
396 	}
397 	if (!trap) {
398 	    boolean castit = FALSE;
399 	    register int sp_no = 0, energy = 0;
400 
401 	    if (!Teleportation || (u.ulevel < (Role_if(PM_WIZARD) ? 8 : 12)
402 					&& !can_teleport(youmonst.data))) {
403 		/* Try to use teleport away spell. */
404 		if (objects[SPE_TELEPORT_AWAY].oc_name_known && !Confusion)
405 		    for (sp_no = 0; sp_no < MAXSPELL; sp_no++)
406 			if (spl_book[sp_no].sp_id == SPE_TELEPORT_AWAY) {
407 				castit = TRUE;
408 				break;
409 			}
410 #ifdef WIZARD
411 		if (!wizard) {
412 #endif
413 		    if (!castit) {
414 			if (!Teleportation)
415 			    You("don't know that spell.");
416 			else You("are not able to teleport at will.");
417 			return(0);
418 		    }
419 #ifdef WIZARD
420 		}
421 #endif
422 	    }
423 
424 	    if (u.uhunger <= 100 || ACURR(A_STR) < 6) {
425 #ifdef WIZARD
426 		if (!wizard) {
427 #endif
428 			You("lack the strength %s.",
429 			    castit ? "for a teleport spell" : "to teleport");
430 			return 1;
431 #ifdef WIZARD
432 		}
433 #endif
434 	    }
435 
436 	    energy = objects[SPE_TELEPORT_AWAY].oc_level * 7 / 2 - 2;
437 	    if (u.uen <= energy) {
438 #ifdef WIZARD
439 		if (wizard)
440 			energy = u.uen;
441 		else
442 #endif
443 		{
444 			You("lack the energy %s.",
445 			    castit ? "for a teleport spell" : "to teleport");
446 			return 1;
447 		}
448 	    }
449 
450 	    if (check_capacity(
451 			"Your concentration falters from carrying so much."))
452 		return 1;
453 
454 	    if (castit) {
455 		exercise(A_WIS, TRUE);
456 		if (spelleffects(sp_no, TRUE))
457 			return(1);
458 		else
459 #ifdef WIZARD
460 		    if (!wizard)
461 #endif
462 			return(0);
463 	    } else {
464 		u.uen -= energy;
465 		flags.botl = 1;
466 	    }
467 	}
468 
469 	if (next_to_u()) {
470 		if (trap && trap->once) vault_tele();
471 		else tele();
472 		(void) next_to_u();
473 	} else {
474 		You(shudder_for_moment);
475 		return(0);
476 	}
477 	if (!trap) morehungry(100);
478 	return(1);
479 }
480 
481 
482 void
level_tele()483 level_tele()
484 {
485 	register int newlev;
486 	d_level newlevel;
487 	const char *escape_by_flying = 0;	/* when surviving dest of -N */
488 
489 	if ((u.uhave.amulet || In_endgame(&u.uz) || In_sokoban(&u.uz))
490 #ifdef WIZARD
491 						&& !wizard
492 #endif
493 							) {
494 	    You_feel("very disoriented for a moment.");
495 	    return;
496 	}
497 	if (Teleport_control
498 #ifdef WIZARD
499 	   || wizard
500 #endif
501 		) {
502 	    char buf[BUFSZ], qbuf[BUFSZ];
503 	    int trycnt = 0;
504 
505 	    Strcpy(qbuf, "To what level do you want to teleport?");
506 	    do {
507 		if (++trycnt == 2) Strcat(qbuf, " [type a number]");
508 		getlin(qbuf, buf);
509 		if (!strcmp(buf,"\033"))	/* cancelled */
510 		    return;
511 		else if (!strcmp(buf,"*"))
512 		    goto random_levtport;
513 		if ((newlev = lev_by_name(buf)) == 0) newlev = atoi(buf);
514 	    } while (!newlev && !digit(buf[0]) &&
515 		     (buf[0] != '-' || !digit(buf[1])) &&
516 		     trycnt < 10);
517 
518 	    /* no dungeon escape via this route */
519 	    if (newlev == 0) {
520 		if (trycnt >= 10)
521 		    goto random_levtport;
522 		if (ynq("Go to Nowhere.  Are you sure?") != 'y') return;
523 		You("scream in agony as your body begins to warp...");
524 		display_nhwindow(WIN_MESSAGE, FALSE);
525 		You("cease to exist.");
526 		killer_format = NO_KILLER_PREFIX;
527 		killer = "committed suicide";
528 		done(DIED);
529 		return;
530 	    }
531 
532 	    /* if in Knox and the requested level > 0, stay put.
533 	     * we let negative values requests fall into the "heaven" loop.
534 	     */
535 	    if (Is_knox(&u.uz) && newlev > 0) {
536 		You(shudder_for_moment);
537 		return;
538 	    }
539 	    /* if in Quest, the player sees "Home 1", etc., on the status
540 	     * line, instead of the logical depth of the level.  controlled
541 	     * level teleport request is likely to be relativized to the
542 	     * status line, and consequently it should be incremented to
543 	     * the value of the logical depth of the target level.
544 	     *
545 	     * we let negative values requests fall into the "heaven" loop.
546 	     */
547 	    if (In_quest(&u.uz) && newlev > 0)
548 		newlev = newlev + dungeons[u.uz.dnum].depth_start - 1;
549 	} else { /* involuntary level tele */
550  random_levtport:
551 	    newlev = random_teleport_level();
552 	    if (newlev == depth(&u.uz)) {
553 		You(shudder_for_moment);
554 		return;
555 	    }
556 	}
557 
558 	if (!next_to_u()) {
559 		You(shudder_for_moment);
560 		return;
561 	}
562 #ifdef WIZARD
563 	if (In_endgame(&u.uz)) {	/* must already be wizard */
564 	    int llimit = dunlevs_in_dungeon(&u.uz);
565 
566 	    if (newlev >= 0 || newlev <= -llimit) {
567 		You_cant("get there from here.");
568 		return;
569 	    }
570 	    newlevel.dnum = u.uz.dnum;
571 	    newlevel.dlevel = llimit + newlev;
572 	    schedule_goto(&newlevel, FALSE, FALSE, 0, (char *)0, (char *)0);
573 	    return;
574 	}
575 #endif
576 
577 	killer = 0;		/* still alive, so far... */
578 
579 	if (newlev < 0) {
580 		if (newlev <= -10) {
581 			You("arrive in heaven.");
582 			verbalize("Thou art early, but we'll admit thee.");
583 			killer_format = NO_KILLER_PREFIX;
584 			killer = "went to heaven prematurely";
585 		} else if (newlev == -9) {
586 			You_feel("deliriously happy. ");
587 			pline("(In fact, you're on Cloud 9!) ");
588 			display_nhwindow(WIN_MESSAGE, FALSE);
589 		} else
590 			You("are now high above the clouds...");
591 
592 		if (killer) {
593 		    ;		/* arrival in heaven is pending */
594 		} else if (Levitation) {
595 		    escape_by_flying = "float gently down to earth";
596 		} else if (Flying) {
597 		    escape_by_flying = "fly down to the ground";
598 		} else {
599 		    pline("Unfortunately, you don't know how to fly.");
600 		    You("plummet a few thousand feet to your death.");
601 		    killer_format = NO_KILLER_PREFIX;
602 		    killer =
603     self_pronoun("teleported out of the dungeon and fell to %s death","his");
604 		}
605 	}
606 
607 	if (killer) {	/* the chosen destination was not survivable */
608 	    d_level lsav;
609 
610 	    /* set specific death location; this also suppresses bones */
611 	    lsav = u.uz;	/* save current level, see below */
612 	    u.uz.dnum = 0;	/* main dungeon */
613 	    u.uz.dlevel = (newlev <= -10) ? -10 : 0;	/* heaven or surface */
614 	    done(DIED);
615 	    /* can only get here via life-saving (or declining to die in
616 	       explore|debug mode); the hero has now left the dungeon... */
617 	    escape_by_flying = "find yourself back on the surface";
618 	    u.uz = lsav;	/* restore u.uz so escape code works */
619 	}
620 
621 	/* calls done(ESCAPED) if newlevel==0 */
622 	if (escape_by_flying) {
623 	    You("%s.", escape_by_flying);
624 	    newlevel.dnum = 0;		/* specify main dungeon */
625 	    newlevel.dlevel = 0;	/* escape the dungeon */
626 	    /* [dlevel used to be set to 1, but it doesn't make sense to
627 		teleport out of the dungeon and float or fly down to the
628 		surface but then actually arrive back inside the dungeon] */
629 	} else if (u.uz.dnum == medusa_level.dnum &&
630 	    newlev >= dungeons[u.uz.dnum].depth_start +
631 						dunlevs_in_dungeon(&u.uz)) {
632 	    find_hell(&newlevel);
633 	} else {
634 	    /* if invocation did not yet occur, teleporting into
635 	     * the last level of Gehennom is forbidden.
636 	     */
637 #ifdef WIZARD
638 		if (!wizard)
639 #endif
640 	    if (Inhell && !u.uevent.invoked &&
641 			newlev >= (dungeons[u.uz.dnum].depth_start +
642 					dunlevs_in_dungeon(&u.uz) - 1)) {
643 		newlev = dungeons[u.uz.dnum].depth_start +
644 					dunlevs_in_dungeon(&u.uz) - 2;
645 		pline("Sorry...");
646 	    }
647 	    /* no teleporting out of quest dungeon */
648 	    if (In_quest(&u.uz) && newlev < depth(&qstart_level))
649 		newlev = depth(&qstart_level);
650 	    /* the player thinks of levels purely in logical terms, so
651 	     * we must translate newlev to a number relative to the
652 	     * current dungeon.
653 	     */
654 	    get_level(&newlevel, newlev);
655 	}
656 	schedule_goto(&newlevel, FALSE, FALSE, 0, (char *)0, (char *)0);
657 	/* in case player just read a scroll and is about to be asked to
658 	   call it something, we can't defer until the end of the turn */
659 	if (u.utotype && !flags.mon_moving) deferred_goto();
660 }
661 
662 void
domagicportal(ttmp)663 domagicportal(ttmp)
664 register struct trap *ttmp;
665 {
666 	struct d_level target_level;
667 
668 	if (!next_to_u()) {
669 		You(shudder_for_moment);
670 		return;
671 	}
672 
673 	/* if landed from another portal, do nothing */
674 	/* problem: level teleport landing escapes the check */
675 	if (!on_level(&u.uz, &u.uz0)) return;
676 
677 	You("activated a magic portal!");
678 
679 	/* prevent the poor shnook, whose amulet was stolen while in
680 	 * the endgame, from accidently triggering the portal to the
681 	 * next level, and thus losing the game
682 	 */
683 	if (In_endgame(&u.uz) && !u.uhave.amulet) {
684 	    You_feel("dizzy for a moment, but nothing happens...");
685 	    return;
686 	}
687 
688 	target_level = ttmp->dst;
689 	schedule_goto(&target_level, FALSE, FALSE, 1,
690 		      "You feel dizzy for a moment, but the sensation passes.",
691 		      (char *)0);
692 }
693 
694 void
tele_trap(trap)695 tele_trap(trap)
696 struct trap *trap;
697 {
698 	if (In_endgame(&u.uz) || Antimagic) {
699 		if (Antimagic)
700 			shieldeff(u.ux, u.uy);
701 		You_feel("a wrenching sensation.");
702 	} else if (!next_to_u()) {
703 		You(shudder_for_moment);
704 	} else if (trap->once) {
705 		deltrap(trap);
706 		newsym(u.ux,u.uy);	/* get rid of trap symbol */
707 		vault_tele();
708 	} else
709 		tele();
710 }
711 
712 void
level_tele_trap(trap)713 level_tele_trap(trap)
714 struct trap *trap;
715 {
716 	You("%s onto a level teleport trap!",
717 		      Levitation ? (const char *)"float" :
718 				  locomotion(youmonst.data, "step"));
719 	if (Antimagic) {
720 	    shieldeff(u.ux, u.uy);
721 	}
722 	if (Antimagic || In_endgame(&u.uz)) {
723 	    You_feel("a wrenching sensation.");
724 	    return;
725 	}
726 	if (!Blind)
727 	    You("are momentarily blinded by a flash of light.");
728 	else
729 	    You("are momentarily disoriented.");
730 	deltrap(trap);
731 	newsym(u.ux,u.uy);	/* get rid of trap symbol */
732 	level_tele();
733 }
734 
735 /* check whether monster can arrive at location <x,y> via Tport (or fall) */
736 STATIC_OVL boolean
rloc_pos_ok(x,y,mtmp)737 rloc_pos_ok(x, y, mtmp)
738 register int x, y;		/* coordinates of candidate location */
739 struct monst *mtmp;
740 {
741 	register int xx, yy;
742 
743 	if (!goodpos(x, y, mtmp)) return FALSE;
744 	/*
745 	 * Check for restricted areas present in some special levels.
746 	 *
747 	 * `xx' is current column; if 0, then `yy' will contain flag bits
748 	 * rather than row:  bit #0 set => moving upwards; bit #1 set =>
749 	 * inside the Wizard's tower.
750 	 */
751 	xx = mtmp->mx;
752 	yy = mtmp->my;
753 	if (!xx) {
754 	    /* no current location (migrating monster arrival) */
755 	    if (dndest.nlx && On_W_tower_level(&u.uz))
756 		return ((yy & 2) != 0) ^	/* inside xor not within */
757 		       !within_bounded_area(x, y, dndest.nlx, dndest.nly,
758 						  dndest.nhx, dndest.nhy);
759 	    if (updest.lx && (yy & 1) != 0)	/* moving up */
760 		return (within_bounded_area(x, y, updest.lx, updest.ly,
761 						  updest.hx, updest.hy) &&
762 		       (!updest.nlx ||
763 			!within_bounded_area(x, y, updest.nlx, updest.nly,
764 						   updest.nhx, updest.nhy)));
765 	    if (dndest.lx && (yy & 1) == 0)	/* moving down */
766 		return (within_bounded_area(x, y, dndest.lx, dndest.ly,
767 						  dndest.hx, dndest.hy) &&
768 		       (!dndest.nlx ||
769 			!within_bounded_area(x, y, dndest.nlx, dndest.nly,
770 						   dndest.nhx, dndest.nhy)));
771 	} else {
772 	    /* current location is <xx,yy> */
773 	    if (!tele_jump_ok(xx, yy, x, y)) return FALSE;
774 	}
775 	/* <x,y> is ok */
776 	return TRUE;
777 }
778 
779 /*
780  * rloc_to()
781  *
782  * Pulls a monster from its current position and places a monster at
783  * a new x and y.  If oldx is 0, then the monster was not in the levels.monsters
784  * array.  However, if oldx is 0, oldy may still have a value because mtmp is a
785  * migrating_mon.  Worm tails are always placed randomly around the head of
786  * the worm.
787  */
788 void
rloc_to(mtmp,x,y)789 rloc_to(mtmp, x, y)
790 struct monst *mtmp;
791 register int x, y;
792 {
793 	register int oldx = mtmp->mx, oldy = mtmp->my;
794 
795 	if (x == mtmp->mx && y == mtmp->my)	/* that was easy */
796 		return;
797 
798 	if (oldx) {				/* "pick up" monster */
799 	    if (mtmp->wormno)
800 		remove_worm(mtmp);
801 	    else {
802 		remove_monster(oldx, oldy);
803 		newsym(oldx, oldy);		/* update old location */
804 	    }
805 	}
806 
807 	place_monster(mtmp, x, y);		/* put monster down */
808 	update_monster_region(mtmp);
809 
810 	if (mtmp->wormno)			/* now put down tail */
811 		place_worm_tail_randomly(mtmp, x, y);
812 
813 	if (u.ustuck == mtmp) {
814 		if (u.uswallow) {
815 			u.ux = x;
816 			u.uy = y;
817 			docrt();
818 		} else	u.ustuck = 0;
819 	}
820 
821 	newsym(x, y);				/* update new location */
822 	set_apparxy(mtmp);			/* orient monster */
823 }
824 
825 /* place a monster at a random location, typically due to teleport */
826 void
rloc(mtmp)827 rloc(mtmp)
828 struct monst *mtmp;	/* mx==0 implies migrating monster arrival */
829 {
830 	register int x, y, trycount;
831 	xchar omx = mtmp->mx, omy = mtmp->my;
832 
833 #ifdef STEED
834 	if (mtmp == u.usteed) {
835 	    tele();
836 	    return;
837 	}
838 #endif
839 
840 	if (mtmp->iswiz && omx) {	/* Wizard, not just arriving */
841 	    if (!In_W_tower(u.ux, u.uy, &u.uz))
842 		x = xupstair,  y = yupstair;
843 	    else if (!xdnladder)	/* bottom level of tower */
844 		x = xupladder,  y = yupladder;
845 	    else
846 		x = xdnladder,  y = ydnladder;
847 	    /* if the wiz teleports away to heal, try the up staircase,
848 	       to block the player's escaping before he's healed
849 	       (deliberately use `goodpos' rather than `rloc_pos_ok' here) */
850 	    if (goodpos(x, y, mtmp))
851 		goto found_xy;
852 	}
853 
854 	trycount = 0;
855 	do {
856 	    x = rn1(COLNO-3,2);
857 	    y = rn2(ROWNO);
858 	    if ((trycount < 500) ? rloc_pos_ok(x, y, mtmp)
859 				 : goodpos(x, y, mtmp))
860 		goto found_xy;
861 	} while (++trycount < 1000);
862 
863 	/* last ditch attempt to find a good place */
864 	for (x = 2; x < COLNO - 1; x++)
865 	    for (y = 0; y < ROWNO; y++)
866 		if (goodpos(x, y, mtmp))
867 		    goto found_xy;
868 
869 	/* level either full of monsters or somehow faulty */
870 	impossible("rloc(): couldn't relocate monster");
871 	return;
872 
873  found_xy:
874 	rloc_to(mtmp, x, y);
875 	/* shopkeepers will only teleport if you zap them with a wand of
876 	   teleportation or if they've been transformed into a jumpy monster;
877 	   the latter only happens if you've attacked them with polymorph */
878 	if (mtmp->isshk && !inhishop(mtmp)) make_angry_shk(mtmp, omx, omy);
879 }
880 
881 STATIC_OVL void
mvault_tele(mtmp)882 mvault_tele(mtmp)
883 struct monst *mtmp;
884 {
885 	register struct mkroom *croom = search_special(VAULT);
886 	coord c;
887 
888 	if (croom && somexy(croom, &c) &&
889 				goodpos(c.x, c.y, mtmp)) {
890 		rloc_to(mtmp, c.x, c.y);
891 		return;
892 	}
893 	rloc(mtmp);
894 }
895 
896 boolean
tele_restrict(mon)897 tele_restrict(mon)
898 struct monst *mon;
899 {
900 	if (level.flags.noteleport) {
901 		if (canseemon(mon))
902 		    pline("A mysterious force prevents %s from teleporting!",
903 			mon_nam(mon));
904 		return TRUE;
905 	}
906 	return FALSE;
907 }
908 
909 void
mtele_trap(mtmp,trap,in_sight)910 mtele_trap(mtmp, trap, in_sight)
911 struct monst *mtmp;
912 struct trap *trap;
913 int in_sight;
914 {
915 	char *monname;
916 
917 	if (tele_restrict(mtmp)) return;
918 	if (teleport_pet(mtmp, FALSE)) {
919 	    /* save name with pre-movement visibility */
920 	    monname = Monnam(mtmp);
921 
922 	    /* Note: don't remove the trap if a vault.  Other-
923 	     * wise the monster will be stuck there, since
924 	     * the guard isn't going to come for it...
925 	     */
926 	    if (trap->once) mvault_tele(mtmp);
927 	    else rloc(mtmp);
928 
929 	    if (in_sight) {
930 		if (canseemon(mtmp))
931 		    pline("%s seems disoriented.", monname);
932 		else
933 		    pline("%s suddenly disappears!", monname);
934 		seetrap(trap);
935 	    }
936 	}
937 }
938 
939 /* return 0 if still on level, 3 if not */
940 int
mlevel_tele_trap(mtmp,trap,force_it,in_sight)941 mlevel_tele_trap(mtmp, trap, force_it, in_sight)
942 struct monst *mtmp;
943 struct trap *trap;
944 boolean force_it;
945 int in_sight;
946 {
947 	int tt = trap->ttyp;
948 	struct permonst *mptr = mtmp->data;
949 
950 	if (mtmp == u.ustuck)	/* probably a vortex */
951 	    return 0;		/* temporary? kludge */
952 	if (teleport_pet(mtmp, force_it)) {
953 	    d_level tolevel;
954 	    int migrate_typ = MIGR_RANDOM;
955 
956 	    if ((tt == HOLE || tt == TRAPDOOR)) {
957 		if (Is_stronghold(&u.uz)) {
958 		    assign_level(&tolevel, &valley_level);
959 		} else if (Is_botlevel(&u.uz)) {
960 		    if (in_sight && trap->tseen)
961 			pline("%s avoids the %s.", Monnam(mtmp),
962 			(tt == HOLE) ? "hole" : "trap");
963 		    return 0;
964 		} else {
965 		    get_level(&tolevel, depth(&u.uz) + 1);
966 		}
967 	    } else if (tt == MAGIC_PORTAL) {
968 		if (In_endgame(&u.uz) &&
969 		    (mon_has_amulet(mtmp) || is_home_elemental(mptr))) {
970 		    if (in_sight && mptr->mlet != S_ELEMENTAL) {
971 			pline("%s seems to shimmer for a moment.",
972 							Monnam(mtmp));
973 			seetrap(trap);
974 		    }
975 		    return 0;
976 		} else {
977 		    assign_level(&tolevel, &trap->dst);
978 		    migrate_typ = MIGR_PORTAL;
979 		}
980 	    } else { /* (tt == LEVEL_TELEP) */
981 		int nlev;
982 
983 		if (mon_has_amulet(mtmp) || In_endgame(&u.uz)) {
984 		    if (in_sight)
985 			pline("%s seems very disoriented for a moment.",
986 				Monnam(mtmp));
987 		    return 0;
988 		}
989 		nlev = random_teleport_level();
990 		if (nlev == depth(&u.uz)) {
991 		    if (in_sight)
992 			pline("%s shudders for a moment.", Monnam(mtmp));
993 		    return 0;
994 		}
995 		get_level(&tolevel, nlev);
996 	    }
997 
998 	    if (in_sight) {
999 		pline("Suddenly, %s disappears out of sight.", mon_nam(mtmp));
1000 		seetrap(trap);
1001 	    }
1002 	    migrate_to_level(mtmp, ledger_no(&tolevel),
1003 			     migrate_typ, (coord *)0);
1004 	    return 3;	/* no longer on this level */
1005 	}
1006 	return 0;
1007 }
1008 
1009 
1010 void
rloco(obj)1011 rloco(obj)
1012 register struct obj *obj;
1013 {
1014 	register xchar tx, ty, otx, oty;
1015 	boolean restricted_fall;
1016 	int try_limit = 4000;
1017 
1018 	if (obj->otyp == CORPSE && is_rider(&mons[obj->corpsenm])) {
1019 	    if (revive_corpse(obj)) return;
1020 	}
1021 
1022 	obj_extract_self(obj);
1023 	otx = obj->ox;
1024 	oty = obj->oy;
1025 	restricted_fall = (otx == 0 && dndest.lx);
1026 	do {
1027 	    tx = rn1(COLNO-3,2);
1028 	    ty = rn2(ROWNO);
1029 	    if (!--try_limit) break;
1030 	} while (!goodpos(tx, ty, (struct monst *)0) ||
1031 		/* bug: this lacks provision for handling the Wizard's tower */
1032 		 (restricted_fall &&
1033 		  (!within_bounded_area(tx, ty, dndest.lx, dndest.ly,
1034 						dndest.hx, dndest.hy) ||
1035 		   (dndest.nlx &&
1036 		    within_bounded_area(tx, ty, dndest.nlx, dndest.nly,
1037 						dndest.nhx, dndest.nhy)))));
1038 
1039 	if (flooreffects(obj, tx, ty, "fall")) {
1040 	    return;
1041 	} else if (otx == 0 && oty == 0) {
1042 	    ;	/* fell through a trap door; no update of old loc needed */
1043 	} else {
1044 	    if (costly_spot(otx, oty)
1045 	      && (!costly_spot(tx, ty) ||
1046 		  !index(in_rooms(tx, ty, 0), *in_rooms(otx, oty, 0)))) {
1047 		if (costly_spot(u.ux, u.uy) &&
1048 			    index(u.urooms, *in_rooms(otx, oty, 0)))
1049 		    addtobill(obj, FALSE, FALSE, FALSE);
1050 		else (void)stolen_value(obj, otx, oty, FALSE, FALSE);
1051 	    }
1052 	    newsym(otx, oty);	/* update old location */
1053 	}
1054 	place_object(obj, tx, ty);
1055 	newsym(tx, ty);
1056 }
1057 
1058 /* Returns an absolute depth */
1059 int
random_teleport_level()1060 random_teleport_level()
1061 {
1062 	int nlev, max_depth, min_depth;
1063 
1064 	if (!rn2(5) || Is_knox(&u.uz))
1065 		return (int)depth(&u.uz);
1066 
1067 	/* Get a random value relative to the current dungeon */
1068 	/* Range is 1 to current+3, current not counting */
1069 	nlev = rnd((int)depth(&u.uz) + 2);
1070 	if (nlev >= (int)depth(&u.uz)) nlev++;
1071 
1072 	/* What I really want to do is as follows:
1073 	 * -- If in a dungeon that goes down, the new level is to be restricted
1074 	 *    to [top of parent, bottom of current dungeon]
1075 	 * -- If in a dungeon that goes up, the new level is to be restricted
1076 	 *    to [top of current dungeon, bottom of parent]
1077 	 * -- If in a quest dungeon or similar dungeon entered by portals,
1078 	 *    the new level is to be restricted to [top of current dungeon,
1079 	 *    bottom of current dungeon]
1080 	 * The current behavior is not as sophisticated as that ideal, but is
1081 	 * still better what we used to do, which was like this for players
1082 	 * but different for monsters for no obvious reason.  Currently, we
1083 	 * must explicitly check for special dungeons.  We check for Knox
1084 	 * above; endgame is handled in the caller due to its different
1085 	 * message ("disoriented").
1086 	 * --KAA
1087 	 */
1088 	min_depth = 1;
1089 	max_depth = dunlevs_in_dungeon(&u.uz) +
1090 			(dungeons[u.uz.dnum].depth_start - 1);
1091 
1092 	if (nlev > max_depth) {
1093 	    nlev = max_depth;
1094 	    /* teleport up if already on bottom */
1095 	    if (Is_botlevel(&u.uz)) nlev -= rnd(3);
1096 	}
1097 	if (nlev < min_depth) {
1098 	    nlev = min_depth;
1099 	    if ((int)depth(&u.uz) == min_depth) {
1100 		nlev += rnd(3);
1101 		if (nlev > max_depth)
1102 		    nlev = max_depth;
1103 	    }
1104 	}
1105 	return nlev;
1106 }
1107 
1108 /* you teleport a monster (via wand, spell, or poly'd q.mechanic attack);
1109    return false iff the attempt fails */
1110 boolean
u_teleport_mon(mtmp,give_feedback)1111 u_teleport_mon(mtmp, give_feedback)
1112 struct monst *mtmp;
1113 boolean give_feedback;
1114 {
1115 	coord cc;
1116 
1117 	if (mtmp->ispriest && *in_rooms(mtmp->mx, mtmp->my, TEMPLE)) {
1118 	    if (give_feedback)
1119 		pline("%s resists your magic!", Monnam(mtmp));
1120 	    return FALSE;
1121 	} else {
1122 	    if (is_rider(mtmp->data) && rn2(13) &&
1123 		    enexto(&cc, u.ux, u.uy, mtmp->data))
1124 		rloc_to(mtmp, cc.x, cc.y);
1125 	    else
1126 		rloc(mtmp);
1127 	    return TRUE;
1128 	}
1129 }
1130 
1131 /*teleport.c*/
1132