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