1 /**
2  * @file
3  * @brief Functions for using some of the wackier inventory items.
4 **/
5 
6 #include "AppHdr.h"
7 
8 #include "evoke.h"
9 
10 #include <algorithm>
11 #include <cmath>
12 #include <cstdlib>
13 #include <cstring>
14 
15 #include "act-iter.h"
16 #include "areas.h"
17 #include "artefact.h"
18 #include "branch.h"
19 #include "chardump.h"
20 #include "cloud.h"
21 #include "coordit.h"
22 #include "delay.h"
23 #include "directn.h"
24 #include "dungeon.h"
25 #include "english.h"
26 #include "env.h"
27 #include "exercise.h"
28 #include "fight.h"
29 #include "god-abil.h"
30 #include "god-conduct.h"
31 #include "god-passive.h"
32 #include "invent.h"
33 #include "item-prop.h"
34 #include "items.h"
35 #include "level-state-type.h"
36 #include "libutil.h"
37 #include "losglobal.h"
38 #include "message.h"
39 #include "mgen-data.h"
40 #include "misc.h"
41 #include "mon-behv.h"
42 #include "mon-clone.h"
43 #include "mon-pick.h"
44 #include "mon-place.h"
45 #include "mutant-beast.h"
46 #include "place.h"
47 #include "player.h"
48 #include "player-stats.h"
49 #include "prompt.h"
50 #include "religion.h"
51 #include "shout.h"
52 #include "skills.h"
53 #include "spl-book.h"
54 #include "spl-cast.h"
55 #include "spl-clouds.h"
56 #include "spl-damage.h"
57 #include "spl-util.h"
58 #include "state.h"
59 #include "stepdown.h"
60 #include "stringutil.h"
61 #include "tag-version.h"
62 #include "target.h"
63 #include "terrain.h"
64 #include "throw.h"
65 #ifdef USE_TILE
66  #include "tilepick.h"
67 #endif
68 #include "transform.h"
69 #include "traps.h"
70 #include "unicode.h"
71 #include "view.h"
72 
_evoke_horn_of_geryon()73 static bool _evoke_horn_of_geryon()
74 {
75     bool created = false;
76 
77     if (silenced(you.pos()))
78     {
79         mpr("You can't produce a sound!");
80         return false;
81     }
82 
83     mprf(MSGCH_SOUND, "You produce a hideous howling noise!");
84     did_god_conduct(DID_EVIL, 3);
85     int num = 1;
86     const int adjusted_power =
87         player_adjust_evoc_power(you.skill(SK_EVOCATIONS, 10));
88     if (adjusted_power + random2(90) > 130)
89         ++num;
90     if (adjusted_power + random2(90) > 180)
91         ++num;
92     if (adjusted_power + random2(90) > 230)
93         ++num;
94     for (int n = 0; n < num; ++n)
95     {
96         monster* mon;
97         beh_type beh = BEH_HOSTILE;
98 
99         if (random2(adjusted_power) > 7)
100             beh = BEH_FRIENDLY;
101         mgen_data mg(MONS_HELL_BEAST, beh, you.pos(), MHITYOU, MG_FORCE_BEH);
102         mg.set_summoned(&you, 3, SPELL_NO_SPELL);
103         mg.set_prox(PROX_CLOSE_TO_PLAYER);
104         mon = create_monster(mg);
105         if (mon)
106             created = true;
107     }
108     if (!created)
109         mpr("Nothing answers your call.");
110     return true;
111 }
112 
113 /**
114  * Spray lightning in all directions. (Randomly: shock, lightning bolt, OoE.)
115  *
116  * @param range         The range of the beams. (As with all beams, eventually
117  *                      capped at LOS.)
118  * @param power         The power of the beams. (Affects damage.)
119  */
_spray_lightning(int range,int power)120 static void _spray_lightning(int range, int power)
121 {
122     const zap_type which_zap = random_choose(ZAP_SHOCK,
123                                              ZAP_LIGHTNING_BOLT,
124                                              ZAP_ORB_OF_ELECTRICITY);
125 
126     bolt beam;
127     // range has no tracer, so randomness is ok
128     beam.range = range;
129     beam.source = you.pos();
130     beam.target = you.pos();
131     beam.target.x += random2(13) - 6;
132     beam.target.y += random2(13) - 6;
133     // Non-controlleable, so no player tracer.
134     zapping(which_zap, power, beam);
135 }
136 
137 /**
138  * Evoke a lightning rod, creating an arc of lightning that can be sustained
139  * by continuing to evoke.
140  *
141  * @return  Whether anything happened.
142  */
_lightning_rod(dist * preselect)143 static bool _lightning_rod(dist *preselect)
144 {
145     if (you.confused())
146     {
147         canned_msg(MSG_TOO_CONFUSED);
148         return false;
149     }
150 
151     const int power =
152         player_adjust_evoc_power(5 + you.skill(SK_EVOCATIONS, 3));
153 
154     const spret ret = your_spells(SPELL_THUNDERBOLT, power, false,
155                                                         nullptr, preselect);
156 
157     if (ret == spret::abort)
158         return false;
159 
160     return true;
161 }
162 
163 /**
164  * Spray lightning in all directions around the player.
165  *
166  * Quantity, range & power increase with level.
167  */
black_drac_breath()168 void black_drac_breath()
169 {
170     const int num_shots = roll_dice(2, 1 + you.experience_level / 7);
171     const int range = you.experience_level / 3 + 5; // 5-14
172     const int power = 25 + (you.form == transformation::dragon
173                             ? 2 * you.experience_level : you.experience_level);
174     for (int i = 0; i < num_shots; ++i)
175         _spray_lightning(range, power);
176 }
177 
178 /**
179  * Returns the MP cost of zapping a wand, depending on the player's MP-powered wands
180  * level and their available MP (or HP, if they're a djinn).
181  */
wand_mp_cost()182 int wand_mp_cost()
183 {
184     const int cost = you.get_mutation_level(MUT_MP_WANDS) * 3;
185     if (you.has_mutation(MUT_HP_CASTING))
186         return min(you.hp - 1, cost);
187     // Update mutation-data.h when updating this value.
188     return min(you.magic_points, cost);
189 }
190 
wand_power()191 int wand_power()
192 {
193     const int mp_cost = wand_mp_cost();
194     return (15 + you.skill(SK_EVOCATIONS, 7) / 2) * (mp_cost + 9) / 9;
195 }
196 
zap_wand(int slot,dist * _target)197 void zap_wand(int slot, dist *_target)
198 {
199     if (inv_count() < 1)
200     {
201         canned_msg(MSG_NOTHING_CARRIED); // why is this handled here??
202         return;
203     }
204 
205     if (!evoke_check(slot))
206         return;
207 
208     int item_slot;
209     if (slot != -1)
210         item_slot = slot;
211     else
212     {
213         item_slot = prompt_invent_item("Zap which item?",
214                                        menu_type::invlist,
215                                        OBJ_WANDS,
216                                        OPER_ZAP);
217     }
218 
219     if (prompt_failed(item_slot))
220         return;
221 
222     item_def& wand = you.inv[item_slot];
223     if (wand.base_type != OBJ_WANDS)
224     {
225         mpr("You can't zap that!");
226         return;
227     }
228 
229     if (!evoke_check(slot))
230         return;
231 
232     // If you happen to be wielding the wand, its display might change.
233     if (you.equip[EQ_WEAPON] == item_slot)
234         you.wield_change = true;
235 
236     const int mp_cost = wand_mp_cost();
237     const int power = wand_power();
238     pay_mp(mp_cost);
239 
240     const spell_type spell =
241         spell_in_wand(static_cast<wand_type>(wand.sub_type));
242 
243     spret ret = your_spells(spell, power, false, &wand, _target);
244 
245     if (ret == spret::abort)
246     {
247         refund_mp(mp_cost);
248         return;
249     }
250     else if (ret == spret::fail)
251     {
252         refund_mp(mp_cost);
253         canned_msg(MSG_NOTHING_HAPPENS);
254         you.turn_is_over = true;
255         return;
256     }
257 
258     // Spend MP.
259     if (mp_cost)
260         finalize_mp_cost();
261 
262     // Take off a charge.
263     wand.charges--;
264 
265     if (wand.charges == 0)
266     {
267         ASSERT(in_inventory(wand));
268 
269         mpr("The now-empty wand crumbles to dust.");
270         dec_inv_item_quantity(wand.link, 1);
271     }
272 
273     practise_evoking(1);
274     count_action(CACT_EVOKE, EVOC_WAND);
275     alert_nearby_monsters();
276 
277     you.turn_is_over = true;
278 }
279 
manual_skill_names(bool short_text)280 string manual_skill_names(bool short_text)
281 {
282     skill_set skills;
283     for (skill_type sk = SK_FIRST_SKILL; sk < NUM_SKILLS; sk++)
284         if (you.skill_manual_points[sk])
285             skills.insert(sk);
286 
287     if (short_text && skills.size() > 1)
288     {
289         char buf[40];
290         sprintf(buf, "%lu skills", (unsigned long) skills.size());
291         return string(buf);
292     }
293     else
294         return skill_names(skills);
295 }
296 
_box_of_beasts()297 static bool _box_of_beasts()
298 {
299     mpr("You open the lid...");
300 
301     // two rolls to reduce std deviation - +-6 so can get < max even at 27 sk
302     int rnd_factor = random2(7);
303     rnd_factor -= random2(7);
304     const int hd_min = min(27,
305                            player_adjust_evoc_power(you.skill(SK_EVOCATIONS)
306                                                     + rnd_factor));
307     const int tier = mutant_beast_tier(hd_min);
308     ASSERT(tier < NUM_BEAST_TIERS);
309 
310     mgen_data mg(MONS_MUTANT_BEAST, BEH_FRIENDLY, you.pos(), MHITYOU,
311                  MG_AUTOFOE);
312     mg.set_summoned(&you, 3 + random2(3), 0);
313 
314     mg.hd = beast_tiers[tier];
315     dprf("hd %d (min %d, tier %d)", mg.hd, hd_min, tier);
316     const monster* mons = create_monster(mg);
317 
318     if (!mons)
319     {
320         // Failed to create monster for some reason
321         mpr("...but nothing happens.");
322         return false;
323     }
324 
325     mprf("...and %s %s out!",
326          mons->name(DESC_A).c_str(), mons->airborne() ? "flies" : "leaps");
327     did_god_conduct(DID_CHAOS, random_range(5,10));
328 
329     return true;
330 }
331 
_make_zig(item_def & zig)332 static bool _make_zig(item_def &zig)
333 {
334     if (feat_is_critical(env.grid(you.pos())))
335     {
336         mpr("You can't place a gateway to a ziggurat here.");
337         return false;
338     }
339     for (int lev = 1; lev <= brdepth[BRANCH_ZIGGURAT]; lev++)
340     {
341         if (is_level_on_stack(level_id(BRANCH_ZIGGURAT, lev))
342             || you.where_are_you == BRANCH_ZIGGURAT)
343         {
344             mpr("Finish your current ziggurat first!");
345             return false;
346         }
347     }
348 
349     ASSERT(in_inventory(zig));
350     dec_inv_item_quantity(zig.link, 1);
351     dungeon_terrain_changed(you.pos(), DNGN_ENTER_ZIGGURAT);
352     mpr("You set the figurine down, and a mystic portal to a ziggurat forms.");
353     return true;
354 }
355 
_gale_push_dist(const actor * agent,const actor * victim,int pow)356 static int _gale_push_dist(const actor* agent, const actor* victim, int pow)
357 {
358     int dist = 1 + random2(pow / 20);
359 
360     if (victim->body_size(PSIZE_BODY) < SIZE_MEDIUM)
361         dist++;
362     else if (victim->body_size(PSIZE_BODY) > SIZE_BIG)
363         dist /= 2;
364     else if (victim->body_size(PSIZE_BODY) > SIZE_MEDIUM)
365         dist -= 1;
366 
367     int range = victim->pos().distance_from(agent->pos());
368     if (range > 5)
369         dist -= 2;
370     else if (range > 2)
371         dist--;
372 
373     if (dist < 0)
374         return 0;
375     else
376         return dist;
377 }
378 
_angle_between(coord_def origin,coord_def p1,coord_def p2)379 static double _angle_between(coord_def origin, coord_def p1, coord_def p2)
380 {
381     double ang0 = atan2(p1.x - origin.x, p1.y - origin.y);
382     double ang  = atan2(p2.x - origin.x, p2.y - origin.y);
383     return min(fabs(ang - ang0), fabs(ang - ang0 + 2 * PI));
384 }
385 
wind_blast(actor * agent,int pow,coord_def target,bool card)386 void wind_blast(actor* agent, int pow, coord_def target, bool card)
387 {
388     vector<actor *> act_list;
389 
390     int radius = min(5, 4 + div_rand_round(pow, 60));
391 
392     for (actor_near_iterator ai(agent->pos(), LOS_SOLID); ai; ++ai)
393     {
394         if (ai->is_stationary()
395             || ai->pos().distance_from(agent->pos()) > radius
396             || ai->pos() == agent->pos() // so it's never aimed_at_feet
397             || !target.origin()
398                && _angle_between(agent->pos(), target, ai->pos()) > PI/4.0)
399         {
400             continue;
401         }
402 
403         act_list.push_back(*ai);
404     }
405 
406     far_to_near_sorter sorter = {agent->pos()};
407     sort(act_list.begin(), act_list.end(), sorter);
408 
409     bolt wind_beam;
410     wind_beam.hit             = AUTOMATIC_HIT;
411     wind_beam.pierce          = true;
412     wind_beam.affects_nothing = true;
413     wind_beam.source          = agent->pos();
414     wind_beam.range           = LOS_RADIUS;
415     wind_beam.is_tracer       = true;
416 
417     map<actor *, coord_def> collisions;
418 
419     bool player_affected = false;
420     vector<monster *> affected_monsters;
421 
422     for (actor *act : act_list)
423     {
424         wind_beam.target = act->pos();
425         wind_beam.fire();
426 
427         int push = _gale_push_dist(agent, act, pow);
428         bool pushed = false;
429 
430         for (unsigned int j = 0; j < wind_beam.path_taken.size() - 1 && push;
431              ++j)
432         {
433             if (wind_beam.path_taken[j] == act->pos())
434             {
435                 coord_def newpos = wind_beam.path_taken[j+1];
436                 if (!actor_at(newpos) && !cell_is_solid(newpos)
437                     && act->can_pass_through(newpos)
438                     && act->is_habitable(newpos))
439                 {
440                     act->move_to_pos(newpos);
441                     if (act->is_player())
442                         stop_delay(true);
443                     --push;
444                     pushed = true;
445                 }
446                 else //Try to find an alternate route to push
447                 {
448                     bool success = false;
449                     for (adjacent_iterator di(newpos); di; ++di)
450                     {
451                         if (adjacent(*di, act->pos())
452                             && di->distance_from(agent->pos())
453                                 == newpos.distance_from(agent->pos())
454                             && !actor_at(*di) && !cell_is_solid(*di)
455                             && act->can_pass_through(*di)
456                             && act->is_habitable(*di))
457                         {
458                             act->move_to_pos(*di);
459                             if (act->is_player())
460                                 stop_delay(true);
461 
462                             --push;
463                             pushed = true;
464 
465                             // Adjust wind path for moved monster
466                             wind_beam.target = *di;
467                             wind_beam.fire();
468                             success = true;
469                             break;
470                         }
471                     }
472 
473                     // If no luck, they slam into something.
474                     if (!success)
475                         collisions.insert(make_pair(act, newpos));
476                 }
477             }
478         }
479 
480         if (pushed)
481         {
482             if (act->is_monster())
483             {
484                 act->as_monster()->speed_increment -= random2(6) + 4;
485                 if (you.can_see(*act))
486                     affected_monsters.push_back(act->as_monster());
487             }
488             else
489                 player_affected = true;
490         }
491     }
492 
493     // Now move clouds
494     vector<coord_def> cloud_list;
495     for (distance_iterator di(agent->pos(), true, false, radius + 2); di; ++di)
496     {
497         if (cloud_at(*di)
498             && cell_see_cell(agent->pos(), *di, LOS_SOLID)
499             && (target.origin()
500                 || _angle_between(agent->pos(), target, *di) <= PI/4.0))
501         {
502             cloud_list.push_back(*di);
503         }
504     }
505 
506     for (int i = cloud_list.size() - 1; i >= 0; --i)
507     {
508         wind_beam.target = cloud_list[i];
509         wind_beam.fire();
510 
511         int dist = cloud_list[i].distance_from(agent->pos());
512         int push = (dist > 5 ? 2 : dist > 2 ? 3 : 4);
513 
514         if (dist == 0 && agent->is_player())
515         {
516             delete_cloud(agent->pos());
517             break;
518         }
519 
520         for (unsigned int j = 0;
521              j < wind_beam.path_taken.size() - 1 && push;
522              ++j)
523         {
524             if (wind_beam.path_taken[j] == cloud_list[i])
525             {
526                 coord_def newpos = wind_beam.path_taken[j+1];
527                 if (!cell_is_solid(newpos)
528                     && !cloud_at(newpos))
529                 {
530                     swap_clouds(newpos, wind_beam.path_taken[j]);
531                     --push;
532                 }
533                 else //Try to find an alternate route to push
534                 {
535                     for (distance_iterator di(wind_beam.path_taken[j],
536                          false, true, 1); di; ++di)
537                     {
538                         if (di->distance_from(agent->pos())
539                                 == newpos.distance_from(agent->pos())
540                             && *di != agent->pos() // never aimed_at_feet
541                             && !cell_is_solid(*di)
542                             && !cloud_at(*di))
543                         {
544                             swap_clouds(*di, wind_beam.path_taken[j]);
545                             --push;
546                             wind_beam.target = *di;
547                             wind_beam.fire();
548                             j--;
549                             break;
550                         }
551                     }
552                 }
553             }
554         }
555     }
556 
557     if (agent->is_player())
558     {
559         const string source = card ? "card" : "fan";
560 
561         if (pow > 120)
562             mprf("A mighty gale blasts forth from the %s!", source.c_str());
563         else
564             mprf("A fierce wind blows from the %s.", source.c_str());
565     }
566 
567     noisy(8, agent->pos());
568 
569     if (player_affected)
570         mpr("You are blown backwards!");
571 
572     if (!affected_monsters.empty())
573     {
574         counted_monster_list affected = counted_monster_list(affected_monsters);
575         const string message =
576             make_stringf("%s %s blown away by the wind.",
577                          affected.describe().c_str(),
578                          conjugate_verb("be", affected.count() > 1).c_str());
579         if (strwidth(message) < get_number_of_cols() - 2)
580             mpr(message);
581         else
582             mpr("The monsters around you are blown away!");
583     }
584 
585     for (auto it : collisions)
586         if (it.first->alive())
587             it.first->collide(it.second, agent, pow);
588 
589     bool did_disperse = false;
590     // Handle trap triggering, finally. A dispersal before we finish
591     // would lead to weird crashes and behavior in the preceeding.
592     for (auto m : affected_monsters)
593     {
594         if (!m->alive())
595             continue;
596         coord_def landing = m->pos();
597 
598         // XXX: this doesn't properly fire lua position triggers
599         m->apply_location_effects(landing);
600 
601         // Dispersal will fire the location effects for everything dispersed;
602         // it's still possible for something to get blown somewhere it needs
603         // a location effect and not subsequently dispersed but handling that
604         // is more trouble than this headache already is.
605         if (m->pos() != landing)
606         {
607             did_disperse = true;
608             break;
609         }
610     }
611 
612     if (player_affected && !did_disperse)
613         you.apply_location_effects(you.pos());
614 }
615 
_phial_of_floods(dist * target)616 static bool _phial_of_floods(dist *target)
617 {
618     // TODO: code duplication with your_spells
619     if (you.confused())
620     {
621         canned_msg(MSG_TOO_CONFUSED);
622         return false;
623     }
624 
625     dist target_local;
626     if (!target)
627         target = &target_local;
628     bolt beam;
629 
630     if (you.confused())
631     {
632         canned_msg(MSG_TOO_CONFUSED);
633         return false;
634     }
635 
636     const int base_pow = 10 + you.skill(SK_EVOCATIONS, 4); // placeholder?
637     zappy(ZAP_PRIMAL_WAVE, base_pow, false, beam);
638     beam.range = LOS_RADIUS;
639     beam.aimed_at_spot = true;
640 
641     // TODO: this needs a custom targeter
642     direction_chooser_args args;
643     args.mode = TARG_HOSTILE;
644     args.top_prompt = "Aim the phial where?";
645 
646     if (spell_direction(*target, beam, &args)
647         && player_tracer(ZAP_PRIMAL_WAVE, base_pow, beam))
648     {
649         const int power = player_adjust_evoc_power(base_pow);
650         // use real power to recalc hit/dam
651         zappy(ZAP_PRIMAL_WAVE, power, false, beam);
652         beam.fire();
653 
654         return true;
655     }
656 
657     return false;
658 }
659 
_phantom_mirror(dist * target)660 static spret _phantom_mirror(dist *target)
661 {
662     bolt beam;
663     monster* victim = nullptr;
664     dist target_local;
665     if (!target)
666         target = &target_local;
667 
668     targeter_smite tgt(&you, LOS_RADIUS, 0, 0);
669 
670     direction_chooser_args args;
671     args.restricts = DIR_TARGET;
672     args.needs_path = false;
673     args.self = confirm_prompt_type::cancel;
674     args.top_prompt = "Aiming: <white>Phantom Mirror</white>";
675     args.hitfunc = &tgt;
676     if (!spell_direction(*target, beam, &args))
677         return spret::abort;
678     victim = monster_at(beam.target);
679     if (!victim || !you.can_see(*victim))
680     {
681         if (beam.target == you.pos())
682             mpr("You can't use the mirror on yourself.");
683         else
684             mpr("You can't see anything there to clone.");
685         return spret::abort;
686     }
687 
688     // Mirrored monsters (including by Mara, rakshasas) can still be
689     // re-reflected.
690     if (!actor_is_illusion_cloneable(victim)
691         && !victim->has_ench(ENCH_PHANTOM_MIRROR))
692     {
693         mpr("The mirror can't reflect that.");
694         return spret::abort;
695     }
696 
697     monster* mon = clone_mons(victim, true, nullptr, ATT_FRIENDLY);
698     if (!mon)
699     {
700         canned_msg(MSG_NOTHING_HAPPENS);
701         return spret::fail;
702     }
703     const int power = player_adjust_evoc_power(5 + you.skill(SK_EVOCATIONS, 3));
704     int dur = min(6, max(1,
705                          player_adjust_evoc_power(
706                              you.skill(SK_EVOCATIONS, 1) / 4 + 1)
707                          * (100 - victim->check_willpower(power)) / 100));
708 
709     mon->mark_summoned(dur, true, SPELL_PHANTOM_MIRROR);
710 
711     mon->summoner = MID_PLAYER;
712     mons_add_blame(mon, "mirrored by the player character");
713     mon->add_ench(ENCH_PHANTOM_MIRROR);
714     mon->add_ench(mon_enchant(ENCH_DRAINED,
715                               div_rand_round(mon->get_experience_level(), 3),
716                               &you, INFINITE_DURATION));
717 
718     mon->behaviour = BEH_SEEK;
719     set_nearest_monster_foe(mon);
720 
721     mprf("You reflect %s with the mirror!",
722          victim->name(DESC_THE).c_str());
723 
724     return spret::success;
725 }
726 
_valid_tremorstone_target(const monster & m)727 static bool _valid_tremorstone_target(const monster &m)
728 {
729     return !mons_is_firewood(m)
730         && !god_protects(&m)
731         && !always_shoot_through_monster(&you, m);
732 }
733 
734 /**
735  * Find the cell at range 3 closest to the center of mass of monsters in range,
736  * or a random range 3 cell if there are none.
737  *
738  * @param see_targets a boolean parameter indicating if the user can see any of
739  * the targets
740  * @return The cell in question.
741  */
_find_tremorstone_target(bool & see_targets)742 static coord_def _find_tremorstone_target(bool& see_targets)
743 {
744     coord_def com = {0, 0};
745     see_targets = false;
746     int num = 0;
747 
748     for (radius_iterator ri(you.pos(), LOS_NO_TRANS); ri; ++ri)
749     {
750         if (monster_at(*ri) && _valid_tremorstone_target(*monster_at(*ri)))
751         {
752             com += *ri;
753             see_targets = see_targets || you.can_see(*monster_at(*ri));
754             ++num;
755         }
756     }
757 
758     coord_def target = {0, 0};
759     int distance = LOS_RADIUS * num;
760     int ties = 0;
761 
762     for (radius_iterator ri(you.pos(), 3, C_SQUARE, LOS_NO_TRANS, true); ri; ++ri)
763     {
764         if (ri->distance_from(you.pos()) != 3 || cell_is_solid(*ri))
765             continue;
766 
767         if (num > 0)
768         {
769             if (com.distance_from((*ri) * num) < distance)
770             {
771                 ties = 1;
772                 target = *ri;
773                 distance = com.distance_from((*ri) * num);
774             }
775             else if (com.distance_from((*ri) * num) == distance
776                      && one_chance_in(++ties))
777             {
778                 target = *ri;
779             }
780         }
781         else if (one_chance_in(++ties))
782             target = *ri;
783     }
784 
785     return target;
786 }
787 
788 /**
789  * Find an adjacent tile for a tremorstone explosion to go off in.
790  *
791  * @param center    The original target of the stone.
792  * @return          The new, final origin of the stone's explosion.
793  */
_fuzz_tremorstone_target(coord_def center)794 static coord_def _fuzz_tremorstone_target(coord_def center)
795 {
796     coord_def chosen = center;
797     int seen = 1;
798     for (adjacent_iterator ai(center); ai; ++ai)
799         if (!cell_is_solid(*ai) && one_chance_in(++seen))
800             chosen = *ai;
801     return chosen;
802 }
803 
804 /**
805  * Number of explosions, scales up from 1 at 0 evo to 6 at 27 evo,
806  * via a stepdown.
807  *
808  * Currently pow is just evo + 15, but the abstraction is kept around in
809  * case an evocable enhancer returns to the game so that 0 evo with enhancer
810  * gets some amount of enhancement.
811  */
_tremorstone_count(int pow)812 static int _tremorstone_count(int pow)
813 {
814     return 1 + stepdown((pow - 15) / 3, 2, ROUND_CLOSE);
815 }
816 
817 /**
818  * Evokes a tremorstone, blasting something in the general area of a
819  * chosen target.
820  *
821  * @return          spret::abort if the player cancels, spret::fail if they
822  *                  try to evoke but fail, and spret::success otherwise.
823  */
_tremorstone()824 static spret _tremorstone()
825 {
826     if (you.confused())
827     {
828         canned_msg(MSG_TOO_CONFUSED);
829         return spret::abort;
830     }
831 
832     bool see_target;
833     bolt beam;
834 
835     static const int RADIUS = 2;
836     static const int SPREAD = 1;
837     static const int RANGE = RADIUS + SPREAD;
838     const int pow = 15 + you.skill(SK_EVOCATIONS);
839     const int adjust_pow = player_adjust_evoc_power(pow);
840     const int num_explosions = _tremorstone_count(adjust_pow);
841 
842     beam.source_id  = MID_PLAYER;
843     beam.thrower    = KILL_YOU;
844     zappy(ZAP_TREMORSTONE, pow, false, beam);
845     beam.range = RANGE;
846     beam.ex_size = RADIUS;
847     beam.target = _find_tremorstone_target(see_target);
848 
849     targeter_radius hitfunc(&you, LOS_NO_TRANS);
850     auto vulnerable = [](const actor *act) -> bool
851     {
852         return act && _valid_tremorstone_target(*act->as_monster());
853     };
854     if ((!see_target
855         && !yesno("You can't see anything, release a tremorstone anyway?",
856                  true, 'n'))
857         || stop_attack_prompt(hitfunc, "release a tremorstone", vulnerable))
858     {
859         return spret::abort;
860     }
861 
862     mpr("The tremorstone explodes into fragments!");
863     const coord_def center = beam.target;
864 
865     for (int i = 0; i < num_explosions; i++)
866     {
867         bolt explosion = beam;
868         explosion.target = _fuzz_tremorstone_target(center);
869         explosion.explode(i == num_explosions - 1);
870     }
871 
872     return spret::success;
873 }
874 
875 static const vector<random_pick_entry<cloud_type>> condenser_clouds =
876 {
877   { 0,   50, 200, FALL, CLOUD_MEPHITIC },
878   { 0,  100, 125, PEAK, CLOUD_FIRE },
879   { 0,  100, 125, PEAK, CLOUD_COLD },
880   { 0,  100, 125, PEAK, CLOUD_POISON },
881   { 0,  110, 50, RISE, CLOUD_NEGATIVE_ENERGY },
882   { 0,  110, 50, RISE, CLOUD_STORM },
883   { 0,  110, 50, RISE, CLOUD_ACID },
884 };
885 
_condenser()886 static spret _condenser()
887 {
888     if (you.confused())
889     {
890         canned_msg(MSG_TOO_CONFUSED);
891         return spret::abort;
892     }
893 
894     if (env.level_state & LSTATE_STILL_WINDS)
895     {
896         mpr("The air is too still to form clouds.");
897         return spret::abort;
898     }
899 
900     const int pow = 15 + you.skill(SK_EVOCATIONS, 7) / 2;
901     const int adjust_pow = min(110,player_adjust_evoc_power(pow));
902 
903     random_picker<cloud_type, NUM_CLOUD_TYPES> cloud_picker;
904     cloud_type cloud = cloud_picker.pick(condenser_clouds, adjust_pow, CLOUD_NONE);
905 
906     vector<coord_def> target_cells;
907     bool see_targets = false;
908 
909     for (radius_iterator di(you.pos(), LOS_NO_TRANS); di; ++di)
910     {
911         monster *mons = monster_at(*di);
912 
913         if (!mons || mons->wont_attack() || !mons_is_threatening(*mons))
914             continue;
915 
916         if (you.can_see(*mons))
917             see_targets = true;
918 
919         for (adjacent_iterator ai(mons->pos(), false); ai; ++ai)
920         {
921             actor * act = actor_at(*ai);
922             if (!cell_is_solid(*ai) && you.see_cell(*ai) && !cloud_at(*ai)
923                 && !(act && act->wont_attack()))
924             {
925                 target_cells.push_back(*ai);
926             }
927         }
928     }
929 
930     if (!see_targets
931         && !yesno("You can't see anything. Try to condense clouds anyway?",
932                   true, 'n'))
933     {
934         canned_msg(MSG_OK);
935         return spret::abort;
936     }
937 
938     if (target_cells.empty())
939     {
940         canned_msg(MSG_NOTHING_HAPPENS);
941         return spret::fail;
942     }
943 
944     for (auto p : target_cells)
945     {
946         const int cloud_power = 5
947             + random2avg(12 + div_rand_round(adjust_pow * 3, 4), 3);
948         place_cloud(cloud, p, cloud_power, &you);
949     }
950 
951     mprf("Clouds of %s condense around you!", cloud_type_name(cloud).c_str());
952 
953     return spret::success;
954 }
955 
_xoms_chessboard()956 static bool _xoms_chessboard()
957 {
958     if (you.confused())
959     {
960         canned_msg(MSG_TOO_CONFUSED);
961         return false;
962     }
963 
964     vector<monster *> targets;
965     bool see_target = false;
966 
967     for (monster_near_iterator mi(&you, LOS_NO_TRANS); mi; ++mi)
968     {
969         if (mi->friendly() || mi->neutral())
970             continue;
971         if (mons_is_firewood(**mi))
972             continue;
973         if (you.can_see(**mi))
974             see_target = true;
975 
976         targets.emplace_back(*mi);
977     }
978 
979     if (!see_target
980         && !yesno("You can't see anything. Try to make a move anyway?",
981                   true, 'n'))
982     {
983         canned_msg(MSG_OK);
984         return false;
985     }
986 
987     const int power =
988         player_adjust_evoc_power(15 + you.skill(SK_EVOCATIONS, 7) / 2);
989 
990     mpr("You make a move on Xom's chessboard...");
991 
992     if (targets.empty())
993     {
994         canned_msg(MSG_NOTHING_HAPPENS);
995         return true;
996     }
997 
998     bolt beam;
999     const monster * target = *random_iterator(targets);
1000     beam.source = target->pos();
1001     beam.target = target->pos();
1002 
1003     // List of possible effects. Mostly debuffs, a few buffs to keep it
1004     // exciting
1005     zap_type zap = random_choose_weighted(5, ZAP_HASTE,
1006                                           5, ZAP_INVISIBILITY,
1007                                           5, ZAP_MIGHT,
1008                                           10, ZAP_CORONA,
1009                                           15, ZAP_SLOW,
1010                                           15, ZAP_MALMUTATE,
1011                                           15, ZAP_PETRIFY,
1012                                           10, ZAP_PARALYSE,
1013                                           10, ZAP_CONFUSE,
1014                                           10, ZAP_SLEEP);
1015     beam.origin_spell = SPELL_NO_SPELL; // let zapping reset this
1016 
1017     return zapping(zap, power, beam, false) == spret::success;
1018 }
1019 
1020 
1021 // Is there anything that would prevent a player from evoking?
1022 // If slot == -1, it asks this question in general.
1023 // If slot is a particular item, it asks this question for that item. This
1024 // wierdly does not check whether an item is actually evokable! (TODO)
evoke_check(int slot,bool quiet)1025 bool evoke_check(int slot, bool quiet)
1026 {
1027     item_def *i = nullptr;
1028     if (slot >= 0 && slot < ENDOFPACK && you.inv[slot].defined())
1029         i = &you.inv[slot];
1030 
1031     if (i && item_type_removed(i->base_type, i->sub_type))
1032     {
1033         if (!quiet)
1034             mpr("Sorry, this item was removed!");
1035         return false;
1036     }
1037 
1038     // TODO: are these reaching checks necessary any more?
1039     // is slot a wielded reaching weapon, or if no slot, is the player wielding
1040     // a reaching weapon?
1041     const bool wielded = you.weapon()
1042                          && (slot != -1 && slot == you.equip[EQ_WEAPON]
1043                                 || slot == -1 && you.equip[EQ_WEAPON] >= 0);
1044     const bool reaching = wielded
1045                           && weapon_reach(*you.weapon()) > REACH_NONE;
1046 
1047     // ammo checks are done below, this is the precondition for messaging
1048     // about ranged failures
1049     const bool ranged = wielded && is_range_weapon(*you.weapon());
1050 
1051     if ((reaching || ranged) && you.melded[EQ_WEAPON])
1052     {
1053         if (!quiet)
1054             canned_msg(MSG_PRESENT_FORM);
1055         return false;
1056     }
1057 
1058     if (you.berserk() && !reaching)
1059     {
1060         if (!quiet)
1061             canned_msg(MSG_TOO_BERSERK);
1062         return false;
1063     }
1064     if (you.confused() && !ranged) // attack is ok under confusion, but not reaching
1065     {
1066         if (!quiet)
1067             canned_msg(MSG_TOO_CONFUSED);
1068         return false;
1069     }
1070     if (ranged && i && (you.launcher_action.is_empty()
1071                     || !you.launcher_action.get()->is_valid()))
1072     {
1073         if (!quiet)
1074         {
1075             // XX messaging should be unified with actual launching code
1076             mprf("You do not have any ammo quivered for %s.",
1077                                     you.weapon()->name(DESC_YOUR).c_str());
1078         }
1079         return false;
1080     }
1081     if (reaching || ranged)
1082         return true;
1083 
1084     // is this supposed to be allowed under confusion?
1085     if (i && i->base_type == OBJ_MISCELLANY && i->sub_type == MISC_ZIGGURAT)
1086         return true;
1087 
1088     if (!i)
1089     {
1090         // does the player have a zigfig? overrides sac artiface
1091         // this is ugly...this thing should probably be goldified
1092         for (const item_def &s : you.inv)
1093             if (s.defined() && s.base_type == OBJ_MISCELLANY
1094                                      && s.sub_type == MISC_ZIGGURAT)
1095             {
1096                 return true;
1097             }
1098     }
1099 
1100 #if TAG_MAJOR_VERSION == 34
1101     if (player_under_penance(GOD_PAKELLAS))
1102     {
1103         if (!quiet)
1104         {
1105             simple_god_message("'s wrath prevents you from evoking devices!",
1106                            GOD_PAKELLAS);
1107         }
1108         return false;
1109     }
1110 #endif
1111 
1112     if (you.get_mutation_level(MUT_NO_ARTIFICE))
1113     {
1114         if (!quiet)
1115             mpr("You cannot evoke magical items.");
1116         return false;
1117     }
1118 
1119     if (i && i->base_type == OBJ_WANDS && i->charges <= 0)
1120     {
1121         // I think this case should be obsolete? Maybe still could happen with
1122         // an upgrade
1123         if (!quiet)
1124             mpr("This wand has no charges.");
1125         return false;
1126     }
1127 
1128     if (i && is_xp_evoker(*i) && evoker_charges(i->sub_type) <= 0)
1129     {
1130         // DESC_THE prints "The tin of tremorstones (inert) is presently inert."
1131         if (!quiet)
1132             mprf("The %s is presently inert.", i->name(DESC_DBNAME).c_str());
1133         return false;
1134     }
1135 
1136     return true;
1137 }
1138 
evoke_item(int slot,dist * preselect)1139 bool evoke_item(int slot, dist *preselect)
1140 {
1141     if (!evoke_check(slot))
1142         return false;
1143 
1144     if (slot == -1)
1145     {
1146         slot = prompt_invent_item("Evoke which item? (* to show all)",
1147                                    menu_type::invlist,
1148                                    OSEL_EVOKABLE, OPER_EVOKE);
1149 
1150         if (prompt_failed(slot))
1151             return false;
1152     }
1153     else if (!check_warning_inscriptions(you.inv[slot], OPER_EVOKE))
1154         return false;
1155 
1156     ASSERT(slot >= 0);
1157 
1158 #ifdef ASSERTS // Used only by an assert
1159     const bool wielded = (you.equip[EQ_WEAPON] == slot);
1160 #endif /* DEBUG */
1161 
1162     item_def& item = you.inv[slot];
1163     // Also handles messages.
1164     if (!item_is_evokable(item, true, false, true) || !evoke_check(slot))
1165         return false;
1166 
1167     bool did_work   = false;  // "Nothing happens" message
1168     bool unevokable = false;
1169 
1170     const unrandart_entry *entry = is_unrandom_artefact(item)
1171         ? get_unrand_entry(item.unrand_idx) : nullptr;
1172 
1173     if (entry && (entry->evoke_func || entry->targeted_evoke_func))
1174     {
1175         ASSERT(item_is_equipped(item));
1176 
1177         bool qret;
1178         // only use one of these, prioritizing the targeted version. In
1179         // principle we could call them both?
1180         ASSERT(!(entry->evoke_func && entry->targeted_evoke_func)); // probably should be in art-data.pl
1181         if (entry->targeted_evoke_func)
1182             qret = entry->targeted_evoke_func(&item, &did_work, &unevokable, preselect);
1183         else
1184             qret = entry->evoke_func(&item, &did_work, &unevokable);
1185 
1186         if (!unevokable)
1187             count_action(CACT_EVOKE, item.unrand_idx);
1188 
1189         // what even _is_ this return value?
1190         if (qret)
1191             return did_work;
1192     }
1193     else switch (item.base_type)
1194     {
1195     case OBJ_WANDS:
1196         zap_wand(slot, preselect);
1197         return true;
1198 
1199     case OBJ_WEAPONS:
1200     {
1201         ASSERT(wielded);
1202         dist targ_local;
1203         if (!preselect)
1204             preselect = &targ_local;
1205 
1206         quiver::get_primary_action()->trigger(*preselect);
1207         return you.turn_is_over;
1208     }
1209 
1210     case OBJ_MISCELLANY:
1211         did_work = true; // easier to do it this way for misc items
1212 
1213         switch (item.sub_type)
1214         {
1215 #if TAG_MAJOR_VERSION == 34
1216         case MISC_BOTTLED_EFREET:
1217             canned_msg(MSG_NOTHING_HAPPENS);
1218             return false;
1219 
1220         case MISC_FAN_OF_GALES:
1221             canned_msg(MSG_NOTHING_HAPPENS);
1222             return false;
1223 
1224         case MISC_LAMP_OF_FIRE:
1225             canned_msg(MSG_NOTHING_HAPPENS);
1226             return false;
1227 
1228         case MISC_STONE_OF_TREMORS:
1229             canned_msg(MSG_NOTHING_HAPPENS);
1230             return false;
1231 #endif
1232 
1233         case MISC_PHIAL_OF_FLOODS:
1234             if (_phial_of_floods(preselect))
1235             {
1236                 expend_xp_evoker(item.sub_type);
1237                 practise_evoking(3);
1238             }
1239             else
1240                 return false;
1241             break;
1242 
1243         case MISC_HORN_OF_GERYON:
1244             if (_evoke_horn_of_geryon())
1245             {
1246                 expend_xp_evoker(item.sub_type);
1247                 practise_evoking(3);
1248             }
1249             else
1250                 return false;
1251             break;
1252 
1253         case MISC_BOX_OF_BEASTS:
1254             if (_box_of_beasts())
1255             {
1256                 expend_xp_evoker(item.sub_type);
1257                 if (!evoker_charges(item.sub_type))
1258                     mpr("The box is emptied!");
1259                 practise_evoking(1);
1260             }
1261             break;
1262 
1263 #if TAG_MAJOR_VERSION == 34
1264         case MISC_SACK_OF_SPIDERS:
1265             canned_msg(MSG_NOTHING_HAPPENS);
1266             return false;
1267 
1268         case MISC_CRYSTAL_BALL_OF_ENERGY:
1269             canned_msg(MSG_NOTHING_HAPPENS);
1270             return false;
1271 #endif
1272 
1273         case MISC_LIGHTNING_ROD:
1274             if (_lightning_rod(preselect))
1275             {
1276                 practise_evoking(1);
1277                 expend_xp_evoker(item.sub_type);
1278                 if (!evoker_charges(item.sub_type))
1279                     mpr("The lightning rod overheats!");
1280             }
1281             else
1282                 return false;
1283             break;
1284 
1285         case MISC_QUAD_DAMAGE:
1286             mpr("QUAD DAMAGE!");
1287             you.duration[DUR_QUAD_DAMAGE] = 30 * BASELINE_DELAY;
1288             ASSERT(in_inventory(item));
1289             dec_inv_item_quantity(item.link, 1);
1290             invalidate_agrid(true);
1291             break;
1292 
1293         case MISC_PHANTOM_MIRROR:
1294             switch (_phantom_mirror(preselect))
1295             {
1296                 default:
1297                 case spret::abort:
1298                     return false;
1299 
1300                 case spret::success:
1301                     expend_xp_evoker(item.sub_type);
1302                     if (!evoker_charges(item.sub_type))
1303                         mpr("The mirror clouds!");
1304                     // deliberate fall-through
1305                 case spret::fail:
1306                     practise_evoking(1);
1307                     break;
1308             }
1309             break;
1310 
1311         case MISC_ZIGGURAT:
1312             // Don't set did_work to false, _make_zig handles the message.
1313             unevokable = !_make_zig(item);
1314             break;
1315 
1316         case MISC_TIN_OF_TREMORSTONES:
1317             switch (_tremorstone())
1318             {
1319                 default:
1320                 case spret::abort:
1321                     return false;
1322 
1323                 case spret::success:
1324                     expend_xp_evoker(item.sub_type);
1325                     if (!evoker_charges(item.sub_type))
1326                         mpr("The tin is emptied!");
1327                 case spret::fail:
1328                     practise_evoking(1);
1329                     break;
1330             }
1331             break;
1332 
1333         case MISC_CONDENSER_VANE:
1334             switch (_condenser())
1335             {
1336                 default:
1337                 case spret::abort:
1338                     return false;
1339 
1340                 case spret::success:
1341                     expend_xp_evoker(item.sub_type);
1342                     if (!evoker_charges(item.sub_type))
1343                         mpr("The condenser dries out!");
1344                 case spret::fail:
1345                     practise_evoking(1);
1346                     break;
1347             }
1348             break;
1349 
1350         case MISC_XOMS_CHESSBOARD:
1351             if (_xoms_chessboard())
1352             {
1353                 expend_xp_evoker(item.sub_type);
1354                 if (!evoker_charges(item.sub_type))
1355                     mpr("The chess piece greys!");
1356                 practise_evoking(1);
1357             }
1358             else
1359                 return false;
1360             break;
1361 
1362         default:
1363             did_work = false;
1364             unevokable = true;
1365             break;
1366         }
1367         if (did_work && !unevokable)
1368             count_action(CACT_EVOKE, item.sub_type, OBJ_MISCELLANY);
1369         break;
1370 
1371     default:
1372         unevokable = true;
1373         break;
1374     }
1375 
1376     if (!did_work)
1377         canned_msg(MSG_NOTHING_HAPPENS);
1378 
1379     if (!unevokable)
1380         you.turn_is_over = true;
1381     else
1382         crawl_state.zero_turns_taken();
1383 
1384     return did_work;
1385 }
1386