Apply the new ground_level method.
[crawl.git] / crawl-ref / source / spl-transloc.cc
blobc0a16dd337b2ca17de18ef14fbd3de59ce86b1e3
1 /*
2 * File: spl-transloc.cc
3 * Summary: Translocation spells.
4 */
6 #include "AppHdr.h"
8 #include "spl-transloc.h"
9 #include "externs.h"
11 #include "abyss.h"
12 #include "branch.h"
13 #include "cloud.h"
14 #include "coord.h"
15 #include "coordit.h"
16 #include "delay.h"
17 #include "directn.h"
18 #include "dungeon.h"
19 #include "env.h"
20 #include "fprop.h"
21 #include "invent.h"
22 #include "item_use.h"
23 #include "itemprop.h"
24 #include "items.h"
25 #include "message.h"
26 #include "misc.h"
27 #include "mon-behv.h"
28 #include "mon-iter.h"
29 #include "mon-util.h"
30 #include "orb.h"
31 #include "player.h"
32 #include "random.h"
33 #include "shout.h"
34 #include "spl-other.h"
35 #include "spl-util.h"
36 #include "stash.h"
37 #include "state.h"
38 #include "stuff.h"
39 #include "teleport.h"
40 #include "terrain.h"
41 #include "transform.h"
42 #include "traps.h"
43 #include "travel.h"
44 #include "view.h"
45 #include "viewmap.h"
46 #include "xom.h"
48 static bool _abyss_blocks_teleport(bool cblink)
50 // Lugonu worshippers get their perks.
51 if (you.religion == GOD_LUGONU)
52 return (false);
54 // Controlled Blink (the spell) works quite reliably in the Abyss.
55 return (cblink ? one_chance_in(3) : !one_chance_in(3));
58 // If wizard_blink is set, all restriction are ignored (except for
59 // a monster being at the target spot), and the player gains no
60 // contamination.
61 int blink(int pow, bool high_level_controlled_blink, bool wizard_blink,
62 std::string *pre_msg)
64 ASSERT(!crawl_state.game_is_arena());
66 dist beam;
68 if (crawl_state.is_repeating_cmd())
70 crawl_state.cant_cmd_repeat("You can't repeat controlled blinks.");
71 crawl_state.cancel_cmd_again();
72 crawl_state.cancel_cmd_repeat();
73 return (1);
76 // yes, there is a logic to this ordering {dlb}:
77 if (item_blocks_teleport(true, true) && !wizard_blink)
79 if (pre_msg)
80 mpr(pre_msg->c_str());
81 canned_msg(MSG_STRANGE_STASIS);
83 else if (you.level_type == LEVEL_ABYSS
84 && _abyss_blocks_teleport(high_level_controlled_blink)
85 && !wizard_blink)
87 if (pre_msg)
88 mpr(pre_msg->c_str());
89 mpr("The power of the Abyss keeps you in your place!");
91 else if (you.confused() && !wizard_blink)
93 if (pre_msg)
94 mpr(pre_msg->c_str());
95 random_blink(false);
97 else if (!allow_control_teleport(true) && !wizard_blink)
99 if (pre_msg)
100 mpr(pre_msg->c_str());
101 mpr("A powerful magic interferes with your control of the blink.");
102 if (high_level_controlled_blink)
103 return (cast_semi_controlled_blink(pow));
104 random_blink(false);
106 else
108 // query for location {dlb}:
109 while (!crawl_state.seen_hups)
111 direction_chooser_args args;
112 args.restricts = DIR_TARGET;
113 args.needs_path = false;
114 args.may_target_monster = false;
115 args.top_prompt = "Blink to where?";
116 direction(beam, args);
118 if (!beam.isValid || beam.target == you.pos())
120 if (!wizard_blink
121 && !yesno("Are you sure you want to cancel this blink?",
122 false, 'n'))
124 mesclr();
125 continue;
127 canned_msg(MSG_OK);
128 return (-1); // early return {dlb}
131 monster* beholder = you.get_beholder(beam.target);
132 if (!wizard_blink && beholder)
134 mprf("You cannot blink away from %s!",
135 beholder->name(DESC_NOCAP_THE, true).c_str());
136 continue;
139 monster* fearmonger = you.get_fearmonger(beam.target);
140 if (!wizard_blink && fearmonger)
142 mprf("You cannot blink closer to %s!",
143 fearmonger->name(DESC_NOCAP_THE, true).c_str());
144 continue;
147 if (grd(beam.target) == DNGN_OPEN_SEA)
149 mesclr();
150 mpr("You can't blink into the sea!");
152 else if (!check_moveto(beam.target, "blink"))
154 // try again (messages handled by check_moveto)
156 else if (you.see_cell_no_trans(beam.target))
158 // Grid in los, no problem.
159 break;
161 else if (you.trans_wall_blocking(beam.target))
163 // Wizard blink can move past translucent walls.
164 if (wizard_blink)
165 break;
167 mesclr();
168 mpr("You can't blink through translucent walls.");
170 else
172 mesclr();
173 mpr("You can only blink to visible locations.");
177 if (pre_msg)
178 mpr(pre_msg->c_str());
180 // Allow wizard blink to send player into walls, in case the
181 // user wants to alter that grid to something else.
182 if (wizard_blink && feat_is_solid(grd(beam.target)))
183 grd(beam.target) = DNGN_FLOOR;
185 if (feat_is_solid(grd(beam.target)) || monster_at(beam.target))
187 mpr("Oops! Maybe something was there already.");
188 random_blink(false);
190 else if (you.level_type == LEVEL_ABYSS && !wizard_blink)
192 abyss_teleport(false);
193 if (you.pet_target != MHITYOU)
194 you.pet_target = MHITNOT;
196 else
198 // Leave a purple cloud.
199 place_cloud(CLOUD_TLOC_ENERGY, you.pos(), 1 + random2(3), &you);
200 move_player_to_grid(beam.target, false, true);
202 // Controlling teleport contaminates the player. -- bwr
203 if (!wizard_blink)
204 contaminate_player(1, true);
208 crawl_state.cancel_cmd_again();
209 crawl_state.cancel_cmd_repeat();
211 return (1);
214 void random_blink(bool allow_partial_control, bool override_abyss)
216 ASSERT(!crawl_state.game_is_arena());
218 coord_def target;
220 if (item_blocks_teleport(true, true))
221 canned_msg(MSG_STRANGE_STASIS);
222 else if (you.level_type == LEVEL_ABYSS
223 && !override_abyss && !one_chance_in(3))
225 mpr("The power of the Abyss keeps you in your place!");
227 // First try to find a random square not adjacent to the player,
228 // then one adjacent if that fails.
229 else if (!random_near_space(you.pos(), target)
230 && !random_near_space(you.pos(), target, true))
232 mpr("You feel jittery for a moment.");
235 //jmf: Add back control, but effect is cast_semi_controlled_blink(pow).
236 else if (player_control_teleport() && !you.confused()
237 && allow_partial_control && allow_control_teleport())
239 mpr("You may select the general direction of your translocation.");
240 cast_semi_controlled_blink(100);
241 maybe_id_ring_TC();
243 else
245 canned_msg(MSG_YOU_BLINK);
246 coord_def origin = you.pos();
247 move_player_to_grid(target, false, true);
249 // Leave a purple cloud.
250 place_cloud(CLOUD_TLOC_ENERGY, origin, 1 + random2(3), &you);
252 if (you.level_type == LEVEL_ABYSS)
254 abyss_teleport(false);
255 if (you.pet_target != MHITYOU)
256 you.pet_target = MHITNOT;
261 // This function returns true if the player can use controlled teleport
262 // here.
263 bool allow_control_teleport(bool quiet)
265 bool retval = !(testbits(env.level_flags, LFLAG_NO_TELE_CONTROL)
266 || testbits(get_branch_flags(), BFLAG_NO_TELE_CONTROL));
268 // Tell the player why if they have teleport control.
269 if (!quiet && !retval && player_control_teleport())
270 mpr("A powerful magic prevents control of your teleportation.");
272 return (retval);
275 void you_teleport(void)
277 // [Cha] here we block teleportation, which will save the player from
278 // death from read-id'ing scrolls (in sprint)
279 if (crawl_state.game_is_sprint() || item_blocks_teleport(true, true))
280 canned_msg(MSG_STRANGE_STASIS);
281 else if (you.duration[DUR_TELEPORT])
283 mpr("You feel strangely stable.");
284 you.duration[DUR_TELEPORT] = 0;
286 else
288 mpr("You feel strangely unstable.");
290 int teleport_delay = 3 + random2(3);
292 if (you.level_type == LEVEL_ABYSS && !one_chance_in(5))
294 mpr("You have a feeling this translocation may take a while to kick in...");
295 teleport_delay += 5 + random2(10);
298 you.set_duration(DUR_TELEPORT, teleport_delay);
302 // Should return true if we don't want anyone to teleport here.
303 static bool _cell_vetoes_teleport (const coord_def cell, bool check_monsters = true)
305 // Monsters always veto teleport.
306 if (monster_at(cell) && check_monsters)
307 return (true);
309 // As do all clouds; this may change.
310 if (env.cgrid(cell) != EMPTY_CLOUD)
311 return (true);
313 if (cell_is_solid(cell))
314 return (true);
316 return is_feat_dangerous(grd(cell), true);
319 static void _handle_teleport_update (bool large_change, bool check_ring_TC,
320 const coord_def old_pos)
322 if (large_change)
324 viewwindow();
325 for (monster_iterator mi; mi; ++mi)
327 const bool see_cell = you.see_cell(mi->pos());
329 if (mi->foe == MHITYOU && !see_cell)
331 mi->foe_memory = 0;
332 behaviour_event(*mi, ME_EVAL);
334 else if (see_cell)
335 behaviour_event(*mi, ME_EVAL);
338 handle_interrupted_swap(true);
341 // Might identify unknown ring of teleport control.
342 if (check_ring_TC)
343 maybe_id_ring_TC();
345 #ifdef USE_TILE
346 if (you.species == SP_MERFOLK)
348 const dungeon_feature_type new_grid = grd(you.pos());
349 const dungeon_feature_type old_grid = grd(old_pos);
350 if (feat_is_water(old_grid) && !feat_is_water(new_grid)
351 || !feat_is_water(old_grid) && feat_is_water(new_grid))
353 init_player_doll();
356 #endif
359 static bool _teleport_player(bool allow_control, bool new_abyss_area,
360 bool wizard_tele)
362 bool is_controlled = (allow_control && !you.confused()
363 && player_control_teleport()
364 && allow_control_teleport()
365 && !you.berserk());
367 // All wizard teleports are automatically controlled.
368 if (wizard_tele)
369 is_controlled = true;
371 if (!wizard_tele
372 && ((!new_abyss_area && crawl_state.game_is_sprint())
373 || item_blocks_teleport(true, true)))
375 canned_msg(MSG_STRANGE_STASIS);
376 return (false);
379 // After this point, we're guaranteed to teleport. Kill the appropriate
380 // delays.
381 interrupt_activity(AI_TELEPORT);
383 // Update what we can see at the current location as well as its stash,
384 // in case something happened in the exact turn that we teleported
385 // (like picking up/dropping an item).
386 viewwindow();
387 StashTrack.update_stash(you.pos());
389 if (you.level_type == LEVEL_ABYSS)
391 abyss_teleport(new_abyss_area);
392 if (you.pet_target != MHITYOU)
393 you.pet_target = MHITNOT;
395 return (true);
398 coord_def pos(1, 0);
399 const coord_def old_pos = you.pos();
400 bool large_change = false;
401 bool check_ring_TC = false;
403 if (is_controlled)
405 check_ring_TC = true;
407 // Only have the messages and the more prompt for non-wizard.
408 if (!wizard_tele)
410 mpr("You may choose your destination (press '.' or delete to select).");
411 mpr("Expect minor deviation.");
412 more();
415 while (true)
417 level_pos lpos;
418 bool chose = show_map(lpos, false, true, false);
419 pos = lpos.pos;
420 redraw_screen();
422 #if defined(USE_UNIX_SIGNALS) && defined(SIGHUP_SAVE) && defined(USE_CURSES)
423 // If we've received a HUP signal then the user can't choose a
424 // location, so cancel the teleport.
425 if (crawl_state.seen_hups)
427 mpr("Controlled teleport interrupted by HUP signal, "
428 "cancelling teleport.", MSGCH_ERROR);
429 if (!wizard_tele)
430 contaminate_player(1, true);
431 return (false);
433 #endif
435 dprf("Target square (%d,%d)", pos.x, pos.y);
437 if (!chose || pos == you.pos())
439 if (!wizard_tele)
441 if (!yesno("Are you sure you want to cancel this teleport?",
442 true, 'n'))
444 continue;
447 if (!wizard_tele)
448 contaminate_player(1, true);
449 maybe_id_ring_TC();
450 return (false);
453 monster* beholder = you.get_beholder(pos);
454 if (beholder && !wizard_tele)
456 mprf("You cannot teleport away from %s!",
457 beholder->name(DESC_NOCAP_THE, true).c_str());
458 mpr("Choose another destination (press '.' or delete to select).");
459 more();
460 continue;
463 monster* fearmonger = you.get_fearmonger(pos);
464 if (fearmonger && !wizard_tele)
466 mprf("You cannot teleport closer to %s!",
467 fearmonger->name(DESC_NOCAP_THE, true).c_str());
468 mpr("Choose another destination (press '.' or delete to select).");
469 more();
470 continue;
472 break;
475 // Don't randomly walk wizard teleports.
476 if (!wizard_tele)
478 pos.x += random2(3) - 1;
479 pos.y += random2(3) - 1;
481 if (one_chance_in(4))
483 pos.x += random2(3) - 1;
484 pos.y += random2(3) - 1;
486 dprf("Scattered target square (%d, %d)", pos.x, pos.y);
489 if (!in_bounds(pos))
491 mpr("Nearby solid objects disrupt your rematerialisation!");
492 is_controlled = false;
495 if (is_controlled)
497 if (!you.see_cell(pos))
498 large_change = true;
500 // Merfolk should be able to control-tele into deep water.
501 if (_cell_vetoes_teleport(pos))
503 dprf("Target square (%d, %d) vetoed, now random teleport.", pos.x, pos.y);
504 is_controlled = false;
505 large_change = false;
507 else if (testbits(env.pgrid(pos), FPROP_NO_CTELE_INTO) && !wizard_tele)
509 is_controlled = false;
510 large_change = false;
511 mpr("A strong magical force throws you back!", MSGCH_WARN);
513 else
515 // Leave a purple cloud.
516 place_cloud(CLOUD_TLOC_ENERGY, old_pos, 1 + random2(3), &you);
518 // Controlling teleport contaminates the player. - bwr
519 move_player_to_grid(pos, false, true);
520 if (!wizard_tele)
521 contaminate_player(1, true);
526 if (!is_controlled)
528 coord_def newpos;
530 // If in a labyrinth, always teleport well away from the centre.
531 // (Check done for the straight line, no pathfinding involved.)
532 bool need_distance_check = false;
533 coord_def centre;
534 if (you.level_type == LEVEL_LABYRINTH)
536 bool success = false;
537 for (int xpos = 0; xpos < GXM; xpos++)
539 for (int ypos = 0; ypos < GYM; ypos++)
541 centre = coord_def(xpos, ypos);
542 if (!in_bounds(centre))
543 continue;
545 if (grd(centre) == DNGN_ESCAPE_HATCH_UP)
547 success = true;
548 break;
551 if (success)
552 break;
554 need_distance_check = success;
558 newpos = random_in_bounds();
559 while (_cell_vetoes_teleport(newpos)
560 || need_distance_check && (newpos - centre).abs() < 34*34
561 || testbits(env.pgrid(newpos), FPROP_NO_RTELE_INTO));
563 if (newpos == old_pos)
564 mpr("Your surroundings flicker for a moment.");
565 else if (you.see_cell(newpos))
566 mpr("Your surroundings seem slightly different.");
567 else
569 mpr("Your surroundings suddenly seem different.");
570 large_change = true;
573 // Leave a purple cloud.
574 place_cloud(CLOUD_TLOC_ENERGY, old_pos, 1 + random2(3), &you);
576 move_player_to_grid(newpos, false, true);
579 _handle_teleport_update(large_change, check_ring_TC, old_pos);
580 return (!is_controlled);
583 bool you_teleport_to(const coord_def where_to, bool move_monsters)
585 // Attempts to teleport the player from their current location to 'where'.
586 // Follows this line of reasoning:
587 // 1. Check the location (against _cell_vetoes_teleport), if valid,
588 // teleport the player there.
589 // 2. If not because of a monster, and move_monster, teleport that
590 // monster out of the way, then teleport the player there.
591 // 3. Otherwise, iterate over adjacent squares. If a sutiable position is
592 // found (or a monster can be moved out of the way, with move_monster)
593 // then teleport the player there.
594 // 4. If not, give up and return false.
596 bool check_ring_TC = false;
597 const coord_def old_pos = you.pos();
598 coord_def where = where_to;
599 coord_def old_where = where_to;
601 // Don't bother to calculate a possible new position if it's out of bounds.
602 if (!in_bounds(where))
603 return (false);
605 if (_cell_vetoes_teleport(where))
607 if (monster_at(where) && move_monsters && !_cell_vetoes_teleport(where, false))
609 monster* mons = monster_at(where);
610 mons->teleport(true);
612 else
614 for (adjacent_iterator ai(where); ai; ++ai)
616 if (!_cell_vetoes_teleport(*ai))
618 where = *ai;
619 break;
621 else
623 if (monster_at(*ai) && move_monsters
624 && !_cell_vetoes_teleport(*ai, false))
626 monster* mons = monster_at(*ai);
627 mons->teleport(true);
628 where = *ai;
629 break;
633 // Give up, we can't find a suitable spot.
634 if (where == old_where)
635 return (false);
639 // If we got this far, we're teleporting the player.
640 // Leave a purple cloud.
641 place_cloud(CLOUD_TLOC_ENERGY, old_pos, 1 + random2(3), &you);
643 bool large_change = you.see_cell(where);
645 move_player_to_grid(where, false, true);
647 _handle_teleport_update(large_change, check_ring_TC, old_pos);
648 return (true);
651 void you_teleport_now(bool allow_control, bool new_abyss_area, bool wizard_tele)
653 const bool randtele = _teleport_player(allow_control, new_abyss_area,
654 wizard_tele);
656 // Xom is amused by uncontrolled teleports that land you in a
657 // dangerous place, unless the player is in the Abyss and
658 // teleported to escape from all the monsters chasing him/her,
659 // since in that case the new dangerous area is almost certainly
660 // *less* dangerous than the old dangerous area.
661 // Teleporting in a labyrinth is also funny, more so for non-minotaurs.
662 if (randtele
663 && (you.level_type == LEVEL_LABYRINTH
664 || you.level_type != LEVEL_ABYSS && player_in_a_dangerous_place()))
666 if (you.level_type == LEVEL_LABYRINTH && you.species == SP_MINOTAUR)
667 xom_is_stimulated(128);
668 else
669 xom_is_stimulated(255);
673 bool cast_portal_projectile(int pow)
675 dist target;
676 int item = get_ammo_to_shoot(-1, target, true);
677 if (item == -1)
678 return (false);
680 if (cell_is_solid(target.target))
682 mpr("You can't shoot at gazebos.");
683 return (false);
686 // Can't use portal through walls. (That'd be just too cheap!)
687 if (you.trans_wall_blocking(target.target))
689 mpr("A translucent wall is in the way.");
690 return (false);
693 if (!check_warning_inscriptions(you.inv[item], OPER_FIRE))
694 return (false);
696 bolt beam;
697 throw_it(beam, item, true, random2(pow/4), &target);
699 return (true);
702 bool cast_apportation(int pow, bolt& beam)
704 const coord_def where = beam.target;
706 if (you.trans_wall_blocking(where))
708 mpr("Something is in the way.");
709 return (false);
712 // Letting mostly-melee characters spam apport after every Shoals
713 // fight seems like it has too much grinding potential. We could
714 // weaken this for high power.
715 if (grd(where) == DNGN_DEEP_WATER || grd(where) == DNGN_LAVA)
717 mpr("The density of the terrain blocks your spell.");
718 return (false);
721 // Let's look at the top item in that square...
722 // And don't allow apporting from shop inventories.
723 const int item_idx = igrd(where);
724 if (item_idx == NON_ITEM || !in_bounds(where))
726 // Maybe the player *thought* there was something there (a mimic.)
727 if (monster* m = monster_at(where))
729 if (mons_is_item_mimic(m->type) && you.can_see(m))
731 mprf("%s twitches.", m->name(DESC_CAP_THE).c_str());
732 // Nothing else gives this message, so identify the mimic.
733 discover_mimic(m);
734 return (true); // otherwise you get free mimic ID
738 mpr("There are no items there.");
739 return (false);
742 item_def& item = mitm[item_idx];
744 // Can't apport the Orb in zotdef
745 if (crawl_state.game_is_zotdef() && item_is_orb(item))
747 mpr("You cannot apport the sacred Orb!");
748 return (false);
751 // Protect the player from destroying the item.
752 if (feat_destroys_item(grd(you.pos()), item))
754 mpr("That would be silly while over this terrain!");
755 return (false);
758 // Mass of one unit.
759 const int unit_mass = item_mass(item);
760 const int max_mass = pow * 30 + random2(pow * 20);
762 int max_units = item.quantity;
763 if (unit_mass > 0)
764 max_units = max_mass / unit_mass;
766 if (max_units <= 0)
768 if (item_is_orb(item))
770 orb_pickup_noise(where, 30);
771 return (true);
773 else
775 mpr("The mass is resisting your pull.");
776 return (true);
780 // We need to modify the item *before* we move it, because
781 // move_top_item() might change the location, or merge
782 // with something at our position.
783 mprf("Yoink! You pull the item%s towards yourself.",
784 (item.quantity > 1) ? "s" : "");
786 if (item_is_orb(item))
788 fake_noisy(30, where);
790 // There's also a 1-in-6 flat chance of apport failing.
791 if (one_chance_in(6))
793 orb_pickup_noise(where, 30, "The orb shrieks and becomes a dead weight against your magic!",
794 "The orb lets out a furious burst of light and becomes a dead weight against your magic!");
795 return (true);
797 else // Otherwise it's just a noisy little shiny thing
799 orb_pickup_noise(where, 30, "The orb shrieks as your magic touches it!",
800 "The orb lets out a furious burst of light as your magic touches it!");
804 if (max_units < item.quantity)
806 item.quantity = max_units;
807 mpr("You feel that some mass got lost in the cosmic void.");
810 // If we apport a net, free the monster under it.
811 if (item.base_type == OBJ_MISSILES
812 && item.sub_type == MI_THROWING_NET
813 && item_is_stationary(item))
815 remove_item_stationary(item);
816 if (monster* mons = monster_at(where))
817 mons->del_ench(ENCH_HELD, true);
820 if (item_is_orb(item))
822 // The orb drags its heels.
823 beam.is_tracer = true;
824 beam.aimed_at_spot = true;
825 beam.fire();
827 // Pop the orb's location off the end
828 beam.path_taken.pop_back();
830 // The actual number of squares it needs to traverse to get to you.
831 unsigned int dist = beam.path_taken.size();
833 // The maximum number of squares the orb will actually move, always
834 // at least one square.
835 unsigned int max_dist = std::max((pow / 10) - 1, 1);
837 dprf("Orb apport dist=%d, max_dist=%d", dist, max_dist);
839 if (max_dist <= dist)
841 coord_def new_spot = beam.path_taken[beam.path_taken.size()-max_dist];
843 dprf("Orb apport: new spot is %d/%d", new_spot.x, new_spot.y);
845 if (feat_virtually_destroys_item(grd(new_spot), item))
846 return (true);
848 else
850 move_top_item(where, new_spot);
851 origin_set(new_spot);
852 return (true);
855 // if power is high enough it'll just come straight to you
858 // Actually move the item.
859 move_top_item(where, you.pos());
860 // Mark the item as found now.
861 origin_set(you.pos());
863 return (true);
866 static int _quadrant_blink(coord_def where, int pow, int, actor *)
868 if (where == you.pos())
869 return (0);
871 if (you.level_type == LEVEL_ABYSS)
873 abyss_teleport(false);
874 if (you.pet_target != MHITYOU)
875 you.pet_target = MHITNOT;
876 return (1);
879 if (pow > 100)
880 pow = 100;
882 const int dist = random2(6) + 2; // 2-7
884 // This is where you would *like* to go.
885 const coord_def base = you.pos() + (where - you.pos()) * dist;
887 // This can take a while if pow is high and there's lots of translucent
888 // walls nearby.
889 coord_def target;
890 bool found = false;
891 for (int i = 0; i < (pow*pow) / 500 + 1; ++i)
893 // Find a space near our base point...
894 // First try to find a random square not adjacent to the basepoint,
895 // then one adjacent if that fails.
896 if (!random_near_space(base, target)
897 && !random_near_space(base, target, true))
899 return 0;
902 // ... which is close enough, but also far enough from us.
903 if (distance(base, target) > 10 || distance(you.pos(), target) < 8)
904 continue;
906 if (!you.see_cell_no_trans(target))
907 continue;
909 found = true;
910 break;
913 if (!found)
915 random_blink(false);
916 return (1);
919 coord_def origin = you.pos();
920 move_player_to_grid(target, false, true);
922 // Leave a purple cloud.
923 place_cloud(CLOUD_TLOC_ENERGY, origin, 1 + random2(3), &you);
925 return (1);
928 int cast_semi_controlled_blink(int pow)
930 int result = apply_one_neighbouring_square(_quadrant_blink, pow);
932 // Controlled blink causes glowing.
933 if (result)
934 contaminate_player(1, true);
936 return (result);
939 bool can_cast_golubrias_passage()
941 return find_golubria_on_level().size() < 2;
944 bool cast_golubrias_passage(const coord_def& where)
946 // randomize position a bit to make it not as useful to use on monsters
947 // chasing you, as well as to not give away hidden trap positions
948 int tries = 0;
949 coord_def randomized_where = where;
952 tries++;
953 randomized_where = where;
954 randomized_where.x += random_range(-2, 2);
955 randomized_where.y += random_range(-2, 2);
956 } while((!in_bounds(randomized_where) ||
957 grd(randomized_where) != DNGN_FLOOR ||
958 monster_at(randomized_where) ||
959 !you.see_cell(randomized_where) ||
960 you.trans_wall_blocking(randomized_where) ||
961 randomized_where == you.pos()) &&
962 tries < 100);
964 if (tries >= 100)
966 if (you.trans_wall_blocking(randomized_where))
967 mpr("You cannot create a passage on the other side of the transparent wall.");
968 else
969 // XXX: bleh, dumb message
970 mpr("Creating a passage of Golubria requires sufficient empty space.");
971 return false;
974 if (!allow_control_teleport(true) ||
975 testbits(env.pgrid(randomized_where), FPROP_NO_CTELE_INTO))
977 // lose a turn
978 mpr("A powerful magic interferes with the creation of the passage.");
979 place_cloud(CLOUD_TLOC_ENERGY, randomized_where, 3 + random2(3), &you);
980 return true;
983 place_specific_trap(randomized_where, TRAP_GOLUBRIA);
985 trap_def *trap = find_trap(randomized_where);
986 if (!trap)
988 mpr("Something buggy happened.");
989 return false;
992 trap->reveal();
994 return true;