Blindfold removal fix
[slashemextended.git] / src / teleport.c
blobd2e4cce31de14502619ddffd4a072c2884e98bdb
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. */
5 #include "hack.h"
7 STATIC_DCL boolean tele_jump_ok(int,int,int,int);
8 STATIC_DCL boolean teleokX(int,int,BOOLEAN_P);
9 STATIC_DCL boolean teleokXconfused(int,int,BOOLEAN_P);
10 STATIC_DCL void vault_tele(void);
11 STATIC_DCL boolean rloc_pos_ok(int,int,struct monst *);
12 STATIC_DCL void mvault_tele(struct monst *);
15 * Is (x, y) a bad position of mtmp? If mtmp is NULL, then is (x, y) bad
16 * for an object?
18 * Caller is responsible for checking (x, y) with isok() if required.
20 * Returns: -1: Inaccessible, 0: Good pos, 1: Temporally inacessible
22 static int
23 badpos(x, y, mtmp, gpflags)
24 int x, y;
25 struct monst *mtmp;
26 unsigned gpflags;
28 int is_badpos = 0, pool, crystalpool;
29 struct permonst *mdat = NULL;
30 boolean ignorewater = ((gpflags & MM_IGNOREWATER) != 0);
31 boolean crystalornot = ((gpflags & MM_CRYSTALORNOT) != 0);
32 struct monst *mtmp2;
34 /* in many cases, we're trying to create a new monster, which
35 * can't go on top of the player or any existing monster.
36 * however, occasionally we are relocating engravings or objects,
37 * which could be co-located and thus get restricted a bit too much.
38 * oh well.
40 if (mtmp != &youmonst && x == u.ux && y == u.uy && (!u.usteed || mtmp != u.usteed) )
41 is_badpos = 1;
43 if (mtmp) {
44 mtmp2 = m_at(x,y);
46 /* Be careful with long worms. A monster may be placed back in
47 * its own location. Normally, if m_at() returns the same monster
48 * that we're trying to place, the monster is being placed in its
49 * own location. However, that is not correct for worm segments,
50 * because all the segments of the worm return the same m_at().
51 * Actually we overdo the check a little bit--a worm can't be placed
52 * in its own location, period. If we just checked for mtmp->mx
53 * != x || mtmp->my != y, we'd miss the case where we're called
54 * to place the worm segment and the worm's head is at x,y.
56 if (mtmp2 && (mtmp2 != mtmp || mtmp->wormno))
57 is_badpos = 1;
59 mdat = mtmp->data;
60 pool = (is_waterypool(x,y) && !is_crystalwater(x,y));
62 if (crystalornot) pool = (is_drowningpool(x,y) && !is_crystalwater(x,y));
64 crystalpool = is_crystalwater(x,y);
65 if (mdat->mlet == S_EEL && !pool && rn2(13) && !ignorewater)
66 is_badpos = 1;
68 if ((mtmp == &youmonst) && (Flying || Levitation) && crystalpool) return -1;
70 if (pool && !ignorewater && !(crystalornot && (Flying || Levitation || Wwalking || Race_if(PM_KORONST)) ) ) {
72 if (mtmp == &youmonst)
73 return (HLevitation || Flying || Wwalking || Race_if(PM_KORONST) ||
74 Swimming || Amphibious) ? is_badpos : -1;
75 else return (is_flyer(mdat) || is_swimmer(mdat) ||
76 is_clinger(mdat)) ? is_badpos : -1;
77 /* note by Amy: the egotype check causes eternal phantom bugs in this function. According to FIQ, mtmp is
78 * never initialized correctly due to being a filler monster, instead of the actual one teleported. */
80 } else if (is_lava(x,y)) {
81 if (mtmp == &youmonst)
82 return HLevitation ? is_badpos : -1;
83 else
84 return (is_flyer(mdat) || likes_lava(mdat)) ?
85 is_badpos : -1;
87 if (passes_walls(mdat) && may_passwall(x,y)) return is_badpos;
88 if (u.roommatehack) {
89 return is_badpos;
92 if (!ACCESSIBLE(levl[x][y].typ) ) {
93 if (!is_farmland(x,y) && !(is_waterypool(x,y) && !u.roommatehack && (ignorewater || crystalornot))) return -1;
96 if (closed_door(x, y) && (!mdat || !amorphous(mdat)))
97 return mdat && (nohands(mdat) || verysmall(mdat)) ? -1 : 1;
98 if (sobj_at(BOULDER, x, y) && (!mdat || !throws_rocks(mdat)))
99 return mdat ? -1 : 1;
100 if (is_raincloud(x,y) && !crystalornot) return -1;
102 return is_badpos;
106 * Is (x,y) a good position of mtmp? If mtmp is NULL, then is (x,y) good
107 * for an object?
109 * This function will only look at mtmp->mdat, so makemon, mplayer, etc can
110 * call it to generate new monster positions with fake monster structures.
112 boolean
113 goodpos(x, y, mtmp, gpflags)
114 int x,y;
115 struct monst *mtmp;
116 unsigned gpflags;
118 if (!isok(x, y)) return FALSE;
120 return !badpos(x, y, mtmp, gpflags);
124 * "entity next to"
126 * Attempt to find a good place for the given monster type in the closest
127 * position to (xx,yy). Do so in successive square rings around (xx,yy).
128 * If there is more than one valid positon in the ring, choose one randomly.
129 * Return TRUE and the position chosen when successful, FALSE otherwise.
131 boolean
132 enexto(cc, xx, yy, mdat)
133 coord *cc;
134 register xchar xx, yy;
135 struct permonst *mdat;
137 return enexto_core(cc, xx, yy, mdat, 0);
140 boolean
141 enexto_core(cc, xx, yy, mdat, entflags)
142 coord *cc;
143 register xchar xx, yy;
144 struct permonst *mdat;
145 unsigned entflags;
147 #define MAX_GOOD 15
148 coord good[MAX_GOOD], *good_ptr;
149 int x, y, range, i;
150 int xmin, xmax, ymin, ymax;
151 struct monst fakemon; /* dummy monster */
153 if (!mdat) {
154 #ifdef DEBUG
155 pline("enexto() called with mdat==0");
156 #endif
157 /* default to player's original monster type */
158 mdat = &mons[u.umonster];
160 fakemon.data = mdat; /* set up for goodpos */
161 good_ptr = good;
162 range = 1;
164 * Walk around the border of the square with center (xx,yy) and
165 * radius range. Stop when we find at least one valid position.
167 do {
168 xmin = max(1, xx-range);
169 xmax = min(COLNO-1, xx+range);
170 ymin = max(0, yy-range);
171 ymax = min(ROWNO-1, yy+range);
173 for (x = xmin; x <= xmax; x++)
174 if (goodpos(x, ymin, &fakemon, entflags)) {
175 good_ptr->x = x;
176 good_ptr->y = ymin ;
177 /* beware of accessing beyond segment boundaries.. */
178 if (good_ptr++ == &good[MAX_GOOD-1]) goto full;
180 for (x = xmin; x <= xmax; x++)
181 if (goodpos(x, ymax, &fakemon, entflags)) {
182 good_ptr->x = x;
183 good_ptr->y = ymax ;
184 /* beware of accessing beyond segment boundaries.. */
185 if (good_ptr++ == &good[MAX_GOOD-1]) goto full;
187 for (y = ymin+1; y < ymax; y++)
188 if (goodpos(xmin, y, &fakemon, entflags)) {
189 good_ptr->x = xmin;
190 good_ptr-> y = y ;
191 /* beware of accessing beyond segment boundaries.. */
192 if (good_ptr++ == &good[MAX_GOOD-1]) goto full;
194 for (y = ymin+1; y < ymax; y++)
195 if (goodpos(xmax, y, &fakemon, entflags)) {
196 good_ptr->x = xmax;
197 good_ptr->y = y ;
198 /* beware of accessing beyond segment boundaries.. */
199 if (good_ptr++ == &good[MAX_GOOD-1]) goto full;
201 range++;
203 /* return if we've grown too big (nothing is valid) */
204 if (range > ROWNO && range > COLNO) return FALSE;
205 } while (good_ptr == good);
207 full:
208 i = rn2((int)(good_ptr - good));
209 cc->x = good[i].x;
210 cc->y = good[i].y;
211 return TRUE;
215 * "entity path to"
217 * Attempt to find nc good places for the given monster type with the shortest
218 * path to (xx,yy). Where there is more than one valid set of positions, one
219 * will be chosen at random. Return the number of positions found.
220 * Warning: This routine is much slower than enexto and should be used
221 * with caution.
224 #define EPATHTO_UNSEEN 0x0
225 #define EPATHTO_INACCESSIBLE 0x1
226 #define EPATHTO_DONE 0x2
227 #define EPATHTO_TAIL(n) (0x3 + ((n) & 1))
229 #define EPATHTO_XY(x,y) (((y) + 1) * COLNO + (x))
230 #define EPATHTO_Y(xy) ((xy) / COLNO - 1)
231 #define EPATHTO_X(xy) ((xy) % COLNO)
233 #ifdef DEBUG
234 coord epathto_debug_cc[100];
235 #endif
238 epathto(cc, nc, xx, yy, mdat)
239 coord *cc;
240 int nc;
241 register xchar xx, yy;
242 struct permonst *mdat;
244 int i, j, dir, ndirs, xy, x, y, r;
245 int path_len, postype;
246 int first_col, last_col;
247 int nd, n;
248 unsigned char *map;
249 static const int dirs[8] =
250 /* N, S, E, W, NW, NE, SE, SW */
251 { -COLNO, COLNO, 1, -1, -COLNO-1, -COLNO+1, COLNO+1, COLNO-1};
252 struct monst fakemon; /* dummy monster */
253 fakemon.data = mdat; /* set up for badpos */
254 map = (unsigned char *)alloc(COLNO * (ROWNO + 2));
255 (void) memset((void *)map, EPATHTO_INACCESSIBLE, COLNO * (ROWNO + 2));
256 for(i = 1; i < COLNO; i++)
257 for(j = 0; j < ROWNO; j++)
258 map[EPATHTO_XY(i, j)] = EPATHTO_UNSEEN;
259 map[EPATHTO_XY(xx, yy)] = EPATHTO_TAIL(0);
260 if (badpos(xx, yy, &fakemon, 0) == 0) {
261 cc[0].x = xx;
262 cc[0].y = yy;
263 nd = n = 1;
265 else
266 nd = n = 0;
267 for(path_len = 0; nd < nc; path_len++)
269 first_col = max(1, xx - path_len);
270 last_col = min(COLNO - 1, xx + path_len);
271 for(j = max(0, yy - path_len); j <= min(ROWNO - 1, yy + path_len); j++)
272 for(i = first_col; i <= last_col; i++)
273 if (map[EPATHTO_XY(i, j)] == EPATHTO_TAIL(path_len)) {
274 map[EPATHTO_XY(i, j)] = EPATHTO_DONE;
275 ndirs = (isgridbug(mdat)) ? 4 : 8;
276 for(dir = 0; dir < ndirs; dir++) {
277 xy = EPATHTO_XY(i, j) + dirs[dir];
278 if (map[xy] == EPATHTO_UNSEEN) {
279 x = EPATHTO_X(xy);
280 y = EPATHTO_Y(xy);
281 postype = badpos(x, y, &fakemon, 0);
282 map[xy] = postype < 0 ? EPATHTO_INACCESSIBLE :
283 EPATHTO_TAIL(path_len + 1);
284 if (postype == 0) {
285 if (n < nc)
287 cc[n].x = x;
288 cc[n].y = y;
290 else if (rn2(n - nd + 1) < nc - nd)
292 r = rn2(nc - nd) + nd;
293 cc[r].x = x;
294 cc[r].y = y;
296 ++n;
301 if (nd == n)
302 break; /* No more positions */
303 else
304 nd = n;
306 if (nd > nc)
307 nd = nc;
308 #ifdef DEBUG
309 if (cc == epathto_debug_cc)
311 winid win;
312 int glyph;
313 char row[COLNO+1];
315 win = create_nhwindow(NHW_TEXT);
316 putstr(win, 0, "");
317 for (y = 0; y < ROWNO; y++) {
318 for (x = 1; x < COLNO; x++) {
319 xy = EPATHTO_XY(x, y);
320 if (map[xy] == EPATHTO_INACCESSIBLE) {
321 glyph = back_to_glyph(x, y);
322 row[x] = showsyms[glyph_to_cmap(glyph)];
324 else
325 row[x] = ' ';
327 for (i = 0; i < nd; i++)
328 if (cc[i].y == y)
329 row[cc[i].x] = i < 10 ? '0' + i :
330 i < 36 ? 'a' + i - 10 :
331 i < 62 ? 'A' + i - 36 :
332 '?';
333 /* remove trailing spaces */
334 for (x = COLNO-1; x >= 1; x--)
335 if (row[x] != ' ') break;
336 row[x+1] = '\0';
338 putstr(win, 0, &row[1]);
340 display_nhwindow(win, TRUE);
341 destroy_nhwindow(win);
343 #endif
345 free((void *)map);
346 return nd;
350 * func should return 1 if the location should be counted as inaccessible
351 * (path won't continue through this point) or 0 if it is accessible.
354 void
355 xpathto(r, xx, yy, func, data)
356 int r;
357 register xchar xx, yy;
358 int (*func)(void *, int, int);
359 void * data;
361 int i, j, dir, xy, x, y;
362 int path_len, postype;
363 int first_col, last_col;
364 int nd, n;
365 unsigned char *map;
366 static const int dirs[8] =
367 /* N, S, E, W, NW, NE, SE, SW */
368 { -COLNO, COLNO, 1, -1, -COLNO-1, -COLNO+1, COLNO+1, COLNO-1};
369 map = (unsigned char *)alloc(COLNO * (ROWNO + 2));
370 (void) memset((void *)map, EPATHTO_INACCESSIBLE, COLNO * (ROWNO + 2));
371 for(i = 1; i < COLNO; i++)
372 for(j = 0; j < ROWNO; j++)
373 map[EPATHTO_XY(i, j)] = EPATHTO_UNSEEN;
374 map[EPATHTO_XY(xx, yy)] = EPATHTO_TAIL(0);
375 if (func(data, xx, yy) == 0)
376 nd = n = 1;
377 else
378 nd = n = 0;
379 for(path_len = 0; path_len < r; path_len++)
381 first_col = max(1, xx - path_len);
382 last_col = min(COLNO - 1, xx + path_len);
383 for(j = max(0, yy - path_len); j <= min(ROWNO - 1, yy + path_len); j++)
384 for(i = first_col; i <= last_col; i++)
385 if (map[EPATHTO_XY(i, j)] == EPATHTO_TAIL(path_len)) {
386 map[EPATHTO_XY(i, j)] = EPATHTO_DONE;
387 for(dir = 0; dir < 8; dir++) {
388 xy = EPATHTO_XY(i, j) + dirs[dir];
389 if (map[xy] == EPATHTO_UNSEEN) {
390 x = EPATHTO_X(xy);
391 y = EPATHTO_Y(xy);
392 postype = func(data, x, y);
393 map[xy] = postype ? EPATHTO_INACCESSIBLE :
394 EPATHTO_TAIL(path_len + 1);
395 if (postype == 0)
396 ++n;
400 if (nd == n)
401 break; /* No more positions */
402 else
403 nd = n;
405 free((void *)map);
408 #ifdef DEBUG
409 void
410 wiz_debug_cmd() /* in this case, run epathto on arbitary monster & goal */
412 struct permonst *ptr;
413 int mndx, i;
414 coord cc;
415 char buf[BUFSIZ];
416 for(i = 0; ; i++) {
417 if(i >= 5) {
418 pline(thats_enough_tries);
419 return;
421 getlin("What monster do you want to test? [type the name]", buf);
423 mndx = name_to_mon(buf);
424 if (mndx == NON_PM) {
425 pline("Such creatures do not exist in this world.");
426 continue;
428 ptr = &mons[mndx];
429 pline("Which position do you want to aim for?");
430 cc.x = u.ux;
431 cc.y = u.uy;
432 if (getpos(&cc, TRUE, "the goal position") < 0)
433 return; /* abort */
434 epathto(epathto_debug_cc, SIZE(epathto_debug_cc), cc.x, cc.y, ptr);
435 break;
438 #endif /* DEBUG */
441 * Check for restricted areas present in some special levels. (This might
442 * need to be augmented to allow deliberate passage in wizard mode, but
443 * only for explicitly chosen destinations.)
445 STATIC_OVL boolean
446 tele_jump_ok(x1, y1, x2, y2)
447 int x1, y1, x2, y2;
449 if (dndest.nlx > 0) {
450 /* if inside a restricted region, can't teleport outside */
451 if (within_bounded_area(x1, y1, dndest.nlx, dndest.nly,
452 dndest.nhx, dndest.nhy) &&
453 !within_bounded_area(x2, y2, dndest.nlx, dndest.nly,
454 dndest.nhx, dndest.nhy))
455 # ifdef WIZARD
456 if (!wizard)
457 # endif /* WIZARD */
458 return FALSE;
459 /* and if outside, can't teleport inside */
460 if (!within_bounded_area(x1, y1, dndest.nlx, dndest.nly,
461 dndest.nhx, dndest.nhy) &&
462 within_bounded_area(x2, y2, dndest.nlx, dndest.nly,
463 dndest.nhx, dndest.nhy))
464 # ifdef WIZARD
465 if (!wizard)
466 # endif /* WIZARD */
467 return FALSE;
469 if (updest.nlx > 0) { /* ditto */
470 if (within_bounded_area(x1, y1, updest.nlx, updest.nly,
471 updest.nhx, updest.nhy) &&
472 !within_bounded_area(x2, y2, updest.nlx, updest.nly,
473 updest.nhx, updest.nhy))
474 # ifdef WIZARD
475 if (!wizard)
476 # endif /* WIZARD */
477 return FALSE;
478 if (!within_bounded_area(x1, y1, updest.nlx, updest.nly,
479 updest.nhx, updest.nhy) &&
480 within_bounded_area(x2, y2, updest.nlx, updest.nly,
481 updest.nhx, updest.nhy))
482 # ifdef WIZARD
483 if (!wizard)
484 # endif /* WIZARD */
485 return FALSE;
487 return TRUE;
490 boolean
491 teleok(x, y, trapok)
492 register int x, y;
493 boolean trapok;
495 if (!trapok && t_at(x, y)) return FALSE;
496 if (!goodpos(x, y, &youmonst, 0)) return FALSE;
498 /* In Soviet Russia, water is considered safe as long as you can swim, because hehehe. --Amy */
500 if (is_waterypool(x, y) && !(HLevitation || Flying || Wwalking || Race_if(PM_KORONST) || (issoviet && (Swimming || Amphibious) ) )) return FALSE;
501 if (is_watertunnel(x,y) && (Levitation || Flying) && !Passes_walls) return FALSE;
502 if (is_watertunnel(x,y) && !(Levitation || Flying || (issoviet && (Swimming || Amphibious) ))) return FALSE;
504 if (!tele_jump_ok(u.ux, u.uy, x, y)) return FALSE;
505 if (!in_out_region(x, y)) return FALSE;
506 return TRUE;
509 boolean
510 teleok_normalterrain(x, y, trapok)
511 register int x, y;
512 boolean trapok;
514 if (!trapok && t_at(x, y)) return FALSE;
515 if (!goodpos(x, y, &youmonst, 0)) return FALSE;
517 /* In Soviet Russia, water is considered safe as long as you can swim, because hehehe. --Amy */
519 if (is_waterypool(x, y)) return FALSE;
520 if (is_watertunnel(x,y)) return FALSE;
521 if (!ACCESSIBLE(levl[x][y].typ) ) return FALSE;
523 if (closed_door(x, y)) return FALSE;
524 if (is_raincloud(x,y)) return FALSE;
526 if (!tele_jump_ok(u.ux, u.uy, x, y)) return FALSE;
527 if (!in_out_region(x, y)) return FALSE;
528 return TRUE;
531 STATIC_OVL boolean
532 teleokX(x, y, trapok)
533 register int x, y;
534 boolean trapok;
536 int udist = distu(x,y);
538 if (!trapok && t_at(x, y)) return FALSE;
539 if (!goodpos(x, y, &youmonst, 0)) return FALSE;
541 if (is_waterypool(x, y) && !(HLevitation || Flying || Wwalking || Race_if(PM_KORONST))) return FALSE;
542 if (is_watertunnel(x,y) && (Levitation || Flying) && !Passes_walls) return FALSE;
543 if (is_watertunnel(x,y) && !(Levitation || Flying)) return FALSE;
545 if (!tele_jump_ok(u.ux, u.uy, x, y)) return FALSE;
546 if (!in_out_region(x, y)) return FALSE;
547 if (udist < 3) return FALSE;
548 if (udist > 100) return FALSE;
550 return TRUE;
553 STATIC_OVL boolean
554 teleokXconfused(x, y, trapok)
555 register int x, y;
556 boolean trapok;
558 int udist = distu(x,y);
560 if (!trapok && t_at(x, y)) return FALSE;
561 if (!goodpos(x, y, &youmonst, 0)) return FALSE;
563 if (is_waterypool(x, y) && !(HLevitation || Flying || Wwalking || Race_if(PM_KORONST))) return FALSE;
564 if (is_watertunnel(x,y) && (Levitation || Flying) && !Passes_walls) return FALSE;
565 if (is_watertunnel(x,y) && !(Levitation || Flying)) return FALSE;
567 if (!tele_jump_ok(u.ux, u.uy, x, y)) return FALSE;
568 if (!in_out_region(x, y)) return FALSE;
569 if (udist < 3) return FALSE;
570 if (udist > 200) return FALSE;
572 return TRUE;
575 void
576 teleds(nux, nuy, allow_drag)
577 register int nux,nuy;
578 boolean allow_drag;
580 boolean ball_active = (Punished && uball->where != OBJ_FREE),
581 ball_still_in_range = FALSE;
583 /* If they have to move the ball, then drag if allow_drag is true;
584 * otherwise they are teleporting, so unplacebc().
585 * If they don't have to move the ball, then always "drag" whether or
586 * not allow_drag is true, because we are calling that function, not
587 * to drag, but to move the chain. *However* there are some dumb
588 * special cases:
589 * 0 0
590 * _X move east -----> X_
591 * @ @
592 * These are permissible if teleporting, but not if dragging. As a
593 * result, drag_ball() needs to know about allow_drag and might end
594 * up dragging the ball anyway. Also, drag_ball() might find that
595 * dragging the ball is completely impossible (ball in range but there's
596 * rock in the way), in which case it teleports the ball on its own.
598 if (ball_active) {
599 if (!carried(uball) && distmin(nux, nuy, uball->ox, uball->oy) <= 2)
600 ball_still_in_range = TRUE; /* don't have to move the ball */
601 else {
602 /* have to move the ball */
603 if (!allow_drag || distmin(u.ux, u.uy, nux, nuy) > 1) {
604 /* we should not have dist > 1 and allow_drag at the same
605 * time, but just in case, we must then revert to teleport.
607 allow_drag = FALSE;
608 unplacebc();
612 u.utrap = 0;
613 setustuck(0);
614 u.ux0 = u.ux;
615 u.uy0 = u.uy;
617 if (hides_under(youmonst.data) || (uarmh && itemhasappearance(uarmh, APP_SECRET_HELMET) ) || (!night() && uarmg && uarmg->oartifact == ART_NIGHTLY_HIGHWAY) || (uarmc && uarmc->oartifact == ART_JANA_S_EXTREME_HIDE_AND_SE))
618 u.uundetected = OBJ_AT(nux, nuy);
619 else if (is_wagon(nux, nuy))
620 u.uundetected = TRUE;
621 else if (youmonst.data->mlet == S_EEL)
622 u.uundetected = is_waterypool(nux, nuy);
623 else {
624 u.uundetected = 0;
625 /* mimics stop being unnoticed */
626 if (youmonst.data->mlet == S_MIMIC)
627 youmonst.m_ap_type = M_AP_NOTHING;
630 if (u.uswallow) {
631 u.uswldtim = u.uswallow = 0;
632 if (Punished && !ball_active) {
633 /* ensure ball placement, like unstuck */
634 ball_active = TRUE;
635 allow_drag = FALSE;
637 docrt();
639 if (ball_active) {
640 if (ball_still_in_range || allow_drag) {
641 int bc_control;
642 xchar ballx, bally, chainx, chainy;
643 boolean cause_delay;
645 if (drag_ball(nux, nuy, &bc_control, &ballx, &bally,
646 &chainx, &chainy, &cause_delay, allow_drag))
647 move_bc(0, bc_control, ballx, bally, chainx, chainy);
650 /* must set u.ux, u.uy after drag_ball(), which may need to know
651 the old position if allow_drag is true... */
652 u.ux = nux;
653 u.uy = nuy;
654 fill_pit(u.ux0, u.uy0);
655 if (ball_active) {
656 if (!ball_still_in_range && !allow_drag)
657 placebc();
659 initrack(); /* teleports mess up tracking monsters without this */
660 update_player_regions();
661 /* Move your steed, too */
662 if (u.usteed) {
663 u.usteed->mx = nux;
664 u.usteed->my = nuy;
668 * Make sure the hero disappears from the old location. This will
669 * not happen if she is teleported within sight of her previous
670 * location. Force a full vision recalculation because the hero
671 * is now in a new location.
673 newsym(u.ux0,u.uy0);
674 see_monsters();
675 vision_full_recalc = 1;
676 nomul(0, 0, FALSE);
677 vision_recalc(0); /* vision before effects */
678 spoteffects(TRUE);
679 invocation_message();
682 boolean
683 safe_teleds(allow_drag)
684 boolean allow_drag;
686 register int nux, nuy, tcnt = 0;
688 do {
689 nux = rnd(COLNO-1);
690 nuy = rn2(ROWNO);
691 } while (!teleok(nux, nuy, (boolean)(tcnt > 200)) && ++tcnt <= 400);
693 if (tcnt <= 400) {
694 teleds(nux, nuy, allow_drag);
695 return TRUE;
696 } else
697 return FALSE;
700 /* safer teleportation that always ignores stuff like phaseable walls, water and so on --Amy
701 * used for e.g. automatic relocation when entering forging chambers, where we really don't want players to end up
702 * outside of the actual playing field with sucky odds of getting back (e.g. sokoban level clones) */
703 boolean
704 safe_teleds_normalterrain(allow_drag)
705 boolean allow_drag;
707 register int nux, nuy, tcnt = 0;
709 do {
710 nux = rnd(COLNO-1);
711 nuy = rn2(ROWNO);
712 } while (!teleok_normalterrain(nux, nuy, (boolean)(tcnt > 200)) && ++tcnt <= 4000);
714 if (tcnt <= 4000) {
715 teleds(nux, nuy, allow_drag);
716 return TRUE;
717 } else /* still didn't find a place? grudgingly use the regular method then */
719 do {
720 nux = rnd(COLNO-1);
721 nuy = rn2(ROWNO);
722 } while (!teleok(nux, nuy, (boolean)(tcnt > 200)) && ++tcnt <= 400);
724 if (tcnt <= 400) {
725 teleds(nux, nuy, allow_drag);
726 return TRUE;
731 return FALSE;
734 boolean
735 safe_teledsPD(confused)
736 boolean confused;
738 register int nux, nuy, tcnt, udist, goodspot = 0;
739 tcnt = 0;
741 if (confused) do {
742 nux = rnd(COLNO-1);
743 nuy = rn2(ROWNO);
744 } while (!teleokXconfused(nux, nuy, (boolean)(tcnt > 200)) && ++tcnt <= 2000 );
746 if (!confused) do {
747 nux = rnd(COLNO-1);
748 nuy = rn2(ROWNO);
749 } while (!teleokX(nux, nuy, (boolean)(tcnt > 200)) && ++tcnt <= 2000 );
751 if (tcnt <= 2000) {
752 /*pline("Phase door destination: %d,%d", nux, nuy);*/
753 /* this debug information is no longer needed now --Amy */
755 teleds(nux, nuy, 0);
756 return TRUE;
757 } else {
758 /*pline("Phase door failed. Destination would have been: %d,%d", nux, nuy);*/
760 return FALSE;
764 boolean
765 safe_teledsNOTRAP(allow_drag)
766 boolean allow_drag;
768 register int nux, nuy, tcnt = 0;
770 do {
771 nux = rnd(COLNO-1);
772 nuy = rn2(ROWNO);
773 } while ((!teleok(nux, nuy, (boolean)(tcnt > 200)) || (t_at(nux, nuy)) ) && ++tcnt <= 400);
775 if (tcnt <= 400) {
776 teleds(nux, nuy, allow_drag);
777 return TRUE;
778 } else
779 return FALSE;
782 STATIC_OVL void
783 vault_tele()
785 register struct mkroom *croom = search_special(VAULT);
786 coord c;
788 if (croom && somexy(croom, &c) && teleok(c.x,c.y,FALSE)) {
789 teleds(c.x,c.y,FALSE);
790 return;
792 tele();
795 boolean
796 teleport_pet(mtmp, force_it)
797 register struct monst *mtmp;
798 boolean force_it;
800 register struct obj *otmp;
802 if (mtmp == u.usteed)
803 return (FALSE);
805 if (mtmp->mleashed) {
806 otmp = get_mleash(mtmp);
807 if (!otmp) {
808 impossible("%s is leashed, without a leash.", Monnam(mtmp));
809 goto release_it;
811 if (otmp->cursed && !force_it) {
812 yelp(mtmp);
813 return FALSE;
814 } else {
815 Your("leash goes slack.");
816 release_it:
817 m_unleash(mtmp, FALSE);
818 return TRUE;
821 return TRUE;
824 void
825 tele()
827 coord cc;
829 /* Disable teleportation in stronghold && Vlad's Tower */
830 if ((level.flags.noteleport || Race_if(PM_STABILISATOR) || u.antitelespelltimeout) && !Race_if(PM_RODNEYAN) ) {
831 #ifdef WIZARD
832 if (!wizard) {
833 #endif
834 pline("A mysterious force prevents you from teleporting!");
835 return;
836 #ifdef WIZARD
838 #endif
841 /* don't show trap if "Sorry..." */
842 if (!Blinded) make_blinded(0L,FALSE);
845 #ifdef WIZARD
847 #endif
848 ((u.uhave.amulet && !u.freeplaymode && (u.amuletcompletelyimbued || !rn2(3))) || CannotTeleport || On_W_tower_level(&u.uz)
849 || (u.usteed && mon_has_amulet(u.usteed))
851 #ifdef WIZARD
852 && (!wizard) )
853 #endif
855 You_feel("disoriented for a moment.");
856 return;
859 /* at this point, you will definitely be teleported... unless something prevents it */
862 boolean teletrapactive = FALSE;
863 struct monst *teletrapmon;
864 for (teletrapmon = fmon; teletrapmon; teletrapmon = teletrapmon->nmon) {
865 if (DEADMONSTER(teletrapmon)) continue;
866 if (teletrapmon->mnum == PM_TELEPORT_TRAP) {
867 teletrapactive = TRUE;
868 break;
872 if (teletrapactive) {
874 int nastytrapdur = (Role_if(PM_GRADUATE) ? 6 : Role_if(PM_GEEK) ? 12 : 24);
875 if (!nastytrapdur) nastytrapdur = 24; /* fail safe */
876 int blackngdur = (Role_if(PM_GRADUATE) ? 2000 : Role_if(PM_GEEK) ? 1000 : 500);
877 if (!blackngdur ) blackngdur = 500; /* fail safe */
878 randomnastytrapeffect(rnz(nastytrapdur * (monster_difficulty() + 1)), blackngdur - (monster_difficulty() * 3));
880 badeffect();
881 return;
886 if ((Teleport_control && !Stunned && (!level.flags.has_insideroom || !rn2(5)) && rn2(StrongTeleport_control ? 20 : 4)) /* low chance for tele control to fail --Amy */
887 #ifdef WIZARD
888 || (wizard && yn_function("Invoke wizard-mode teleport control?", ynchars, 'y') == 'y')
889 #endif
891 if (unconscious()) {
892 pline("Being unconscious, you cannot control your teleport.");
893 } else {
894 char buf[BUFSZ];
895 if (u.usteed) sprintf(buf," and %s", mon_nam(u.usteed));
896 pline("To what position do you%s want to be teleported?", u.usteed ? buf : "");
897 cc.x = u.ux;
898 cc.y = u.uy;
899 if (getpos(&cc, TRUE, "the desired position") < 0)
900 return; /* abort */
901 /* possible extensions: introduce a small error if
902 magic power is low; allow transfer to solid rock */
904 /* Amy edit: teleporting on a trap will trigger it, instead of being invalid. I've specifically made it
905 * so that weird-looking rooms make teleport control likely to fail, but if you spam-spam-spam Ctrl-T to
906 * skip past that and teleport on the pentagram anyway, and there's a trap on it, well... :P */
907 if (teleok(cc.x, cc.y, TRUE)) {
908 teleds(cc.x, cc.y, FALSE);
909 return;
911 pline("Sorry...");
915 u.cnd_teleportcount++;
916 (void) safe_teleds(FALSE);
919 void
920 teleX()
922 /* Disable teleportation in stronghold && Vlad's Tower */
923 if ((level.flags.noteleport || Race_if(PM_STABILISATOR) || u.antitelespelltimeout) && !Race_if(PM_RODNEYAN) ) {
924 pline("A mysterious force prevents you from teleporting!");
925 return;
928 /* don't show trap if "Sorry..." */
929 if (!Blinded) make_blinded(0L,FALSE);
932 ((u.uhave.amulet && !u.freeplaymode && (u.amuletcompletelyimbued || !rn2(3))) || CannotTeleport || On_W_tower_level(&u.uz)
933 || (u.usteed && mon_has_amulet(u.usteed))
936 You_feel("disoriented for a moment.");
937 return;
939 u.cnd_teleportcount++;
940 (void) safe_teleds(FALSE);
943 void
944 phase_door(confused)
945 boolean confused;
947 /* Disable teleportation in stronghold && Vlad's Tower */
948 if ((level.flags.noteleport || Race_if(PM_STABILISATOR) || u.antitelespelltimeout) && !Race_if(PM_RODNEYAN) ) {
949 pline("A mysterious force prevents you from phasing!");
950 return;
954 ((u.uhave.amulet && !u.freeplaymode && (u.amuletcompletelyimbued || !rn2(3))) || CannotTeleport || On_W_tower_level(&u.uz)
955 || (u.usteed && mon_has_amulet(u.usteed))
958 You_feel("disoriented for a moment.");
959 return;
961 #ifdef PUBLIC_SERVER
962 pline("Your body is transported to another location!"); /* for debug purposes --Amy */
963 #endif
964 u.cnd_phasedoorcount++;
965 (void) safe_teledsPD(confused);
968 /* the player has used the Ctrl-T or "dotele" command, as opposed to automatically trying to teleport after falling into
969 * a pool of water or something. This is a very powerful ability that only costs 30 Pw, so there needs to be a downside */
971 dotele()
973 return dotele_post(TRUE);
977 dotele_post(costly)
978 boolean costly;
980 struct trap *trap;
981 boolean reallycostly = FALSE;
983 trap = t_at(u.ux, u.uy);
984 if (trap && (!trap->tseen || trap->ttyp != TELEP_TRAP))
985 trap = 0;
987 if (trap) {
988 if (trap->once) {
989 pline("This is a vault teleport, usable once only.");
990 if (yn("Jump in?") == 'n')
991 trap = 0;
992 else {
993 deltrap(trap);
994 newsym(u.ux, u.uy);
997 if (trap)
998 You("%s onto the teleportation trap.",
999 locomotion(youmonst.data, "jump"));
1001 if (!trap) {
1002 boolean castit = FALSE;
1003 register int sp_no = 0, energy = 0;
1005 if ((!Teleportation || (u.ulevel < (Race_if(PM_LICH_WARRIOR) ? 1 : Race_if(PM_RODNEYAN) ? 1 : Role_if(PM_WIZARD) ? 8 : 12) && !can_teleport(youmonst.data))) && !(uarmf && uarmf->oartifact == ART_HAWAIIAN_KAMEHAMEHA) && !(uarmh && uarmh->oartifact == ART_TRIP_TERRAIN)) {
1006 /* Try to use teleport away spell. */
1007 if (objects[SPE_TELEPORT_AWAY].oc_name_known && !Confusion && !costly) {
1008 for (sp_no = 0; sp_no < MAXSPELL; sp_no++) {
1009 if (spl_book[sp_no].sp_id == SPE_TELEPORT_AWAY) {
1010 castit = TRUE;
1011 break;
1013 if (spl_book[sp_no].sp_id == SPE_TELEPORT_SELF) {
1014 castit = TRUE;
1015 break;
1019 #ifdef WIZARD
1020 if (!wizard) {
1021 #endif
1022 if (!castit) {
1023 if (!Teleportation)
1024 You("don't know that spell.");
1025 else You("are not able to teleport at will.");
1026 return(0);
1028 #ifdef WIZARD
1030 #endif
1032 else if (!wizard) {
1033 reallycostly = TRUE; /* no trap, and using teleportitis at will */
1036 if ( (u.uhunger <= (costly ? 100 : 30)) || ACURR(A_STR) < 6) {
1037 #ifdef WIZARD
1038 if (!wizard) {
1039 #endif
1040 You("lack the strength %s.",
1041 castit ? "for a teleport spell" : "to teleport");
1042 return /*1*/0;
1043 #ifdef WIZARD
1045 #endif
1048 energy = objects[SPE_TELEPORT_AWAY].oc_level * 5; /* even if it was teleport self (arbitrary) --Amy */
1049 if (costly) energy = 100;
1050 if (powerfulimplants() && uimplant && uimplant->oartifact == ART_KATRIN_S_SUDDEN_APPEARANCE) energy /= 2;
1051 if (uarmh && uarmh->oartifact == ART_TRIP_TERRAIN) energy /= 3;
1052 if (u.uen < energy) {
1053 #ifdef WIZARD
1054 if (wizard)
1055 energy = u.uen;
1056 else
1057 #endif
1059 You("lack the energy %s. You need at least %d.",
1060 castit ? "for a teleport spell" : "to teleport", energy);
1061 return /*1*/0;
1065 /* unless you have double teleportitis, which will be the case very rarely, you'll be unable to control it */
1066 if (reallycostly && !StrongTeleportation) u.uprops[DEAC_TELEPORT_CONTROL].intrinsic++;
1068 if (check_capacity(
1069 "Your concentration falters from carrying so much."))
1070 return 1;
1072 if (castit) {
1073 exercise(A_WIS, TRUE);
1074 if (spelleffects(sp_no, TRUE))
1075 return(1);
1076 else
1077 #ifdef WIZARD
1078 if (!wizard)
1079 #endif
1080 return(0);
1081 } else {
1082 u.uen -= energy;
1083 flags.botl = 1;
1087 if (next_to_u()) {
1088 if (trap && trap->once) vault_tele();
1089 else {
1090 tele();
1091 /* using teleportitis at will now stuns you, to reduce the player's ability to abuse it --Amy */
1092 if (reallycostly) make_stunned(HStun + rn1(3,3), TRUE);
1094 (void) next_to_u();
1095 } else {
1096 You("%s", shudder_for_moment);
1097 return(0);
1099 if (!trap) morehungry(costly ? 100 : 30);
1100 return(1);
1103 void
1104 level_tele()
1106 register int newlev;
1107 d_level newlevel;
1108 const char *escape_by_flying = 0; /* when surviving dest of -N */
1109 char buf[BUFSZ];
1110 boolean force_dest = FALSE;
1111 if (iflags.debug_fuzzer) goto random_levtport;
1113 if (((u.uhave.amulet && !u.freeplaymode) || CannotTeleport || In_endgame(&u.uz) || In_sokoban_real(&u.uz) || (Role_if(PM_CAMPERSTRIKER) && In_quest(&u.uz)) || (u.usteed && mon_has_amulet(u.usteed)) )
1114 #ifdef WIZARD
1115 && !wizard
1116 #endif
1118 You_feel("very disoriented for a moment.");
1120 if (uarmh && itemhasappearance(uarmh, APP_WEEPING_HELMET) ) {
1121 pline("Your helmet does not like the idea of blocked level teleportation!");
1122 losexp("weeping helmet", TRUE, FALSE);
1123 /* This ignores level-drain resistance (not a bug). --Amy */
1127 if (RngeWeeping) {
1129 You_hear("faint weeping...");
1130 losexp("weeping", TRUE, FALSE);
1134 return;
1136 /* Skipping the quest via teleport control is lame. --Amy */
1137 if ((Teleport_control && !(In_quest(&u.uz)) && !(In_minotaurmaze(&u.uz)) && !Stunned && (!level.flags.has_insideroom || !rn2(5)) && rn2(StrongTeleport_control ? 10 : 3)) /* Teleport control might not always work. --Amy */
1138 #ifdef WIZARD
1139 || (wizard && yn_function("Invoke wizard-mode teleport control?", ynchars, 'y') == 'y')
1140 #endif
1142 char qbuf[BUFSZ];
1143 int trycnt = 0;
1145 strcpy(qbuf, "To what level do you want to teleport?");
1146 do {
1147 if (++trycnt == 2) {
1148 #ifdef WIZARD
1149 if (wizard) strcat(qbuf, " [type a number or ? for a menu]");
1150 else
1151 #endif
1152 strcat(qbuf, " [type a number]");
1154 getlin(qbuf, buf);
1155 if (!strcmp(buf,"\033")) { /* cancelled */
1156 if (Confusion && rnl(5)) {
1157 pline("Uh-oh..."); /* don't make player jump out of their seat with a fake panic message! --Amy */
1158 goto random_levtport;
1160 return;
1161 } else if (!strcmp(buf,"*")) {
1162 goto random_levtport;
1163 } else if (Confusion && rnl(5)) {
1164 pline("Uh-oh...");
1165 goto random_levtport;
1167 #ifdef WIZARD
1168 if (wizard && !strcmp(buf,"?")) {
1169 schar destlev = 0;
1170 xchar destdnum = 0;
1172 if ((newlev = (int)print_dungeon(TRUE, &destlev, &destdnum))) {
1173 newlevel.dnum = destdnum;
1174 newlevel.dlevel = destlev;
1175 if (In_endgame(&newlevel) && !In_endgame(&u.uz)) {
1176 sprintf(buf,
1177 "Destination is earth level");
1178 if (!u.uhave.amulet) {
1179 struct obj *obj;
1180 obj = mksobj(AMULET_OF_YENDOR, TRUE, FALSE, FALSE);
1181 if (obj) {
1182 obj = addinv(obj);
1183 strcat(buf, " with the amulet");
1186 assign_level(&newlevel, &earth_level);
1187 pline("%s.", buf);
1189 force_dest = TRUE;
1190 } else return;
1191 } else
1192 #endif
1193 if ((newlev = lev_by_name(buf)) == 0) {
1194 #ifdef WIZARD
1195 s_level *slev;
1197 /* if you're using wizard mode, you shouldn't really need
1198 * the game to interpret things like `mine town level' */
1200 if (wizard && (slev = find_level(buf))) {
1202 schedule_goto(&slev->dlevel, FALSE, FALSE, 0,
1203 (char *)0, (char *)0);
1204 return;
1206 #endif
1207 newlev = atoi(buf);
1209 } while (!newlev && !digit(buf[0]) &&
1210 (buf[0] != '-' || !digit(buf[1])) &&
1211 trycnt < 10);
1213 /* no dungeon escape via this route */
1214 if (newlev == 0) {
1215 if (trycnt >= 10)
1216 goto random_levtport;
1217 if (ynq("Go to Nowhere. Are you sure?") != 'y') return;
1218 u.youaredead = 1;
1219 You("%s in agony as your body begins to warp...",
1220 is_silent(youmonst.data) ? "writhe" : "scream");
1221 display_nhwindow(WIN_MESSAGE, FALSE);
1222 You("cease to exist.");
1223 if (invent) Your("possessions land on the %s with a thud.",
1224 surface(u.ux, u.uy));
1225 killer_format = NO_KILLER_PREFIX;
1226 killer = "committed suicide";
1227 done(DIED);
1228 u.youaredead = 0;
1229 pline("An energized cloud of dust begins to coalesce.");
1230 Your("body rematerializes%s.", invent ?
1231 ", and you gather up all your possessions" : "");
1232 return;
1235 /* if in Knox and the requested level > 0, stay put.
1236 * we let negative values requests fall into the "heaven" loop.
1237 * [ALI] Add other single level dungeons entered via portal.
1239 if ((Is_knox(&u.uz) ||
1240 Is_blackmarket(&u.uz) ||
1241 Is_aligned_quest(&u.uz)) && newlev > 0) {
1242 You("%s", shudder_for_moment);
1243 return;
1245 /* if in Quest, the player sees "Home 1", etc., on the status
1246 * line, instead of the logical depth of the level. controlled
1247 * level teleport request is likely to be relativized to the
1248 * status line, and consequently it should be incremented to
1249 * the value of the logical depth of the target level.
1251 * we let negative values requests fall into the "heaven" loop.
1253 if (In_quest(&u.uz) && newlev > 0)
1254 newlev = newlev + dungeons[u.uz.dnum].depth_start - 1;
1255 } else { /* involuntary level tele */
1256 random_levtport:
1257 newlev = random_teleport_level();
1258 if (newlev == depth(&u.uz)) {
1259 You("%s", shudder_for_moment);
1260 return;
1264 if (!next_to_u()) {
1265 You("%s", shudder_for_moment);
1266 return;
1268 #ifdef WIZARD
1269 if (In_endgame(&u.uz)) { /* must already be wizard */
1270 int llimit = dunlevs_in_dungeon(&u.uz);
1272 if (newlev >= 0 || newlev <= -llimit) {
1273 You_cant("get there from here.");
1274 return;
1276 newlevel.dnum = u.uz.dnum;
1277 newlevel.dlevel = llimit + newlev;
1278 schedule_goto(&newlevel, FALSE, FALSE, 0, (char *)0, (char *)0);
1279 return;
1281 #endif
1282 killer = 0; /* still alive, so far... */
1284 if (iflags.debug_fuzzer && newlev < 0) goto random_levtport;
1286 if (newlev < 0 && !force_dest) {
1287 if (*u.ushops0) {
1288 /* take unpaid inventory items off of shop bills */
1289 in_mklev = TRUE; /* suppress map update */
1290 u_left_shop(u.ushops0, TRUE);
1291 /* you're now effectively out of the shop */
1292 *u.ushops0 = *u.ushops = '\0';
1293 in_mklev = FALSE;
1295 if (newlev <= -10) {
1296 You("arrive in heaven.");
1297 verbalize("Thou art early, but we'll admit thee.");
1298 killer_format = NO_KILLER_PREFIX;
1299 killer = "went to heaven prematurely";
1300 } else if (newlev == -9) {
1301 You_feel("deliriously happy. ");
1302 pline("(In fact, you're on Cloud 9!) ");
1303 display_nhwindow(WIN_MESSAGE, FALSE);
1304 } else
1305 You("are now high above the clouds...");
1307 if (killer) {
1308 ; /* arrival in heaven is pending */
1309 } else if (Levitation) {
1310 escape_by_flying = "float gently down to earth";
1311 } else if (Flying) {
1312 escape_by_flying = "fly down to the ground";
1313 } else {
1314 pline("Unfortunately, you don't know how to fly.");
1315 You("plummet a few thousand feet to your death.");
1316 sprintf(buf,
1317 "teleported out of the dungeon and fell to %s death",
1318 uhis());
1319 killer = buf;
1320 killer_format = NO_KILLER_PREFIX;
1324 if (killer) { /* the chosen destination was not survivable */
1325 d_level lsav;
1327 /* set specific death location; this also suppresses bones */
1328 lsav = u.uz; /* save current level, see below */
1329 u.uz.dnum = 0; /* main dungeon */
1330 u.uz.dlevel = (newlev <= -10) ? -10 : 0; /* heaven or surface */
1331 done(DIED);
1332 /* can only get here via life-saving (or declining to die in
1333 explore|debug mode); the hero has now left the dungeon... */
1334 escape_by_flying = "find yourself back on the surface";
1335 u.uz = lsav; /* restore u.uz so escape code works */
1338 /* calls done(ESCAPED) if newlevel==0 */
1339 if (escape_by_flying) {
1340 You("%s.", escape_by_flying);
1341 newlevel.dnum = 0; /* specify main dungeon */
1342 newlevel.dlevel = 0; /* escape the dungeon */
1343 /* [dlevel used to be set to 1, but it doesn't make sense to
1344 teleport out of the dungeon and float or fly down to the
1345 surface but then actually arrive back inside the dungeon] */
1346 } else if (u.uz.dnum == medusa_level.dnum &&
1347 newlev >= dungeons[u.uz.dnum].depth_start +
1348 dunlevs_in_dungeon(&u.uz)) {
1349 #ifdef WIZARD
1350 if (!(wizard && force_dest))
1351 #endif
1352 find_hell(&newlevel);
1353 } else {
1354 /* if invocation did not yet occur, teleporting into
1355 * the last level of Gehennom is forbidden.
1357 #ifdef WIZARD
1358 if (!wizard)
1359 #endif
1360 if (In_gehennom(&u.uz) && !u.uevent.invoked &&
1361 newlev >= (dungeons[u.uz.dnum].depth_start +
1362 dunlevs_in_dungeon(&u.uz) - 1)) {
1363 # ifdef WIZARD
1364 if (!wizard)
1366 # endif /* WIZARD */
1367 newlev = dungeons[u.uz.dnum].depth_start +
1368 dunlevs_in_dungeon(&u.uz) - 2;
1369 pline("Sorry...");
1370 # ifdef WIZARD
1372 # endif /* WIZARD */
1375 /* no teleporting out of quest dungeon */
1377 # ifdef WIZARD
1378 ((!wizard) &&
1379 # endif /* WIZARD */
1380 (In_quest(&u.uz) && newlev < depth(&qstart_level))
1381 # ifdef WIZARD
1383 # endif /* WIZARD */
1384 newlev = depth(&qstart_level);
1385 /* the player thinks of levels purely in logical terms, so
1386 * we must translate newlev to a number relative to the
1387 * current dungeon.
1389 #ifdef WIZARD
1390 if (!(wizard && force_dest))
1391 #endif
1392 get_level(&newlevel, newlev);
1394 u.cnd_telelevelcount++;
1396 schedule_goto(&newlevel, FALSE, FALSE, 0, (char *)0, (char *)0);
1397 /* in case player just read a scroll and is about to be asked to
1398 call it something, we can't defer until the end of the turn */
1399 if (u.utotype && !flags.mon_moving) deferred_goto();
1402 void
1403 domagicportal(ttmp)
1404 register struct trap *ttmp;
1406 struct d_level target_level;
1408 if (!next_to_u()) {
1409 You("%s", shudder_for_moment);
1410 return;
1413 /* if landed from another portal, do nothing */
1414 /* problem: level teleport landing escapes the check */
1415 if (!on_level(&u.uz, &u.uz0)) return;
1417 You("activated a magic portal!");
1419 if (!rn2(isfriday ? 3 : 5)) u.stairscumslowing += rn1(5,5);
1421 /* prevent the poor shnook, whose amulet was stolen while in
1422 * the endgame, from accidently triggering the portal to the
1423 * next level, and thus losing the game
1425 if (In_endgame(&u.uz) && !u.uhave.amulet && !u.freeplaymode) {
1426 You_feel("dizzy for a moment, but nothing happens...");
1427 return;
1430 target_level = ttmp->dst;
1432 /* a slashem bug: it always panics if you're punished on water... should be fixed now --Amy */
1433 /*if (In_endgame(&u.uz) && Punished && Is_firelevel(&u.uz) ) {
1434 You_feel("the iron ball preventing you from proceeding...");
1435 return;
1438 schedule_goto(&target_level, FALSE, FALSE, 1,
1439 "You feel dizzy for a moment, but the sensation passes.",
1440 (char *)0);
1444 void
1445 tele_trap(trap)
1446 struct trap *trap;
1448 if (In_endgame(&u.uz) || Antimagic) {
1449 if (Antimagic)
1450 shieldeff(u.ux, u.uy);
1451 You_feel("a wrenching sensation.");
1452 } else if (!next_to_u()) {
1453 You("%s", shudder_for_moment);
1454 } else if (trap->once) {
1455 You("%s onto a vault teleporter!",
1456 Levitation ? (const char *)"float" :
1457 locomotion(youmonst.data, "step"));
1458 if (flags.moreforced && !MessagesSuppressed) display_nhwindow(WIN_MESSAGE, TRUE); /* --More-- */
1459 deltrap(trap);
1460 newsym(u.ux,u.uy); /* get rid of trap symbol */
1461 vault_tele();
1462 } else {
1463 You("%s onto a teleport trap!",
1464 Levitation ? (const char *)"float" :
1465 locomotion(youmonst.data, "step"));
1466 if (flags.moreforced && !MessagesSuppressed) display_nhwindow(WIN_MESSAGE, TRUE); /* --More-- */
1467 tele();
1471 /* beamer trap - ignores magic resistance --Amy */
1472 void
1473 tele_trapX(trap)
1474 struct trap *trap;
1476 if (In_endgame(&u.uz)) {
1477 You_feel("a wrenching sensation.");
1478 } else if (!next_to_u()) {
1479 You("%s", shudder_for_moment);
1480 } else if (trap->once) {
1481 You("%s onto a vault teleporter!",
1482 Levitation ? (const char *)"float" :
1483 locomotion(youmonst.data, "step"));
1484 if (flags.moreforced && !MessagesSuppressed) display_nhwindow(WIN_MESSAGE, TRUE); /* --More-- */
1485 deltrap(trap);
1486 newsym(u.ux,u.uy); /* get rid of trap symbol */
1487 vault_tele();
1488 } else {
1489 You("%s onto a teleport trap!",
1490 Levitation ? (const char *)"float" :
1491 locomotion(youmonst.data, "step"));
1492 if (flags.moreforced && !MessagesSuppressed) display_nhwindow(WIN_MESSAGE, TRUE); /* --More-- */
1493 tele();
1497 void
1498 level_tele_trap(trap)
1499 struct trap *trap;
1501 You("%s onto a level teleport trap!",
1502 Levitation ? (const char *)"float" :
1503 locomotion(youmonst.data, "step"));
1504 if (Antimagic) {
1505 shieldeff(u.ux, u.uy);
1507 if (Antimagic || In_endgame(&u.uz)) {
1508 You_feel("a wrenching sensation.");
1509 return;
1511 if (!Blind) {
1512 You("are momentarily blinded by a flash of light.");
1513 if (evilfriday) make_blinded(Blinded+rnz(100),FALSE);
1514 } else
1515 You("are momentarily disoriented.");
1516 deltrap(trap);
1517 newsym(u.ux,u.uy); /* get rid of trap symbol */
1518 if (!playerlevelportdisabled()) level_tele();
1519 else pline("The trap doesn't seem to have any effect on you.");
1522 /* level beamer: ignores magic resistance --Amy */
1523 void
1524 level_tele_trapX(trap)
1525 struct trap *trap;
1527 You("%s onto a level teleport trap!",
1528 Levitation ? (const char *)"float" :
1529 locomotion(youmonst.data, "step"));
1530 if (In_endgame(&u.uz)) {
1531 You_feel("a wrenching sensation.");
1532 return;
1534 if (!Blind) {
1535 You("are momentarily blinded by a flash of light.");
1536 if (evilfriday) make_blinded(Blinded+rnz(100),FALSE);
1537 } else
1538 You("are momentarily disoriented.");
1539 deltrap(trap);
1540 newsym(u.ux,u.uy); /* get rid of trap symbol */
1541 if (!playerlevelportdisabled()) level_tele();
1542 else pline("The trap doesn't seem to have any effect on you.");
1545 /* check whether monster can arrive at location <x,y> via Tport (or fall) */
1546 STATIC_OVL boolean
1547 rloc_pos_ok(x, y, mtmp)
1548 register int x, y; /* coordinates of candidate location */
1549 struct monst *mtmp;
1551 register int xx, yy;
1553 if (!goodpos(x, y, mtmp, 0)) return FALSE;
1555 * Check for restricted areas present in some special levels.
1557 * `xx' is current column; if 0, then `yy' will contain flag bits
1558 * rather than row: bit #0 set => moving upwards; bit #1 set =>
1559 * inside the Wizard's tower.
1561 xx = mtmp->mx;
1562 yy = mtmp->my;
1563 if (!xx) {
1564 /* no current location (migrating monster arrival) */
1565 if (dndest.nlx && On_W_tower_level(&u.uz))
1566 return ((yy & 2) != 0) ^ /* inside xor not within */
1567 !within_bounded_area(x, y, dndest.nlx, dndest.nly,
1568 dndest.nhx, dndest.nhy);
1569 if (updest.lx && (yy & 1) != 0) /* moving up */
1570 return (within_bounded_area(x, y, updest.lx, updest.ly,
1571 updest.hx, updest.hy) &&
1572 (!updest.nlx ||
1573 !within_bounded_area(x, y, updest.nlx, updest.nly,
1574 updest.nhx, updest.nhy)));
1575 if (dndest.lx && (yy & 1) == 0) /* moving down */
1576 return (within_bounded_area(x, y, dndest.lx, dndest.ly,
1577 dndest.hx, dndest.hy) &&
1578 (!dndest.nlx ||
1579 !within_bounded_area(x, y, dndest.nlx, dndest.nly,
1580 dndest.nhx, dndest.nhy)));
1581 } else {
1582 /* current location is <xx,yy> */
1583 if (!tele_jump_ok(xx, yy, x, y)) return FALSE;
1585 /* <x,y> is ok */
1586 return TRUE;
1590 * rloc_to()
1592 * Pulls a monster from its current position and places a monster at
1593 * a new x and y. If oldx is 0, then the monster was not in the levels.monsters
1594 * array. However, if oldx is 0, oldy may still have a value because mtmp is a
1595 * migrating_mon. Worm tails are always placed randomly around the head of
1596 * the worm.
1598 void
1599 rloc_to(mtmp, x, y)
1600 struct monst *mtmp;
1601 register int x, y;
1603 register int oldx = mtmp->mx, oldy = mtmp->my;
1604 boolean resident_shk = mtmp->isshk && inhishop(mtmp);
1606 if (x == mtmp->mx && y == mtmp->my) /* that was easy */
1607 return;
1609 if (oldx) { /* "pick up" monster */
1610 if (mtmp->wormno)
1611 remove_worm(mtmp);
1612 else {
1613 remove_monster(oldx, oldy);
1614 newsym(oldx, oldy); /* update old location */
1618 place_monster(mtmp, x, y); /* put monster down */
1619 update_monster_region(mtmp);
1621 if (mtmp->wormno) /* now put down tail */
1622 place_worm_tail_randomly(mtmp, x, y);
1624 if (u.ustuck == mtmp) {
1625 if (u.uswallow) {
1626 u.ux = x;
1627 u.uy = y;
1628 docrt();
1629 } else setustuck(0);
1632 newsym(x, y); /* update new location */
1633 set_apparxy(mtmp); /* orient monster */
1635 /* shopkeepers will only teleport if you zap them with a wand of
1636 teleportation or if they've been transformed into a jumpy monster;
1637 the latter only happens if you've attacked them with polymorph
1638 Amy edit: that is no longer the case, so this shouldn't make them hostile anymore! */
1639 if (resident_shk && issoviet && !inhishop(mtmp)) {
1640 make_angry_shk(mtmp, oldx, oldy);
1641 pline("VA-KHA-KHA-KHA, lavochnik ub'yet tebya.");
1645 /* place a monster at a random location, typically due to teleport */
1646 /* return TRUE if successful, FALSE if not */
1647 boolean
1648 rloc(mtmp, suppress_impossible)
1649 struct monst *mtmp; /* mx==0 implies migrating monster arrival */
1650 boolean suppress_impossible;
1652 register int x, y, trycount;
1654 if (mtmp == u.usteed) {
1655 tele();
1656 return TRUE;
1659 if (mtmp->iswiz && mtmp->mx) { /* Wizard, not just arriving */
1660 if (!In_W_tower(u.ux, u.uy, &u.uz))
1661 x = xupstair, y = yupstair;
1662 else if (!xdnladder) /* bottom level of tower */
1663 x = xupladder, y = yupladder;
1664 else
1665 x = xdnladder, y = ydnladder;
1666 /* if the wiz teleports away to heal, try the up staircase,
1667 to block the player's escaping before he's healed
1668 (deliberately use `goodpos' rather than `rloc_pos_ok' here) */
1669 if (goodpos(x, y, mtmp, 0))
1670 goto found_xy;
1673 trycount = 0;
1674 do {
1675 x = rn1(COLNO-3,2);
1676 y = rn2(ROWNO);
1677 if ((trycount < 500) ? rloc_pos_ok(x, y, mtmp)
1678 : goodpos(x, y, mtmp, 0))
1679 goto found_xy;
1680 } while (++trycount < 1000);
1682 /* last ditch attempt to find a good place */
1683 for (x = 2; x < COLNO - 1; x++)
1684 for (y = 0; y < ROWNO; y++)
1685 if (goodpos(x, y, mtmp, 0))
1686 goto found_xy;
1688 /* level either full of monsters or somehow faulty */
1689 if (!suppress_impossible)
1690 impossible("rloc(): couldn't relocate monster");
1691 return FALSE;
1693 found_xy:
1694 rloc_to(mtmp, x, y);
1695 return TRUE;
1698 STATIC_OVL void
1699 mvault_tele(mtmp)
1700 struct monst *mtmp;
1702 register struct mkroom *croom = search_special(VAULT);
1703 coord c;
1705 if (croom && somexy(croom, &c) &&
1706 goodpos(c.x, c.y, mtmp, 0)) {
1707 rloc_to(mtmp, c.x, c.y);
1708 return;
1710 (void) rloc(mtmp, FALSE);
1713 boolean
1714 tele_restrict(mon)
1715 struct monst *mon;
1717 if (level.flags.noteleport || Race_if(PM_STABILISATOR) || u.antitelespelltimeout) {
1718 if (canseemon(mon))
1719 pline("A mysterious force prevents %s from teleporting!",
1720 mon_nam(mon));
1721 return TRUE;
1723 return FALSE;
1726 void
1727 mtele_trap(mtmp, trap, in_sight)
1728 struct monst *mtmp;
1729 struct trap *trap;
1730 int in_sight;
1732 char *monname;
1734 if (tele_restrict(mtmp)) return;
1735 if (teleport_pet(mtmp, FALSE)) {
1736 /* save name with pre-movement visibility */
1737 monname = Monnam(mtmp);
1739 /* Note: don't remove the trap if a vault. Other-
1740 * wise the monster will be stuck there, since
1741 * the guard isn't going to come for it...
1743 if (trap->once) mvault_tele(mtmp);
1744 else (void) rloc(mtmp, FALSE);
1746 if (in_sight) {
1747 if (canseemon(mtmp))
1748 pline("%s seems disoriented.", monname);
1749 else
1750 pline("%s suddenly disappears!", monname);
1751 seetrap(trap);
1756 /* return 0 if still on level, 3 if not */
1758 mlevel_tele_trap(mtmp, trap, force_it, in_sight)
1759 struct monst *mtmp;
1760 struct trap *trap;
1761 boolean force_it;
1762 int in_sight;
1764 int tt = trap->ttyp;
1765 struct permonst *mptr = mtmp->data;
1767 if (mtmp == u.ustuck) /* probably a vortex */
1768 return 0; /* temporary? kludge */
1769 if (teleport_pet(mtmp, force_it)) {
1770 d_level tolevel;
1771 int migrate_typ = MIGR_RANDOM;
1773 if ((tt == HOLE || tt == TRAPDOOR || tt == SHAFT_TRAP || tt == CURRENT_SHAFT)) {
1774 if (Is_stronghold(&u.uz)) {
1775 assign_level(&tolevel, &valley_level);
1776 } else if (Is_botlevel(&u.uz)) {
1777 if (in_sight && trap->tseen)
1778 pline("%s avoids the %s.", Monnam(mtmp),
1779 (tt == HOLE) ? "hole" : "trap");
1780 return 0;
1781 } else {
1782 get_level(&tolevel, depth(&u.uz) + 1);
1784 } else if (tt == MAGIC_PORTAL) {
1785 if (In_endgame(&u.uz) &&
1786 (mon_has_amulet(mtmp) || is_home_elemental(mptr))) {
1787 if (in_sight && mptr->mlet != S_ELEMENTAL) {
1788 pline("%s seems to shimmer for a moment.",
1789 Monnam(mtmp));
1790 seetrap(trap);
1792 return 0;
1794 else if (mtmp->mtame &&
1795 (Is_blackmarket(&trap->dst) || Is_blackmarket(&u.uz))) {
1796 if (in_sight) {
1797 pline("%s seems to shimmer for a moment.",
1798 Monnam(mtmp));
1799 seetrap(trap);
1801 return 0;
1803 else {
1804 assign_level(&tolevel, &trap->dst);
1805 migrate_typ = MIGR_PORTAL;
1807 } else { /* (tt == LEVEL_TELEP) */
1808 int nlev;
1810 if (mon_has_amulet(mtmp) || In_endgame(&u.uz)) {
1811 if (in_sight)
1812 pline("%s seems very disoriented for a moment.",
1813 Monnam(mtmp));
1814 return 0;
1816 nlev = random_teleport_level();
1817 if (nlev == depth(&u.uz)) {
1818 if (in_sight)
1819 pline("%s shudders for a moment.", Monnam(mtmp));
1820 return 0;
1822 get_level(&tolevel, nlev);
1825 if (in_sight) {
1826 pline("Suddenly, %s disappears out of sight.", mon_nam(mtmp));
1827 seetrap(trap);
1829 migrate_to_level(mtmp, ledger_no(&tolevel),
1830 migrate_typ, (coord *)0);
1831 return 3; /* no longer on this level */
1833 return 0;
1837 void
1838 rloco(obj)
1839 register struct obj *obj;
1841 register xchar tx, ty, otx, oty;
1842 boolean restricted_fall;
1843 int try_limit = 4000;
1845 if (obj->dynamitekaboom) return;
1847 if (obj->otyp == CORPSE && is_rider(&mons[obj->corpsenm])) {
1848 if (revive_corpse(obj, FALSE)) return;
1850 if (obj->otyp == CORPSE && is_deadlysin(&mons[obj->corpsenm])) {
1851 if (revive_corpse(obj, FALSE)) return;
1854 obj_extract_self(obj);
1855 otx = obj->ox;
1856 oty = obj->oy;
1857 restricted_fall = (otx == 0 && dndest.lx);
1858 do {
1859 tx = rn1(COLNO-3,2);
1860 ty = rn2(ROWNO);
1861 if (!--try_limit) break;
1862 } while (!goodpos(tx, ty, (struct monst *)0, 0) ||
1863 /* bug: this lacks provision for handling the Wizard's tower */
1864 (restricted_fall &&
1865 (!within_bounded_area(tx, ty, dndest.lx, dndest.ly,
1866 dndest.hx, dndest.hy) ||
1867 (dndest.nlx &&
1868 within_bounded_area(tx, ty, dndest.nlx, dndest.nly,
1869 dndest.nhx, dndest.nhy)))));
1871 if (flooreffects(obj, tx, ty, "fall")) {
1872 return;
1873 } else if (otx == 0 && oty == 0) {
1874 ; /* fell through a trap door; no update of old loc needed */
1875 } else {
1876 if (costly_spot(otx, oty)
1877 && (!costly_spot(tx, ty) ||
1878 !index(in_rooms(tx, ty, 0), *in_rooms(otx, oty, 0)))) {
1879 if (costly_spot(u.ux, u.uy) &&
1880 index(u.urooms, *in_rooms(otx, oty, 0)))
1881 addtobill(obj, FALSE, FALSE, FALSE);
1882 else (void)stolen_value(obj, otx, oty, FALSE, FALSE, FALSE);
1884 newsym(otx, oty); /* update old location */
1886 place_object(obj, tx, ty);
1887 newsym(tx, ty);
1890 /* Returns an absolute depth */
1892 random_teleport_level()
1894 int nlev, max_depth, min_depth,
1895 cur_depth = (int)depth(&u.uz);
1897 if (!rn2(5) || Is_knox(&u.uz) ||
1898 Is_blackmarket(&u.uz) ||
1899 Is_aligned_quest(&u.uz))
1900 return cur_depth;
1902 /* What I really want to do is as follows:
1903 * -- If in a dungeon that goes down, the new level is to be restricted
1904 * to [top of parent, bottom of current dungeon]
1905 * -- If in a dungeon that goes up, the new level is to be restricted
1906 * to [top of current dungeon, bottom of parent]
1907 * -- If in a quest dungeon or similar dungeon entered by portals,
1908 * the new level is to be restricted to [top of current dungeon,
1909 * bottom of current dungeon]
1910 * The current behavior is not as sophisticated as that ideal, but is
1911 * still better what we used to do, which was like this for players
1912 * but different for monsters for no obvious reason. Currently, we
1913 * must explicitly check for special dungeons. We check for Knox
1914 * above; endgame is handled in the caller due to its different
1915 * message ("disoriented").
1916 * --KAA
1917 * [ALI] Also check for Sam's blackmarket and the three aligned quests
1918 * above.
1919 * 3.4.2: explicitly handle quest here too, to fix the problem of
1920 * monsters sometimes level teleporting out of it into main dungeon.
1921 * Also prevent monsters reaching the Sanctum prior to invocation.
1923 min_depth = In_quest(&u.uz) ? dungeons[u.uz.dnum].depth_start : 1;
1924 max_depth = dunlevs_in_dungeon(&u.uz) +
1925 (dungeons[u.uz.dnum].depth_start - 1);
1927 /* can't reach the Sanctum if the invocation hasn't been performed */
1928 if (In_gehennom(&u.uz) && !u.uevent.invoked) max_depth -= 1;
1930 /* Get a random value relative to the current dungeon */
1931 /* Range is 1 to current+3, current not counting */
1932 /* Amy edit: somehow this is just stupid. Why not make it so that your deepest level counts? */
1933 if (In_quest(&u.uz)) nlev = dungeons[u.uz.dnum].depth_start + rnd(6);
1934 else { nlev = rn2(/*cur_depth*/deepest_lev_reached(TRUE) + 3 - min_depth) + min_depth;
1935 if (nlev >= cur_depth) nlev++;
1938 if (nlev > max_depth) {
1939 nlev = max_depth;
1940 /* teleport up if already on bottom */
1941 if (Is_botlevel(&u.uz)) nlev -= rnd(3);
1943 if (nlev < min_depth) {
1944 nlev = min_depth;
1945 if (nlev == cur_depth) {
1946 nlev += rnd(3);
1947 if (nlev > max_depth)
1948 nlev = max_depth;
1951 return nlev;
1954 /* teleport player to a random branch --Amy */
1955 void
1956 randombranchtele()
1959 d_level dtmp;
1961 /* make sure you can't be branchported if you're supposed to be immune --Amy */
1962 if (((u.uhave.amulet) && !u.freeplaymode) || CannotTeleport || (u.usteed && mon_has_amulet(u.usteed))) {
1963 return;
1966 if (playerlevelportdisabled()) {
1967 return;
1970 dtmp = random_branchport_level();
1972 schedule_goto(&dtmp, FALSE, FALSE, 0, (char *)0, (char *)0);
1973 u.cnd_branchportcount++;
1977 /* Random branchport level decision */
1978 d_level
1979 random_branchport_level()
1982 d_level dtmp;
1983 extern int n_dgns; /* from dungeon.c */
1984 int duncounter, num_ok_dungeons, last_ok_dungeon = 0;
1985 int randomnumber;
1987 for (duncounter = num_ok_dungeons = 0; duncounter < n_dgns; duncounter++) {
1988 if (!dungeons[duncounter].dunlev_ureached) continue;
1989 if (flags.wonderland && !achieve.perform_invocation) {
1990 if (!strcmp(dungeons[duncounter].dname, "Yendorian Tower")) continue;
1991 if (!strcmp(dungeons[duncounter].dname, "Forging Chamber")) continue;
1992 if (!strcmp(dungeons[duncounter].dname, "Dead Grounds")) continue;
1993 if (!strcmp(dungeons[duncounter].dname, "Ordered Chaos")) continue;
1994 if (!strcmp(dungeons[duncounter].dname, "Resting Zone TA")) continue;
1995 if (!strcmp(dungeons[duncounter].dname, "Resting Zone TB")) continue;
1996 if (!strcmp(dungeons[duncounter].dname, "Resting Zone TC")) continue;
1997 if (!strcmp(dungeons[duncounter].dname, "Resting Zone TD")) continue;
1998 if (!strcmp(dungeons[duncounter].dname, "Resting Zone TE")) continue;
1999 if (!strcmp(dungeons[duncounter].dname, "Resting Zone TF")) continue;
2000 if (!strcmp(dungeons[duncounter].dname, "Resting Zone TG")) continue;
2001 if (!strcmp(dungeons[duncounter].dname, "Resting Zone TH")) continue;
2002 if (!strcmp(dungeons[duncounter].dname, "Resting Zone TI")) continue;
2003 if (!strcmp(dungeons[duncounter].dname, "Resting Zone TJ")) continue;
2005 num_ok_dungeons++;
2006 last_ok_dungeon = duncounter;
2009 if (num_ok_dungeons > 1) randomnumber = rnd(num_ok_dungeons);
2010 else randomnumber = 1;
2012 dtmp.dnum = u.uz.dnum;
2014 while (randomnumber > 0) {
2016 randomnumber--;
2018 dtmp.dnum++;
2019 if (dtmp.dnum >= n_dgns) dtmp.dnum = 0;
2021 while (!dungeons[dtmp.dnum].dunlev_ureached || (flags.wonderland && !achieve.perform_invocation && ( !strcmp(dungeons[dtmp.dnum].dname, "Yendorian Tower") || !strcmp(dungeons[dtmp.dnum].dname, "Forging Chamber") || !strcmp(dungeons[dtmp.dnum].dname, "Dead Grounds") || !strcmp(dungeons[dtmp.dnum].dname, "Ordered Chaos") || !strcmp(dungeons[dtmp.dnum].dname, "Resting Zone TA") || !strcmp(dungeons[dtmp.dnum].dname, "Resting Zone TB") || !strcmp(dungeons[dtmp.dnum].dname, "Resting Zone TC") || !strcmp(dungeons[dtmp.dnum].dname, "Resting Zone TD") || !strcmp(dungeons[dtmp.dnum].dname, "Resting Zone TE") || !strcmp(dungeons[dtmp.dnum].dname, "Resting Zone TF") || !strcmp(dungeons[dtmp.dnum].dname, "Resting Zone TG") || !strcmp(dungeons[dtmp.dnum].dname, "Resting Zone TH") || !strcmp(dungeons[dtmp.dnum].dname, "Resting Zone TI") || !strcmp(dungeons[dtmp.dnum].dname, "Resting Zone TJ") ) ) ) {
2023 dtmp.dnum++;
2024 if (dtmp.dnum >= n_dgns) dtmp.dnum = 0;
2028 dtmp.dlevel = 1;
2029 if (dungeons[dtmp.dnum].dunlev_ureached > 1) dtmp.dlevel = rnd(dungeons[dtmp.dnum].dunlev_ureached);
2031 return dtmp;
2035 /* Levelport level decision */
2037 random_banish_level()
2039 int nlev, max_depth, min_depth, cur_depth = (int)depth(&u.uz);
2042 if (Is_knox(&u.uz) ||
2043 Is_blackmarket(&u.uz) ||
2044 Is_aligned_quest(&u.uz))
2045 return cur_depth;
2047 min_depth = In_quest(&u.uz) ? dungeons[u.uz.dnum].depth_start : 1;
2048 max_depth = dunlevs_in_dungeon(&u.uz) +
2049 (dungeons[u.uz.dnum].depth_start - 1);
2050 /* can't reach the Sanctum, no matter if invocation or not */
2051 if (In_gehennom(&u.uz)) max_depth -= 1;
2053 /* Get a random value relative to the current dungeon */
2055 nlev = rn2(max_depth - min_depth) + min_depth;
2057 if (nlev > max_depth) nlev = max_depth;
2059 if (nlev < min_depth) nlev = min_depth;
2061 return nlev;
2064 /* Random branchport level decision */
2065 d_level
2066 random_banishment_level()
2069 d_level dtmp;
2070 boolean minusworld = FALSE;
2072 dtmp.dnum = dname_to_dnum("The Dungeons of Doom"); /* fail safe in case something goes wrong */
2073 dtmp.dlevel = 1; /* ditto */
2075 if (!rn2(100)) {
2076 dtmp.dnum = dname_to_dnum("Minus World");
2077 dtmp.dlevel = dunlevs_in_dungeon(&dtmp);
2078 minusworld = TRUE;
2079 } else if (rn2(2)) {
2080 dtmp.dnum = dname_to_dnum("The Dungeons of Doom");
2081 } else if (rn2(2)) {
2082 dtmp.dnum = dname_to_dnum("Gehennom");
2083 } else if (rn2(4)) {
2084 upperdungeonagain:
2085 switch (rnd(32)) {
2086 case 1:
2087 dtmp.dnum = dname_to_dnum("The Gnomish Mines");
2088 break;
2089 case 2:
2090 dtmp.dnum = dname_to_dnum("The Quest");
2091 break;
2092 case 3:
2093 if (!u.silverbellget && !u.prematuresubquest) goto upperdungeonagain;
2094 dtmp.dnum = dname_to_dnum("The Subquest");
2095 break;
2096 case 4:
2097 if (!u.silverbellget && !!u.prematuresubquest) goto upperdungeonagain;
2098 dtmp.dnum = dname_to_dnum("Bell Caves");
2099 break;
2100 case 5:
2101 dtmp.dnum = dname_to_dnum("Lawful Quest");
2102 break;
2103 case 6:
2104 dtmp.dnum = dname_to_dnum("Neutral Quest");
2105 break;
2106 case 7:
2107 dtmp.dnum = dname_to_dnum("Chaotic Quest");
2108 break;
2109 case 8:
2110 dtmp.dnum = dname_to_dnum("Sokoban");
2111 break;
2112 case 9:
2113 dtmp.dnum = dname_to_dnum("Town");
2114 break;
2115 case 10:
2116 dtmp.dnum = dname_to_dnum("Grund's Stronghold");
2117 break;
2118 case 11:
2119 if (!u.havebeeninludios) goto upperdungeonagain;
2120 dtmp.dnum = dname_to_dnum("Fort Ludios");
2121 break;
2122 case 12:
2123 dtmp.dnum = dname_to_dnum("The Wyrm Caves");
2124 break;
2125 case 13:
2126 dtmp.dnum = dname_to_dnum("One-eyed Sam's Market");
2127 break;
2128 case 14:
2129 dtmp.dnum = dname_to_dnum("The Lost Tomb");
2130 break;
2131 case 15:
2132 dtmp.dnum = dname_to_dnum("The Spider Caves");
2133 break;
2134 case 16:
2135 dtmp.dnum = dname_to_dnum("The Sunless Sea");
2136 break;
2137 case 17:
2138 dtmp.dnum = dname_to_dnum("The Temple of Moloch");
2139 break;
2140 case 18:
2141 dtmp.dnum = dname_to_dnum("Grue Challenge");
2142 break;
2143 case 19:
2144 dtmp.dnum = dname_to_dnum("Joust Challenge");
2145 break;
2146 case 20:
2147 dtmp.dnum = dname_to_dnum("Pacman Challenge");
2148 break;
2149 case 21:
2150 dtmp.dnum = dname_to_dnum("Pool Challenge");
2151 break;
2152 case 22:
2153 dtmp.dnum = dname_to_dnum("Digdug Challenge");
2154 break;
2155 case 23:
2156 dtmp.dnum = dname_to_dnum("Illusory Castle");
2157 break;
2158 case 24:
2159 dtmp.dnum = dname_to_dnum("Deep Mines");
2160 break;
2161 case 25:
2162 dtmp.dnum = dname_to_dnum("Space Base");
2163 break;
2164 case 26: /* not a bug that the space base subdungeons are always accessible --Amy */
2165 dtmp.dnum = dname_to_dnum("Sewer Plant");
2166 break;
2167 case 27:
2168 dtmp.dnum = dname_to_dnum("Gamma Caves");
2169 break;
2170 case 28:
2171 dtmp.dnum = dname_to_dnum("Mainframe");
2172 break;
2173 case 29:
2174 dtmp.dnum = dname_to_dnum("Minotaur Maze");
2175 break;
2176 case 30:
2177 if (!u.greencrossopen && !Role_if(PM_PREVERSIONER) && !Role_if(PM_SPACEWARS_FIGHTER) && !Role_if(PM_CAMPERSTRIKER) && !(Role_if(PM_GANG_SCHOLAR) && u.greencrosschance < 5) && !(Role_if(PM_WALSCHOLAR) && u.greencrosschance < 5) && !(u.greencrosschance < 2) ) goto upperdungeonagain;
2178 dtmp.dnum = dname_to_dnum("Green Cross");
2179 break;
2180 case 31:
2181 dtmp.dnum = dname_to_dnum("The Giant Caverns");
2182 break;
2183 case 32:
2184 dtmp.dnum = dname_to_dnum("The Ice Queen's Realm");
2185 break;
2187 } else {
2188 lowerdungeonagain:
2189 switch (rnd(33)) {
2190 case 1:
2191 if (!u.silverbellget) goto lowerdungeonagain;
2192 dtmp.dnum = dname_to_dnum("Rival Quest");
2193 break;
2194 case 2:
2195 dtmp.dnum = dname_to_dnum("Void");
2196 break;
2197 case 3:
2198 dtmp.dnum = dname_to_dnum("Nether Realm");
2199 break;
2200 case 4:
2201 dtmp.dnum = dname_to_dnum("Angmar");
2202 break;
2203 case 5:
2204 dtmp.dnum = dname_to_dnum("Emyn Luin");
2205 break;
2206 case 6:
2207 dtmp.dnum = dname_to_dnum("Swimming Pool");
2208 break;
2209 case 7:
2210 dtmp.dnum = dname_to_dnum("Hell's Bathroom");
2211 break;
2212 case 8:
2213 dtmp.dnum = dname_to_dnum("Frankenstein's Lab");
2214 break;
2215 case 9:
2216 dtmp.dnum = dname_to_dnum("Sheol");
2217 break;
2218 case 10:
2219 dtmp.dnum = dname_to_dnum("Vlad's Tower");
2220 break;
2221 case 11:
2222 if (!achieve.get_amulet && !u.prematureyendortower) goto lowerdungeonagain;
2223 dtmp.dnum = dname_to_dnum("Yendorian Tower");
2224 break;
2225 case 12:
2226 if (!achieve.get_amulet && !u.prematureyendortower) goto lowerdungeonagain;
2227 dtmp.dnum = dname_to_dnum("Forging Chamber");
2228 break;
2229 case 13:
2230 if (!achieve.get_amulet && !u.prematureyendortower) goto lowerdungeonagain;
2231 dtmp.dnum = dname_to_dnum("Dead Grounds");
2232 break;
2233 case 14:
2234 if (!achieve.get_amulet && !u.prematureyendortower) goto lowerdungeonagain;
2235 dtmp.dnum = dname_to_dnum("Ordered Chaos");
2236 break;
2237 case 15:
2238 dtmp.dnum = dname_to_dnum("Resting Zone GA");
2239 break;
2240 case 16:
2241 dtmp.dnum = dname_to_dnum("Resting Zone GB");
2242 break;
2243 case 17:
2244 dtmp.dnum = dname_to_dnum("Resting Zone GC");
2245 break;
2246 case 18:
2247 dtmp.dnum = dname_to_dnum("Resting Zone GD");
2248 break;
2249 case 19:
2250 dtmp.dnum = dname_to_dnum("Resting Zone GE");
2251 break;
2252 case 20:
2253 if (!achieve.get_amulet && !u.prematureyendortower) goto lowerdungeonagain;
2254 dtmp.dnum = dname_to_dnum("Resting Zone TA");
2255 break;
2256 case 21:
2257 if (!achieve.get_amulet && !u.prematureyendortower) goto lowerdungeonagain;
2258 dtmp.dnum = dname_to_dnum("Resting Zone TB");
2259 break;
2260 case 22:
2261 if (!achieve.get_amulet && !u.prematureyendortower) goto lowerdungeonagain;
2262 dtmp.dnum = dname_to_dnum("Resting Zone TC");
2263 break;
2264 case 23:
2265 if (!achieve.get_amulet && !u.prematureyendortower) goto lowerdungeonagain;
2266 dtmp.dnum = dname_to_dnum("Resting Zone TD");
2267 break;
2268 case 24:
2269 if (!achieve.get_amulet && !u.prematureyendortower) goto lowerdungeonagain;
2270 dtmp.dnum = dname_to_dnum("Resting Zone TE");
2271 break;
2272 case 25:
2273 if (!achieve.get_amulet && !u.prematureyendortower) goto lowerdungeonagain;
2274 dtmp.dnum = dname_to_dnum("Resting Zone TF");
2275 break;
2276 case 26:
2277 if (!achieve.get_amulet && !u.prematureyendortower) goto lowerdungeonagain;
2278 dtmp.dnum = dname_to_dnum("Resting Zone TG");
2279 break;
2280 case 27:
2281 if (!achieve.get_amulet && !u.prematureyendortower) goto lowerdungeonagain;
2282 dtmp.dnum = dname_to_dnum("Resting Zone TH");
2283 break;
2284 case 28:
2285 if (!achieve.get_amulet && !u.prematureyendortower) goto lowerdungeonagain;
2286 dtmp.dnum = dname_to_dnum("Resting Zone TI");
2287 break;
2288 case 29:
2289 if (!achieve.get_amulet && !u.prematureyendortower) goto lowerdungeonagain;
2290 dtmp.dnum = dname_to_dnum("Resting Zone TJ");
2291 break;
2292 case 30:
2293 dtmp.dnum = dname_to_dnum("Resting Zone A");
2294 break;
2295 case 31:
2296 dtmp.dnum = dname_to_dnum("Resting Zone S");
2297 break;
2298 case 32:
2299 if (!u.freeplaymode || !u.freeplayplanes) goto lowerdungeonagain;
2300 dtmp.dnum = dname_to_dnum("The Elemental Planes");
2301 break;
2302 case 33:
2303 dtmp.dnum = dname_to_dnum("Resting Zone E");
2304 break;
2308 if (!minusworld) {
2309 dtmp.dlevel = rnd(dunlevs_in_dungeon(&dtmp));
2310 if (!strcmp(dungeons[dtmp.dnum].dname, "Gehennom") && !u.uevent.invoked) dtmp.dlevel = rnd((dunlevs_in_dungeon(&dtmp)) - 1);
2313 return dtmp;
2316 /* the player is being banished to a random level. Usually it'll be in the upper dungeons, sometimes in Gehennom,
2317 * but occasionally also some branch, which should be accessible so as to prevent sequence breaking.
2318 * 1% chance to end up in Minus World, which is initially the only way to get there. --Amy */
2319 void
2320 banishplayer()
2322 d_level dtmp;
2324 /* make sure you can't be banished if you're supposed to be immune --Amy */
2325 if (((u.uhave.amulet) && !u.freeplaymode) || CannotTeleport || (u.usteed && mon_has_amulet(u.usteed))) {
2326 return;
2329 if (playerlevelportdisabled()) {
2330 return;
2333 dtmp = random_banishment_level();
2335 if (multi >= 0) {
2336 nomovemsg = "You feel a little dizzy.";
2337 nomul(-1, "being banished", FALSE); /* because it's not called until you get another turn... */
2340 schedule_goto(&dtmp, FALSE, FALSE, 0, (char *)0, (char *)0);
2341 u.cnd_banishmentcount++;
2345 /* you teleport a monster (via wand, spell, or poly'd q.mechanic attack);
2346 return false iff the attempt fails */
2347 boolean
2348 u_teleport_mon(mtmp, give_feedback)
2349 struct monst *mtmp;
2350 boolean give_feedback;
2352 coord cc;
2354 if (evilfriday && (level.flags.noteleport || Race_if(PM_STABILISATOR) || u.antitelespelltimeout)) {
2355 if (give_feedback)
2356 pline("Ha ha ha, the wand destruction patch made it so that your wand of teleportation does jack diddly on a no-teleport level. You just wasted a charge, sucker!");
2357 return FALSE;
2358 } else if (mtmp->ispriest && *in_rooms(mtmp->mx, mtmp->my, TEMPLE)) {
2359 if (give_feedback)
2360 pline("%s resists your magic!", Monnam(mtmp));
2361 return FALSE;
2362 } else if ((level.flags.noteleport || Race_if(PM_STABILISATOR) || u.antitelespelltimeout) && u.uswallow && mtmp == u.ustuck) {
2363 if (give_feedback)
2364 You("are no longer inside %s!", mon_nam(mtmp));
2365 unstuck(mtmp);
2366 rloc(mtmp, FALSE);
2367 } else if (is_rider(mtmp->data) && rn2(13) &&
2368 enexto(&cc, u.ux, u.uy, mtmp->data))
2369 rloc_to(mtmp, cc.x, cc.y);
2370 else if (is_deadlysin(mtmp->data) && rn2(13) &&
2371 enexto(&cc, u.ux, u.uy, mtmp->data))
2372 rloc_to(mtmp, cc.x, cc.y);
2373 else {
2374 #ifdef WIZARD
2375 if (wizard && Teleport_control)
2378 * [ALI] This code will only allow monsters to be
2379 * teleported to positions acceptable to rloc_pos_ok().
2380 * We could use goodpos() which would allow more
2381 * locations but, in my view, is less informative.
2383 xchar omx, omy;
2384 pline("To what position do you want %s to be teleported?",
2385 mon_nam(mtmp));
2386 cc.x = omx = mtmp->mx;
2387 cc.y = omy = mtmp->my;
2388 if (getpos(&cc, TRUE, "the desired position") < 0)
2389 rloc(mtmp, FALSE); /* abort */
2390 else if (rloc_pos_ok(cc.x, cc.y, mtmp)) {
2391 rloc_to(mtmp, cc.x, cc.y);
2392 /* As rloc() ... */
2393 if (mtmp->isshk && !inhishop(mtmp) && issoviet) {
2394 make_angry_shk(mtmp, omx, omy);
2395 pline("VA-KHA-KHA-KHA, lavochnik ub'yet tebya.");
2397 } else {
2398 pline("Sorry...");
2399 rloc(mtmp, FALSE);
2401 } else
2402 #endif /* WIZARD */
2403 rloc(mtmp, FALSE);
2405 return TRUE;
2408 /* monster is levelported */
2409 boolean
2410 u_teleport_monB(mtmp, give_feedback)
2411 struct monst *mtmp;
2412 boolean give_feedback;
2414 boolean ball_active = (Punished && uball->where != OBJ_FREE);
2416 if (mtmp->data == &mons[PM_BAN_EVADING_TROLL]) return FALSE;
2418 if (mtmp->isshk && issoviet) {
2419 make_angry_shk(mtmp, 0, 0);
2420 pline("VA-KHA-KHA-KHA, lavochnik ub'yet tebya.");
2423 int nlev;
2424 d_level flev;
2426 if (mon_has_amulet(mtmp) || In_endgame(&u.uz)) {
2427 if (give_feedback) pline("%s seems very disoriented for a moment.", Monnam(mtmp));
2428 return 2;
2430 nlev = random_banish_level();
2431 if (nlev == depth(&u.uz)) {
2432 if (give_feedback) pline("%s shudders for a moment.", Monnam(mtmp));
2433 return 2;
2436 if (u.uswallow) {
2437 u.uswldtim = u.uswallow = 0;
2438 if (Punished && !ball_active) {
2439 /* ensure ball placement, like unstuck */
2440 ball_active = TRUE;
2442 docrt();
2445 get_level(&flev, nlev);
2446 migrate_to_level(mtmp, ledger_no(&flev), MIGR_RANDOM, (coord *)0);
2448 return TRUE;
2451 /* monster is branchported */
2452 boolean
2453 u_teleport_monC(mtmp, give_feedback)
2454 struct monst *mtmp;
2455 boolean give_feedback;
2457 boolean ball_active = (Punished && uball->where != OBJ_FREE);
2459 if (mtmp->data == &mons[PM_BAN_EVADING_TROLL]) return FALSE;
2461 if (mtmp->isshk && issoviet) {
2462 make_angry_shk(mtmp, 0, 0);
2463 pline("VA-KHA-KHA-KHA, lavochnik ub'yet tebya.");
2466 int nlev;
2467 d_level flev;
2469 if (mon_has_amulet(mtmp) || In_endgame(&u.uz)) {
2470 if (give_feedback) pline("%s seems very disoriented for a moment.", Monnam(mtmp));
2471 return 2;
2474 flev = random_branchport_level();
2475 migrate_to_level(mtmp, ledger_no(&flev), MIGR_RANDOM, (coord *)0);
2477 return TRUE;
2480 /* monster is banished */
2481 boolean
2482 u_teleport_monD(mtmp, give_feedback)
2483 struct monst *mtmp;
2484 boolean give_feedback;
2486 boolean ball_active = (Punished && uball->where != OBJ_FREE);
2488 if (mtmp->data == &mons[PM_BAN_EVADING_TROLL]) return FALSE;
2490 if (mtmp->isshk && issoviet) {
2491 make_angry_shk(mtmp, 0, 0);
2492 pline("VA-KHA-KHA-KHA, lavochnik ub'yet tebya.");
2495 int nlev;
2496 d_level flev;
2498 if (mon_has_amulet(mtmp) || In_endgame(&u.uz)) {
2499 if (give_feedback) pline("%s seems very disoriented for a moment.", Monnam(mtmp));
2500 return 2;
2503 flev = random_banishment_level();
2504 migrate_to_level(mtmp, ledger_no(&flev), MIGR_RANDOM, (coord *)0);
2506 return TRUE;
2509 /* scroll/spell/whatever of return: lets the player choose a previously visited dungeon level to return to --Amy */
2510 void
2511 setupreturn(returntype)
2512 int returntype; /* 0 = let player choose, 1 = let RNG choose, 2 = destination is specifically level 62 of Gehennom */
2514 int possiblechoices = 1;
2516 /* have the amulet? then sorry, pal, it won't work at all --Amy */
2517 if ((u.uhave.amulet && !u.freeplaymode) || (u.usteed && mon_has_amulet(u.usteed))) {
2518 pline_The("charge is absorbed by the amulet!");
2519 return;
2521 /* otherwise, set up return; if you're prevented from levelporting at the time it triggers, it fizzles */
2523 u.returntimer = rn1(50, 50);
2524 u.returndestination = 1; /* fail safe: Dungeons of Doom, level 1 */
2526 if (returntype == 2) {
2527 u.returndestination = 99999; /* Gehennom, level 62, eevn if you've not been there yet */
2528 You_feel("the air change around you..."); /* intentionally says "change", not "charge" */
2529 return;
2532 if (returntype == 0) pline("Pick a destination to return to. The prompt will loop until you actually make a choice.");
2534 if (returntype == 0) {
2535 returnagain:
2536 if (yn("Dungeons of Doom, level 1?") == 'y') {
2537 u.returndestination = 1;
2538 goto madeachoice;
2539 } else if (u.returndest_dod14 && yn("Dungeons of Doom, level 14?") == 'y') {
2540 u.returndestination = 2;
2541 goto madeachoice;
2542 } else if (u.returndest_dod29 && yn("Dungeons of Doom, level 29?") == 'y') {
2543 u.returndestination = 3;
2544 goto madeachoice;
2545 } else if (u.returndest_dod44 && yn("Dungeons of Doom, level 44?") == 'y') {
2546 u.returndestination = 4;
2547 goto madeachoice;
2548 } else if (u.returndest_geh53 && yn("Gehennom, level 53?") == 'y') {
2549 u.returndestination = 5;
2550 goto madeachoice;
2551 } else if (u.returndest_geh74 && yn("Gehennom, level 74?") == 'y') {
2552 u.returndestination = 6;
2553 goto madeachoice;
2554 } else if (u.returndest_geh95 && yn("Gehennom, level 95?") == 'y') {
2555 u.returndestination = 7;
2556 goto madeachoice;
2557 } else if (u.returndest_min7 && yn("Gnomish Mines, level 7?") == 'y') {
2558 u.returndestination = 8;
2559 goto madeachoice;
2560 } else if (u.returndest_ill11 && yn("Illusory Castle, level 11?") == 'y') {
2561 u.returndestination = 9;
2562 goto madeachoice;
2563 } else if (u.returndest_ill22 && yn("Illusory Castle, level 22?") == 'y') {
2564 u.returndestination = 10;
2565 goto madeachoice;
2566 } else if (u.returndest_dee11 && yn("Deep Mines, level 11?") == 'y') {
2567 u.returndestination = 11;
2568 goto madeachoice;
2569 } else if (u.returndest_dee22 && yn("Deep Mines, level 22?") == 'y') {
2570 u.returndestination = 12;
2571 goto madeachoice;
2572 } else if (u.returndest_spa6 && yn("Space Base, level 6?") == 'y') {
2573 u.returndestination = 13;
2574 goto madeachoice;
2575 } else if (u.returndest_ang7 && yn("Angmar, level 7?") == 'y') {
2576 u.returndestination = 14;
2577 goto madeachoice;
2578 } else if (u.returndest_emy10 && yn("Emyn Luin, level 10?") == 'y') {
2579 u.returndestination = 15;
2580 goto madeachoice;
2581 } else if (u.returndest_swi8 && yn("Swimming Pools, level 8?") == 'y') {
2582 u.returndestination = 16;
2583 goto madeachoice;
2584 } else if (u.returndest_gre13 && yn("Green Cross, level 13?") == 'y') {
2585 u.returndestination = 17;
2586 goto madeachoice;
2587 } else if (u.returndest_gre28 && yn("Green Cross, level 28?") == 'y') {
2588 u.returndestination = 18;
2589 goto madeachoice;
2590 } else if (u.returndest_gre43 && yn("Green Cross, level 43?") == 'y') {
2591 u.returndestination = 19;
2592 goto madeachoice;
2593 } else if (u.returndest_gre58 && yn("Green Cross, level 58?") == 'y') {
2594 u.returndestination = 20;
2595 goto madeachoice;
2596 } else if (u.returndest_maz11 && yn("Minotaur Maze, level 11?") == 'y') {
2597 u.returndestination = 21;
2598 goto madeachoice;
2599 } else if (u.returndest_maz22 && yn("Minotaur Maze, level 22?") == 'y') {
2600 u.returndestination = 22;
2601 goto madeachoice;
2602 } else if (u.returndest_she5 && yn("Sheol, level 5?") == 'y') {
2603 u.returndestination = 23;
2604 goto madeachoice;
2605 } else if (u.returndest_she20 && yn("Sheol, level 20?") == 'y') {
2606 u.returndestination = 24;
2607 goto madeachoice;
2608 } else if (u.returndest_yen4 && yn("Yendorian Tower, level 4?") == 'y') {
2609 u.returndestination = 25;
2610 goto madeachoice;
2611 } else if (u.returndest_yen19 && yn("Yendorian Tower, level 19?") == 'y') {
2612 u.returndestination = 26;
2613 goto madeachoice;
2614 } else if (u.returndest_yen34 && yn("Yendorian Tower, level 34?") == 'y') {
2615 u.returndestination = 27;
2616 goto madeachoice;
2617 } else if (u.returndest_yen49 && yn("Yendorian Tower, level 49?") == 'y') {
2618 u.returndestination = 28;
2619 goto madeachoice;
2620 } else if (u.returndest_yen64 && yn("Yendorian Tower, level 64?") == 'y') {
2621 u.returndestination = 29;
2622 goto madeachoice;
2623 } else if (u.returndest_yen79 && yn("Yendorian Tower, level 79?") == 'y') {
2624 u.returndestination = 30;
2625 goto madeachoice;
2626 } else if (u.returndest_yen94 && yn("Yendorian Tower, level 94?") == 'y') {
2627 u.returndestination = 31;
2628 goto madeachoice;
2629 } else goto returnagain;
2632 if (returntype == 1) {
2633 u.returndestination = 1;
2634 possiblechoices = 1;
2635 if (u.returndest_dod14) {
2636 possiblechoices++;
2637 if (!rn2(possiblechoices)) u.returndestination = 2;
2639 if (u.returndest_dod29) {
2640 possiblechoices++;
2641 if (!rn2(possiblechoices)) u.returndestination = 3;
2643 if (u.returndest_dod44) {
2644 possiblechoices++;
2645 if (!rn2(possiblechoices)) u.returndestination = 4;
2647 if (u.returndest_geh53) {
2648 possiblechoices++;
2649 if (!rn2(possiblechoices)) u.returndestination = 5;
2651 if (u.returndest_geh74) {
2652 possiblechoices++;
2653 if (!rn2(possiblechoices)) u.returndestination = 6;
2655 if (u.returndest_geh95) {
2656 possiblechoices++;
2657 if (!rn2(possiblechoices)) u.returndestination = 7;
2659 if (u.returndest_min7) {
2660 possiblechoices++;
2661 if (!rn2(possiblechoices)) u.returndestination = 8;
2663 if (u.returndest_ill11) {
2664 possiblechoices++;
2665 if (!rn2(possiblechoices)) u.returndestination = 9;
2667 if (u.returndest_ill22) {
2668 possiblechoices++;
2669 if (!rn2(possiblechoices)) u.returndestination = 10;
2671 if (u.returndest_dee11) {
2672 possiblechoices++;
2673 if (!rn2(possiblechoices)) u.returndestination = 11;
2675 if (u.returndest_dee22) {
2676 possiblechoices++;
2677 if (!rn2(possiblechoices)) u.returndestination = 12;
2679 if (u.returndest_spa6) {
2680 possiblechoices++;
2681 if (!rn2(possiblechoices)) u.returndestination = 13;
2683 if (u.returndest_ang7) {
2684 possiblechoices++;
2685 if (!rn2(possiblechoices)) u.returndestination = 14;
2687 if (u.returndest_emy10) {
2688 possiblechoices++;
2689 if (!rn2(possiblechoices)) u.returndestination = 15;
2691 if (u.returndest_swi8) {
2692 possiblechoices++;
2693 if (!rn2(possiblechoices)) u.returndestination = 16;
2695 if (u.returndest_gre13) {
2696 possiblechoices++;
2697 if (!rn2(possiblechoices)) u.returndestination = 17;
2699 if (u.returndest_gre28) {
2700 possiblechoices++;
2701 if (!rn2(possiblechoices)) u.returndestination = 18;
2703 if (u.returndest_gre43) {
2704 possiblechoices++;
2705 if (!rn2(possiblechoices)) u.returndestination = 19;
2707 if (u.returndest_gre58) {
2708 possiblechoices++;
2709 if (!rn2(possiblechoices)) u.returndestination = 20;
2711 if (u.returndest_maz11) {
2712 possiblechoices++;
2713 if (!rn2(possiblechoices)) u.returndestination = 21;
2715 if (u.returndest_maz22) {
2716 possiblechoices++;
2717 if (!rn2(possiblechoices)) u.returndestination = 22;
2719 if (u.returndest_she5) {
2720 possiblechoices++;
2721 if (!rn2(possiblechoices)) u.returndestination = 23;
2723 if (u.returndest_she20) {
2724 possiblechoices++;
2725 if (!rn2(possiblechoices)) u.returndestination = 24;
2727 if (u.returndest_yen4) {
2728 possiblechoices++;
2729 if (!rn2(possiblechoices)) u.returndestination = 25;
2731 if (u.returndest_yen19) {
2732 possiblechoices++;
2733 if (!rn2(possiblechoices)) u.returndestination = 26;
2735 if (u.returndest_yen34) {
2736 possiblechoices++;
2737 if (!rn2(possiblechoices)) u.returndestination = 27;
2739 if (u.returndest_yen49) {
2740 possiblechoices++;
2741 if (!rn2(possiblechoices)) u.returndestination = 28;
2743 if (u.returndest_yen64) {
2744 possiblechoices++;
2745 if (!rn2(possiblechoices)) u.returndestination = 29;
2747 if (u.returndest_yen79) {
2748 possiblechoices++;
2749 if (!rn2(possiblechoices)) u.returndestination = 30;
2751 if (u.returndest_yen94) {
2752 possiblechoices++;
2753 if (!rn2(possiblechoices)) u.returndestination = 31;
2757 madeachoice:
2758 You_feel("the air charge around you..."); /* here it says "charge", this isn't a mistake */
2760 return; /* todo */
2763 /* A function that pushes the player around, mainly to be used by ranged attackers so they can get a shot. --Amy
2764 * "allowtrap" should be FALSE if it's the result of a monster attack, because otherwise we could get segfaults
2765 * and bus errors when the trap moves you off the level before the monster's attack routine is finished! */
2766 void
2767 pushplayer(allowtrap)
2768 boolean allowtrap;
2770 coord ccc;
2771 int direction, pushwidth, trycnt;
2772 register struct obj *otmp;
2773 trycnt = 0;
2775 if (uwep && uwep->oartifact == ART_IMHULLU && rn2(10)) return;
2776 if (uarmf && uarmf->oartifact == ART_STAND_TALL_IN_THE_STORM) return;
2778 newtry:
2779 direction = rnd(8);
2780 pushwidth = rnd(2);
2781 if (!rn2(2)) pushwidth += rnd(2);
2782 if (uarmf && itemhasappearance(uarmf, APP_ZERO_DROP_SHOES)) {
2783 pushwidth = rnd(3);
2784 if (!rn2(2)) pushwidth += rnd(3);
2786 ccc.x = u.ux;
2787 ccc.y = u.uy;
2789 while (pushwidth--) {
2790 if (direction == 1 || direction == 5) ccc.x += 1;
2791 else if (direction == 2 || direction == 6) ccc.x -= 1;
2792 else if (direction == 3 || direction == 7) ccc.y += 1;
2793 else if (direction == 4 || direction == 8) ccc.y -= 1;
2795 if (direction == 5) ccc.y += 1;
2796 else if (direction == 6) ccc.y -= 1;
2797 else if (direction == 7) ccc.x -= 1;
2798 else if (direction == 8) ccc.x += 1;
2800 if (!isok(ccc.x, ccc.y)) break; /* otherwise the game could segfault! */
2802 if ((levl[ccc.x][ccc.y].typ != ROOM && levl[ccc.x][ccc.y].typ != AIR && levl[ccc.x][ccc.y].typ != STAIRS && levl[ccc.x][ccc.y].typ != LADDER && levl[ccc.x][ccc.y].typ != FOUNTAIN && levl[ccc.x][ccc.y].typ != THRONE && levl[ccc.x][ccc.y].typ != SINK && levl[ccc.x][ccc.y].typ != TOILET && levl[ccc.x][ccc.y].typ != GRAVE && levl[ccc.x][ccc.y].typ != ALTAR && levl[ccc.x][ccc.y].typ != ICE && levl[ccc.x][ccc.y].typ != CLOUD && levl[ccc.x][ccc.y].typ != SNOW && levl[ccc.x][ccc.y].typ != ASH && levl[ccc.x][ccc.y].typ != SAND && levl[ccc.x][ccc.y].typ != PAVEDFLOOR && levl[ccc.x][ccc.y].typ != HIGHWAY && levl[ccc.x][ccc.y].typ != GRASSLAND && levl[ccc.x][ccc.y].typ != NETHERMIST && levl[ccc.x][ccc.y].typ != STALACTITE && levl[ccc.x][ccc.y].typ != CRYPTFLOOR && levl[ccc.x][ccc.y].typ != BUBBLES && levl[ccc.x][ccc.y].typ != RAINCLOUD &&
2803 levl[ccc.x][ccc.y].typ != CORR) || MON_AT(ccc.x, ccc.y) || (otmp = sobj_at(BOULDER, ccc.x, ccc.y)) != 0 ) break;
2806 if ((levl[ccc.x][ccc.y].typ != ROOM && levl[ccc.x][ccc.y].typ != AIR && levl[ccc.x][ccc.y].typ != STAIRS && levl[ccc.x][ccc.y].typ != LADDER && levl[ccc.x][ccc.y].typ != FOUNTAIN && levl[ccc.x][ccc.y].typ != THRONE && levl[ccc.x][ccc.y].typ != SINK && levl[ccc.x][ccc.y].typ != TOILET && levl[ccc.x][ccc.y].typ != GRAVE && levl[ccc.x][ccc.y].typ != ALTAR && levl[ccc.x][ccc.y].typ != ICE && levl[ccc.x][ccc.y].typ != CLOUD && levl[ccc.x][ccc.y].typ != SNOW && levl[ccc.x][ccc.y].typ != ASH && levl[ccc.x][ccc.y].typ != SAND && levl[ccc.x][ccc.y].typ != PAVEDFLOOR && levl[ccc.x][ccc.y].typ != HIGHWAY && levl[ccc.x][ccc.y].typ != GRASSLAND && levl[ccc.x][ccc.y].typ != NETHERMIST && levl[ccc.x][ccc.y].typ != STALACTITE && levl[ccc.x][ccc.y].typ != CRYPTFLOOR && levl[ccc.x][ccc.y].typ != BUBBLES && levl[ccc.x][ccc.y].typ != RAINCLOUD &&
2807 levl[ccc.x][ccc.y].typ != CORR) || MON_AT(ccc.x, ccc.y) || (t_at(ccc.x, ccc.y) && !allowtrap) || (otmp = sobj_at(BOULDER, ccc.x, ccc.y)) != 0) {
2808 if (trycnt < 50) {trycnt++; goto newtry;}
2809 return; /* more than 50 tries */
2812 if (!isok(ccc.x, ccc.y)) return; /* otherwise the game could segfault! */
2814 pline("You're pushed back!");
2816 teleds(ccc.x, ccc.y, allowtrap);
2818 if (!(InterfaceScrewed || u.uprops[INTERFACE_SCREW].extrinsic || have_interfacescrewstone())) doredraw();
2819 return;
2822 void
2823 pushplayerfar(allowtrap, distance)
2824 boolean allowtrap;
2825 int distance;
2827 coord ccc;
2828 int direction, pushwidth, trycnt;
2829 register struct obj *otmp;
2830 trycnt = 0;
2832 if (uwep && uwep->oartifact == ART_IMHULLU && rn2(10)) return;
2833 if (uarmf && uarmf->oartifact == ART_STAND_TALL_IN_THE_STORM) return;
2835 newtry:
2836 direction = rnd(8);
2837 pushwidth = rnd(distance);
2838 ccc.x = u.ux;
2839 ccc.y = u.uy;
2841 while (pushwidth--) {
2842 if (direction == 1 || direction == 5) ccc.x += 1;
2843 else if (direction == 2 || direction == 6) ccc.x -= 1;
2844 else if (direction == 3 || direction == 7) ccc.y += 1;
2845 else if (direction == 4 || direction == 8) ccc.y -= 1;
2847 if (direction == 5) ccc.y += 1;
2848 else if (direction == 6) ccc.y -= 1;
2849 else if (direction == 7) ccc.x -= 1;
2850 else if (direction == 8) ccc.x += 1;
2852 if (!isok(ccc.x, ccc.y)) break; /* otherwise the game could segfault! */
2854 if ((levl[ccc.x][ccc.y].typ != ROOM && levl[ccc.x][ccc.y].typ != AIR && levl[ccc.x][ccc.y].typ != STAIRS && levl[ccc.x][ccc.y].typ != LADDER && levl[ccc.x][ccc.y].typ != FOUNTAIN && levl[ccc.x][ccc.y].typ != THRONE && levl[ccc.x][ccc.y].typ != SINK && levl[ccc.x][ccc.y].typ != TOILET && levl[ccc.x][ccc.y].typ != GRAVE && levl[ccc.x][ccc.y].typ != ALTAR && levl[ccc.x][ccc.y].typ != ICE && levl[ccc.x][ccc.y].typ != CLOUD && levl[ccc.x][ccc.y].typ != SNOW && levl[ccc.x][ccc.y].typ != ASH && levl[ccc.x][ccc.y].typ != SAND && levl[ccc.x][ccc.y].typ != PAVEDFLOOR && levl[ccc.x][ccc.y].typ != HIGHWAY && levl[ccc.x][ccc.y].typ != GRASSLAND && levl[ccc.x][ccc.y].typ != NETHERMIST && levl[ccc.x][ccc.y].typ != STALACTITE && levl[ccc.x][ccc.y].typ != CRYPTFLOOR && levl[ccc.x][ccc.y].typ != BUBBLES && levl[ccc.x][ccc.y].typ != RAINCLOUD &&
2855 levl[ccc.x][ccc.y].typ != CORR) || MON_AT(ccc.x, ccc.y) || (otmp = sobj_at(BOULDER, ccc.x, ccc.y)) != 0 ) break;
2858 if ((levl[ccc.x][ccc.y].typ != ROOM && levl[ccc.x][ccc.y].typ != AIR && levl[ccc.x][ccc.y].typ != STAIRS && levl[ccc.x][ccc.y].typ != LADDER && levl[ccc.x][ccc.y].typ != FOUNTAIN && levl[ccc.x][ccc.y].typ != THRONE && levl[ccc.x][ccc.y].typ != SINK && levl[ccc.x][ccc.y].typ != TOILET && levl[ccc.x][ccc.y].typ != GRAVE && levl[ccc.x][ccc.y].typ != ALTAR && levl[ccc.x][ccc.y].typ != ICE && levl[ccc.x][ccc.y].typ != CLOUD && levl[ccc.x][ccc.y].typ != SNOW && levl[ccc.x][ccc.y].typ != ASH && levl[ccc.x][ccc.y].typ != SAND && levl[ccc.x][ccc.y].typ != PAVEDFLOOR && levl[ccc.x][ccc.y].typ != HIGHWAY && levl[ccc.x][ccc.y].typ != GRASSLAND && levl[ccc.x][ccc.y].typ != NETHERMIST && levl[ccc.x][ccc.y].typ != STALACTITE && levl[ccc.x][ccc.y].typ != CRYPTFLOOR && levl[ccc.x][ccc.y].typ != BUBBLES && levl[ccc.x][ccc.y].typ != RAINCLOUD &&
2859 levl[ccc.x][ccc.y].typ != CORR) || MON_AT(ccc.x, ccc.y) || (t_at(ccc.x, ccc.y) && !allowtrap) || (otmp = sobj_at(BOULDER, ccc.x, ccc.y)) != 0) {
2860 if (trycnt < 5000) {trycnt++; goto newtry;}
2861 return; /* more than 5000 tries */
2864 if (!isok(ccc.x, ccc.y)) return; /* otherwise the game could segfault! */
2866 pline("You're pushed back!");
2868 teleds(ccc.x, ccc.y, allowtrap);
2870 if (!(InterfaceScrewed || u.uprops[INTERFACE_SCREW].extrinsic || have_interfacescrewstone())) doredraw();
2871 return;
2874 void
2875 pushplayersilently(allowtrap)
2876 boolean allowtrap;
2878 coord ccc;
2879 int direction, pushwidth, trycnt;
2880 register struct obj *otmp;
2881 trycnt = 0;
2883 if (uwep && uwep->oartifact == ART_IMHULLU && rn2(10)) return;
2884 if (uarmf && uarmf->oartifact == ART_STAND_TALL_IN_THE_STORM) return;
2886 newtry:
2887 direction = rnd(8);
2888 pushwidth = rnd(2);
2889 if (!rn2(2)) pushwidth += rnd(2);
2890 if (uarmf && itemhasappearance(uarmf, APP_ZERO_DROP_SHOES)) {
2891 pushwidth = rnd(3);
2892 if (!rn2(2)) pushwidth += rnd(3);
2894 ccc.x = u.ux;
2895 ccc.y = u.uy;
2897 while (pushwidth--) {
2898 if (direction == 1 || direction == 5) ccc.x += 1;
2899 else if (direction == 2 || direction == 6) ccc.x -= 1;
2900 else if (direction == 3 || direction == 7) ccc.y += 1;
2901 else if (direction == 4 || direction == 8) ccc.y -= 1;
2903 if (direction == 5) ccc.y += 1;
2904 else if (direction == 6) ccc.y -= 1;
2905 else if (direction == 7) ccc.x -= 1;
2906 else if (direction == 8) ccc.x += 1;
2908 if (!isok(ccc.x, ccc.y)) break; /* otherwise the game could segfault! */
2910 if ((levl[ccc.x][ccc.y].typ != ROOM && levl[ccc.x][ccc.y].typ != AIR && levl[ccc.x][ccc.y].typ != STAIRS && levl[ccc.x][ccc.y].typ != LADDER && levl[ccc.x][ccc.y].typ != FOUNTAIN && levl[ccc.x][ccc.y].typ != THRONE && levl[ccc.x][ccc.y].typ != SINK && levl[ccc.x][ccc.y].typ != TOILET && levl[ccc.x][ccc.y].typ != GRAVE && levl[ccc.x][ccc.y].typ != ALTAR && levl[ccc.x][ccc.y].typ != ICE && levl[ccc.x][ccc.y].typ != CLOUD && levl[ccc.x][ccc.y].typ != SNOW && levl[ccc.x][ccc.y].typ != ASH && levl[ccc.x][ccc.y].typ != SAND && levl[ccc.x][ccc.y].typ != PAVEDFLOOR && levl[ccc.x][ccc.y].typ != HIGHWAY && levl[ccc.x][ccc.y].typ != GRASSLAND && levl[ccc.x][ccc.y].typ != NETHERMIST && levl[ccc.x][ccc.y].typ != STALACTITE && levl[ccc.x][ccc.y].typ != CRYPTFLOOR && levl[ccc.x][ccc.y].typ != BUBBLES && levl[ccc.x][ccc.y].typ != RAINCLOUD &&
2911 levl[ccc.x][ccc.y].typ != CORR) || MON_AT(ccc.x, ccc.y) || (otmp = sobj_at(BOULDER, ccc.x, ccc.y)) != 0 ) break;
2914 if ((levl[ccc.x][ccc.y].typ != ROOM && levl[ccc.x][ccc.y].typ != AIR && levl[ccc.x][ccc.y].typ != STAIRS && levl[ccc.x][ccc.y].typ != LADDER && levl[ccc.x][ccc.y].typ != FOUNTAIN && levl[ccc.x][ccc.y].typ != THRONE && levl[ccc.x][ccc.y].typ != SINK && levl[ccc.x][ccc.y].typ != TOILET && levl[ccc.x][ccc.y].typ != GRAVE && levl[ccc.x][ccc.y].typ != ALTAR && levl[ccc.x][ccc.y].typ != ICE && levl[ccc.x][ccc.y].typ != CLOUD && levl[ccc.x][ccc.y].typ != SNOW && levl[ccc.x][ccc.y].typ != ASH && levl[ccc.x][ccc.y].typ != SAND && levl[ccc.x][ccc.y].typ != PAVEDFLOOR && levl[ccc.x][ccc.y].typ != HIGHWAY && levl[ccc.x][ccc.y].typ != GRASSLAND && levl[ccc.x][ccc.y].typ != NETHERMIST && levl[ccc.x][ccc.y].typ != STALACTITE && levl[ccc.x][ccc.y].typ != CRYPTFLOOR && levl[ccc.x][ccc.y].typ != BUBBLES && levl[ccc.x][ccc.y].typ != RAINCLOUD &&
2915 levl[ccc.x][ccc.y].typ != CORR) || MON_AT(ccc.x, ccc.y) || (t_at(ccc.x, ccc.y) && !allowtrap) || (otmp = sobj_at(BOULDER, ccc.x, ccc.y)) != 0) {
2916 if (trycnt < 50) {trycnt++; goto newtry;}
2917 return; /* more than 50 tries */
2920 if (!isok(ccc.x, ccc.y)) return; /* otherwise the game could segfault! */
2922 teleds(ccc.x, ccc.y, allowtrap);
2924 if (!(InterfaceScrewed || u.uprops[INTERFACE_SCREW].extrinsic || have_interfacescrewstone())) doredraw();
2925 return;
2928 boolean
2929 pushmonster(mtmp)
2930 struct monst *mtmp;
2932 coord ccc;
2933 int direction, pushwidth, trycnt;
2934 register struct obj *otmp;
2935 trycnt = 0;
2937 if (!mtmp) {
2938 impossible("pushmonster() called with no monster.");
2939 return 0;
2942 if (!isok(mtmp->mx, mtmp->my)) {
2943 impossible("monster coordinates for pushmonster() out of range: %d, %d", mtmp->mx, mtmp->my);
2944 return 0;
2947 newtry:
2948 direction = rnd(8);
2949 pushwidth = rnd(2);
2950 if (!rn2(2)) pushwidth += rnd(2);
2951 ccc.x = mtmp->mx;
2952 ccc.y = mtmp->my;
2954 while (pushwidth--) {
2955 if (direction == 1 || direction == 5) ccc.x += 1;
2956 else if (direction == 2 || direction == 6) ccc.x -= 1;
2957 else if (direction == 3 || direction == 7) ccc.y += 1;
2958 else if (direction == 4 || direction == 8) ccc.y -= 1;
2960 if (direction == 5) ccc.y += 1;
2961 else if (direction == 6) ccc.y -= 1;
2962 else if (direction == 7) ccc.x -= 1;
2963 else if (direction == 8) ccc.x += 1;
2965 if (!isok(ccc.x, ccc.y)) break; /* otherwise the game could segfault! */
2967 if ((levl[ccc.x][ccc.y].typ != ROOM && levl[ccc.x][ccc.y].typ != AIR && levl[ccc.x][ccc.y].typ != STAIRS && levl[ccc.x][ccc.y].typ != LADDER && levl[ccc.x][ccc.y].typ != FOUNTAIN && levl[ccc.x][ccc.y].typ != THRONE && levl[ccc.x][ccc.y].typ != SINK && levl[ccc.x][ccc.y].typ != TOILET && levl[ccc.x][ccc.y].typ != GRAVE && levl[ccc.x][ccc.y].typ != ALTAR && levl[ccc.x][ccc.y].typ != ICE && levl[ccc.x][ccc.y].typ != CLOUD && levl[ccc.x][ccc.y].typ != SNOW && levl[ccc.x][ccc.y].typ != ASH && levl[ccc.x][ccc.y].typ != SAND && levl[ccc.x][ccc.y].typ != PAVEDFLOOR && levl[ccc.x][ccc.y].typ != HIGHWAY && levl[ccc.x][ccc.y].typ != GRASSLAND && levl[ccc.x][ccc.y].typ != NETHERMIST && levl[ccc.x][ccc.y].typ != STALACTITE && levl[ccc.x][ccc.y].typ != CRYPTFLOOR && levl[ccc.x][ccc.y].typ != BUBBLES && levl[ccc.x][ccc.y].typ != RAINCLOUD &&
2968 levl[ccc.x][ccc.y].typ != CORR) || MON_AT(ccc.x, ccc.y) || (otmp = sobj_at(BOULDER, ccc.x, ccc.y)) != 0 ) break;
2971 if ((levl[ccc.x][ccc.y].typ != ROOM && levl[ccc.x][ccc.y].typ != AIR && levl[ccc.x][ccc.y].typ != STAIRS && levl[ccc.x][ccc.y].typ != LADDER && levl[ccc.x][ccc.y].typ != FOUNTAIN && levl[ccc.x][ccc.y].typ != THRONE && levl[ccc.x][ccc.y].typ != SINK && levl[ccc.x][ccc.y].typ != TOILET && levl[ccc.x][ccc.y].typ != GRAVE && levl[ccc.x][ccc.y].typ != ALTAR && levl[ccc.x][ccc.y].typ != ICE && levl[ccc.x][ccc.y].typ != CLOUD && levl[ccc.x][ccc.y].typ != SNOW && levl[ccc.x][ccc.y].typ != ASH && levl[ccc.x][ccc.y].typ != SAND && levl[ccc.x][ccc.y].typ != PAVEDFLOOR && levl[ccc.x][ccc.y].typ != HIGHWAY && levl[ccc.x][ccc.y].typ != GRASSLAND && levl[ccc.x][ccc.y].typ != NETHERMIST && levl[ccc.x][ccc.y].typ != STALACTITE && levl[ccc.x][ccc.y].typ != CRYPTFLOOR && levl[ccc.x][ccc.y].typ != BUBBLES && levl[ccc.x][ccc.y].typ != RAINCLOUD &&
2972 levl[ccc.x][ccc.y].typ != CORR) || MON_AT(ccc.x, ccc.y) || (otmp = sobj_at(BOULDER, ccc.x, ccc.y)) != 0) {
2973 if (trycnt < 50) {trycnt++; goto newtry;}
2974 return 0; /* more than 50 tries */
2977 if (!isok(ccc.x, ccc.y)) return 0; /* otherwise the game could segfault! */
2979 remove_monster(mtmp->mx, mtmp->my);
2980 place_monster(mtmp, ccc.x, ccc.y);
2982 return 1;
2985 /*teleport.c*/