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. */
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,gpflags)21 goodpos(x, y, mtmp, gpflags)
22 int x,y;
23 struct monst *mtmp;
24 unsigned gpflags;
25 {
26 struct permonst *mdat = NULL;
27 boolean ignorewater = ((gpflags & MM_IGNOREWATER) != 0);
28
29 if (!isok(x, y)) return FALSE;
30
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.
35 * oh well.
36 */
37 if (mtmp != &youmonst && x == u.ux && y == u.uy
38 #ifdef STEED
39 && (!u.usteed || mtmp != u.usteed)
40 #endif
41 )
42 return FALSE;
43
44 if (mtmp) {
45 struct monst *mtmp2 = m_at(x,y);
46
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.
56 */
57 if (mtmp2 && (mtmp2 != mtmp || mtmp->wormno))
58 return FALSE;
59
60 mdat = mtmp->data;
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) ||
66 is_clinger(mdat));
67 } else if (mdat->mlet == S_EEL && rn2(13) && !ignorewater) {
68 return FALSE;
69 } else if (is_lava(x,y)) {
70 if (mtmp == &youmonst)
71 return !!HLevitation;
72 else
73 return (is_flyer(mdat) || likes_lava(mdat));
74 }
75 if (passes_walls(mdat) && may_passwall(x,y)) return TRUE;
76 }
77 if (!ACCESSIBLE(levl[x][y].typ)) {
78 if (!(is_pool(x,y) && ignorewater)) return FALSE;
79 }
80
81 if (closed_door(x, y) && (!mdat || !amorphous(mdat)))
82 return FALSE;
83 if (sobj_at(BOULDER, x, y) && (!mdat || !throws_rocks(mdat)))
84 return FALSE;
85 return TRUE;
86 }
87
88 /*
89 * "entity next to"
90 *
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.
95 */
96 boolean
enexto(cc,xx,yy,mdat)97 enexto(cc, xx, yy, mdat)
98 coord *cc;
99 register xchar xx, yy;
100 struct permonst *mdat;
101 {
102 return enexto_core(cc, xx, yy, mdat, 0);
103 }
104
105 boolean
enexto_core(cc,xx,yy,mdat,entflags)106 enexto_core(cc, xx, yy, mdat, entflags)
107 coord *cc;
108 register xchar xx, yy;
109 struct permonst *mdat;
110 unsigned entflags;
111 {
112 #define MAX_GOOD 15
113 coord good[MAX_GOOD], *good_ptr;
114 int x, y, range, i;
115 int xmin, xmax, ymin, ymax;
116 struct monst fakemon; /* dummy monster */
117
118 if (!mdat) {
119 #ifdef DEBUG
120 pline("enexto() called with mdat==0");
121 #endif
122 /* default to player's original monster type */
123 mdat = &mons[u.umonster];
124 }
125 fakemon.data = mdat; /* set up for goodpos */
126 good_ptr = good;
127 range = 1;
128 /*
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.
131 */
132 do {
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);
137
138 for (x = xmin; x <= xmax; x++)
139 if (goodpos(x, ymin, &fakemon, entflags)) {
140 good_ptr->x = x;
141 good_ptr->y = ymin ;
142 /* beware of accessing beyond segment boundaries.. */
143 if (good_ptr++ == &good[MAX_GOOD-1]) goto full;
144 }
145 for (x = xmin; x <= xmax; x++)
146 if (goodpos(x, ymax, &fakemon, entflags)) {
147 good_ptr->x = x;
148 good_ptr->y = ymax ;
149 /* beware of accessing beyond segment boundaries.. */
150 if (good_ptr++ == &good[MAX_GOOD-1]) goto full;
151 }
152 for (y = ymin+1; y < ymax; y++)
153 if (goodpos(xmin, y, &fakemon, entflags)) {
154 good_ptr->x = xmin;
155 good_ptr-> y = y ;
156 /* beware of accessing beyond segment boundaries.. */
157 if (good_ptr++ == &good[MAX_GOOD-1]) goto full;
158 }
159 for (y = ymin+1; y < ymax; y++)
160 if (goodpos(xmax, y, &fakemon, entflags)) {
161 good_ptr->x = xmax;
162 good_ptr->y = y ;
163 /* beware of accessing beyond segment boundaries.. */
164 if (good_ptr++ == &good[MAX_GOOD-1]) goto full;
165 }
166 range++;
167
168 /* return if we've grown too big (nothing is valid) */
169 if (range > ROWNO && range > COLNO) return FALSE;
170 } while (good_ptr == good);
171
172 full:
173 i = rn2((int)(good_ptr - good));
174 cc->x = good[i].x;
175 cc->y = good[i].y;
176 return TRUE;
177 }
178
179 /*
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.)
183 */
184 STATIC_OVL boolean
tele_jump_ok(x1,y1,x2,y2)185 tele_jump_ok(x1, y1, x2, y2)
186 int x1, y1, x2, y2;
187 {
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))
194 return FALSE;
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))
200 return FALSE;
201 }
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))
207 return FALSE;
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))
212 return FALSE;
213 }
214 return TRUE;
215 }
216
217 STATIC_OVL boolean
teleok(x,y,trapok)218 teleok(x, y, trapok)
219 register int x, y;
220 boolean trapok;
221 {
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;
226 return TRUE;
227 }
228
229 void
teleds(nux,nuy,allow_drag)230 teleds(nux, nuy, allow_drag)
231 register int nux,nuy;
232 boolean allow_drag;
233 {
234 boolean ball_active = (Punished && uball->where != OBJ_FREE),
235 ball_still_in_range = FALSE;
236
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
242 * special cases:
243 * 0 0
244 * _X move east -----> X_
245 * @ @
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.
251 */
252 if (ball_active) {
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 */
255 else {
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.
260 */
261 allow_drag = FALSE;
262 unplacebc();
263 }
264 }
265 }
266 u.utrap = 0;
267 u.ustuck = 0;
268 u.ux0 = u.ux;
269 u.uy0 = u.uy;
270
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);
275 else {
276 u.uundetected = 0;
277 /* mimics stop being unnoticed */
278 if (youmonst.data->mlet == S_MIMIC)
279 youmonst.m_ap_type = M_AP_NOTHING;
280 }
281
282 if (u.uswallow) {
283 u.uswldtim = u.uswallow = 0;
284 if (Punished && !ball_active) {
285 /* ensure ball placement, like unstuck */
286 ball_active = TRUE;
287 allow_drag = FALSE;
288 }
289 docrt();
290 }
291 if (ball_active) {
292 if (ball_still_in_range || allow_drag) {
293 int bc_control;
294 xchar ballx, bally, chainx, chainy;
295 boolean cause_delay;
296
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);
300 }
301 }
302 /* must set u.ux, u.uy after drag_ball(), which may need to know
303 the old position if allow_drag is true... */
304 u.ux = nux;
305 u.uy = nuy;
306 fill_pit(u.ux0, u.uy0);
307 if (ball_active) {
308 if (!ball_still_in_range && !allow_drag)
309 placebc();
310 }
311 initrack(); /* teleports mess up tracking monsters without this */
312 update_player_regions();
313 #ifdef STEED
314 /* Move your steed, too */
315 if (u.usteed) {
316 u.usteed->mx = nux;
317 u.usteed->my = nuy;
318 }
319 #endif
320 /*
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.
325 */
326 newsym(u.ux0,u.uy0);
327 see_monsters();
328 vision_full_recalc = 1;
329 nomul(0);
330 vision_recalc(0); /* vision before effects */
331 spoteffects(TRUE);
332 invocation_message();
333 }
334
335 boolean
safe_teleds(allow_drag)336 safe_teleds(allow_drag)
337 boolean allow_drag;
338 {
339 register int nux, nuy, tcnt = 0;
340
341 do {
342 nux = rnd(COLNO-1);
343 nuy = rn2(ROWNO);
344 } while (!teleok(nux, nuy, (boolean)(tcnt > 200)) && ++tcnt <= 400);
345
346 if (tcnt <= 400) {
347 teleds(nux, nuy, allow_drag);
348 return TRUE;
349 } else
350 return FALSE;
351 }
352
353 STATIC_OVL void
vault_tele()354 vault_tele()
355 {
356 register struct mkroom *croom = search_special(VAULT);
357 coord c;
358
359 if (croom && somexy(croom, &c) && teleok(c.x,c.y,FALSE)) {
360 teleds(c.x,c.y,FALSE);
361 return;
362 }
363 tele();
364 }
365
366 boolean
teleport_pet(mtmp,force_it)367 teleport_pet(mtmp, force_it)
368 register struct monst *mtmp;
369 boolean force_it;
370 {
371 register struct obj *otmp;
372
373 #ifdef STEED
374 if (mtmp == u.usteed)
375 return (FALSE);
376 #endif
377
378 if (mtmp->mleashed) {
379 otmp = get_mleash(mtmp);
380 if (!otmp) {
381 impossible("%s is leashed, without a leash.", Monnam(mtmp));
382 goto release_it;
383 }
384 if (otmp->cursed && !force_it) {
385 yelp(mtmp);
386 return FALSE;
387 } else {
388 Your("leash goes slack.");
389 release_it:
390 m_unleash(mtmp, FALSE);
391 return TRUE;
392 }
393 }
394 return TRUE;
395 }
396
397 void
tele()398 tele()
399 {
400 coord cc;
401
402 /* Disable teleportation in stronghold && Vlad's Tower */
403 if (level.flags.noteleport) {
404 #ifdef WIZARD
405 if (!wizard) {
406 #endif
407 pline("A mysterious force prevents you from teleporting!");
408 return;
409 #ifdef WIZARD
410 }
411 #endif
412 }
413
414 /* don't show trap if "Sorry..." */
415 if (!Blinded) make_blinded(0L,FALSE);
416
417 if ((u.uhave.amulet || On_W_tower_level(&u.uz)) && !rn2(3)) {
418 You_feel("disoriented for a moment.");
419 return;
420 }
421 if ((Teleport_control && !Stunned)
422 #ifdef WIZARD
423 || wizard
424 #endif
425 ) {
426 if (unconscious()) {
427 pline("Being unconscious, you cannot control your teleport.");
428 } else {
429 #ifdef STEED
430 char buf[BUFSZ];
431 if (u.usteed) Sprintf(buf," and %s", mon_nam(u.usteed));
432 #endif
433 pline("To what position do you%s want to be teleported?",
434 #ifdef STEED
435 u.usteed ? buf :
436 #endif
437 "");
438 cc.x = u.ux;
439 cc.y = u.uy;
440 if (getpos(&cc, TRUE, "the desired position") < 0)
441 return; /* abort */
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);
446 return;
447 }
448 pline("Sorry...");
449 }
450 }
451
452 (void) safe_teleds(FALSE);
453 }
454
455 int
dotele()456 dotele()
457 {
458 struct trap *trap;
459
460 trap = t_at(u.ux, u.uy);
461 if (trap && (!trap->tseen || trap->ttyp != TELEP_TRAP))
462 trap = 0;
463
464 if (trap) {
465 if (trap->once) {
466 pline("This is a vault teleport, usable once only.");
467 if (yn("Jump in?") == 'n')
468 trap = 0;
469 else {
470 deltrap(trap);
471 newsym(u.ux, u.uy);
472 }
473 }
474 if (trap)
475 You("%s onto the teleportation trap.",
476 locomotion(youmonst.data, "jump"));
477 }
478 if (!trap) {
479 boolean castit = FALSE;
480 register int sp_no = 0, energy = 0;
481
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) {
488 castit = TRUE;
489 break;
490 }
491 #ifdef WIZARD
492 if (!wizard) {
493 #endif
494 if (!castit) {
495 if (!Teleportation)
496 You("don't know that spell.");
497 else You("are not able to teleport at will.");
498 return(0);
499 }
500 #ifdef WIZARD
501 }
502 #endif
503 }
504
505 if (u.uhunger <= 100 || ACURR(A_STR) < 6) {
506 #ifdef WIZARD
507 if (!wizard) {
508 #endif
509 You("lack the strength %s.",
510 castit ? "for a teleport spell" : "to teleport");
511 return 1;
512 #ifdef WIZARD
513 }
514 #endif
515 }
516
517 energy = objects[SPE_TELEPORT_AWAY].oc_level * 7 / 2 - 2;
518 if (u.uen <= energy) {
519 #ifdef WIZARD
520 if (wizard)
521 energy = u.uen;
522 else
523 #endif
524 {
525 You("lack the energy %s.",
526 castit ? "for a teleport spell" : "to teleport");
527 return 1;
528 }
529 }
530
531 if (check_capacity(
532 "Your concentration falters from carrying so much."))
533 return 1;
534
535 if (castit) {
536 exercise(A_WIS, TRUE);
537 if (spelleffects(sp_no, TRUE))
538 return(1);
539 else
540 #ifdef WIZARD
541 if (!wizard)
542 #endif
543 return(0);
544 } else {
545 u.uen -= energy;
546 flags.botl = 1;
547 }
548 }
549
550 if (next_to_u()) {
551 if (trap && trap->once) vault_tele();
552 else tele();
553 (void) next_to_u();
554 } else {
555 You(shudder_for_moment);
556 return(0);
557 }
558 if (!trap) morehungry(100);
559 return(1);
560 }
561
562
563 void
level_tele()564 level_tele()
565 {
566 register int newlev;
567 d_level newlevel;
568 const char *escape_by_flying = 0; /* when surviving dest of -N */
569 char buf[BUFSZ];
570 boolean force_dest = FALSE;
571
572 if ((u.uhave.amulet || In_endgame(&u.uz) || In_sokoban(&u.uz))
573 #ifdef WIZARD
574 && !wizard
575 #endif
576 ) {
577 You_feel("very disoriented for a moment.");
578 return;
579 }
580 if ((Teleport_control && !Stunned)
581 #ifdef WIZARD
582 || wizard
583 #endif
584 ) {
585 char qbuf[BUFSZ];
586 int trycnt = 0;
587
588 Strcpy(qbuf, "To what level do you want to teleport?");
589 do {
590 if (++trycnt == 2) {
591 #ifdef WIZARD
592 if (wizard) Strcat(qbuf, " [type a number or ? for a menu]");
593 else
594 #endif
595 Strcat(qbuf, " [type a number]");
596 }
597 getlin(qbuf, buf);
598 if (!strcmp(buf,"\033")) { /* cancelled */
599 if (Confusion && rnl(5)) {
600 pline("Oops...");
601 goto random_levtport;
602 }
603 return;
604 } else if (!strcmp(buf,"*")) {
605 goto random_levtport;
606 } else if (Confusion && rnl(5)) {
607 pline("Oops...");
608 goto random_levtport;
609 }
610 #ifdef WIZARD
611 if (wizard && !strcmp(buf,"?")) {
612 schar destlev = 0;
613 xchar destdnum = 0;
614
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)) {
619 Sprintf(buf,
620 "Destination is earth level");
621 if (!u.uhave.amulet) {
622 struct obj *obj;
623 obj = mksobj(AMULET_OF_YENDOR,
624 TRUE, FALSE);
625 if (obj) {
626 obj = addinv(obj);
627 Strcat(buf, " with the amulet");
628 }
629 }
630 assign_level(&newlevel, &earth_level);
631 pline("%s.", buf);
632 }
633 force_dest = TRUE;
634 } else return;
635 } else
636 #endif
637 if ((newlev = lev_by_name(buf)) == 0) newlev = atoi(buf);
638 } while (!newlev && !digit(buf[0]) &&
639 (buf[0] != '-' || !digit(buf[1])) &&
640 trycnt < 10);
641
642 /* no dungeon escape via this route */
643 if (newlev == 0) {
644 if (trycnt >= 10)
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";
655 done(DIED);
656 pline("An energized cloud of dust begins to coalesce.");
657 Your("body rematerializes%s.", invent ?
658 ", and you gather up all your possessions" : "");
659 return;
660 }
661
662 /* if in Knox and the requested level > 0, stay put.
663 * we let negative values requests fall into the "heaven" loop.
664 */
665 if (Is_knox(&u.uz) && newlev > 0) {
666 You(shudder_for_moment);
667 return;
668 }
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.
674 *
675 * we let negative values requests fall into the "heaven" loop.
676 */
677 if (In_quest(&u.uz) && newlev > 0)
678 newlev = newlev + dungeons[u.uz.dnum].depth_start - 1;
679 } else { /* involuntary level tele */
680 random_levtport:
681 newlev = random_teleport_level();
682 if (newlev == depth(&u.uz)) {
683 You(shudder_for_moment);
684 return;
685 }
686 }
687
688 if (!next_to_u()) {
689 You(shudder_for_moment);
690 return;
691 }
692 #ifdef WIZARD
693 if (In_endgame(&u.uz)) { /* must already be wizard */
694 int llimit = dunlevs_in_dungeon(&u.uz);
695
696 if (newlev >= 0 || newlev <= -llimit) {
697 You_cant("get there from here.");
698 return;
699 }
700 newlevel.dnum = u.uz.dnum;
701 newlevel.dlevel = llimit + newlev;
702 schedule_goto(&newlevel, FALSE, FALSE, 0, (char *)0, (char *)0);
703 return;
704 }
705 #endif
706
707 killer = 0; /* still alive, so far... */
708
709 if (newlev < 0 && !force_dest) {
710 if (*u.ushops0) {
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';
716 in_mklev = FALSE;
717 }
718 if (newlev <= -10) {
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);
727 } else
728 You("are now high above the clouds...");
729
730 if (killer) {
731 ; /* arrival in heaven is pending */
732 } else if (Levitation) {
733 escape_by_flying = "float gently down to earth";
734 } else if (Flying) {
735 escape_by_flying = "fly down to the ground";
736 } else {
737 pline("Unfortunately, you don't know how to fly.");
738 You("plummet a few thousand feet to your death.");
739 Sprintf(buf,
740 "teleported out of the dungeon and fell to %s death",
741 uhis());
742 killer = buf;
743 killer_format = NO_KILLER_PREFIX;
744 }
745 }
746
747 if (killer) { /* the chosen destination was not survivable */
748 d_level lsav;
749
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 */
754 done(DIED);
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 */
759 }
760
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)) {
772 #ifdef WIZARD
773 if (!(wizard && force_dest))
774 #endif
775 find_hell(&newlevel);
776 } else {
777 /* if invocation did not yet occur, teleporting into
778 * the last level of Gehennom is forbidden.
779 */
780 #ifdef WIZARD
781 if (!wizard)
782 #endif
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;
788 pline("Sorry...");
789 }
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
795 * current dungeon.
796 */
797 #ifdef WIZARD
798 if (!(wizard && force_dest))
799 #endif
800 get_level(&newlevel, newlev);
801 }
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();
806 }
807
808 void
domagicportal(ttmp)809 domagicportal(ttmp)
810 register struct trap *ttmp;
811 {
812 struct d_level target_level;
813
814 if (!next_to_u()) {
815 You(shudder_for_moment);
816 return;
817 }
818
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;
822
823 You("activated a magic portal!");
824
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
828 */
829 if (In_endgame(&u.uz) && !u.uhave.amulet) {
830 You_feel("dizzy for a moment, but nothing happens...");
831 return;
832 }
833
834 target_level = ttmp->dst;
835 schedule_goto(&target_level, FALSE, FALSE, 1,
836 "You feel dizzy for a moment, but the sensation passes.",
837 (char *)0);
838 }
839
840 void
tele_trap(trap)841 tele_trap(trap)
842 struct trap *trap;
843 {
844 if (In_endgame(&u.uz) || Antimagic) {
845 if (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) {
851 deltrap(trap);
852 newsym(u.ux,u.uy); /* get rid of trap symbol */
853 vault_tele();
854 } else
855 tele();
856 }
857
858 void
level_tele_trap(trap)859 level_tele_trap(trap)
860 struct trap *trap;
861 {
862 You("%s onto a level teleport trap!",
863 Levitation ? (const char *)"float" :
864 locomotion(youmonst.data, "step"));
865 if (Antimagic) {
866 shieldeff(u.ux, u.uy);
867 }
868 if (Antimagic || In_endgame(&u.uz)) {
869 You_feel("a wrenching sensation.");
870 return;
871 }
872 if (!Blind)
873 You("are momentarily blinded by a flash of light.");
874 else
875 You("are momentarily disoriented.");
876 deltrap(trap);
877 newsym(u.ux,u.uy); /* get rid of trap symbol */
878 level_tele();
879 }
880
881 /* check whether monster can arrive at location <x,y> via Tport (or fall) */
882 STATIC_OVL boolean
rloc_pos_ok(x,y,mtmp)883 rloc_pos_ok(x, y, mtmp)
884 register int x, y; /* coordinates of candidate location */
885 struct monst *mtmp;
886 {
887 register int xx, yy;
888
889 if (!goodpos(x, y, mtmp, 0)) return FALSE;
890 /*
891 * Check for restricted areas present in some special levels.
892 *
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.
896 */
897 xx = mtmp->mx;
898 yy = mtmp->my;
899 if (!xx) {
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) &&
908 (!updest.nlx ||
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) &&
914 (!dndest.nlx ||
915 !within_bounded_area(x, y, dndest.nlx, dndest.nly,
916 dndest.nhx, dndest.nhy)));
917 } else {
918 /* current location is <xx,yy> */
919 if (!tele_jump_ok(xx, yy, x, y)) return FALSE;
920 }
921 /* <x,y> is ok */
922 return TRUE;
923 }
924
925 /*
926 * rloc_to()
927 *
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
932 * the worm.
933 */
934 void
rloc_to(mtmp,x,y)935 rloc_to(mtmp, x, y)
936 struct monst *mtmp;
937 register int x, y;
938 {
939 register int oldx = mtmp->mx, oldy = mtmp->my;
940 boolean resident_shk = mtmp->isshk && inhishop(mtmp);
941
942 if (x == mtmp->mx && y == mtmp->my) /* that was easy */
943 return;
944
945 if (oldx) { /* "pick up" monster */
946 if (mtmp->wormno)
947 remove_worm(mtmp);
948 else {
949 remove_monster(oldx, oldy);
950 newsym(oldx, oldy); /* update old location */
951 }
952 }
953
954 place_monster(mtmp, x, y); /* put monster down */
955 update_monster_region(mtmp);
956
957 if (mtmp->wormno) /* now put down tail */
958 place_worm_tail_randomly(mtmp, x, y);
959
960 if (u.ustuck == mtmp) {
961 if (u.uswallow) {
962 u.ux = x;
963 u.uy = y;
964 docrt();
965 } else u.ustuck = 0;
966 }
967
968 newsym(x, y); /* update new location */
969 set_apparxy(mtmp); /* orient monster */
970
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);
975 }
976
977 /* place a monster at a random location, typically due to teleport */
978 /* return TRUE if successful, FALSE if not */
979 boolean
rloc(mtmp,suppress_impossible)980 rloc(mtmp, suppress_impossible)
981 struct monst *mtmp; /* mx==0 implies migrating monster arrival */
982 boolean suppress_impossible;
983 {
984 register int x, y, trycount;
985
986 #ifdef STEED
987 if (mtmp == u.usteed) {
988 tele();
989 return TRUE;
990 }
991 #endif
992
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;
998 else
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))
1004 goto found_xy;
1005 }
1006
1007 trycount = 0;
1008 do {
1009 x = rn1(COLNO-3,2);
1010 y = rn2(ROWNO);
1011 if ((trycount < 500) ? rloc_pos_ok(x, y, mtmp)
1012 : goodpos(x, y, mtmp, 0))
1013 goto found_xy;
1014 } while (++trycount < 1000);
1015
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))
1020 goto found_xy;
1021
1022 /* level either full of monsters or somehow faulty */
1023 if (!suppress_impossible)
1024 impossible("rloc(): couldn't relocate monster");
1025 return FALSE;
1026
1027 found_xy:
1028 rloc_to(mtmp, x, y);
1029 return TRUE;
1030 }
1031
1032 STATIC_OVL void
mvault_tele(mtmp)1033 mvault_tele(mtmp)
1034 struct monst *mtmp;
1035 {
1036 register struct mkroom *croom = search_special(VAULT);
1037 coord c;
1038
1039 if (croom && somexy(croom, &c) &&
1040 goodpos(c.x, c.y, mtmp, 0)) {
1041 rloc_to(mtmp, c.x, c.y);
1042 return;
1043 }
1044 (void) rloc(mtmp, FALSE);
1045 }
1046
1047 boolean
tele_restrict(mon)1048 tele_restrict(mon)
1049 struct monst *mon;
1050 {
1051 if (level.flags.noteleport) {
1052 if (canseemon(mon))
1053 pline("A mysterious force prevents %s from teleporting!",
1054 mon_nam(mon));
1055 return TRUE;
1056 }
1057 return FALSE;
1058 }
1059
1060 void
mtele_trap(mtmp,trap,in_sight)1061 mtele_trap(mtmp, trap, in_sight)
1062 struct monst *mtmp;
1063 struct trap *trap;
1064 int in_sight;
1065 {
1066 char *monname;
1067
1068 if (tele_restrict(mtmp)) return;
1069 if (teleport_pet(mtmp, FALSE)) {
1070 /* save name with pre-movement visibility */
1071 monname = Monnam(mtmp);
1072
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...
1076 */
1077 if (trap->once) mvault_tele(mtmp);
1078 else (void) rloc(mtmp, FALSE);
1079
1080 if (in_sight) {
1081 if (canseemon(mtmp))
1082 pline("%s seems disoriented.", monname);
1083 else
1084 pline("%s suddenly disappears!", monname);
1085 seetrap(trap);
1086 }
1087 }
1088 }
1089
1090 /* return 0 if still on level, 3 if not */
1091 int
mlevel_tele_trap(mtmp,trap,force_it,in_sight)1092 mlevel_tele_trap(mtmp, trap, force_it, in_sight)
1093 struct monst *mtmp;
1094 struct trap *trap;
1095 boolean force_it;
1096 int in_sight;
1097 {
1098 int tt = trap->ttyp;
1099 struct permonst *mptr = mtmp->data;
1100
1101 if (mtmp == u.ustuck) /* probably a vortex */
1102 return 0; /* temporary? kludge */
1103 if (teleport_pet(mtmp, force_it)) {
1104 d_level tolevel;
1105 int migrate_typ = MIGR_RANDOM;
1106
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");
1114 return 0;
1115 } else {
1116 get_level(&tolevel, depth(&u.uz) + 1);
1117 }
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.",
1123 Monnam(mtmp));
1124 seetrap(trap);
1125 }
1126 return 0;
1127 } else {
1128 assign_level(&tolevel, &trap->dst);
1129 migrate_typ = MIGR_PORTAL;
1130 }
1131 } else { /* (tt == LEVEL_TELEP) */
1132 int nlev;
1133
1134 if (mon_has_amulet(mtmp) || In_endgame(&u.uz)) {
1135 if (in_sight)
1136 pline("%s seems very disoriented for a moment.",
1137 Monnam(mtmp));
1138 return 0;
1139 }
1140 nlev = random_teleport_level();
1141 if (nlev == depth(&u.uz)) {
1142 if (in_sight)
1143 pline("%s shudders for a moment.", Monnam(mtmp));
1144 return 0;
1145 }
1146 get_level(&tolevel, nlev);
1147 }
1148
1149 if (in_sight) {
1150 pline("Suddenly, %s disappears out of sight.", mon_nam(mtmp));
1151 seetrap(trap);
1152 }
1153 migrate_to_level(mtmp, ledger_no(&tolevel),
1154 migrate_typ, (coord *)0);
1155 return 3; /* no longer on this level */
1156 }
1157 return 0;
1158 }
1159
1160
1161 void
rloco(obj)1162 rloco(obj)
1163 register struct obj *obj;
1164 {
1165 register xchar tx, ty, otx, oty;
1166 boolean restricted_fall;
1167 int try_limit = 4000;
1168
1169 if (obj->otyp == CORPSE && is_rider(&mons[obj->corpsenm])) {
1170 if (revive_corpse(obj)) return;
1171 }
1172
1173 obj_extract_self(obj);
1174 otx = obj->ox;
1175 oty = obj->oy;
1176 restricted_fall = (otx == 0 && dndest.lx);
1177 do {
1178 tx = rn1(COLNO-3,2);
1179 ty = rn2(ROWNO);
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 */
1183 (restricted_fall &&
1184 (!within_bounded_area(tx, ty, dndest.lx, dndest.ly,
1185 dndest.hx, dndest.hy) ||
1186 (dndest.nlx &&
1187 within_bounded_area(tx, ty, dndest.nlx, dndest.nly,
1188 dndest.nhx, dndest.nhy)))));
1189
1190 if (flooreffects(obj, tx, ty, "fall")) {
1191 return;
1192 } else if (otx == 0 && oty == 0) {
1193 ; /* fell through a trap door; no update of old loc needed */
1194 } else {
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);
1202 }
1203 newsym(otx, oty); /* update old location */
1204 }
1205 place_object(obj, tx, ty);
1206 newsym(tx, ty);
1207 }
1208
1209 /* Returns an absolute depth */
1210 int
random_teleport_level()1211 random_teleport_level()
1212 {
1213 int nlev, max_depth, min_depth,
1214 cur_depth = (int)depth(&u.uz);
1215
1216 if (!rn2(5) || Is_knox(&u.uz))
1217 return cur_depth;
1218
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").
1233 * --KAA
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.
1237 */
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;
1243
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++;
1248
1249 if (nlev > max_depth) {
1250 nlev = max_depth;
1251 /* teleport up if already on bottom */
1252 if (Is_botlevel(&u.uz)) nlev -= rnd(3);
1253 }
1254 if (nlev < min_depth) {
1255 nlev = min_depth;
1256 if (nlev == cur_depth) {
1257 nlev += rnd(3);
1258 if (nlev > max_depth)
1259 nlev = max_depth;
1260 }
1261 }
1262 return nlev;
1263 }
1264
1265 /* you teleport a monster (via wand, spell, or poly'd q.mechanic attack);
1266 return false iff the attempt fails */
1267 boolean
u_teleport_mon(mtmp,give_feedback)1268 u_teleport_mon(mtmp, give_feedback)
1269 struct monst *mtmp;
1270 boolean give_feedback;
1271 {
1272 coord cc;
1273
1274 if (mtmp->ispriest && *in_rooms(mtmp->mx, mtmp->my, TEMPLE)) {
1275 if (give_feedback)
1276 pline("%s resists your magic!", Monnam(mtmp));
1277 return FALSE;
1278 } else if (level.flags.noteleport && u.uswallow && mtmp == u.ustuck) {
1279 if (give_feedback)
1280 You("are no longer inside %s!", mon_nam(mtmp));
1281 unstuck(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);
1286 else
1287 (void) rloc(mtmp, FALSE);
1288 return TRUE;
1289 }
1290
1291 /*teleport.c*/
1292