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 bad position of mtmp? If mtmp is NULL, then is (x, y) bad
15 * for an object?
16 *
17 * Caller is responsible for checking (x, y) with isok() if required.
18 *
19 * Returns: -1: Inaccessible, 0: Good pos, 1: Temporally inacessible
20 */
21 static int
badpos(x,y,mtmp,gpflags)22 badpos(x, y, mtmp, gpflags)
23 int x, y;
24 struct monst *mtmp;
25 unsigned gpflags;
26 {
27 int is_badpos = 0, pool;
28 struct permonst *mdat = NULL;
29 boolean ignorewater = ((gpflags & MM_IGNOREWATER) != 0);
30 struct monst *mtmp2;
31
32 /* in many cases, we're trying to create a new monster, which
33 * can't go on top of the player or any existing monster.
34 * however, occasionally we are relocating engravings or objects,
35 * which could be co-located and thus get restricted a bit too much.
36 * oh well.
37 */
38 if (mtmp != &youmonst && x == u.ux && y == u.uy
39 #ifdef STEED
40 && (!u.usteed || mtmp != u.usteed)
41 #endif
42 )
43 is_badpos = 1;
44
45 if (mtmp) {
46 mtmp2 = m_at(x,y);
47
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.
57 */
58 if (mtmp2 && (mtmp2 != mtmp || mtmp->wormno))
59 is_badpos = 1;
60
61 mdat = mtmp->data;
62 pool = is_pool(x,y);
63 if (mdat->mlet == S_EEL && !pool && rn2(13) && !ignorewater)
64 is_badpos = 1;
65
66 if (pool && !ignorewater) {
67 if (mtmp == &youmonst)
68 return (HLevitation || Flying || Wwalking ||
69 Swimming || Amphibious) ? is_badpos : -1;
70 else return (is_flyer(mdat) || is_swimmer(mdat) ||
71 is_clinger(mdat)) ? is_badpos : -1;
72 } else if (is_lava(x,y)) {
73 if (mtmp == &youmonst)
74 return HLevitation ? is_badpos : -1;
75 else
76 return (is_flyer(mdat) || likes_lava(mdat)) ?
77 is_badpos : -1;
78 }
79 if (passes_walls(mdat) && may_passwall(x,y)) return is_badpos;
80 }
81 if (!ACCESSIBLE(levl[x][y].typ)) {
82 if (!(is_pool(x,y) && ignorewater)) return -1;
83 }
84
85 if (closed_door(x, y) && (!mdat || !amorphous(mdat)))
86 return mdat && (nohands(mdat) || verysmall(mdat)) ? -1 : 1;
87 if (sobj_at(BOULDER, x, y) && (!mdat || !throws_rocks(mdat)))
88 return mdat ? -1 : 1;
89 return is_badpos;
90 }
91
92 /*
93 * Is (x,y) a good position of mtmp? If mtmp is NULL, then is (x,y) good
94 * for an object?
95 *
96 * This function will only look at mtmp->mdat, so makemon, mplayer, etc can
97 * call it to generate new monster positions with fake monster structures.
98 */
99 boolean
goodpos(x,y,mtmp,gpflags)100 goodpos(x, y, mtmp, gpflags)
101 int x,y;
102 struct monst *mtmp;
103 unsigned gpflags;
104 {
105 if (!isok(x, y)) return FALSE;
106
107 return !badpos(x, y, mtmp, gpflags);
108 }
109
110 /*
111 * "entity next to"
112 *
113 * Attempt to find a good place for the given monster type in the closest
114 * position to (xx,yy). Do so in successive square rings around (xx,yy).
115 * If there is more than one valid positon in the ring, choose one randomly.
116 * Return TRUE and the position chosen when successful, FALSE otherwise.
117 */
118 boolean
enexto(cc,xx,yy,mdat)119 enexto(cc, xx, yy, mdat)
120 coord *cc;
121 register xchar xx, yy;
122 struct permonst *mdat;
123 {
124 return enexto_core(cc, xx, yy, mdat, 0);
125 }
126
127 boolean
enexto_core(cc,xx,yy,mdat,entflags)128 enexto_core(cc, xx, yy, mdat, entflags)
129 coord *cc;
130 register xchar xx, yy;
131 struct permonst *mdat;
132 unsigned entflags;
133 {
134 #define MAX_GOOD 15
135 coord good[MAX_GOOD], *good_ptr;
136 int x, y, range, i;
137 int xmin, xmax, ymin, ymax;
138 struct monst fakemon; /* dummy monster */
139
140 if (!mdat) {
141 #ifdef DEBUG
142 pline("enexto() called with mdat==0");
143 #endif
144 /* default to player's original monster type */
145 mdat = &mons[u.umonster];
146 }
147 fakemon.data = mdat; /* set up for goodpos */
148 good_ptr = good;
149 range = 1;
150 /*
151 * Walk around the border of the square with center (xx,yy) and
152 * radius range. Stop when we find at least one valid position.
153 */
154 do {
155 xmin = max(1, xx-range);
156 xmax = min(COLNO-1, xx+range);
157 ymin = max(0, yy-range);
158 ymax = min(ROWNO-1, yy+range);
159
160 for (x = xmin; x <= xmax; x++)
161 if (goodpos(x, ymin, &fakemon, entflags)) {
162 good_ptr->x = x;
163 good_ptr->y = ymin ;
164 /* beware of accessing beyond segment boundaries.. */
165 if (good_ptr++ == &good[MAX_GOOD-1]) goto full;
166 }
167 for (x = xmin; x <= xmax; x++)
168 if (goodpos(x, ymax, &fakemon, entflags)) {
169 good_ptr->x = x;
170 good_ptr->y = ymax ;
171 /* beware of accessing beyond segment boundaries.. */
172 if (good_ptr++ == &good[MAX_GOOD-1]) goto full;
173 }
174 for (y = ymin+1; y < ymax; y++)
175 if (goodpos(xmin, y, &fakemon, entflags)) {
176 good_ptr->x = xmin;
177 good_ptr-> y = y ;
178 /* beware of accessing beyond segment boundaries.. */
179 if (good_ptr++ == &good[MAX_GOOD-1]) goto full;
180 }
181 for (y = ymin+1; y < ymax; y++)
182 if (goodpos(xmax, y, &fakemon, entflags)) {
183 good_ptr->x = xmax;
184 good_ptr->y = y ;
185 /* beware of accessing beyond segment boundaries.. */
186 if (good_ptr++ == &good[MAX_GOOD-1]) goto full;
187 }
188 range++;
189
190 /* return if we've grown too big (nothing is valid) */
191 if (range > ROWNO && range > COLNO) return FALSE;
192 } while (good_ptr == good);
193
194 full:
195 i = rn2((int)(good_ptr - good));
196 cc->x = good[i].x;
197 cc->y = good[i].y;
198 return TRUE;
199 }
200
201 /*
202 * "entity path to"
203 *
204 * Attempt to find nc good places for the given monster type with the shortest
205 * path to (xx,yy). Where there is more than one valid set of positions, one
206 * will be chosen at random. Return the number of positions found.
207 * Warning: This routine is much slower than enexto and should be used
208 * with caution.
209 */
210
211 #define EPATHTO_UNSEEN 0x0
212 #define EPATHTO_INACCESSIBLE 0x1
213 #define EPATHTO_DONE 0x2
214 #define EPATHTO_TAIL(n) (0x3 + ((n) & 1))
215
216 #define EPATHTO_XY(x,y) (((y) + 1) * COLNO + (x))
217 #define EPATHTO_Y(xy) ((xy) / COLNO - 1)
218 #define EPATHTO_X(xy) ((xy) % COLNO)
219
220 #ifdef DEBUG
221 coord epathto_debug_cc[100];
222 #endif
223
224 int
epathto(cc,nc,xx,yy,mdat)225 epathto(cc, nc, xx, yy, mdat)
226 coord *cc;
227 int nc;
228 register xchar xx, yy;
229 struct permonst *mdat;
230 {
231 int i, j, dir, ndirs, xy, x, y, r;
232 int path_len, postype;
233 int first_col, last_col;
234 int nd, n;
235 unsigned char *map;
236 static const int dirs[8] =
237 /* N, S, E, W, NW, NE, SE, SW */
238 { -COLNO, COLNO, 1, -1, -COLNO-1, -COLNO+1, COLNO+1, COLNO-1};
239 struct monst fakemon; /* dummy monster */
240 fakemon.data = mdat; /* set up for badpos */
241 map = (unsigned char *)alloc(COLNO * (ROWNO + 2));
242 (void) memset((genericptr_t)map, EPATHTO_INACCESSIBLE, COLNO * (ROWNO + 2));
243 for(i = 1; i < COLNO; i++)
244 for(j = 0; j < ROWNO; j++)
245 map[EPATHTO_XY(i, j)] = EPATHTO_UNSEEN;
246 map[EPATHTO_XY(xx, yy)] = EPATHTO_TAIL(0);
247 if (badpos(xx, yy, &fakemon, 0) == 0) {
248 cc[0].x = xx;
249 cc[0].y = yy;
250 nd = n = 1;
251 }
252 else
253 nd = n = 0;
254 for(path_len = 0; nd < nc; path_len++)
255 {
256 first_col = max(1, xx - path_len);
257 last_col = min(COLNO - 1, xx + path_len);
258 for(j = max(0, yy - path_len); j <= min(ROWNO - 1, yy + path_len); j++)
259 for(i = first_col; i <= last_col; i++)
260 if (map[EPATHTO_XY(i, j)] == EPATHTO_TAIL(path_len)) {
261 map[EPATHTO_XY(i, j)] = EPATHTO_DONE;
262 ndirs = mdat == &mons[PM_GRID_BUG] ? 4 : 8;
263 for(dir = 0; dir < ndirs; dir++) {
264 xy = EPATHTO_XY(i, j) + dirs[dir];
265 if (map[xy] == EPATHTO_UNSEEN) {
266 x = EPATHTO_X(xy);
267 y = EPATHTO_Y(xy);
268 postype = badpos(x, y, &fakemon, 0);
269 map[xy] = postype < 0 ? EPATHTO_INACCESSIBLE :
270 EPATHTO_TAIL(path_len + 1);
271 if (postype == 0) {
272 if (n < nc)
273 {
274 cc[n].x = x;
275 cc[n].y = y;
276 }
277 else if (rn2(n - nd + 1) < nc - nd)
278 {
279 r = rn2(nc - nd) + nd;
280 cc[r].x = x;
281 cc[r].y = y;
282 }
283 ++n;
284 }
285 }
286 }
287 }
288 if (nd == n)
289 break; /* No more positions */
290 else
291 nd = n;
292 }
293 if (nd > nc)
294 nd = nc;
295 #ifdef DEBUG
296 if (cc == epathto_debug_cc)
297 {
298 winid win;
299 int glyph;
300 char row[COLNO+1];
301
302 win = create_nhwindow(NHW_TEXT);
303 putstr(win, 0, "");
304 for (y = 0; y < ROWNO; y++) {
305 for (x = 1; x < COLNO; x++) {
306 xy = EPATHTO_XY(x, y);
307 if (map[xy] == EPATHTO_INACCESSIBLE) {
308 glyph = back_to_glyph(x, y);
309 row[x] = showsyms[glyph_to_cmap(glyph)];
310 }
311 else
312 row[x] = ' ';
313 }
314 for (i = 0; i < nd; i++)
315 if (cc[i].y == y)
316 row[cc[i].x] = i < 10 ? '0' + i :
317 i < 36 ? 'a' + i - 10 :
318 i < 62 ? 'A' + i - 36 :
319 '?';
320 /* remove trailing spaces */
321 for (x = COLNO-1; x >= 1; x--)
322 if (row[x] != ' ') break;
323 row[x+1] = '\0';
324
325 putstr(win, 0, &row[1]);
326 }
327 display_nhwindow(win, TRUE);
328 destroy_nhwindow(win);
329 }
330 #endif
331
332 free((genericptr_t)map);
333 return nd;
334 }
335
336 /*
337 * func should return 1 if the location should be counted as inaccessible
338 * (path won't continue through this point) or 0 if it is accessible.
339 */
340
341 void
xpathto(r,xx,yy,func,data)342 xpathto(r, xx, yy, func, data)
343 int r;
344 register xchar xx, yy;
345 int (*func)(genericptr_t, int, int);
346 genericptr_t data;
347 {
348 int i, j, dir, xy, x, y;
349 int path_len, postype;
350 int first_col, last_col;
351 int nd, n;
352 unsigned char *map;
353 static const int dirs[8] =
354 /* N, S, E, W, NW, NE, SE, SW */
355 { -COLNO, COLNO, 1, -1, -COLNO-1, -COLNO+1, COLNO+1, COLNO-1};
356 map = (unsigned char *)alloc(COLNO * (ROWNO + 2));
357 (void) memset((genericptr_t)map, EPATHTO_INACCESSIBLE, COLNO * (ROWNO + 2));
358 for(i = 1; i < COLNO; i++)
359 for(j = 0; j < ROWNO; j++)
360 map[EPATHTO_XY(i, j)] = EPATHTO_UNSEEN;
361 map[EPATHTO_XY(xx, yy)] = EPATHTO_TAIL(0);
362 if (func(data, xx, yy) == 0)
363 nd = n = 1;
364 else
365 nd = n = 0;
366 for(path_len = 0; path_len < r; path_len++)
367 {
368 first_col = max(1, xx - path_len);
369 last_col = min(COLNO - 1, xx + path_len);
370 for(j = max(0, yy - path_len); j <= min(ROWNO - 1, yy + path_len); j++)
371 for(i = first_col; i <= last_col; i++)
372 if (map[EPATHTO_XY(i, j)] == EPATHTO_TAIL(path_len)) {
373 map[EPATHTO_XY(i, j)] = EPATHTO_DONE;
374 for(dir = 0; dir < 8; dir++) {
375 xy = EPATHTO_XY(i, j) + dirs[dir];
376 if (map[xy] == EPATHTO_UNSEEN) {
377 x = EPATHTO_X(xy);
378 y = EPATHTO_Y(xy);
379 postype = func(data, x, y);
380 map[xy] = postype ? EPATHTO_INACCESSIBLE :
381 EPATHTO_TAIL(path_len + 1);
382 if (postype == 0)
383 ++n;
384 }
385 }
386 }
387 if (nd == n)
388 break; /* No more positions */
389 else
390 nd = n;
391 }
392 free((genericptr_t)map);
393 }
394
395 #ifdef DEBUG
396 void
wiz_debug_cmd()397 wiz_debug_cmd() /* in this case, run epathto on arbitary monster & goal */
398 {
399 struct permonst *ptr;
400 int mndx, i;
401 coord cc;
402 char buf[BUFSIZ];
403 for(i = 0; ; i++) {
404 if(i >= 5) {
405 pline(thats_enough_tries);
406 return;
407 }
408 getlin("What monster do you want to test? [type the name]", buf);
409
410 mndx = name_to_mon(buf);
411 if (mndx == NON_PM) {
412 pline("Such creatures do not exist in this world.");
413 continue;
414 }
415 ptr = &mons[mndx];
416 pline("Which position do you want to aim for?");
417 cc.x = u.ux;
418 cc.y = u.uy;
419 if (getpos(&cc, TRUE, "the goal position") < 0)
420 return; /* abort */
421 epathto(epathto_debug_cc, SIZE(epathto_debug_cc), cc.x, cc.y, ptr);
422 break;
423 }
424 }
425 #endif /* DEBUG */
426
427 /*
428 * Check for restricted areas present in some special levels. (This might
429 * need to be augmented to allow deliberate passage in wizard mode, but
430 * only for explicitly chosen destinations.)
431 */
432 STATIC_OVL boolean
tele_jump_ok(x1,y1,x2,y2)433 tele_jump_ok(x1, y1, x2, y2)
434 int x1, y1, x2, y2;
435 {
436 if (dndest.nlx > 0) {
437 /* if inside a restricted region, can't teleport outside */
438 if (within_bounded_area(x1, y1, dndest.nlx, dndest.nly,
439 dndest.nhx, dndest.nhy) &&
440 !within_bounded_area(x2, y2, dndest.nlx, dndest.nly,
441 dndest.nhx, dndest.nhy))
442 # ifdef WIZARD
443 if (!wizard)
444 # endif /* WIZARD */
445 return FALSE;
446 /* and if outside, can't teleport inside */
447 if (!within_bounded_area(x1, y1, dndest.nlx, dndest.nly,
448 dndest.nhx, dndest.nhy) &&
449 within_bounded_area(x2, y2, dndest.nlx, dndest.nly,
450 dndest.nhx, dndest.nhy))
451 # ifdef WIZARD
452 if (!wizard)
453 # endif /* WIZARD */
454 return FALSE;
455 }
456 if (updest.nlx > 0) { /* ditto */
457 if (within_bounded_area(x1, y1, updest.nlx, updest.nly,
458 updest.nhx, updest.nhy) &&
459 !within_bounded_area(x2, y2, updest.nlx, updest.nly,
460 updest.nhx, updest.nhy))
461 # ifdef WIZARD
462 if (!wizard)
463 # endif /* WIZARD */
464 return FALSE;
465 if (!within_bounded_area(x1, y1, updest.nlx, updest.nly,
466 updest.nhx, updest.nhy) &&
467 within_bounded_area(x2, y2, updest.nlx, updest.nly,
468 updest.nhx, updest.nhy))
469 # ifdef WIZARD
470 if (!wizard)
471 # endif /* WIZARD */
472 return FALSE;
473 }
474 return TRUE;
475 }
476
477 STATIC_OVL boolean
teleok(x,y,trapok)478 teleok(x, y, trapok)
479 register int x, y;
480 boolean trapok;
481 {
482 if (!trapok && t_at(x, y)) return FALSE;
483 if (!goodpos(x, y, &youmonst, 0)) return FALSE;
484 if (!tele_jump_ok(u.ux, u.uy, x, y)) return FALSE;
485 if (!in_out_region(x, y)) return FALSE;
486 return TRUE;
487 }
488
489 void
teleds(nux,nuy,allow_drag)490 teleds(nux, nuy, allow_drag)
491 register int nux,nuy;
492 boolean allow_drag;
493 {
494 boolean ball_active = (Punished && uball->where != OBJ_FREE),
495 ball_still_in_range = FALSE;
496
497 /* If they have to move the ball, then drag if allow_drag is true;
498 * otherwise they are teleporting, so unplacebc().
499 * If they don't have to move the ball, then always "drag" whether or
500 * not allow_drag is true, because we are calling that function, not
501 * to drag, but to move the chain. *However* there are some dumb
502 * special cases:
503 * 0 0
504 * _X move east -----> X_
505 * @ @
506 * These are permissible if teleporting, but not if dragging. As a
507 * result, drag_ball() needs to know about allow_drag and might end
508 * up dragging the ball anyway. Also, drag_ball() might find that
509 * dragging the ball is completely impossible (ball in range but there's
510 * rock in the way), in which case it teleports the ball on its own.
511 */
512 if (ball_active) {
513 if (!carried(uball) && distmin(nux, nuy, uball->ox, uball->oy) <= 2)
514 ball_still_in_range = TRUE; /* don't have to move the ball */
515 else {
516 /* have to move the ball */
517 if (!allow_drag || distmin(u.ux, u.uy, nux, nuy) > 1) {
518 /* we should not have dist > 1 and allow_drag at the same
519 * time, but just in case, we must then revert to teleport.
520 */
521 allow_drag = FALSE;
522 unplacebc();
523 }
524 }
525 }
526 u.utrap = 0;
527 setustuck(0);
528 u.ux0 = u.ux;
529 u.uy0 = u.uy;
530
531 if (hides_under(youmonst.data))
532 u.uundetected = OBJ_AT(nux, nuy);
533 else if (youmonst.data->mlet == S_EEL)
534 u.uundetected = is_pool(nux, nuy);
535 else {
536 u.uundetected = 0;
537 /* mimics stop being unnoticed */
538 if (youmonst.data->mlet == S_MIMIC)
539 youmonst.m_ap_type = M_AP_NOTHING;
540 }
541
542 if (u.uswallow) {
543 u.uswldtim = u.uswallow = 0;
544 if (Punished && !ball_active) {
545 /* ensure ball placement, like unstuck */
546 ball_active = TRUE;
547 allow_drag = FALSE;
548 }
549 docrt();
550 }
551 if (ball_active) {
552 if (ball_still_in_range || allow_drag) {
553 int bc_control;
554 xchar ballx, bally, chainx, chainy;
555 boolean cause_delay;
556
557 if (drag_ball(nux, nuy, &bc_control, &ballx, &bally,
558 &chainx, &chainy, &cause_delay, allow_drag))
559 move_bc(0, bc_control, ballx, bally, chainx, chainy);
560 }
561 }
562 /* must set u.ux, u.uy after drag_ball(), which may need to know
563 the old position if allow_drag is true... */
564 u.ux = nux;
565 u.uy = nuy;
566 fill_pit(u.ux0, u.uy0);
567 if (ball_active) {
568 if (!ball_still_in_range && !allow_drag)
569 placebc();
570 }
571 initrack(); /* teleports mess up tracking monsters without this */
572 update_player_regions();
573 #ifdef STEED
574 /* Move your steed, too */
575 if (u.usteed) {
576 u.usteed->mx = nux;
577 u.usteed->my = nuy;
578 }
579 #endif
580
581 /*
582 * Make sure the hero disappears from the old location. This will
583 * not happen if she is teleported within sight of her previous
584 * location. Force a full vision recalculation because the hero
585 * is now in a new location.
586 */
587 newsym(u.ux0,u.uy0);
588 see_monsters();
589 vision_full_recalc = 1;
590 nomul(0);
591 vision_recalc(0); /* vision before effects */
592 spoteffects(TRUE);
593 invocation_message();
594 }
595
596 boolean
safe_teleds(allow_drag)597 safe_teleds(allow_drag)
598 boolean allow_drag;
599 {
600 register int nux, nuy, tcnt = 0;
601
602 do {
603 nux = rnd(COLNO-1);
604 nuy = rn2(ROWNO);
605 } while (!teleok(nux, nuy, (boolean)(tcnt > 200)) && ++tcnt <= 400);
606
607 if (tcnt <= 400) {
608 teleds(nux, nuy, allow_drag);
609 return TRUE;
610 } else
611 return FALSE;
612 }
613
614 STATIC_OVL void
vault_tele()615 vault_tele()
616 {
617 register struct mkroom *croom = search_special(VAULT);
618 coord c;
619
620 if (croom && somexy(croom, &c) && teleok(c.x,c.y,FALSE)) {
621 teleds(c.x,c.y,FALSE);
622 return;
623 }
624 tele();
625 }
626
627 boolean
teleport_pet(mtmp,force_it)628 teleport_pet(mtmp, force_it)
629 register struct monst *mtmp;
630 boolean force_it;
631 {
632 register struct obj *otmp;
633
634 #ifdef STEED
635 if (mtmp == u.usteed)
636 return (FALSE);
637 #endif
638
639 if (mtmp->mleashed) {
640 otmp = get_mleash(mtmp);
641 if (!otmp) {
642 impossible("%s is leashed, without a leash.", Monnam(mtmp));
643 goto release_it;
644 }
645 if (otmp->cursed && !force_it) {
646 yelp(mtmp);
647 return FALSE;
648 } else {
649 Your("leash goes slack.");
650 release_it:
651 m_unleash(mtmp, FALSE);
652 return TRUE;
653 }
654 }
655 return TRUE;
656 }
657
658 void
tele()659 tele()
660 {
661 coord cc;
662
663 /* Disable teleportation in stronghold && Vlad's Tower */
664 if (level.flags.noteleport) {
665 #ifdef WIZARD
666 if (!wizard) {
667 #endif
668 pline("A mysterious force prevents you from teleporting!");
669 return;
670 #ifdef WIZARD
671 }
672 #endif
673 }
674
675 /* don't show trap if "Sorry..." */
676 if (!Blinded) make_blinded(0L,FALSE);
677
678 if
679 #ifdef WIZARD
680 (
681 #endif
682 (u.uhave.amulet || On_W_tower_level(&u.uz)
683 #ifdef STEED
684 || (u.usteed && mon_has_amulet(u.usteed))
685 #endif
686 )
687 #ifdef WIZARD
688 && (!wizard) )
689 #endif
690 {
691 You_feel("disoriented for a moment.");
692 return;
693 }
694 if ((Teleport_control && !Stunned)
695 #ifdef WIZARD
696 || wizard
697 #endif
698 ) {
699 if (unconscious()) {
700 pline("Being unconscious, you cannot control your teleport.");
701 } else {
702 #ifdef STEED
703 char buf[BUFSZ];
704 if (u.usteed) Sprintf(buf," and %s", mon_nam(u.usteed));
705 #endif
706 pline("To what position do you%s want to be teleported?",
707 #ifdef STEED
708 u.usteed ? buf :
709 #endif
710 "");
711 cc.x = u.ux;
712 cc.y = u.uy;
713 if (getpos(&cc, TRUE, "the desired position") < 0)
714 return; /* abort */
715 /* possible extensions: introduce a small error if
716 magic power is low; allow transfer to solid rock */
717 if (teleok(cc.x, cc.y, FALSE)) {
718 teleds(cc.x, cc.y, FALSE);
719 return;
720 }
721 pline("Sorry...");
722 }
723 }
724
725 (void) safe_teleds(FALSE);
726 }
727
728 int
dotele()729 dotele()
730 {
731 struct trap *trap;
732
733 trap = t_at(u.ux, u.uy);
734 if (trap && (!trap->tseen || trap->ttyp != TELEP_TRAP))
735 trap = 0;
736
737 if (trap) {
738 if (trap->once) {
739 pline("This is a vault teleport, usable once only.");
740 if (yn("Jump in?") == 'n')
741 trap = 0;
742 else {
743 deltrap(trap);
744 newsym(u.ux, u.uy);
745 }
746 }
747 if (trap)
748 You("%s onto the teleportation trap.",
749 locomotion(youmonst.data, "jump"));
750 }
751 if (!trap) {
752 boolean castit = FALSE;
753 register int sp_no = 0, energy = 0;
754
755 if (!Teleportation || (u.ulevel < (Role_if(PM_WIZARD) ? 8 : 12)
756 && !can_teleport(youmonst.data))) {
757 /* Try to use teleport away spell. */
758 if (objects[SPE_TELEPORT_AWAY].oc_name_known && !Confusion)
759 for (sp_no = 0; sp_no < MAXSPELL; sp_no++)
760 if (spl_book[sp_no].sp_id == SPE_TELEPORT_AWAY) {
761 castit = TRUE;
762 break;
763 }
764 #ifdef WIZARD
765 if (!wizard) {
766 #endif
767 if (!castit) {
768 if (!Teleportation)
769 You("don't know that spell.");
770 else You("are not able to teleport at will.");
771 return(0);
772 }
773 #ifdef WIZARD
774 }
775 #endif
776 }
777
778 if (u.uhunger <= 10 || ACURR(A_STR) < 6) {
779 #ifdef WIZARD
780 if (!wizard) {
781 #endif
782 You("lack the strength %s.",
783 castit ? "for a teleport spell" : "to teleport");
784 return 1;
785 #ifdef WIZARD
786 }
787 #endif
788 }
789
790 energy = objects[SPE_TELEPORT_AWAY].oc_level * 5;
791 if (u.uen <= energy) {
792 #ifdef WIZARD
793 if (wizard)
794 energy = u.uen;
795 else
796 #endif
797 {
798 You("lack the energy %s.",
799 castit ? "for a teleport spell" : "to teleport");
800 return 1;
801 }
802 }
803
804 if (check_capacity(
805 "Your concentration falters from carrying so much."))
806 return 1;
807
808 if (castit) {
809 exercise(A_WIS, TRUE);
810 if (spelleffects(sp_no, TRUE))
811 return(1);
812 else
813 #ifdef WIZARD
814 if (!wizard)
815 #endif
816 return(0);
817 } else {
818 u.uen -= energy;
819 flags.botl = 1;
820 }
821 }
822
823 if (next_to_u()) {
824 if (trap && trap->once) vault_tele();
825 else tele();
826 (void) next_to_u();
827 } else {
828 You(shudder_for_moment);
829 return(0);
830 }
831 if (!trap) morehungry(10);
832 return(1);
833 }
834
835 void
level_tele()836 level_tele()
837 {
838 register int newlev;
839 d_level newlevel;
840 const char *escape_by_flying = 0; /* when surviving dest of -N */
841 char buf[BUFSZ];
842 boolean force_dest = FALSE;
843
844 if ((u.uhave.amulet || In_endgame(&u.uz) || In_sokoban(&u.uz)
845 #ifdef STEED
846 || (u.usteed && mon_has_amulet(u.usteed))
847 #endif
848 )
849 #ifdef WIZARD
850 && !wizard
851 #endif
852 ) {
853 You_feel("very disoriented for a moment.");
854 return;
855 }
856 if ((Teleport_control && !Stunned)
857 #ifdef WIZARD
858 || wizard
859 #endif
860 ) {
861 char qbuf[BUFSZ];
862 int trycnt = 0;
863
864 Strcpy(qbuf, "To what level do you want to teleport?");
865 do {
866 if (++trycnt == 2) {
867 #ifdef WIZARD
868 if (wizard) Strcat(qbuf, " [type a number or ? for a menu]");
869 else
870 #endif
871 Strcat(qbuf, " [type a number]");
872 }
873 getlin(qbuf, buf);
874 if (!strcmp(buf,"\033")) { /* cancelled */
875 if (Confusion && rnl(5)) {
876 pline("Oops...");
877 goto random_levtport;
878 }
879 return;
880 } else if (!strcmp(buf,"*")) {
881 goto random_levtport;
882 } else if (Confusion && rnl(5)) {
883 pline("Oops...");
884 goto random_levtport;
885 }
886 #ifdef WIZARD
887 if (wizard && !strcmp(buf,"?")) {
888 schar destlev = 0;
889 xchar destdnum = 0;
890
891 if ((newlev = (int)print_dungeon(TRUE, &destlev, &destdnum))) {
892 newlevel.dnum = destdnum;
893 newlevel.dlevel = destlev;
894 if (In_endgame(&newlevel) && !In_endgame(&u.uz)) {
895 Sprintf(buf,
896 "Destination is earth level");
897 if (!u.uhave.amulet) {
898 struct obj *obj;
899 obj = mksobj(AMULET_OF_YENDOR,
900 TRUE, FALSE);
901 if (obj) {
902 obj = addinv(obj);
903 Strcat(buf, " with the amulet");
904 }
905 }
906 assign_level(&newlevel, &earth_level);
907 pline("%s.", buf);
908 }
909 force_dest = TRUE;
910 } else return;
911 } else
912 #endif
913 if ((newlev = lev_by_name(buf)) == 0) {
914 #ifdef WIZARD
915 s_level *slev;
916
917 /* if you're using wizard mode, you shouldn't really need
918 * the game to interpret things like `mine town level' */
919 if (wizard && (slev = find_level(buf))) {
920 schedule_goto(&slev->dlevel, FALSE, FALSE, 0,
921 (char *)0, (char *)0);
922 return;
923 }
924 #endif
925 newlev = atoi(buf);
926 }
927 } while (!newlev && !digit(buf[0]) &&
928 (buf[0] != '-' || !digit(buf[1])) &&
929 trycnt < 10);
930
931 /* no dungeon escape via this route */
932 if (newlev == 0) {
933 if (trycnt >= 10)
934 goto random_levtport;
935 if (ynq("Go to Nowhere. Are you sure?") != 'y') return;
936 You("%s in agony as your body begins to warp...",
937 is_silent(youmonst.data) ? "writhe" : "scream");
938 display_nhwindow(WIN_MESSAGE, FALSE);
939 You("cease to exist.");
940 if (invent) Your("possessions land on the %s with a thud.",
941 surface(u.ux, u.uy));
942 killer_format = NO_KILLER_PREFIX;
943 killer = "committed suicide";
944 done(DIED);
945 pline("An energized cloud of dust begins to coalesce.");
946 Your("body rematerializes%s.", invent ?
947 ", and you gather up all your possessions" : "");
948 return;
949 }
950
951 /* if in Knox and the requested level > 0, stay put.
952 * we let negative values requests fall into the "heaven" loop.
953 * [ALI] Add other single level dungeons entered via portal.
954 */
955 if ((Is_knox(&u.uz) ||
956 #ifdef BLACKMARKET
957 Is_blackmarket(&u.uz) ||
958 #endif
959 Is_aligned_quest(&u.uz)) && newlev > 0) {
960 You(shudder_for_moment);
961 return;
962 }
963 /* if in Quest, the player sees "Home 1", etc., on the status
964 * line, instead of the logical depth of the level. controlled
965 * level teleport request is likely to be relativized to the
966 * status line, and consequently it should be incremented to
967 * the value of the logical depth of the target level.
968 *
969 * we let negative values requests fall into the "heaven" loop.
970 */
971 if (In_quest(&u.uz) && newlev > 0)
972 newlev = newlev + dungeons[u.uz.dnum].depth_start - 1;
973 } else { /* involuntary level tele */
974 random_levtport:
975 newlev = random_teleport_level();
976 if (newlev == depth(&u.uz)) {
977 You(shudder_for_moment);
978 return;
979 }
980 }
981
982 if (!next_to_u()) {
983 You(shudder_for_moment);
984 return;
985 }
986 #ifdef WIZARD
987 if (In_endgame(&u.uz)) { /* must already be wizard */
988 int llimit = dunlevs_in_dungeon(&u.uz);
989
990 if (newlev >= 0 || newlev <= -llimit) {
991 You_cant("get there from here.");
992 return;
993 }
994 newlevel.dnum = u.uz.dnum;
995 newlevel.dlevel = llimit + newlev;
996 schedule_goto(&newlevel, FALSE, FALSE, 0, (char *)0, (char *)0);
997 return;
998 }
999 #endif
1000 killer = 0; /* still alive, so far... */
1001
1002 if (newlev < 0 && !force_dest) {
1003 if (*u.ushops0) {
1004 /* take unpaid inventory items off of shop bills */
1005 in_mklev = TRUE; /* suppress map update */
1006 u_left_shop(u.ushops0, TRUE);
1007 /* you're now effectively out of the shop */
1008 *u.ushops0 = *u.ushops = '\0';
1009 in_mklev = FALSE;
1010 }
1011 if (newlev <= -10) {
1012 You("arrive in heaven.");
1013 verbalize("Thou art early, but we'll admit thee.");
1014 killer_format = NO_KILLER_PREFIX;
1015 killer = "went to heaven prematurely";
1016 } else if (newlev == -9) {
1017 You_feel("deliriously happy. ");
1018 pline("(In fact, you're on Cloud 9!) ");
1019 display_nhwindow(WIN_MESSAGE, FALSE);
1020 } else
1021 You("are now high above the clouds...");
1022
1023 if (killer) {
1024 ; /* arrival in heaven is pending */
1025 } else if (Levitation) {
1026 escape_by_flying = "float gently down to earth";
1027 } else if (Flying) {
1028 escape_by_flying = "fly down to the ground";
1029 } else {
1030 pline("Unfortunately, you don't know how to fly.");
1031 You("plummet a few thousand feet to your death.");
1032 Sprintf(buf,
1033 "teleported out of the dungeon and fell to %s death",
1034 uhis());
1035 killer = buf;
1036 killer_format = NO_KILLER_PREFIX;
1037 }
1038 }
1039
1040 if (killer) { /* the chosen destination was not survivable */
1041 d_level lsav;
1042
1043 /* set specific death location; this also suppresses bones */
1044 lsav = u.uz; /* save current level, see below */
1045 u.uz.dnum = 0; /* main dungeon */
1046 u.uz.dlevel = (newlev <= -10) ? -10 : 0; /* heaven or surface */
1047 done(DIED);
1048 /* can only get here via life-saving (or declining to die in
1049 explore|debug mode); the hero has now left the dungeon... */
1050 escape_by_flying = "find yourself back on the surface";
1051 u.uz = lsav; /* restore u.uz so escape code works */
1052 }
1053
1054 /* calls done(ESCAPED) if newlevel==0 */
1055 if (escape_by_flying) {
1056 You("%s.", escape_by_flying);
1057 newlevel.dnum = 0; /* specify main dungeon */
1058 newlevel.dlevel = 0; /* escape the dungeon */
1059 /* [dlevel used to be set to 1, but it doesn't make sense to
1060 teleport out of the dungeon and float or fly down to the
1061 surface but then actually arrive back inside the dungeon] */
1062 } else if (u.uz.dnum == medusa_level.dnum &&
1063 newlev >= dungeons[u.uz.dnum].depth_start +
1064 dunlevs_in_dungeon(&u.uz)) {
1065 #ifdef WIZARD
1066 if (!(wizard && force_dest))
1067 #endif
1068 find_hell(&newlevel);
1069 } else {
1070 /* if invocation did not yet occur, teleporting into
1071 * the last level of Gehennom is forbidden.
1072 */
1073 #ifdef WIZARD
1074 if (!wizard)
1075 #endif
1076 if (Inhell && !u.uevent.invoked &&
1077 newlev >= (dungeons[u.uz.dnum].depth_start +
1078 dunlevs_in_dungeon(&u.uz) - 1)) {
1079 # ifdef WIZARD
1080 if (!wizard)
1081 {
1082 # endif /* WIZARD */
1083 newlev = dungeons[u.uz.dnum].depth_start +
1084 dunlevs_in_dungeon(&u.uz) - 2;
1085 pline("Sorry...");
1086 # ifdef WIZARD
1087 }
1088 # endif /* WIZARD */
1089
1090 }
1091 /* no teleporting out of quest dungeon */
1092 if
1093 # ifdef WIZARD
1094 ((!wizard) &&
1095 # endif /* WIZARD */
1096 (In_quest(&u.uz) && newlev < depth(&qstart_level))
1097 # ifdef WIZARD
1098 )
1099 # endif /* WIZARD */
1100 newlev = depth(&qstart_level);
1101 /* the player thinks of levels purely in logical terms, so
1102 * we must translate newlev to a number relative to the
1103 * current dungeon.
1104 */
1105 #ifdef WIZARD
1106 if (!(wizard && force_dest))
1107 #endif
1108 get_level(&newlevel, newlev);
1109 }
1110 schedule_goto(&newlevel, FALSE, FALSE, 0, (char *)0, (char *)0);
1111 /* in case player just read a scroll and is about to be asked to
1112 call it something, we can't defer until the end of the turn */
1113 if (u.utotype && !flags.mon_moving) deferred_goto();
1114 }
1115
1116 void
domagicportal(ttmp)1117 domagicportal(ttmp)
1118 register struct trap *ttmp;
1119 {
1120 struct d_level target_level;
1121
1122 if (!next_to_u()) {
1123 You(shudder_for_moment);
1124 return;
1125 }
1126
1127 /* if landed from another portal, do nothing */
1128 /* problem: level teleport landing escapes the check */
1129 if (!on_level(&u.uz, &u.uz0)) return;
1130
1131 You("activated a magic portal!");
1132
1133 /* prevent the poor shnook, whose amulet was stolen while in
1134 * the endgame, from accidently triggering the portal to the
1135 * next level, and thus losing the game
1136 */
1137 if (In_endgame(&u.uz) && !u.uhave.amulet) {
1138 You_feel("dizzy for a moment, but nothing happens...");
1139 return;
1140 }
1141
1142 target_level = ttmp->dst;
1143 schedule_goto(&target_level, FALSE, FALSE, 1,
1144 "You feel dizzy for a moment, but the sensation passes.",
1145 (char *)0);
1146 }
1147
1148 void
tele_trap(trap)1149 tele_trap(trap)
1150 struct trap *trap;
1151 {
1152 if (In_endgame(&u.uz) || Antimagic) {
1153 if (Antimagic)
1154 shieldeff(u.ux, u.uy);
1155 You_feel("a wrenching sensation.");
1156 } else if (!next_to_u()) {
1157 You(shudder_for_moment);
1158 } else if (trap->once) {
1159 deltrap(trap);
1160 newsym(u.ux,u.uy); /* get rid of trap symbol */
1161 vault_tele();
1162 } else
1163 tele();
1164 }
1165
1166 void
level_tele_trap(trap)1167 level_tele_trap(trap)
1168 struct trap *trap;
1169 {
1170 You("%s onto a level teleport trap!",
1171 Levitation ? (const char *)"float" :
1172 locomotion(youmonst.data, "step"));
1173 if (Antimagic) {
1174 shieldeff(u.ux, u.uy);
1175 }
1176 if (Antimagic || In_endgame(&u.uz)) {
1177 You_feel("a wrenching sensation.");
1178 return;
1179 }
1180 if (!Blind)
1181 You("are momentarily blinded by a flash of light.");
1182 else
1183 You("are momentarily disoriented.");
1184 deltrap(trap);
1185 newsym(u.ux,u.uy); /* get rid of trap symbol */
1186 level_tele();
1187 }
1188
1189 /* check whether monster can arrive at location <x,y> via Tport (or fall) */
1190 STATIC_OVL boolean
rloc_pos_ok(x,y,mtmp)1191 rloc_pos_ok(x, y, mtmp)
1192 register int x, y; /* coordinates of candidate location */
1193 struct monst *mtmp;
1194 {
1195 register int xx, yy;
1196
1197 if (!goodpos(x, y, mtmp, 0)) return FALSE;
1198 /*
1199 * Check for restricted areas present in some special levels.
1200 *
1201 * `xx' is current column; if 0, then `yy' will contain flag bits
1202 * rather than row: bit #0 set => moving upwards; bit #1 set =>
1203 * inside the Wizard's tower.
1204 */
1205 xx = mtmp->mx;
1206 yy = mtmp->my;
1207 if (!xx) {
1208 /* no current location (migrating monster arrival) */
1209 if (dndest.nlx && On_W_tower_level(&u.uz))
1210 return ((yy & 2) != 0) ^ /* inside xor not within */
1211 !within_bounded_area(x, y, dndest.nlx, dndest.nly,
1212 dndest.nhx, dndest.nhy);
1213 if (updest.lx && (yy & 1) != 0) /* moving up */
1214 return (within_bounded_area(x, y, updest.lx, updest.ly,
1215 updest.hx, updest.hy) &&
1216 (!updest.nlx ||
1217 !within_bounded_area(x, y, updest.nlx, updest.nly,
1218 updest.nhx, updest.nhy)));
1219 if (dndest.lx && (yy & 1) == 0) /* moving down */
1220 return (within_bounded_area(x, y, dndest.lx, dndest.ly,
1221 dndest.hx, dndest.hy) &&
1222 (!dndest.nlx ||
1223 !within_bounded_area(x, y, dndest.nlx, dndest.nly,
1224 dndest.nhx, dndest.nhy)));
1225 } else {
1226 /* current location is <xx,yy> */
1227 if (!tele_jump_ok(xx, yy, x, y)) return FALSE;
1228 }
1229 /* <x,y> is ok */
1230 return TRUE;
1231 }
1232
1233 /*
1234 * rloc_to()
1235 *
1236 * Pulls a monster from its current position and places a monster at
1237 * a new x and y. If oldx is 0, then the monster was not in the levels.monsters
1238 * array. However, if oldx is 0, oldy may still have a value because mtmp is a
1239 * migrating_mon. Worm tails are always placed randomly around the head of
1240 * the worm.
1241 */
1242 void
rloc_to(mtmp,x,y)1243 rloc_to(mtmp, x, y)
1244 struct monst *mtmp;
1245 register int x, y;
1246 {
1247 register int oldx = mtmp->mx, oldy = mtmp->my;
1248 boolean resident_shk = mtmp->isshk && inhishop(mtmp);
1249
1250 if (x == mtmp->mx && y == mtmp->my) /* that was easy */
1251 return;
1252
1253 if (oldx) { /* "pick up" monster */
1254 if (mtmp->wormno)
1255 remove_worm(mtmp);
1256 else {
1257 remove_monster(oldx, oldy);
1258 newsym(oldx, oldy); /* update old location */
1259 }
1260 }
1261
1262 place_monster(mtmp, x, y); /* put monster down */
1263 update_monster_region(mtmp);
1264
1265 if (mtmp->wormno) /* now put down tail */
1266 place_worm_tail_randomly(mtmp, x, y);
1267
1268 if (u.ustuck == mtmp) {
1269 if (u.uswallow) {
1270 u.ux = x;
1271 u.uy = y;
1272 docrt();
1273 } else setustuck(0);
1274 }
1275
1276 newsym(x, y); /* update new location */
1277 set_apparxy(mtmp); /* orient monster */
1278
1279 /* shopkeepers will only teleport if you zap them with a wand of
1280 teleportation or if they've been transformed into a jumpy monster;
1281 the latter only happens if you've attacked them with polymorph */
1282 if (resident_shk && !inhishop(mtmp)) make_angry_shk(mtmp, oldx, oldy);
1283 }
1284
1285 /* place a monster at a random location, typically due to teleport */
1286 /* return TRUE if successful, FALSE if not */
1287 boolean
rloc(mtmp,suppress_impossible)1288 rloc(mtmp, suppress_impossible)
1289 struct monst *mtmp; /* mx==0 implies migrating monster arrival */
1290 boolean suppress_impossible;
1291 {
1292 register int x, y, trycount;
1293
1294 #ifdef STEED
1295 if (mtmp == u.usteed) {
1296 tele();
1297 return TRUE;
1298 }
1299 #endif
1300
1301 if (mtmp->iswiz && mtmp->mx) { /* Wizard, not just arriving */
1302 if (!In_W_tower(u.ux, u.uy, &u.uz))
1303 x = xupstair, y = yupstair;
1304 else if (!xdnladder) /* bottom level of tower */
1305 x = xupladder, y = yupladder;
1306 else
1307 x = xdnladder, y = ydnladder;
1308 /* if the wiz teleports away to heal, try the up staircase,
1309 to block the player's escaping before he's healed
1310 (deliberately use `goodpos' rather than `rloc_pos_ok' here) */
1311 if (goodpos(x, y, mtmp, 0))
1312 goto found_xy;
1313 }
1314
1315 trycount = 0;
1316 do {
1317 x = rn1(COLNO-3,2);
1318 y = rn2(ROWNO);
1319 if ((trycount < 500) ? rloc_pos_ok(x, y, mtmp)
1320 : goodpos(x, y, mtmp, 0))
1321 goto found_xy;
1322 } while (++trycount < 1000);
1323
1324 /* last ditch attempt to find a good place */
1325 for (x = 2; x < COLNO - 1; x++)
1326 for (y = 0; y < ROWNO; y++)
1327 if (goodpos(x, y, mtmp, 0))
1328 goto found_xy;
1329
1330 /* level either full of monsters or somehow faulty */
1331 if (!suppress_impossible)
1332 impossible("rloc(): couldn't relocate monster");
1333 return FALSE;
1334
1335 found_xy:
1336 rloc_to(mtmp, x, y);
1337 return TRUE;
1338 }
1339
1340 STATIC_OVL void
mvault_tele(mtmp)1341 mvault_tele(mtmp)
1342 struct monst *mtmp;
1343 {
1344 register struct mkroom *croom = search_special(VAULT);
1345 coord c;
1346
1347 if (croom && somexy(croom, &c) &&
1348 goodpos(c.x, c.y, mtmp, 0)) {
1349 rloc_to(mtmp, c.x, c.y);
1350 return;
1351 }
1352 (void) rloc(mtmp, FALSE);
1353 }
1354
1355 boolean
tele_restrict(mon)1356 tele_restrict(mon)
1357 struct monst *mon;
1358 {
1359 if (level.flags.noteleport) {
1360 if (canseemon(mon))
1361 pline("A mysterious force prevents %s from teleporting!",
1362 mon_nam(mon));
1363 return TRUE;
1364 }
1365 return FALSE;
1366 }
1367
1368 void
mtele_trap(mtmp,trap,in_sight)1369 mtele_trap(mtmp, trap, in_sight)
1370 struct monst *mtmp;
1371 struct trap *trap;
1372 int in_sight;
1373 {
1374 char *monname;
1375
1376 if (tele_restrict(mtmp)) return;
1377 if (teleport_pet(mtmp, FALSE)) {
1378 /* save name with pre-movement visibility */
1379 monname = Monnam(mtmp);
1380
1381 /* Note: don't remove the trap if a vault. Other-
1382 * wise the monster will be stuck there, since
1383 * the guard isn't going to come for it...
1384 */
1385 if (trap->once) mvault_tele(mtmp);
1386 else (void) rloc(mtmp, FALSE);
1387
1388 if (in_sight) {
1389 if (canseemon(mtmp))
1390 pline("%s seems disoriented.", monname);
1391 else
1392 pline("%s suddenly disappears!", monname);
1393 seetrap(trap);
1394 }
1395 }
1396 }
1397
1398 /* return 0 if still on level, 3 if not */
1399 int
mlevel_tele_trap(mtmp,trap,force_it,in_sight)1400 mlevel_tele_trap(mtmp, trap, force_it, in_sight)
1401 struct monst *mtmp;
1402 struct trap *trap;
1403 boolean force_it;
1404 int in_sight;
1405 {
1406 int tt = trap->ttyp;
1407 struct permonst *mptr = mtmp->data;
1408
1409 if (mtmp == u.ustuck) /* probably a vortex */
1410 return 0; /* temporary? kludge */
1411 if (teleport_pet(mtmp, force_it)) {
1412 d_level tolevel;
1413 int migrate_typ = MIGR_RANDOM;
1414
1415 if ((tt == HOLE || tt == TRAPDOOR)) {
1416 if (Is_stronghold(&u.uz)) {
1417 assign_level(&tolevel, &valley_level);
1418 } else if (Is_botlevel(&u.uz)) {
1419 if (in_sight && trap->tseen)
1420 pline("%s avoids the %s.", Monnam(mtmp),
1421 (tt == HOLE) ? "hole" : "trap");
1422 return 0;
1423 } else {
1424 get_level(&tolevel, depth(&u.uz) + 1);
1425 }
1426 } else if (tt == MAGIC_PORTAL) {
1427 if (In_endgame(&u.uz) &&
1428 (mon_has_amulet(mtmp) || is_home_elemental(mptr))) {
1429 if (in_sight && mptr->mlet != S_ELEMENTAL) {
1430 pline("%s seems to shimmer for a moment.",
1431 Monnam(mtmp));
1432 seetrap(trap);
1433 }
1434 return 0;
1435 }
1436 #ifdef BLACKMARKET
1437 else if (mtmp->mtame &&
1438 (Is_blackmarket(&trap->dst) || Is_blackmarket(&u.uz))) {
1439 if (in_sight) {
1440 pline("%s seems to shimmer for a moment.",
1441 Monnam(mtmp));
1442 seetrap(trap);
1443 }
1444 return 0;
1445 }
1446 #endif /* BLACKMARKET */
1447 else {
1448 assign_level(&tolevel, &trap->dst);
1449 migrate_typ = MIGR_PORTAL;
1450 }
1451 } else { /* (tt == LEVEL_TELEP) */
1452 int nlev;
1453
1454 if (mon_has_amulet(mtmp) || In_endgame(&u.uz)) {
1455 if (in_sight)
1456 pline("%s seems very disoriented for a moment.",
1457 Monnam(mtmp));
1458 return 0;
1459 }
1460 nlev = random_teleport_level();
1461 if (nlev == depth(&u.uz)) {
1462 if (in_sight)
1463 pline("%s shudders for a moment.", Monnam(mtmp));
1464 return 0;
1465 }
1466 get_level(&tolevel, nlev);
1467 }
1468
1469 if (in_sight) {
1470 pline("Suddenly, %s disappears out of sight.", mon_nam(mtmp));
1471 seetrap(trap);
1472 }
1473 migrate_to_level(mtmp, ledger_no(&tolevel),
1474 migrate_typ, (coord *)0);
1475 return 3; /* no longer on this level */
1476 }
1477 return 0;
1478 }
1479
1480
1481 void
rloco(obj)1482 rloco(obj)
1483 register struct obj *obj;
1484 {
1485 register xchar tx, ty, otx, oty;
1486 boolean restricted_fall;
1487 int try_limit = 4000;
1488
1489 if (obj->otyp == CORPSE && is_rider(&mons[obj->corpsenm])) {
1490 if (revive_corpse(obj, FALSE)) return;
1491 }
1492
1493 obj_extract_self(obj);
1494 otx = obj->ox;
1495 oty = obj->oy;
1496 restricted_fall = (otx == 0 && dndest.lx);
1497 do {
1498 tx = rn1(COLNO-3,2);
1499 ty = rn2(ROWNO);
1500 if (!--try_limit) break;
1501 } while (!goodpos(tx, ty, (struct monst *)0, 0) ||
1502 /* bug: this lacks provision for handling the Wizard's tower */
1503 (restricted_fall &&
1504 (!within_bounded_area(tx, ty, dndest.lx, dndest.ly,
1505 dndest.hx, dndest.hy) ||
1506 (dndest.nlx &&
1507 within_bounded_area(tx, ty, dndest.nlx, dndest.nly,
1508 dndest.nhx, dndest.nhy)))));
1509
1510 if (flooreffects(obj, tx, ty, "fall")) {
1511 return;
1512 } else if (otx == 0 && oty == 0) {
1513 ; /* fell through a trap door; no update of old loc needed */
1514 } else {
1515 if (costly_spot(otx, oty)
1516 && (!costly_spot(tx, ty) ||
1517 !index(in_rooms(tx, ty, 0), *in_rooms(otx, oty, 0)))) {
1518 if (costly_spot(u.ux, u.uy) &&
1519 index(u.urooms, *in_rooms(otx, oty, 0)))
1520 addtobill(obj, FALSE, FALSE, FALSE);
1521 else (void)stolen_value(obj, otx, oty, FALSE, FALSE, FALSE);
1522 }
1523 newsym(otx, oty); /* update old location */
1524 }
1525 place_object(obj, tx, ty);
1526 newsym(tx, ty);
1527 }
1528
1529 /* Returns an absolute depth */
1530 int
random_teleport_level()1531 random_teleport_level()
1532 {
1533 int nlev, max_depth, min_depth,
1534 cur_depth = (int)depth(&u.uz);
1535
1536 if (!rn2(5) || Is_knox(&u.uz) ||
1537 #ifdef BLACKMARKET
1538 Is_blackmarket(&u.uz) ||
1539 #endif
1540 Is_aligned_quest(&u.uz))
1541 return cur_depth;
1542
1543 /* What I really want to do is as follows:
1544 * -- If in a dungeon that goes down, the new level is to be restricted
1545 * to [top of parent, bottom of current dungeon]
1546 * -- If in a dungeon that goes up, the new level is to be restricted
1547 * to [top of current dungeon, bottom of parent]
1548 * -- If in a quest dungeon or similar dungeon entered by portals,
1549 * the new level is to be restricted to [top of current dungeon,
1550 * bottom of current dungeon]
1551 * The current behavior is not as sophisticated as that ideal, but is
1552 * still better what we used to do, which was like this for players
1553 * but different for monsters for no obvious reason. Currently, we
1554 * must explicitly check for special dungeons. We check for Knox
1555 * above; endgame is handled in the caller due to its different
1556 * message ("disoriented").
1557 * --KAA
1558 * [ALI] Also check for Sam's blackmarket and the three aligned quests
1559 * above.
1560 * 3.4.2: explicitly handle quest here too, to fix the problem of
1561 * monsters sometimes level teleporting out of it into main dungeon.
1562 * Also prevent monsters reaching the Sanctum prior to invocation.
1563 */
1564 min_depth = In_quest(&u.uz) ? dungeons[u.uz.dnum].depth_start : 1;
1565 max_depth = dunlevs_in_dungeon(&u.uz) +
1566 (dungeons[u.uz.dnum].depth_start - 1);
1567 /* can't reach the Sanctum if the invocation hasn't been performed */
1568 if (Inhell && !u.uevent.invoked) max_depth -= 1;
1569
1570 /* Get a random value relative to the current dungeon */
1571 /* Range is 1 to current+3, current not counting */
1572 nlev = rn2(cur_depth + 3 - min_depth) + min_depth;
1573 if (nlev >= cur_depth) nlev++;
1574
1575 if (nlev > max_depth) {
1576 nlev = max_depth;
1577 /* teleport up if already on bottom */
1578 if (Is_botlevel(&u.uz)) nlev -= rnd(3);
1579 }
1580 if (nlev < min_depth) {
1581 nlev = min_depth;
1582 if (nlev == cur_depth) {
1583 nlev += rnd(3);
1584 if (nlev > max_depth)
1585 nlev = max_depth;
1586 }
1587 }
1588 return nlev;
1589 }
1590
1591 /* you teleport a monster (via wand, spell, or poly'd q.mechanic attack);
1592 return false iff the attempt fails */
1593 boolean
u_teleport_mon(mtmp,give_feedback)1594 u_teleport_mon(mtmp, give_feedback)
1595 struct monst *mtmp;
1596 boolean give_feedback;
1597 {
1598 coord cc;
1599
1600 if (mtmp->ispriest && *in_rooms(mtmp->mx, mtmp->my, TEMPLE)) {
1601 if (give_feedback)
1602 pline("%s resists your magic!", Monnam(mtmp));
1603 return FALSE;
1604 } else if (level.flags.noteleport && u.uswallow && mtmp == u.ustuck) {
1605 if (give_feedback)
1606 You("are no longer inside %s!", mon_nam(mtmp));
1607 unstuck(mtmp);
1608 rloc(mtmp, FALSE);
1609 } else if (is_rider(mtmp->data) && rn2(13) &&
1610 enexto(&cc, u.ux, u.uy, mtmp->data))
1611 rloc_to(mtmp, cc.x, cc.y);
1612 else {
1613 #ifdef WIZARD
1614 if (wizard && Teleport_control)
1615 {
1616 /*
1617 * [ALI] This code will only allow monsters to be
1618 * teleported to positions acceptable to rloc_pos_ok().
1619 * We could use goodpos() which would allow more
1620 * locations but, in my view, is less informative.
1621 */
1622 xchar omx, omy;
1623 pline("To what position do you want %s to be teleported?",
1624 mon_nam(mtmp));
1625 cc.x = omx = mtmp->mx;
1626 cc.y = omy = mtmp->my;
1627 if (getpos(&cc, TRUE, "the desired position") < 0)
1628 rloc(mtmp, FALSE); /* abort */
1629 else if (rloc_pos_ok(cc.x, cc.y, mtmp)) {
1630 rloc_to(mtmp, cc.x, cc.y);
1631 /* As rloc() ... */
1632 if (mtmp->isshk && !inhishop(mtmp))
1633 make_angry_shk(mtmp, omx, omy);
1634 } else {
1635 pline("Sorry...");
1636 rloc(mtmp, FALSE);
1637 }
1638 } else
1639 #endif /* WIZARD */
1640 rloc(mtmp, FALSE);
1641 }
1642 return TRUE;
1643 }
1644 /*teleport.c*/
1645