Revert "Track who destroys an item; incur Nemelex penance for deck destruction."
[crawl.git] / crawl-ref / source / spl-transloc.cc
1 /**
2  * @file
3  * @brief Translocation spells.
4 **/
5
6 #include "AppHdr.h"
7
8 #include <cmath>
9 #include <vector>
10 #include <algorithm>
11
12 #include "spl-transloc.h"
13 #include "externs.h"
14
15 #include "abyss.h"
16 #include "areas.h"
17 #include "cloud.h"
18 #include "coord.h"
19 #include "coordit.h"
20 #include "delay.h"
21 #include "directn.h"
22 #include "dungeon.h"
23 #include "env.h"
24 #include "fprop.h"
25 #include "invent.h"
26 #include "item_use.h"
27 #include "itemprop.h"
28 #include "items.h"
29 #include "libutil.h"
30 #include "losglobal.h"
31 #include "message.h"
32 #include "misc.h"
33 #include "mon-behv.h"
34 #include "mon-iter.h"
35 #include "mon-util.h"
36 #include "mon-stuff.h"
37 #include "orb.h"
38 #include "random.h"
39 #include "shout.h"
40 #include "spl-util.h"
41 #include "stash.h"
42 #include "state.h"
43 #include "stuff.h"
44 #include "teleport.h"
45 #include "terrain.h"
46 #include "throw.h"
47 #include "transform.h"
48 #include "traps.h"
49 #include "view.h"
50 #include "viewmap.h"
51 #include "xom.h"
52
53 static bool _abyss_blocks_teleport(bool cblink)
54 {
55     // Controlled Blink (the spell) works more reliably in the Abyss.
56     return (cblink ? coinflip() : !one_chance_in(3));
57 }
58
59 // XXX: can miscast before cancelling.
60 spret_type cast_controlled_blink(int pow, bool fail)
61 {
62     fail_check();
63     if (blink(pow, true) == -1)
64         return SPRET_ABORT;
65     return SPRET_SUCCESS;
66 }
67
68 spret_type cast_disjunction(int pow, bool fail)
69 {
70     fail_check();
71     int rand = random_range(35, 45) + random2(pow / 12);
72     you.duration[DUR_DISJUNCTION] = min(90 + pow / 12,
73         max(you.duration[DUR_DISJUNCTION] + rand,
74         30 + rand));
75     contaminate_player(1, true);
76     disjunction();
77     return SPRET_SUCCESS;
78 }
79
80 void disjunction()
81 {
82     int steps = you.time_taken;
83     invalidate_agrid(true);
84     for (int step = 0; step < steps; ++step)
85     {
86         vector<monster*> mvec;
87         for (radius_iterator ri(you.pos(), LOS_RADIUS, C_ROUND); ri; ++ri)
88         {
89             monster* mons = monster_at(*ri);
90             if (!mons || !you.see_cell(*ri))
91                 continue;
92             mvec.push_back(mons);
93         }
94         if (mvec.empty())
95             return;
96         // blink should be isotropic
97         random_shuffle(mvec.begin(), mvec.end());
98         for (vector<monster*>::iterator mitr = mvec.begin();
99             mitr != mvec.end(); mitr++)
100         {
101             monster* mons = *mitr;
102             if (!mons->alive() || mons->no_tele())
103                 continue;
104             coord_def p = mons->pos();
105             if (!disjunction_haloed(p))
106                 continue;
107
108             int dist = grid_distance(you.pos(), p);
109             int decay = max(1, (dist - 1) * (dist + 1));
110             int chance = pow(0.8, 1.0 / decay) * 1000;
111             if (!x_chance_in_y(chance, 1000))
112                 blink_away(mons, &you, false);
113         }
114     }
115 }
116
117 // If wizard_blink is set, all restriction are ignored (except for
118 // a monster being at the target spot), and the player gains no
119 // contamination.
120 int blink(int pow, bool high_level_controlled_blink, bool wizard_blink,
121           string *pre_msg)
122 {
123     ASSERT(!crawl_state.game_is_arena());
124
125     dist beam;
126
127     if (crawl_state.is_repeating_cmd())
128     {
129         crawl_state.cant_cmd_repeat("You can't repeat controlled blinks.");
130         crawl_state.cancel_cmd_again();
131         crawl_state.cancel_cmd_repeat();
132         return -1;
133     }
134
135     // yes, there is a logic to this ordering {dlb}:
136     if (you.no_tele(true, true, true) && !wizard_blink)
137     {
138         if (pre_msg)
139             mpr(pre_msg->c_str());
140         canned_msg(MSG_STRANGE_STASIS);
141     }
142     else if (player_in_branch(BRANCH_ABYSS)
143              && _abyss_blocks_teleport(high_level_controlled_blink)
144              && !wizard_blink)
145     {
146         if (pre_msg)
147             mpr(pre_msg->c_str());
148         mpr("The power of the Abyss keeps you in your place!");
149     }
150     else if (you.confused() && !wizard_blink)
151     {
152         if (pre_msg)
153             mpr(pre_msg->c_str());
154         random_blink(false);
155     }
156     // The orb sometimes degrades controlled blinks to completely uncontrolled.
157     else if (orb_haloed(you.pos()) && !wizard_blink)
158     {
159         if (pre_msg)
160             mpr(pre_msg->c_str());
161         mpr("The orb interferes with your control of the blink!", MSGCH_ORB);
162         // abort still wastes the turn
163         if (high_level_controlled_blink && coinflip())
164             return (cast_semi_controlled_blink(pow, false, false) ? 1 : 0);
165         random_blink(false);
166     }
167     else if (!allow_control_teleport(true) && !wizard_blink)
168     {
169         if (pre_msg)
170             mpr(pre_msg->c_str());
171         mpr("A powerful magic interferes with your control of the blink.");
172         // FIXME: cancel shouldn't waste a turn here -- need to rework Abyss handling
173         if (high_level_controlled_blink)
174             return (cast_semi_controlled_blink(pow, false/*true*/, false) ? 1 : -1);
175         random_blink(false);
176     }
177     else
178     {
179         // query for location {dlb}:
180         while (1)
181         {
182             direction_chooser_args args;
183             args.restricts = DIR_TARGET;
184             args.needs_path = false;
185             args.may_target_monster = false;
186             args.top_prompt = "Blink to where?";
187             direction(beam, args);
188
189             if (crawl_state.seen_hups)
190             {
191                 mpr("Cancelling blink due to HUP.");
192                 return -1;
193             }
194
195             if (!beam.isValid || beam.target == you.pos())
196             {
197                 if (!wizard_blink
198                     && !yesno("Are you sure you want to cancel this blink?",
199                               false, 'n'))
200                 {
201                     mesclr();
202                     continue;
203                 }
204                 canned_msg(MSG_OK);
205                 return -1;         // early return {dlb}
206             }
207
208             monster* beholder = you.get_beholder(beam.target);
209             if (!wizard_blink && beholder)
210             {
211                 mprf("You cannot blink away from %s!",
212                     beholder->name(DESC_THE, true).c_str());
213                 continue;
214             }
215
216             monster* fearmonger = you.get_fearmonger(beam.target);
217             if (!wizard_blink && fearmonger)
218             {
219                 mprf("You cannot blink closer to %s!",
220                     fearmonger->name(DESC_THE, true).c_str());
221                 continue;
222             }
223
224             if (grd(beam.target) == DNGN_OPEN_SEA)
225             {
226                 mesclr();
227                 mpr("You can't blink into the sea!");
228             }
229             else if (grd(beam.target) == DNGN_LAVA_SEA)
230             {
231                 mesclr();
232                 mpr("You can't blink into the sea of lava!");
233             }
234             else if (!check_moveto(beam.target, "blink"))
235             {
236                 // try again (messages handled by check_moveto)
237             }
238             else if (you.see_cell_no_trans(beam.target))
239             {
240                 // Grid in los, no problem.
241                 break;
242             }
243             else if (you.trans_wall_blocking(beam.target))
244             {
245                 // Wizard blink can move past translucent walls.
246                 if (wizard_blink)
247                     break;
248
249                 mesclr();
250                 mpr("There's something in the way!");
251             }
252             else
253             {
254                 mesclr();
255                 mpr("You can only blink to visible locations.");
256             }
257         }
258
259         if (!you.attempt_escape(2))
260             return false;
261
262         if (pre_msg)
263             mpr(pre_msg->c_str());
264
265         // Allow wizard blink to send player into walls, in case the
266         // user wants to alter that grid to something else.
267         if (wizard_blink && feat_is_solid(grd(beam.target)))
268             grd(beam.target) = DNGN_FLOOR;
269
270         if (feat_is_solid(grd(beam.target)) || monster_at(beam.target))
271         {
272             mpr("Oops! Maybe something was there already.");
273             random_blink(false);
274         }
275         else if (player_in_branch(BRANCH_ABYSS) && !wizard_blink)
276         {
277             abyss_teleport(false);
278             if (you.pet_target != MHITYOU)
279                 you.pet_target = MHITNOT;
280         }
281         else
282         {
283             // Leave a purple cloud.
284             if (!wizard_blink)
285                 place_cloud(CLOUD_TLOC_ENERGY, you.pos(), 1 + random2(3), &you);
286
287             move_player_to_grid(beam.target, false, true);
288
289             // Controlling teleport contaminates the player. -- bwr
290             if (!wizard_blink)
291                 contaminate_player(1, true);
292         }
293     }
294
295     crawl_state.cancel_cmd_again();
296     crawl_state.cancel_cmd_repeat();
297
298     return 1;
299 }
300
301 spret_type cast_blink(bool allow_partial_control, bool fail)
302 {
303     fail_check();
304     random_blink(allow_partial_control);
305     return SPRET_SUCCESS;
306 }
307
308 void random_blink(bool allow_partial_control, bool override_abyss, bool override_stasis)
309 {
310     ASSERT(!crawl_state.game_is_arena());
311
312     coord_def target;
313
314     if (you.no_tele(true, true, true) && !override_stasis)
315         canned_msg(MSG_STRANGE_STASIS);
316     else if (player_in_branch(BRANCH_ABYSS)
317              && !override_abyss
318              && _abyss_blocks_teleport(false))
319     {
320         mpr("The power of the Abyss keeps you in your place!");
321     }
322     // First try to find a random square not adjacent to the player,
323     // then one adjacent if that fails.
324     else if (!random_near_space(you.pos(), target)
325              && !random_near_space(you.pos(), target, true))
326     {
327         mpr("You feel jittery for a moment.");
328     }
329
330     //jmf: Add back control, but effect is cast_semi_controlled_blink(pow).
331     else if (player_control_teleport() && !you.confused() && allow_partial_control
332              && allow_control_teleport())
333     {
334         mpr("You may select the general direction of your translocation.");
335         // FIXME: handle aborts here, don't waste the turn
336         cast_semi_controlled_blink(100, false, true);
337     }
338     else if (you.attempt_escape(2))
339     {
340         canned_msg(MSG_YOU_BLINK);
341         coord_def origin = you.pos();
342         move_player_to_grid(target, false, true);
343
344         // Leave a purple cloud.
345         place_cloud(CLOUD_TLOC_ENERGY, origin, 1 + random2(3), &you);
346     }
347 }
348
349 // This function returns true if the player can use controlled teleport
350 // here.
351 bool allow_control_teleport(bool quiet)
352 {
353     const bool retval = !(testbits(env.level_flags, LFLAG_NO_TELE_CONTROL)
354                           || orb_haloed(you.pos()) || you.beheld());
355
356     // Tell the player why if they have teleport control.
357     if (!quiet && !retval && player_control_teleport())
358     {
359         if (orb_haloed(you.pos()))
360             mpr("The orb prevents control of your teleportation!", MSGCH_ORB);
361         else if (you.beheld())
362             mpr("It is impossible to concentrate on your destination whilst mesmerised.");
363         else
364             mpr("A powerful magic prevents control of your teleportation.");
365     }
366
367     return retval;
368 }
369
370 spret_type cast_teleport_self(bool fail)
371 {
372     fail_check();
373     you_teleport();
374     return SPRET_SUCCESS;
375 }
376
377 void you_teleport(void)
378 {
379     // [Cha] here we block teleportation, which will save the player from
380     // death from read-id'ing scrolls (in sprint)
381     if (you.no_tele(true, true))
382         canned_msg(MSG_STRANGE_STASIS);
383     else if (you.duration[DUR_TELEPORT])
384     {
385         mpr("You feel strangely stable.");
386         you.duration[DUR_TELEPORT] = 0;
387     }
388     else
389     {
390         mpr("You feel strangely unstable.");
391
392         int teleport_delay = 3 + random2(3);
393
394         // Doesn't care whether the cTele will actually work or not.
395         if (player_control_teleport())
396         {
397             mpr("You feel your translocation being delayed.");
398             teleport_delay += 1 + random2(3);
399         }
400         if (player_in_branch(BRANCH_ABYSS) && !one_chance_in(5))
401         {
402             mpr("You feel the power of the Abyss delaying your translocation.");
403             teleport_delay += 5 + random2(10);
404         }
405         else if (orb_haloed(you.pos()))
406         {
407             mpr("You feel the orb delaying this translocation!", MSGCH_ORB);
408             teleport_delay += 5 + random2(5);
409         }
410
411         you.set_duration(DUR_TELEPORT, teleport_delay);
412     }
413 }
414
415 // Should return true if we don't want anyone to teleport here.
416 static bool _cell_vetoes_teleport(const coord_def cell, bool check_monsters = true,
417                                   bool wizard_tele = false)
418 {
419     // Monsters always veto teleport.
420     if (monster_at(cell) && check_monsters)
421         return true;
422
423     // As do all clouds; this may change.
424     if (env.cgrid(cell) != EMPTY_CLOUD && !wizard_tele)
425         return true;
426
427     if (cell_is_solid(cell))
428         return true;
429
430     return is_feat_dangerous(grd(cell), true) && !wizard_tele;
431 }
432
433 static void _handle_teleport_update(bool large_change, const coord_def old_pos)
434 {
435     if (large_change)
436     {
437         viewwindow();
438         for (monster_iterator mi; mi; ++mi)
439         {
440             const bool see_cell = you.see_cell(mi->pos());
441
442             if (mi->foe == MHITYOU && !see_cell && !you.penance[GOD_ASHENZARI])
443             {
444                 mi->foe_memory = 0;
445                 behaviour_event(*mi, ME_EVAL);
446             }
447             else if (see_cell)
448                 behaviour_event(*mi, ME_EVAL);
449         }
450
451         handle_interrupted_swap(true);
452     }
453
454 #ifdef USE_TILE
455     if (you.species == SP_MERFOLK)
456     {
457         const dungeon_feature_type new_grid = grd(you.pos());
458         const dungeon_feature_type old_grid = grd(old_pos);
459         if (feat_is_water(old_grid) && !feat_is_water(new_grid)
460             || !feat_is_water(old_grid) && feat_is_water(new_grid))
461         {
462             init_player_doll();
463         }
464     }
465 #endif
466 }
467
468 static bool _teleport_player(bool allow_control, bool new_abyss_area,
469                              bool wizard_tele, int range)
470 {
471     bool is_controlled = (allow_control && !you.confused()
472                           && player_control_teleport()
473                           && allow_control_teleport()
474                           && !you.berserk());
475
476     // All wizard teleports are automatically controlled.
477     if (wizard_tele)
478         is_controlled = true;
479
480     // Stasis can't block the Abyss from shifting.
481     if (!wizard_tele
482         && (crawl_state.game_is_sprint() || you.no_tele(true, true))
483             && !new_abyss_area)
484     {
485         canned_msg(MSG_STRANGE_STASIS);
486         return false;
487     }
488
489     // After this point, we're guaranteed to teleport. Kill the appropriate
490     // delays.
491     interrupt_activity(AI_TELEPORT);
492
493     // Update what we can see at the current location as well as its stash,
494     // in case something happened in the exact turn that we teleported
495     // (like picking up/dropping an item).
496     viewwindow();
497     StashTrack.update_stash(you.pos());
498
499     if (player_in_branch(BRANCH_ABYSS) && !wizard_tele)
500     {
501         abyss_teleport(new_abyss_area);
502         if (you.pet_target != MHITYOU)
503             you.pet_target = MHITNOT;
504
505         return true;
506     }
507
508     coord_def pos(1, 0);
509     const coord_def old_pos = you.pos();
510     bool      large_change  = false;
511
512     if (is_controlled)
513     {
514         // Only have the messages and the more prompt for non-wizard.
515         if (!wizard_tele)
516         {
517             mpr("You may choose your destination (press '.' or delete to select).");
518             mpr("Expect minor deviation.");
519             more();
520         }
521
522         while (true)
523         {
524             level_pos lpos;
525             bool chose = show_map(lpos, false, true, false);
526             pos = lpos.pos;
527             redraw_screen();
528
529             // If we've received a HUP signal then the user can't choose a
530             // location, so cancel the teleport.
531             if (crawl_state.seen_hups)
532             {
533                 mpr("Controlled teleport interrupted by HUP signal, "
534                     "cancelling teleport.", MSGCH_ERROR);
535                 if (!wizard_tele)
536                     contaminate_player(1, true);
537                 return false;
538             }
539
540             dprf("Target square (%d,%d)", pos.x, pos.y);
541
542             if (!chose || pos == you.pos())
543             {
544                 if (!wizard_tele)
545                 {
546                     if (!yesno("Are you sure you want to cancel this teleport?",
547                                true, 'n'))
548                     {
549                         continue;
550                     }
551                 }
552                 if (!wizard_tele)
553                     contaminate_player(1, true);
554                 return false;
555             }
556
557             monster* beholder = you.get_beholder(pos);
558             if (beholder && !wizard_tele)
559             {
560                 mprf("You cannot teleport away from %s!",
561                      beholder->name(DESC_THE, true).c_str());
562                 mpr("Choose another destination (press '.' or delete to select).");
563                 more();
564                 continue;
565             }
566
567             monster* fearmonger = you.get_fearmonger(pos);
568             if (fearmonger && !wizard_tele)
569             {
570                 mprf("You cannot teleport closer to %s!",
571                      fearmonger->name(DESC_THE, true).c_str());
572                 mpr("Choose another destination (press '.' or delete to select).");
573                 more();
574                 continue;
575             }
576             break;
577         }
578
579         // Don't randomly walk wizard teleports.
580         if (!wizard_tele)
581         {
582             pos.x += random2(3) - 1;
583             pos.y += random2(3) - 1;
584
585             if (one_chance_in(4))
586             {
587                 pos.x += random2(3) - 1;
588                 pos.y += random2(3) - 1;
589             }
590             dprf("Scattered target square (%d, %d)", pos.x, pos.y);
591         }
592
593         if (!in_bounds(pos))
594         {
595             mpr("Nearby solid objects disrupt your rematerialisation!");
596             is_controlled = false;
597         }
598
599         if (is_controlled)
600         {
601             if (!you.see_cell(pos))
602                 large_change = true;
603
604             // Merfolk should be able to control-tele into deep water.
605             if (_cell_vetoes_teleport(pos, true, wizard_tele))
606             {
607                 if (wizard_tele)
608                 {
609                     mpr("Even you can't go there right now. Sorry!", MSGCH_WARN);
610                     return false;
611                 }
612
613                 dprf("Target square (%d, %d) vetoed, now random teleport.", pos.x, pos.y);
614                 is_controlled = false;
615                 large_change  = false;
616             }
617             else if (testbits(env.pgrid(pos), FPROP_NO_CTELE_INTO) && !wizard_tele)
618             {
619                 is_controlled = false;
620                 large_change = false;
621                 mpr("A strong magical force throws you back!", MSGCH_WARN);
622             }
623             else
624             {
625                 // Leave a purple cloud.
626                 if (!wizard_tele)
627                     place_cloud(CLOUD_TLOC_ENERGY, old_pos, 1 + random2(3), &you);
628
629                 move_player_to_grid(pos, false, true);
630
631                 // Controlling teleport contaminates the player. - bwr
632                 if (!wizard_tele)
633                     contaminate_player(1, true);
634             }
635             // End teleport control.
636             if (you.duration[DUR_CONTROL_TELEPORT])
637             {
638                 mpr("You feel uncertain.", MSGCH_DURATION);
639                 you.duration[DUR_CONTROL_TELEPORT] = 0;
640             }
641         }
642     }
643
644     if (!is_controlled)
645     {
646         coord_def newpos;
647
648         // If in a labyrinth, always teleport well away from the centre.
649         // (Check done for the straight line, no pathfinding involved.)
650         bool need_distance_check = false;
651         coord_def centre;
652         if (player_in_branch(BRANCH_LABYRINTH))
653         {
654             bool success = false;
655             for (int xpos = 0; xpos < GXM; xpos++)
656             {
657                 for (int ypos = 0; ypos < GYM; ypos++)
658                 {
659                     centre = coord_def(xpos, ypos);
660                     if (!in_bounds(centre))
661                         continue;
662
663                     if (grd(centre) == DNGN_ESCAPE_HATCH_UP)
664                     {
665                         success = true;
666                         break;
667                     }
668                 }
669                 if (success)
670                     break;
671             }
672             need_distance_check = success;
673         }
674
675         do
676             newpos = random_in_bounds();
677         while (_cell_vetoes_teleport(newpos)
678                || (newpos - old_pos).abs() > dist_range(range)
679                || need_distance_check && (newpos - centre).abs()
680                                           <= dist_range(min(range - 1, 34))
681                || testbits(env.pgrid(newpos), FPROP_NO_RTELE_INTO));
682
683         if (newpos == old_pos)
684             mpr("Your surroundings flicker for a moment.");
685         else if (you.see_cell(newpos))
686             mpr("Your surroundings seem slightly different.");
687         else
688         {
689             mpr("Your surroundings suddenly seem different.");
690             large_change = true;
691         }
692
693         // Leave a purple cloud.
694         place_cloud(CLOUD_TLOC_ENERGY, old_pos, 1 + random2(3), &you);
695
696         move_player_to_grid(newpos, false, true);
697     }
698
699     _handle_teleport_update(large_change, old_pos);
700     return (!is_controlled);
701 }
702
703 bool you_teleport_to(const coord_def where_to, bool move_monsters)
704 {
705     // Attempts to teleport the player from their current location to 'where'.
706     // Follows this line of reasoning:
707     //   1. Check the location (against _cell_vetoes_teleport), if valid,
708     //      teleport the player there.
709     //   2. If not because of a monster, and move_monster, teleport that
710     //      monster out of the way, then teleport the player there.
711     //   3. Otherwise, iterate over adjacent squares. If a sutiable position is
712     //      found (or a monster can be moved out of the way, with move_monster)
713     //      then teleport the player there.
714     //   4. If not, give up and return false.
715
716     const coord_def old_pos = you.pos();
717     coord_def where = where_to;
718     coord_def old_where = where_to;
719
720     // Don't bother to calculate a possible new position if it's out of bounds.
721     if (!in_bounds(where))
722         return false;
723
724     if (_cell_vetoes_teleport(where))
725     {
726         if (monster_at(where) && move_monsters && !_cell_vetoes_teleport(where, false))
727         {
728             // dlua only, don't heed no_tele
729             monster* mons = monster_at(where);
730             mons->teleport(true);
731         }
732         else
733         {
734             for (adjacent_iterator ai(where); ai; ++ai)
735             {
736                 if (!_cell_vetoes_teleport(*ai))
737                 {
738                     where = *ai;
739                     break;
740                 }
741                 else
742                 {
743                     if (monster_at(*ai) && move_monsters
744                             && !_cell_vetoes_teleport(*ai, false))
745                     {
746                         monster* mons = monster_at(*ai);
747                         mons->teleport(true);
748                         where = *ai;
749                         break;
750                     }
751                 }
752             }
753             // Give up, we can't find a suitable spot.
754             if (where == old_where)
755                 return false;
756         }
757     }
758
759     // If we got this far, we're teleporting the player.
760     // Leave a purple cloud.
761     place_cloud(CLOUD_TLOC_ENERGY, old_pos, 1 + random2(3), &you);
762
763     bool large_change = you.see_cell(where);
764
765     move_player_to_grid(where, false, true);
766
767     _handle_teleport_update(large_change, old_pos);
768     return true;
769 }
770
771 void you_teleport_now(bool allow_control, bool new_abyss_area,
772                       bool wizard_tele, int range)
773 {
774     const bool randtele = _teleport_player(allow_control, new_abyss_area,
775                                            wizard_tele, range);
776
777     // Xom is amused by uncontrolled teleports that land you in a
778     // dangerous place, unless the player is in the Abyss and
779     // teleported to escape from all the monsters chasing him/her,
780     // since in that case the new dangerous area is almost certainly
781     // *less* dangerous than the old dangerous area.
782     // Teleporting in a labyrinth is also funny, more so for non-minotaurs.
783     if (randtele
784         && (player_in_branch(BRANCH_LABYRINTH)
785             || !player_in_branch(BRANCH_ABYSS) && player_in_a_dangerous_place()))
786     {
787         if (player_in_branch(BRANCH_LABYRINTH) && you.species == SP_MINOTAUR)
788             xom_is_stimulated(100);
789         else
790             xom_is_stimulated(200);
791     }
792 }
793
794 spret_type cast_portal_projectile(int pow, bool fail)
795 {
796     dist target;
797     int item = get_ammo_to_shoot(-1, target, true);
798     if (item == -1)
799         return SPRET_ABORT;
800
801     if (cell_is_solid(target.target))
802     {
803         mpr("You can't shoot at gazebos.");
804         return SPRET_ABORT;
805     }
806
807     // Can't use portal through walls. (That'd be just too cheap!)
808     if (you.trans_wall_blocking(target.target))
809     {
810         mpr("There's something in the way!");
811         return SPRET_ABORT;
812     }
813
814     if (!check_warning_inscriptions(you.inv[item], OPER_FIRE))
815         return SPRET_ABORT;
816
817     fail_check();
818     bolt beam;
819     throw_it(beam, item, true, random2(pow/4), &target);
820
821     return SPRET_SUCCESS;
822 }
823
824 spret_type cast_apportation(int pow, bolt& beam, bool fail)
825 {
826     const coord_def where = beam.target;
827
828     if (!cell_see_cell(you.pos(), where, LOS_SOLID))
829     {
830         mpr("There's something in the way!");
831         return SPRET_ABORT;
832     }
833
834     // Letting mostly-melee characters spam apport after every Shoals
835     // fight seems like it has too much grinding potential.  We could
836     // weaken this for high power.
837     if (grd(where) == DNGN_DEEP_WATER || grd(where) == DNGN_LAVA)
838     {
839         mpr("The density of the terrain blocks your spell.");
840         return SPRET_ABORT;
841     }
842
843     // Let's look at the top item in that square...
844     // And don't allow apporting from shop inventories.
845     const int item_idx = igrd(where);
846     if (item_idx == NON_ITEM || !in_bounds(where))
847     {
848         mpr("There are no items there.");
849         return SPRET_ABORT;
850     }
851
852     item_def& item = mitm[item_idx];
853
854     // Can't apport the Orb in zotdef
855     if (crawl_state.game_is_zotdef() && item_is_orb(item))
856     {
857         mpr("You cannot apport the sacred Orb!");
858         return SPRET_ABORT;
859     }
860
861     fail_check();
862     // Mass of one unit.
863     const int unit_mass = item_mass(item);
864     const int max_mass = pow * 30 + random2(pow * 20);
865
866     int max_units = item.quantity;
867     if (unit_mass > 0)
868         max_units = max_mass / unit_mass;
869
870     if (max_units <= 0)
871     {
872         if (item_is_orb(item))
873             orb_pickup_noise(where, 30);
874
875         mpr("The mass is resisting your pull.");
876
877         return SPRET_SUCCESS;
878     }
879
880     // We need to modify the item *before* we move it, because
881     // move_top_item() might change the location, or merge
882     // with something at our position.
883     if (item_is_orb(item))
884     {
885         fake_noisy(30, where);
886
887         // There's also a 1-in-3 flat chance of apport failing.
888         if (one_chance_in(3))
889         {
890             orb_pickup_noise(where, 30,
891                 "The orb shrieks and becomes a dead weight against your magic!",
892                 "The orb lets out a furious burst of light and becomes "
893                     "a dead weight against your magic!");
894             return SPRET_SUCCESS;
895         }
896         else // Otherwise it's just a noisy little shiny thing
897         {
898             orb_pickup_noise(where, 30,
899                 "The orb shrieks as your magic touches it!",
900                 "The orb lets out a furious burst of light as your magic touches it!");
901         }
902     }
903
904     // If we apport a net, free the monster under it.
905     if (item.base_type == OBJ_MISSILES
906         && item.sub_type == MI_THROWING_NET
907         && item_is_stationary(item))
908     {
909         remove_item_stationary(item);
910         if (monster* mons = monster_at(where))
911             mons->del_ench(ENCH_HELD, true);
912     }
913
914     // Heavy items require more power to apport directly to your feet.
915     // They might end up just moving a few squares, depending on spell
916     // power and item mass.
917     beam.is_tracer = true;
918     beam.aimed_at_spot = true;
919     beam.affects_nothing = true;
920     beam.fire();
921
922     // Pop the item's location off the end
923     beam.path_taken.pop_back();
924
925     // The actual number of squares it needs to traverse to get to you.
926     int dist = beam.path_taken.size();
927
928     // The maximum number of squares the item will actually move, always
929     // at least one square.
930     int quantity = item.quantity;
931     int apported_mass = unit_mass * min(quantity, max_units);
932
933     int max_dist = max(60 * pow / (apported_mass + 150), 1);
934
935     dprf("Apport dist=%d, max_dist=%d", dist, max_dist);
936
937     int location_on_path = max(-1, dist - max_dist);
938     // Don't move mimics under you.
939     if ((item.flags & ISFLAG_MIMIC) && location_on_path == -1)
940         location_on_path = 0;
941     coord_def new_spot;
942     if (location_on_path == -1)
943         new_spot = you.pos();
944     else
945         new_spot = beam.path_taken[location_on_path];
946     // Try to find safe terrain for the item.
947     while (location_on_path < dist)
948     {
949         if (!feat_virtually_destroys_item(grd(new_spot), item))
950             break;
951         location_on_path++;
952         new_spot = beam.path_taken[location_on_path];
953     }
954     if (location_on_path == dist)
955     {
956         mpr("Not with that terrain in the way!");
957         return SPRET_SUCCESS;
958     }
959     dprf("Apport: new spot is %d/%d", new_spot.x, new_spot.y);
960
961     // Actually move the item.
962     mprf("Yoink! You pull the item%s towards yourself.",
963          (item.quantity > 1) ? "s" : "");
964
965     if (max_units < item.quantity)
966     {
967         if (!copy_item_to_grid(item, new_spot, max_units))
968         {
969             // Always >1 item.
970             mpr("They abruptly stop in place!");
971             // Too late to abort.
972             return SPRET_SUCCESS;
973         }
974         item.quantity -= max_units;
975     }
976     else
977         move_top_item(where, new_spot);
978
979     // Mark the item as found now.
980     origin_set(new_spot);
981
982     return SPRET_SUCCESS;
983 }
984
985 static bool _quadrant_blink(coord_def dir, int pow)
986 {
987     if (pow > 100)
988         pow = 100;
989
990     const int dist = random2(6) + 2;  // 2-7
991
992     // This is where you would *like* to go.
993     const coord_def base = you.pos() + dir * dist;
994
995     // This can take a while if pow is high and there's lots of translucent
996     // walls nearby.
997     coord_def target;
998     bool found = false;
999     for (int i = 0; i < (pow*pow) / 500 + 1; ++i)
1000     {
1001         // Find a space near our base point...
1002         // First try to find a random square not adjacent to the basepoint,
1003         // then one adjacent if that fails.
1004         if (!random_near_space(base, target)
1005             && !random_near_space(base, target, true))
1006         {
1007             // Uh oh, WHY should this fail the blink?
1008             return false;
1009         }
1010
1011         // ... which is close enough, but also far enough from us.
1012         if (distance2(base, target) > 10 || distance2(you.pos(), target) < 8)
1013             continue;
1014
1015         if (!you.see_cell_no_trans(target))
1016             continue;
1017
1018         found = true;
1019         break;
1020     }
1021
1022     if (!found)
1023     {
1024         // We've already succeeded at blinking, so the Abyss shouldn't block it.
1025         random_blink(false, true);
1026         return true;
1027     }
1028
1029     coord_def origin = you.pos();
1030     move_player_to_grid(target, false, true);
1031
1032     // Leave a purple cloud.
1033     place_cloud(CLOUD_TLOC_ENERGY, origin, 1 + random2(3), &you);
1034
1035     return true;
1036 }
1037
1038 spret_type cast_semi_controlled_blink(int pow, bool cheap_cancel, bool end_ctele, bool fail)
1039 {
1040     dist bmove;
1041     direction_chooser_args args;
1042     args.restricts = DIR_DIR;
1043     args.mode = TARG_ANY;
1044
1045     while (1)
1046     {
1047         mpr("Which direction? [ESC to cancel]", MSGCH_PROMPT);
1048         direction(bmove, args);
1049
1050         if (crawl_state.seen_hups)
1051         {
1052             mpr("Cancelling blink due to HUP.");
1053             return SPRET_ABORT;
1054         }
1055
1056         if (bmove.isValid && !bmove.delta.origin())
1057             break;
1058
1059         if (cheap_cancel
1060             || yesno("Are you sure you want to cancel this blink?", false ,'n'))
1061         {
1062             canned_msg(MSG_OK);
1063             return SPRET_ABORT;
1064         }
1065     }
1066
1067     fail_check();
1068
1069     // Note: this can silently fail, eating the blink -- WHY?
1070     if (you.attempt_escape(2) && _quadrant_blink(bmove.delta, pow))
1071     {
1072         // Controlled blink causes glowing.
1073         contaminate_player(1, true);
1074         // End teleport control if this was a random blink upgraded by cTele.
1075         if (end_ctele && you.duration[DUR_CONTROL_TELEPORT])
1076         {
1077             mpr("You feel uncertain.", MSGCH_DURATION);
1078             you.duration[DUR_CONTROL_TELEPORT] = 0;
1079         }
1080     }
1081
1082     return SPRET_SUCCESS;
1083 }
1084
1085 spret_type cast_golubrias_passage(const coord_def& where, bool fail)
1086 {
1087     // randomize position a bit to make it not as useful to use on monsters
1088     // chasing you, as well as to not give away hidden trap positions
1089     int tries = 0;
1090     int tries2 = 0;
1091     coord_def randomized_where = where;
1092     coord_def randomized_here = you.pos();
1093     do
1094     {
1095         tries++;
1096         randomized_where = where;
1097         randomized_where.x += random_range(-2, 2);
1098         randomized_where.y += random_range(-2, 2);
1099     } while ((!in_bounds(randomized_where) ||
1100              grd(randomized_where) != DNGN_FLOOR ||
1101              monster_at(randomized_where) ||
1102              !you.see_cell(randomized_where) ||
1103              you.trans_wall_blocking(randomized_where) ||
1104              randomized_where == you.pos()) &&
1105             tries < 100);
1106
1107     do
1108     {
1109         tries2++;
1110         randomized_here = you.pos();
1111         randomized_here.x += random_range(-2, 2);
1112         randomized_here.y += random_range(-2, 2);
1113     } while ((!in_bounds(randomized_here) ||
1114              grd(randomized_here) != DNGN_FLOOR ||
1115              monster_at(randomized_here) ||
1116              !you.see_cell(randomized_here) ||
1117              you.trans_wall_blocking(randomized_here) ||
1118              randomized_here == you.pos() ||
1119              randomized_here == randomized_where) &&
1120             tries2 < 100);
1121
1122     if (tries >= 100 || tries2 >= 100)
1123     {
1124         if (you.trans_wall_blocking(randomized_where))
1125             mpr("You cannot create a passage on the other side of the transparent wall.");
1126         else
1127             // XXX: bleh, dumb message
1128             mpr("Creating passages of Golubria requires sufficient empty space.");
1129         return SPRET_ABORT;
1130     }
1131
1132     if (!allow_control_teleport(true) ||
1133         testbits(env.pgrid(randomized_where), FPROP_NO_CTELE_INTO) ||
1134         testbits(env.pgrid(randomized_here), FPROP_NO_CTELE_INTO))
1135     {
1136         mpr("A powerful magic interferes with the creation of the passage.");
1137         return SPRET_ABORT;
1138     }
1139
1140     fail_check();
1141     place_specific_trap(randomized_where, TRAP_GOLUBRIA);
1142     place_specific_trap(randomized_here, TRAP_GOLUBRIA);
1143     env.level_state |= LSTATE_GOLUBRIA;
1144
1145     trap_def *trap = find_trap(randomized_where);
1146     trap_def *trap2 = find_trap(randomized_here);
1147     if (!trap || !trap2)
1148     {
1149         mpr("Something buggy happened.");
1150         return SPRET_ABORT;
1151     }
1152
1153     trap->reveal();
1154     trap2->reveal();
1155
1156     return SPRET_SUCCESS;
1157 }