Apply the new ground_level method.
[crawl.git] / crawl-ref / source / spl-miscast.cc
blob1894ceb968e323ef2ffb37f69d581a249afa059c
1 /*
2 * File: spl-miscast.cc
3 * Summary: Spell miscast class.
4 * Written by: Matthew Cline
5 */
7 #include "AppHdr.h"
9 #include "spl-miscast.h"
11 #include "externs.h"
13 #include <sstream>
15 #include "colour.h"
16 #include "cloud.h"
17 #include "directn.h"
18 #include "effects.h"
19 #include "env.h"
20 #include "it_use2.h"
21 #include "kills.h"
22 #include "libutil.h"
23 #include "misc.h"
24 #include "mon-place.h"
25 #include "mgen_data.h"
26 #include "mon-stuff.h"
27 #include "mon-util.h"
28 #include "mutation.h"
29 #include "player.h"
30 #include "player-stats.h"
31 #include "religion.h"
32 #include "spl-clouds.h"
33 #include "state.h"
34 #include "stuff.h"
35 #include "areas.h"
36 #include "terrain.h"
37 #include "transform.h"
38 #include "view.h"
39 #include "shout.h"
40 #include "viewchar.h"
41 #include "xom.h"
43 // This determines how likely it is that more powerful wild magic
44 // effects will occur. Set to 100 for the old probabilities (although
45 // the individual effects have been made much nastier since then).
46 #define WILD_MAGIC_NASTINESS 150
48 #define MAX_RECURSE 100
50 MiscastEffect::MiscastEffect(actor* _target, int _source, spell_type _spell,
51 int _pow, int _fail, std::string _cause,
52 nothing_happens_when_type _nothing_happens,
53 int _lethality_margin, std::string _hand_str,
54 bool _can_plural) :
55 target(_target), source(_source), cause(_cause), spell(_spell),
56 school(SPTYP_NONE), pow(_pow), fail(_fail), level(-1), kc(KC_NCATEGORIES),
57 kt(KILL_NONE), nothing_happens_when(_nothing_happens),
58 lethality_margin(_lethality_margin), hand_str(_hand_str),
59 can_plural_hand(_can_plural)
61 ASSERT(is_valid_spell(_spell));
62 unsigned int schools = get_spell_disciplines(_spell);
63 ASSERT(schools != SPTYP_NONE);
64 ASSERT(!(schools & SPTYP_HOLY));
65 UNUSED(schools);
67 init();
68 do_miscast();
71 MiscastEffect::MiscastEffect(actor* _target, int _source,
72 spschool_flag_type _school, int _level,
73 std::string _cause,
74 nothing_happens_when_type _nothing_happens,
75 int _lethality_margin, std::string _hand_str,
76 bool _can_plural) :
77 target(_target), source(_source), cause(_cause), spell(SPELL_NO_SPELL),
78 school(_school), pow(-1), fail(-1), level(_level), kc(KC_NCATEGORIES),
79 kt(KILL_NONE), nothing_happens_when(_nothing_happens),
80 lethality_margin(_lethality_margin), hand_str(_hand_str),
81 can_plural_hand(_can_plural)
83 ASSERT(!_cause.empty());
84 ASSERT(count_bits(_school) == 1);
85 ASSERT(_school < SPTYP_HOLY || _school == SPTYP_RANDOM);
86 ASSERT(level >= 0 && level <= 3);
88 init();
89 do_miscast();
92 MiscastEffect::MiscastEffect(actor* _target, int _source,
93 spschool_flag_type _school, int _pow, int _fail,
94 std::string _cause,
95 nothing_happens_when_type _nothing_happens,
96 int _lethality_margin, std::string _hand_str,
97 bool _can_plural) :
98 target(_target), source(_source), cause(_cause), spell(SPELL_NO_SPELL),
99 school(_school), pow(_pow), fail(_fail), level(-1), kc(KC_NCATEGORIES),
100 kt(KILL_NONE), nothing_happens_when(_nothing_happens),
101 lethality_margin(_lethality_margin), hand_str(_hand_str),
102 can_plural_hand(_can_plural)
104 ASSERT(!_cause.empty());
105 ASSERT(count_bits(_school) == 1);
106 ASSERT(_school < SPTYP_HOLY || _school == SPTYP_RANDOM);
108 init();
109 do_miscast();
112 MiscastEffect::~MiscastEffect()
114 ASSERT(recursion_depth == 0);
117 void MiscastEffect::init()
119 ASSERT(spell != SPELL_NO_SPELL && school == SPTYP_NONE
120 || spell == SPELL_NO_SPELL && school != SPTYP_NONE);
121 ASSERT(pow != -1 && fail != -1 && level == -1
122 || pow == -1 && fail == -1 && level >= 0 && level <= 3);
124 ASSERT(target != NULL);
125 ASSERT(target->alive());
127 ASSERT(lethality_margin == 0 || target->atype() == ACT_PLAYER);
129 recursion_depth = 0;
131 source_known = target_known = false;
133 act_source = guilty = NULL;
135 const bool death_curse = (cause.find("death curse") != std::string::npos);
137 if (target->atype() == ACT_MONSTER)
138 target_known = you.can_see(target);
139 else
140 target_known = true;
142 kill_source = source;
143 if (source == WIELD_MISCAST || source == MELEE_MISCAST)
145 if (target->atype() == ACT_MONSTER)
146 kill_source = target->mindex();
147 else
148 kill_source = NON_MONSTER;
151 if (kill_source == NON_MONSTER)
153 kc = KC_YOU;
154 kt = KILL_YOU_MISSILE;
155 act_source = &you;
156 guilty = &you;
157 source_known = true;
159 else if (!invalid_monster_index(kill_source))
161 monster* mon_source = &menv[kill_source];
162 ASSERT(mon_source->type != -1);
164 act_source = guilty = mon_source;
166 if (death_curse && target->atype() == ACT_MONSTER
167 && target_as_monster()->confused_by_you())
169 kt = KILL_YOU_CONF;
171 else if (!death_curse && mon_source->confused_by_you()
172 && !mon_source->friendly())
174 kt = KILL_YOU_CONF;
176 else
177 kt = KILL_MON_MISSILE;
179 if (mon_source->friendly())
180 kc = KC_FRIENDLY;
181 else
182 kc = KC_OTHER;
184 source_known = you.can_see(mon_source);
186 if (target_known && death_curse)
187 source_known = true;
189 else
191 ASSERT(source == ZOT_TRAP_MISCAST
192 || source == MISC_MISCAST
193 || (source < 0 && -source < NUM_GODS));
195 act_source = target;
197 kc = KC_OTHER;
198 kt = KILL_MISCAST;
200 if (source == ZOT_TRAP_MISCAST)
202 source_known = target_known;
204 if (target->atype() == ACT_MONSTER
205 && target_as_monster()->confused_by_you())
207 kt = KILL_YOU_CONF;
210 else if (source == MISC_MISCAST)
211 source_known = true, guilty = &you;
212 else
213 source_known = true;
216 ASSERT(kc != KC_NCATEGORIES && kt != KILL_NONE);
218 if (death_curse && !invalid_monster_index(kill_source))
220 if (starts_with(cause, "a "))
221 cause.replace(cause.begin(), cause.begin() + 1, "an indirect");
222 else if (starts_with(cause, "an "))
223 cause.replace(cause.begin(), cause.begin() + 2, "an indirect");
224 else
225 cause = replace_all(cause, "death curse", "indirect death curse");
228 // source_known = false for MELEE_MISCAST so that melee miscasts
229 // won't give a "nothing happens" message.
230 if (source == MELEE_MISCAST)
231 source_known = false;
233 if (hand_str.empty())
234 target->hand_name(true, &can_plural_hand);
236 // Explosion stuff.
237 beam.is_explosion = true;
239 // [ds] Don't attribute the beam's cause to the actor, because the
240 // death message will name the actor anyway.
241 if (cause.empty())
242 cause = get_default_cause(false);
243 beam.aux_source = cause;
244 beam.beam_source = (0 <= kill_source && kill_source <= MHITYOU)
245 ? kill_source : MHITNOT;
246 beam.thrower = kt;
249 std::string MiscastEffect::get_default_cause(bool attribute_to_user) const
251 // This is only for true miscasts, which means both a spell and that
252 // the source of the miscast is the same as the target of the miscast.
253 ASSERT(source >= 0 && source <= NON_MONSTER);
254 ASSERT(spell != SPELL_NO_SPELL);
255 ASSERT(school == SPTYP_NONE);
257 if (source == NON_MONSTER)
259 ASSERT(target->atype() == ACT_PLAYER);
260 std::string str = "miscasting ";
261 str += spell_title(spell);
262 return str;
265 ASSERT(act_source->atype() == ACT_MONSTER);
266 ASSERT(act_source == target);
268 if (attribute_to_user)
270 return (std::string(you.can_see(act_source)?
271 act_source->name(DESC_NOCAP_A)
272 : "something")
273 + " miscasting " + spell_title(spell));
275 else
277 return std::string("miscast of ") + spell_title(spell);
281 bool MiscastEffect::neither_end_silenced()
283 return (!silenced(you.pos()) && !silenced(target->pos()));
286 void MiscastEffect::do_miscast()
288 ASSERT(recursion_depth >= 0 && recursion_depth < MAX_RECURSE);
290 if (recursion_depth == 0)
291 did_msg = false;
293 unwind_var<int> unwind_depth(recursion_depth);
294 recursion_depth++;
296 // Repeated calls to do_miscast() on a single object instance have
297 // killed a target which was alive when the object was created.
298 if (!target->alive())
300 dprf("Miscast target '%s' already dead",
301 target->name(DESC_PLAIN, true).c_str());
302 return;
305 spschool_flag_type sp_type;
306 int severity;
308 if (spell != SPELL_NO_SPELL)
310 std::vector<int> school_list;
311 for (int i = 0; i < SPTYP_LAST_EXPONENT; i++)
312 if (spell_typematch(spell, 1 << i))
313 school_list.push_back(i);
315 unsigned int _school = school_list[random2(school_list.size())];
316 sp_type = static_cast<spschool_flag_type>(1 << _school);
318 else
320 sp_type = school;
321 if (sp_type == SPTYP_RANDOM)
323 int exp = (random2(SPTYP_LAST_EXPONENT));
324 sp_type = (spschool_flag_type) (1 << exp);
328 if (level != -1)
329 severity = level;
330 else
332 severity = (pow * fail * (10 + pow) / 7 * WILD_MAGIC_NASTINESS) / 100;
334 #if defined(DEBUG_DIAGNOSTICS) || defined(DEBUG_MISCAST)
335 mprf(MSGCH_DIAGNOSTICS, "'%s' miscast power: %d",
336 spell != SPELL_NO_SPELL ? spell_title(spell)
337 : spelltype_short_name(sp_type),
338 severity);
339 #endif
341 if (random2(40) > severity && random2(40) > severity)
343 if (target->atype() == ACT_PLAYER)
344 canned_msg(MSG_NOTHING_HAPPENS);
345 return;
348 severity /= 100;
349 severity = random2(severity);
350 if (severity > 3)
351 severity = 3;
352 else if (severity < 0)
353 severity = 0;
356 #if defined(DEBUG_DIAGNOSTICS) || defined(DEBUG_MISCAST)
357 mprf(MSGCH_DIAGNOSTICS, "Sptype: %s, severity: %d",
358 spelltype_short_name(sp_type), severity);
359 #endif
361 beam.ex_size = 1;
362 beam.name = "";
363 beam.damage = dice_def(0, 0);
364 beam.flavour = BEAM_NONE;
365 beam.msg_generated = false;
366 beam.in_explosion_phase = false;
368 // Do this here since multiple miscasts (wizmode testing) might move
369 // the target around.
370 beam.source = target->pos();
371 beam.target = target->pos();
372 beam.use_target_as_pos = true;
374 all_msg = you_msg = mon_msg = mon_msg_seen = mon_msg_unseen = "";
375 msg_ch = MSGCH_PLAIN;
376 sound_loudness = 0;
378 switch (sp_type)
380 case SPTYP_CONJURATION: _conjuration(severity); break;
381 case SPTYP_HEXES:
382 case SPTYP_CHARMS: _enchantment(severity); break;
383 case SPTYP_TRANSLOCATION: _translocation(severity); break;
384 case SPTYP_SUMMONING: _summoning(severity); break;
385 case SPTYP_NECROMANCY: _necromancy(severity); break;
386 case SPTYP_TRANSMUTATION: _transmutation(severity); break;
387 case SPTYP_FIRE: _fire(severity); break;
388 case SPTYP_ICE: _ice(severity); break;
389 case SPTYP_EARTH: _earth(severity); break;
390 case SPTYP_AIR: _air(severity); break;
391 case SPTYP_POISON: _poison(severity); break;
392 case SPTYP_DIVINATION:
393 // Divination miscasts have nothing in common between the player
394 // and monsters.
395 if (target->atype() == ACT_PLAYER)
396 _divination_you(severity);
397 else
398 _divination_mon(severity);
399 break;
401 default:
402 die("Invalid miscast spell discipline.");
405 if (target->atype() == ACT_PLAYER)
406 xom_is_stimulated(severity * 50);
409 void MiscastEffect::do_msg(bool suppress_nothing_happens)
411 ASSERT(!did_msg);
413 if (target->atype() == ACT_MONSTER && !mons_near(target_as_monster()))
414 return;
416 did_msg = true;
418 std::string msg;
420 if (!all_msg.empty())
421 msg = all_msg;
422 else if (target->atype() == ACT_PLAYER)
423 msg = you_msg;
424 else if (!mon_msg.empty())
426 msg = mon_msg;
427 // Monster might be unseen with hands that can't be seen.
428 ASSERT(msg.find("@hand") == std::string::npos);
430 else
432 if (you.can_see(target))
433 msg = mon_msg_seen;
434 else
436 msg = mon_msg_unseen;
437 // Can't see the hands of invisible monsters.
438 ASSERT(msg.find("@hand") == std::string::npos);
442 if (msg.empty())
444 if (!suppress_nothing_happens
445 && (nothing_happens_when == NH_ALWAYS
446 || (nothing_happens_when == NH_DEFAULT && source_known
447 && target_known)))
449 canned_msg(MSG_NOTHING_HAPPENS);
452 return;
455 bool plural;
457 if (hand_str.empty())
459 msg = replace_all(msg, "@hand@", target->hand_name(false, &plural));
460 msg = replace_all(msg, "@hands@", target->hand_name(true));
462 else
464 plural = can_plural_hand;
465 msg = replace_all(msg, "@hand@", hand_str);
466 if (can_plural_hand)
467 msg = replace_all(msg, "@hands@", pluralise(hand_str));
468 else
469 msg = replace_all(msg, "@hands@", hand_str);
472 if (plural)
473 msg = replace_all(msg, "@hand_conj@", "");
474 else
475 msg = replace_all(msg, "@hand_conj@", "s");
477 if (target->atype() == ACT_MONSTER)
479 msg = do_mon_str_replacements(msg, target_as_monster(), S_SILENT);
480 if (!mons_has_body(target_as_monster()))
481 msg = replace_all(msg, "'s body", "");
484 mpr(msg.c_str(), msg_ch);
486 if (msg_ch == MSGCH_SOUND)
488 // Those monsters of normal or greater intelligence will realize that they
489 // were the source of the sound.
490 int src = target->atype() == ACT_PLAYER ? you.mindex()
491 : mons_intel(target_as_monster()) >= I_NORMAL ? target->mindex()
492 : -1;
493 noisy(sound_loudness, target->pos(), src);
497 bool MiscastEffect::_ouch(int dam, beam_type flavour)
499 // Delay do_msg() until after avoid_lethal().
500 if (target->atype() == ACT_MONSTER)
502 monster* mon_target = target_as_monster();
504 do_msg(true);
506 bolt beem;
508 beem.flavour = flavour;
509 dam = mons_adjust_flavoured(mon_target, beem, dam, true);
510 mon_target->hurt(NULL, dam, BEAM_MISSILE, false);
512 if (!mon_target->alive())
513 monster_die(mon_target, kt, kill_source);
515 else
517 dam = check_your_resists(dam, flavour, cause);
519 if (avoid_lethal(dam))
520 return (false);
522 do_msg(true);
524 kill_method_type method;
526 if (source == NON_MONSTER && spell != SPELL_NO_SPELL)
527 method = KILLED_BY_WILD_MAGIC;
528 else if (source == ZOT_TRAP_MISCAST)
529 method = KILLED_BY_TRAP;
530 else if (source < 0 && -source < NUM_GODS)
532 god_type god = static_cast<god_type>(-source);
534 if (god == GOD_XOM && you.penance[GOD_XOM] == 0)
535 method = KILLED_BY_XOM;
536 else
537 method = KILLED_BY_DIVINE_WRATH;
539 else
540 method = KILLED_BY_SOMETHING;
542 bool see_source = act_source && you.can_see(act_source);
543 ouch(dam, kill_source, method, cause.c_str(), see_source);
546 return (true);
549 bool MiscastEffect::_explosion()
551 ASSERT(!beam.name.empty());
552 ASSERT(beam.damage.num != 0 && beam.damage.size != 0);
553 ASSERT(beam.flavour != BEAM_NONE);
555 int max_dam = beam.damage.num * beam.damage.size;
556 max_dam = check_your_resists(max_dam, beam.flavour, cause);
557 if (avoid_lethal(max_dam))
558 return (false);
560 do_msg(true);
561 beam.explode();
563 return (true);
566 bool MiscastEffect::_big_cloud(cloud_type cl_type, int cloud_pow, int size,
567 int spread_rate)
569 if (avoid_lethal(2 * max_cloud_damage(cl_type, cloud_pow)))
570 return (false);
572 do_msg(true);
573 big_cloud(cl_type, guilty, target->pos(), cloud_pow, size, spread_rate);
575 return (true);
578 bool MiscastEffect::_lose_stat(stat_type which_stat, int8_t stat_loss)
580 return (lose_stat(which_stat, stat_loss, false, cause));
583 void MiscastEffect::_potion_effect(potion_type pot_eff, int pot_pow)
585 if (target->atype() == ACT_PLAYER)
587 potion_effect(pot_eff, pot_pow, false, false);
588 return;
591 switch (pot_eff)
593 case POT_BERSERK_RAGE:
594 if (target->can_go_berserk())
596 target->go_berserk(false);
597 break;
599 // Intentional fallthrough if that didn't work.
600 case POT_SLOWING:
601 target->slow_down(act_source, pot_pow);
602 break;
603 case POT_PARALYSIS:
604 target->paralyse(act_source, pot_pow);
605 break;
606 case POT_CONFUSION:
607 target->confuse(act_source, pot_pow);
608 break;
610 default:
611 die("unknown potion effect");
615 void MiscastEffect::send_abyss()
617 if (you.level_type == LEVEL_ABYSS)
619 you_msg = "The world appears momentarily distorted.";
620 mon_msg_seen = "@The_monster@ wobbles for a moment.";
621 mon_msg_unseen = "An empty piece of space momentarily distorts.";
622 do_msg();
623 return;
626 target->banish(cause);
629 bool MiscastEffect::avoid_lethal(int dam)
631 if (lethality_margin <= 0 || (you.hp - dam) > lethality_margin)
632 return (false);
634 if (recursion_depth == MAX_RECURSE)
636 #if defined(DEBUG_DIAGNOSTICS) || defined(DEBUG_MISCAST)
637 mpr("Couldn't avoid lethal miscast: too much recursion.",
638 MSGCH_ERROR);
639 #endif
640 return (false);
643 if (did_msg)
645 #if defined(DEBUG_DIAGNOSTICS) || defined(DEBUG_MISCAST)
646 mpr("Couldn't avoid lethal miscast: already printed message for this "
647 "miscast.", MSGCH_ERROR);
648 #endif
649 return (false);
652 #if defined(DEBUG_DIAGNOSTICS) || defined(DEBUG_MISCAST)
653 mpr("Avoided lethal miscast.", MSGCH_DIAGNOSTICS);
654 #endif
656 do_miscast();
658 return (true);
661 bool MiscastEffect::_create_monster(monster_type what, int abj_deg,
662 bool alert)
664 const god_type god =
665 (crawl_state.is_god_acting()) ? crawl_state.which_god_acting()
666 : GOD_NO_GOD;
668 if (cause.empty())
669 cause = get_default_cause(true);
670 mgen_data data = mgen_data::hostile_at(what, cause, alert,
671 abj_deg, 0, target->pos(), 0, god);
673 // hostile_at() assumes the monster is hostile to the player,
674 // but should be hostile to the target monster unless the miscast
675 // is a result of either divine wrath or a Zot trap.
676 if (target->atype() == ACT_MONSTER && you.penance[god] == 0
677 && source != ZOT_TRAP_MISCAST)
679 monster* mon_target = target_as_monster();
681 switch (mon_target->temp_attitude())
683 case ATT_FRIENDLY: data.behaviour = BEH_HOSTILE; break;
684 case ATT_HOSTILE: data.behaviour = BEH_FRIENDLY; break;
685 case ATT_GOOD_NEUTRAL:
686 case ATT_NEUTRAL:
687 case ATT_STRICT_NEUTRAL:
688 data.behaviour = BEH_NEUTRAL;
689 break;
692 if (alert)
693 data.foe = mon_target->mindex();
695 // No permanent allies from miscasts.
696 if (data.behaviour == BEH_FRIENDLY && abj_deg == 0)
697 data.abjuration_duration = 6;
700 // If data.abjuration_duration == 0, then data.summon_type will
701 // simply be ignored.
702 if (data.abjuration_duration != 0)
704 if (you.penance[god] > 0)
705 data.summon_type = MON_SUMM_WRATH;
706 else if (source == ZOT_TRAP_MISCAST)
707 data.summon_type = MON_SUMM_ZOT;
708 else
709 data.summon_type = MON_SUMM_MISCAST;
712 return (create_monster(data) != -1);
715 static bool _has_hair(actor* target)
717 // Don't bother for monsters.
718 if (target->atype() == ACT_MONSTER)
719 return (false);
721 return (!form_changed_physiology() && you.species != SP_GHOUL
722 && you.species != SP_KENKU && !player_genus(GENPC_DRACONIAN));
725 static std::string _hair_str(actor* target, bool &plural)
727 ASSERT(target->atype() == ACT_PLAYER);
729 if (you.species == SP_MUMMY)
731 plural = true;
732 return "bandages";
734 else
736 plural = false;
737 return "hair";
741 void MiscastEffect::_conjuration(int severity)
743 int num;
744 switch (severity)
746 case 0: // just a harmless message
747 num = 10 + (_has_hair(target) ? 1 : 0);
748 switch (random2(num))
750 case 0:
751 you_msg = "Sparks fly from your @hands@!";
752 mon_msg_seen = "Sparks fly from @the_monster@'s @hands@!";
753 break;
754 case 1:
755 you_msg = "The air around you crackles with energy!";
756 mon_msg_seen = "The air around @the_monster@ crackles "
757 "with energy!";
758 break;
759 case 2:
760 you_msg = "Wisps of smoke drift from your @hands@.";
761 mon_msg_seen = "Wisps of smoke drift from @the_monster@'s "
762 "@hands@.";
763 break;
764 case 3:
765 you_msg = "You feel a strange surge of energy!";
766 // Monster messages needed.
767 break;
768 case 4:
769 you_msg = "You are momentarily dazzled by a flash of light!";
770 mon_msg_seen = "@The_monster@ emits a flash of light!";
771 break;
772 case 5:
773 you_msg = "Strange energies run through your body.";
774 mon_msg_seen = "@The_monster@ glows " + weird_glowing_colour() +
775 " for a moment.";
776 break;
777 case 6:
778 you_msg = "Your skin tingles.";
779 mon_msg_seen = "@The_monster@ twitches.";
780 break;
781 case 7:
782 you_msg = "Your skin glows momentarily.";
783 mon_msg_seen = "@The_monster@ glows momentarily.";
784 // A small glow isn't going to make it past invisibility.
785 break;
786 case 8:
787 // Set nothing; canned_msg(MSG_NOTHING_HAPPENS) will be taken
788 // care of elsewhere.
789 break;
790 case 9:
791 if (you.can_smell())
792 all_msg = "You smell something strange.";
793 else if (you.species == SP_MUMMY)
794 you_msg = "Your bandages flutter.";
795 break;
796 case 10:
798 // Player only (for now).
799 bool plural;
800 std::string hair = _hair_str(target, plural);
801 you_msg = make_stringf("Your %s stand%s on end.", hair.c_str(),
802 plural ? "" : "s");
805 do_msg();
806 break;
808 case 1: // a bit less harmless stuff
809 switch (random2(2))
811 case 0:
812 you_msg = "Smoke pours from your @hands@!";
813 mon_msg_seen = "Smoke pours from @the_monster@'s @hands@!";
814 mon_msg_unseen = "Smoke appears from out of nowhere!";
816 _big_cloud(CLOUD_GREY_SMOKE, 20, 7 + random2(7));
817 break;
818 case 1:
819 you_msg = "A wave of violent energy washes through your body!";
820 mon_msg_seen = "@The_monster@ lurches violently!";
821 _ouch(6 + random2avg(7, 2));
822 break;
824 break;
826 case 2: // rather less harmless stuff
827 switch (random2(2))
829 case 0:
830 you_msg = "Energy rips through your body!";
831 mon_msg_seen = "@The_monster@ jerks violently!";
832 _ouch(9 + random2avg(17, 2));
833 break;
834 case 1:
835 you_msg = "You are caught in a violent explosion!";
836 mon_msg_seen = "@The_monster@ is caught in a violent explosion!";
837 mon_msg_unseen = "A violent explosion happens from out of thin "
838 "air!";
840 beam.flavour = BEAM_MISSILE;
841 beam.damage = dice_def(3, 12);
842 beam.name = "explosion";
843 beam.colour = random_colour();
845 _explosion();
846 break;
848 break;
850 case 3: // considerably less harmless stuff
851 switch (random2(2))
853 case 0:
854 you_msg = "You are blasted with magical energy!";
855 mon_msg_seen = "@The_monster@ is blasted with magical energy!";
856 // No message for invis monsters?
857 _ouch(12 + random2avg(29, 2));
858 break;
859 case 1:
860 all_msg = "There is a sudden explosion of magical energy!";
862 beam.flavour = BEAM_MISSILE;
863 beam.glyph = dchar_glyph(DCHAR_FIRED_BURST);
864 beam.damage = dice_def(3, 20);
865 beam.name = "explosion";
866 beam.colour = random_colour();
867 beam.ex_size = coinflip() ? 1 : 2;
869 _explosion();
870 break;
875 static void _your_hands_glow(actor* target, std::string& you_msg,
876 std::string& mon_msg_seen, bool pluralise)
878 you_msg = "Your @hands@ ";
879 mon_msg_seen = "@The_monster@'s @hands@ ";
880 // No message for invisible monsters.
882 if (pluralise)
884 you_msg += "glow";
885 mon_msg_seen += "glow";
887 else
889 you_msg += "glows";
890 mon_msg_seen += "glows";
893 you_msg += " momentarily.";
894 mon_msg_seen += " momentarily.";
897 void MiscastEffect::_enchantment(int severity)
899 switch (severity)
901 case 0: // harmless messages only
902 switch (random2(10))
904 case 0:
905 _your_hands_glow(target, you_msg, mon_msg_seen, can_plural_hand);
906 break;
907 case 1:
908 you_msg = "The air around you crackles with energy!";
909 mon_msg_seen = "The air around @the_monster@ crackles with"
910 " energy!";
911 break;
912 case 2:
913 you_msg = "Multicoloured lights dance before your eyes!";
914 mon_msg_seen = "Multicoloured lights dance around @the_monster@!";
915 mon_msg_unseen = "Multicoloured lights dance in the air!";
916 break;
917 case 3:
918 you_msg = "You feel a strange surge of energy!";
919 // Monster messages needed.
920 break;
921 case 4:
922 you_msg = "Waves of light ripple over your body.";
923 mon_msg_seen = "Waves of light ripple over @the_monster@'s body.";
924 break;
925 case 5:
926 you_msg = "Strange energies run through your body.";
927 mon_msg_seen = "@The_monster@ glows " + weird_glowing_colour() +
928 " for a moment.";
929 break;
930 case 6:
931 you_msg = "Your skin tingles.";
932 mon_msg_seen = "@The_monster@ twitches.";
933 break;
934 case 7:
935 you_msg = "Your skin glows momentarily.";
936 mon_msg_seen = "@The_monster@'s body glows momentarily.";
937 break;
938 case 8:
939 // Set nothing; canned_msg(MSG_NOTHING_HAPPENS) will be taken
940 // care of elsewhere.
941 break;
942 case 9:
943 if (neither_end_silenced())
945 all_msg = "You hear something strange.";
946 msg_ch = MSGCH_SOUND;
947 sound_loudness = 2;
948 return;
950 else if (target->atype() == ACT_PLAYER)
951 you_msg = "Your skull vibrates slightly.";
952 break;
954 do_msg();
955 break;
957 case 1: // slightly annoying
958 switch (random2(crawl_state.game_is_arena() ? 1 : 2))
960 case 0:
961 if (target->atype() == ACT_PLAYER && !liquefied(you.pos())
962 && you.ground_level())
964 you.attribute[ATTR_LEV_UNCANCELLABLE] = 1;
965 levitate_player(20);
967 else if (target->atype() == ACT_PLAYER)
969 // Reasoning: miscasts to get levitation to escape the effects of
970 // liquefaction = cheap.
971 random_uselessness();
973 else
975 // There's no levitation enchantment for monsters, and,
976 // anyway, it's not nearly as inconvenient for monsters as
977 // for the player, so backlight them instead.
978 target_as_monster()->add_ench(mon_enchant(ENCH_CORONA, 20, kc));
980 break;
981 case 1:
982 // XXX: Something else for monsters?
983 random_uselessness();
984 break;
986 break;
988 case 2: // much more annoying
989 switch (random2(7))
991 case 0:
992 case 1:
993 case 2:
994 if (target->atype() == ACT_PLAYER)
996 mpr("You sense a malignant aura.");
997 curse_an_item(false);
998 break;
1000 // Intentional fall-through for monsters.
1001 case 3:
1002 case 4:
1003 case 5:
1004 _potion_effect(POT_SLOWING, 10);
1005 break;
1006 case 6:
1007 _potion_effect(POT_BERSERK_RAGE, 10);
1008 break;
1010 break;
1012 case 3: // potentially lethal
1013 // Only use first two cases for monsters.
1014 switch (random2(target->atype() == ACT_PLAYER ? 4 : 2))
1016 case 0:
1017 _potion_effect(POT_PARALYSIS, 10);
1018 break;
1019 case 1:
1020 _potion_effect(POT_CONFUSION, 10);
1021 break;
1022 case 2:
1023 contaminate_player(random2avg(19, 3), spell != SPELL_NO_SPELL);
1024 break;
1025 case 3:
1027 curse_an_item(false);
1028 while (!one_chance_in(3));
1029 mpr("You sense an overwhelmingly malignant aura!");
1030 break;
1032 break;
1036 void MiscastEffect::_translocation(int severity)
1038 switch (severity)
1040 case 0: // harmless messages only
1041 switch (random2(10))
1043 case 0:
1044 you_msg = "Space warps around you.";
1045 mon_msg_seen = "Space warps around @the_monster@.";
1046 break;
1047 case 1:
1048 you_msg = "The air around you crackles with energy!";
1049 mon_msg_seen = "The air around @the_monster@ crackles with "
1050 "energy!";
1051 break;
1052 case 2:
1053 you_msg = "You feel a wrenching sensation.";
1054 mon_msg_seen = "@The_monster@ jerks violently for a moment.";
1055 break;
1056 case 3:
1057 you_msg = "You feel a strange surge of energy!";
1058 // Monster messages needed.
1059 break;
1060 case 4:
1061 you_msg = "You spin around.";
1062 mon_msg_seen = "@The_monster@ spins around.";
1063 break;
1064 case 5:
1065 you_msg = "Strange energies run through your body.";
1066 mon_msg_seen = "@The_monster@ glows " + weird_glowing_colour() +
1067 " for a moment.";
1068 break;
1069 case 6:
1070 you_msg = "Your skin tingles.";
1071 mon_msg_seen = "@The_monster@ twitches.";
1072 break;
1073 case 7:
1074 you_msg = "The world appears momentarily distorted!";
1075 mon_msg_seen = "@The_monster@ appears momentarily distorted!";
1076 break;
1077 case 8:
1078 // Set nothing; canned_msg(MSG_NOTHING_HAPPENS) will be taken
1079 // care of elsewhere.
1080 break;
1081 case 9:
1082 you_msg = "You feel uncomfortable.";
1083 mon_msg_seen = "@The_monster@ scowls.";
1084 break;
1086 do_msg();
1087 break;
1089 case 1: // mostly harmless
1090 switch (random2(6))
1092 case 0:
1093 case 1:
1094 case 2:
1095 you_msg = "You are caught in a localised field of spatial "
1096 "distortion.";
1097 mon_msg_seen = "@The_monster@ is caught in a localised field of "
1098 "spatial distortion.";
1099 mon_msg_unseen = "A piece of empty space twists and distorts.";
1100 _ouch(4 + random2avg(9, 2));
1101 break;
1102 case 3:
1103 case 4:
1104 you_msg = "Space bends around you!";
1105 mon_msg_seen = "Space bends around @the_monster@!";
1106 mon_msg_unseen = "A piece of empty space twists and distorts.";
1107 if (_ouch(4 + random2avg(7, 2)) && target->alive())
1108 target->blink(false);
1109 break;
1110 case 5:
1111 if (_create_monster(MONS_SPATIAL_VORTEX, 3))
1112 all_msg = "Space twists in upon itself!";
1113 do_msg();
1114 break;
1116 break;
1118 case 2: // less harmless
1119 switch (random2(7))
1121 case 0:
1122 case 1:
1123 case 2:
1124 you_msg = "You are caught in a strong localised spatial "
1125 "distortion.";
1126 mon_msg_seen = "@The_monster@ is caught in a strong localised "
1127 "spatial distortion.";
1128 mon_msg_unseen = "A piece of empty space twists and writhes.";
1129 _ouch(9 + random2avg(23, 2));
1130 break;
1131 case 3:
1132 case 4:
1133 you_msg = "Space warps around you!";
1134 mon_msg_seen = "Space warps around @the_monster@!";
1135 mon_msg_unseen = "A piece of empty space twists and writhes.";
1136 if (_ouch(5 + random2avg(9, 2)) && target->alive())
1138 if (one_chance_in(3))
1139 target->teleport(true);
1140 else
1141 target->blink(false);
1142 _potion_effect(POT_CONFUSION, 40);
1144 break;
1145 case 5:
1147 bool success = false;
1149 for (int i = 1 + random2(3); i >= 0; --i)
1151 if (_create_monster(MONS_SPATIAL_VORTEX, 3))
1152 success = true;
1155 if (success)
1156 all_msg = "Space twists in upon itself!";
1157 break;
1159 case 6:
1160 send_abyss();
1161 break;
1163 break;
1165 case 3: // much less harmless
1166 // Don't use the last case for monsters.
1167 switch (random2(target->atype() == ACT_PLAYER ? 4 : 3))
1169 case 0:
1170 you_msg = "You are caught in an extremely strong localised "
1171 "spatial distortion!";
1172 mon_msg_seen = "@The_monster@ is caught in an extremely strong "
1173 "localised spatial distortion!";
1174 mon_msg_unseen = "A rift temporarily opens in the fabric of space!";
1175 _ouch(15 + random2avg(29, 2));
1176 break;
1177 case 1:
1178 you_msg = "Space warps crazily around you!";
1179 mon_msg_seen = "Space warps crazily around @the_monster@!";
1180 mon_msg_unseen = "A rift temporarily opens in the fabric of space!";
1181 if (_ouch(9 + random2avg(17, 2)) && target->alive())
1183 target->teleport(true);
1184 _potion_effect(POT_CONFUSION, 60);
1186 break;
1187 case 2:
1188 send_abyss();
1189 break;
1190 case 3:
1191 contaminate_player(random2avg(19, 3), spell != SPELL_NO_SPELL);
1192 break;
1194 break;
1198 void MiscastEffect::_summoning(int severity)
1200 switch (severity)
1202 case 0: // harmless messages only
1203 switch (random2(10))
1205 case 0:
1206 you_msg = "Shadowy shapes form in the air around you, "
1207 "then vanish.";
1208 mon_msg_seen = "Shadowy shapes form in the air around "
1209 "@the_monster@, then vanish.";
1210 break;
1211 case 1:
1212 if (neither_end_silenced())
1214 all_msg = "You hear strange voices.";
1215 msg_ch = MSGCH_SOUND;
1216 sound_loudness = 2;
1218 else if (target->atype() == ACT_PLAYER)
1219 you_msg = "You feel momentarily dizzy.";
1220 break;
1221 case 2:
1222 you_msg = "Your head hurts.";
1223 // Monster messages needed.
1224 break;
1225 case 3:
1226 you_msg = "You feel a strange surge of energy!";
1227 // Monster messages needed.
1228 break;
1229 case 4:
1230 you_msg = "Your brain hurts!";
1231 // Monster messages needed.
1232 break;
1233 case 5:
1234 you_msg = "Strange energies run through your body.";
1235 mon_msg_seen = "@The_monster@ glows " + weird_glowing_colour() +
1236 " for a moment.";
1237 break;
1238 case 6:
1239 you_msg = "The world appears momentarily distorted.";
1240 mon_msg_seen = "@The_monster@ appears momentarily distorted.";
1241 break;
1242 case 7:
1243 you_msg = "Space warps around you.";
1244 mon_msg_seen = "Space warps around @the_monster@.";
1245 break;
1246 case 8:
1247 // Set nothing; canned_msg(MSG_NOTHING_HAPPENS) will be taken
1248 // care of elsewhere.
1249 break;
1250 case 9:
1251 if (neither_end_silenced())
1253 you_msg = "Distant voices call out to you!";
1254 mon_msg_seen = "Distant voices call out to @the_monster@!";
1255 msg_ch = MSGCH_SOUND;
1256 sound_loudness = 2;
1258 else if (target->atype() == ACT_PLAYER)
1259 you_msg = "You feel watched.";
1260 break;
1262 do_msg();
1263 break;
1265 case 1: // a little bad
1266 switch (random2(6))
1268 case 0: // identical to translocation
1269 case 1:
1270 case 2:
1271 you_msg = "You are caught in a localised spatial "
1272 "distortion.";
1273 mon_msg_seen = "@The_monster@ is caught in a localised spatial "
1274 "distortion.";
1275 mon_msg_unseen = "An empty piece of space distorts and twists.";
1276 _ouch(5 + random2avg(9, 2));
1277 break;
1278 case 3:
1279 if (_create_monster(MONS_SPATIAL_VORTEX, 3))
1280 all_msg = "Space twists in upon itself!";
1281 do_msg();
1282 break;
1283 case 4:
1284 case 5:
1285 if (_create_monster(summon_any_demon(DEMON_LESSER), 5, true))
1286 all_msg = "Something appears in a flash of light!";
1287 do_msg();
1288 break;
1290 break;
1292 case 2: // more bad
1293 switch (random2(6))
1295 case 0:
1297 bool success = false;
1299 for (int i = 1 + random2(3); i >= 0; --i)
1301 if (_create_monster(MONS_SPATIAL_VORTEX, 3))
1302 success = true;
1305 if (success)
1306 all_msg = "Space twists in upon itself!";
1307 do_msg();
1308 break;
1311 case 1:
1312 case 2:
1313 if (_create_monster(summon_any_demon(DEMON_COMMON), 5, true))
1314 all_msg = "Something forms from out of thin air!";
1315 do_msg();
1316 break;
1318 case 3:
1319 case 4:
1320 case 5:
1322 bool success = false;
1324 for (int i = 1 + random2(2); i >= 0; --i)
1326 if (_create_monster(summon_any_demon(DEMON_LESSER), 5, true))
1327 success = true;
1330 if (success && neither_end_silenced())
1332 you_msg = "A chorus of chattering voices calls out to"
1333 " you!";
1334 mon_msg = "A chorus of chattering voices calls out!";
1335 msg_ch = MSGCH_SOUND;
1336 sound_loudness = 3;
1338 do_msg();
1339 break;
1342 break;
1344 case 3: // more bad
1345 switch (random2(4))
1347 case 0:
1348 if (_create_monster(MONS_ABOMINATION_SMALL, 0, true))
1349 all_msg = "Something forms from out of thin air.";
1350 do_msg();
1351 break;
1353 case 1:
1354 if (_create_monster(summon_any_demon(DEMON_GREATER), 0, true))
1355 all_msg = "You sense a hostile presence.";
1356 do_msg();
1357 break;
1359 case 2:
1361 bool success = false;
1363 for (int i = 1 + random2(2); i >= 0; --i)
1365 if (_create_monster(summon_any_demon(DEMON_COMMON), 3, true))
1366 success = true;
1369 if (success)
1371 you_msg = "Something turns its malign attention towards "
1372 "you...";
1373 mon_msg = "You sense a malign presence.";
1375 do_msg();
1376 break;
1379 case 3:
1380 send_abyss();
1381 break;
1383 break;
1387 void MiscastEffect::_divination_you(int severity)
1389 switch (severity)
1391 case 0: // just a harmless message
1392 switch (random2(10))
1394 case 0:
1395 mpr("Weird images run through your mind.");
1396 break;
1397 case 1:
1398 if (!silenced(you.pos()))
1400 mpr("You hear strange voices.", MSGCH_SOUND);
1401 noisy(2, you.pos());
1403 else
1404 mpr("Your nose twitches.");
1405 break;
1406 case 2:
1407 mpr("Your head hurts.");
1408 break;
1409 case 3:
1410 mpr("You feel a strange surge of energy!");
1411 break;
1412 case 4:
1413 mpr("Your brain hurts!");
1414 break;
1415 case 5:
1416 mpr("Strange energies run through your body.");
1417 break;
1418 case 6:
1419 mpr("Everything looks hazy for a moment.");
1420 break;
1421 case 7:
1422 mpr("You seem to have forgotten something, but you can't remember what it was!");
1423 break;
1424 case 8:
1425 canned_msg(MSG_NOTHING_HAPPENS);
1426 break;
1427 case 9:
1428 mpr("You feel uncomfortable.");
1429 break;
1431 break;
1433 case 1: // more annoying things
1434 switch (random2(2))
1436 case 0:
1437 mpr("You feel a little dazed.");
1438 break;
1439 case 1:
1440 potion_effect(POT_CONFUSION, 10);
1441 break;
1443 break;
1445 case 2: // even more annoying things
1446 switch (random2(2))
1448 case 0:
1449 if (you.is_undead)
1450 mpr("You suddenly recall your previous life!");
1451 else if (_lose_stat(STAT_INT, 1 + random2(3)))
1453 mpr("You have damaged your brain!");
1455 else if (!did_msg)
1456 mpr("You have a terrible headache.");
1457 break;
1458 case 1:
1459 mpr("You lose your focus.");
1460 if (you.magic_points > 0)
1462 dec_mp(3 + random2(10));
1463 mpr("You suddenly feel drained of magical energy!", MSGCH_WARN);
1465 break;
1468 potion_effect(POT_CONFUSION, 1); // common to all cases here {dlb}
1469 break;
1471 case 3: // nasty
1472 switch (random2(2))
1474 case 0:
1475 mpr("You lose concentration completely!");
1476 if (you.magic_points > 0)
1478 dec_mp(5 + random2(20));
1479 mpr("You suddenly feel drained of magical energy!", MSGCH_WARN);
1481 break;
1482 case 1:
1483 if (you.is_undead)
1484 mpr("You suddenly recall your previous life.");
1485 else if (_lose_stat(STAT_INT, 3 + random2(3)))
1487 mpr("You have damaged your brain!");
1489 else if (!did_msg)
1490 mpr("You have a terrible headache.");
1491 break;
1494 potion_effect(POT_CONFUSION, 1); // common to all cases here {dlb}
1495 break;
1499 // XXX: Monster divination miscasts.
1500 void MiscastEffect::_divination_mon(int severity)
1502 // Nothing is appropiate for unmoving plants.
1503 if (mons_is_firewood(target_as_monster()))
1504 return;
1506 switch (severity)
1508 case 0: // just a harmless message
1509 mon_msg_seen = "@The_monster@ looks momentarily confused.";
1510 break;
1512 case 1: // more annoying things
1513 switch (random2(2))
1515 case 0:
1516 mon_msg_seen = "@The_monster@ looks slightly disoriented.";
1517 break;
1518 case 1:
1519 mon_msg_seen = "@The_monster@ looks disoriented.";
1520 target->confuse(
1521 act_source,
1522 1 + random2(3 + act_source->get_experience_level()));
1523 break;
1525 break;
1527 case 2: // even more annoying things
1528 mon_msg_seen = "@The_monster@ shudders.";
1529 target->confuse(
1530 act_source,
1531 5 + random2(3 + act_source->get_experience_level()));
1532 break;
1534 case 3: // nasty
1535 mon_msg_seen = "@The_monster@ reels.";
1536 if (one_chance_in(7))
1537 target_as_monster()->forget_random_spell();
1538 target->confuse(
1539 act_source,
1540 8 + random2(3 + act_source->get_experience_level()));
1541 break;
1543 do_msg();
1546 void MiscastEffect::_necromancy(int severity)
1548 if (target->atype() == ACT_PLAYER && you.religion == GOD_KIKUBAAQUDGHA
1549 && !player_under_penance() && you.piety >= piety_breakpoint(1))
1551 const bool death_curse =
1552 (cause.find("death curse") != std::string::npos);
1554 if (spell != SPELL_NO_SPELL)
1556 // An actual necromancy miscast.
1557 if (x_chance_in_y(you.piety, 150))
1559 canned_msg(MSG_NOTHING_HAPPENS);
1560 return;
1563 else if (death_curse)
1565 if (coinflip())
1567 simple_god_message(" averts the curse.");
1568 return;
1570 else
1572 simple_god_message(" partially averts the curse.");
1573 severity = std::max(severity - 1, 0);
1578 switch (severity)
1580 case 0:
1581 switch (random2(10))
1583 case 0:
1584 if (you.can_smell())
1585 all_msg = "You smell decay.";
1586 else if (you.species == SP_MUMMY)
1587 you_msg = "Your bandages flutter.";
1588 break;
1589 case 1:
1590 if (neither_end_silenced())
1592 all_msg = "You hear strange and distant voices.";
1593 msg_ch = MSGCH_SOUND;
1594 sound_loudness = 3;
1596 else if (target->atype() == ACT_PLAYER)
1597 you_msg = "You feel homesick.";
1598 break;
1599 case 2:
1600 you_msg = "Pain shoots through your body.";
1601 // Monster messages needed.
1602 break;
1603 case 3:
1604 you_msg = "Your bones ache.";
1605 // Monster messages needed.
1606 break;
1607 case 4:
1608 you_msg = "The world around you seems to dim momentarily.";
1609 mon_msg_seen = "@The_monster@ seems to dim momentarily.";
1610 break;
1611 case 5:
1612 you_msg = "Strange energies run through your body.";
1613 mon_msg_seen = "@The_monster@ glows " + weird_glowing_colour() +
1614 " for a moment.";
1615 break;
1616 case 6:
1617 you_msg = "You shiver with cold.";
1618 mon_msg_seen = "@The_monster@ shivers with cold.";
1619 break;
1620 case 7:
1621 you_msg = "You sense a malignant aura.";
1622 mon_msg_seen = "@The_monster@ is briefly tinged with black.";
1623 mon_msg_unseen = "The air has a black tinge for a moment.";
1624 // Monster messages needed.
1625 break;
1626 case 8:
1627 // Set nothing; canned_msg(MSG_NOTHING_HAPPENS) will be taken
1628 // care of elsewhere.
1629 break;
1630 case 9:
1631 you_msg = "You feel very uncomfortable.";
1632 mon_msg_seen = "@The_monster@ scowls horribly.";
1633 break;
1635 do_msg();
1636 break;
1638 case 1: // a bit nasty
1639 switch (random2(3))
1641 case 0:
1642 if (target->res_torment())
1644 you_msg = "You feel weird for a moment.";
1645 mon_msg_seen = "@The_monster@ has a weird expression for a "
1646 "moment.";
1648 else
1650 you_msg = "Pain shoots through your body!";
1651 mon_msg_seen = "@The_monster@ convulses with pain!";
1652 _ouch(5 + random2avg(15, 2));
1654 break;
1655 case 1:
1656 you_msg = "You feel horribly lethargic.";
1657 mon_msg_seen = "@The_monster@ looks incredibly listless.";
1658 _potion_effect(POT_SLOWING, 15);
1659 break;
1660 case 2:
1661 if (!target->res_rotting())
1663 if (you.can_smell())
1665 // identical to a harmless message
1666 all_msg = "You smell decay.";
1669 if (target->atype() == ACT_PLAYER)
1670 you.rotting++;
1671 else
1672 target_as_monster()->add_ench(mon_enchant(ENCH_ROT, 1,
1673 kc));
1675 else if (you.species == SP_MUMMY)
1677 // Monster messages needed.
1678 you_msg = "Your bandages flutter.";
1680 break;
1682 if (!did_msg)
1683 do_msg();
1684 break;
1686 case 2: // much nastier
1687 switch (random2(3))
1689 case 0:
1691 bool success = false;
1693 for (int i = random2(3); i >= 0; --i)
1695 if (_create_monster(MONS_SHADOW, 2, true))
1696 success = true;
1699 if (success)
1701 you_msg = "Flickering shadows surround you.";
1702 mon_msg_seen = "Flickering shadows surround @the_monster@.";
1703 mon_msg_unseen = "Shadows flicker in the thin air.";
1705 do_msg();
1706 break;
1709 case 1:
1710 you_msg = "You are engulfed in negative energy!";
1711 mon_msg_seen = "@The_monster@ is engulfed in negative energy!";
1713 if (lethality_margin == 0 || you.experience > 0
1714 || !avoid_lethal(you.hp))
1716 if (one_chance_in(3))
1718 do_msg();
1719 target->drain_exp(act_source);
1720 break;
1724 // If we didn't do anything, just flow through...
1725 if (did_msg)
1726 break;
1728 case 2:
1729 if (target->res_torment())
1731 you_msg = "You feel weird for a moment.";
1732 mon_msg_seen = "@The_monster@ has a weird expression for a "
1733 "moment.";
1735 else
1737 you_msg = "You convulse helplessly as pain tears through "
1738 "your body!";
1739 mon_msg_seen = "@The_monster@ convulses helplessly with pain!";
1740 _ouch(15 + random2avg(23, 2));
1742 if (!did_msg)
1743 do_msg();
1744 break;
1746 break;
1748 case 3: // even nastier
1749 // Don't use last case for monsters.
1750 switch (random2(target->atype() == ACT_PLAYER ? 6 : 5))
1752 case 0:
1753 if (target->holiness() == MH_UNDEAD)
1755 you_msg = "Something just walked over your grave. No, "
1756 "really!";
1757 mon_msg_seen = "@The_monster@ seems frightened for a moment.";
1758 do_msg();
1760 else
1761 torment_monsters(target->pos(), 0, TORMENT_GENERIC);
1762 break;
1764 case 1:
1765 target->rot(act_source, random2avg(7, 2) + 1);
1766 break;
1768 case 2:
1769 if (_create_monster(MONS_SOUL_EATER, 4, true))
1771 you_msg = "Something reaches out for you...";
1772 mon_msg_seen = "Something reaches out for @the_monster@...";
1773 mon_msg_unseen = "Something reaches out from thin air...";
1775 do_msg();
1776 break;
1778 case 3:
1779 if (_create_monster(MONS_REAPER, 4, true))
1781 you_msg = "Death has come for you...";
1782 mon_msg_seen = "Death has come for @the_monster@...";
1783 mon_msg_unseen = "Death appears from thin air...";
1785 do_msg();
1786 break;
1788 case 4:
1789 you_msg = "You are engulfed in negative energy!";
1790 mon_msg_seen = "@The_monster@ is engulfed in negative energy!";
1792 if (lethality_margin == 0 || you.experience > 0
1793 || !avoid_lethal(you.hp))
1795 do_msg();
1796 target->drain_exp(act_source);
1797 break;
1800 // If we didn't do anything, just flow through if it's the player.
1801 if (target->atype() == ACT_MONSTER || did_msg)
1802 break;
1804 case 5:
1805 _lose_stat(STAT_RANDOM, 1 + random2avg(7, 2));
1806 break;
1808 break;
1812 void MiscastEffect::_transmutation(int severity)
1814 int num;
1815 switch (severity)
1817 case 0: // just a harmless message
1818 num = 10 + (_has_hair(target) ? 1 : 0);
1819 switch (random2(num))
1821 case 0:
1822 _your_hands_glow(target, you_msg, mon_msg_seen, can_plural_hand);
1823 break;
1824 case 1:
1825 you_msg = "The air around you crackles with energy!";
1826 mon_msg_seen = "The air around @the_monster@ crackles with "
1827 "energy!";
1828 mon_msg_unseen = "The thin air crackles with energy!";
1829 break;
1830 case 2:
1831 you_msg = "Multicoloured lights dance before your eyes!";
1832 mon_msg_seen = "Multicoloured lights dance around @the_monster@!";
1833 mon_msg_unseen = "Multicoloured lights dance in the air!";
1834 break;
1835 case 3:
1836 you_msg = "You feel a strange surge of energy!";
1837 // Monster messages needed.
1838 break;
1839 case 4:
1840 you_msg = "Waves of light ripple over your body.";
1841 mon_msg_seen = "Waves of light ripple over @the_monster@'s body.";
1842 mon_msg_unseen = "Waves of light ripple in the air.";
1843 break;
1844 case 5:
1845 you_msg = "Strange energies run through your body.";
1846 mon_msg_seen = "@The_monster@ glows " + weird_glowing_colour() +
1847 " for a moment.";
1848 break;
1849 case 6:
1850 you_msg = "Your skin tingles.";
1851 mon_msg_seen = "@The_monster@ twitches.";
1852 break;
1853 case 7:
1854 you_msg = "Your skin glows momentarily.";
1855 mon_msg_seen = "@The_monster@'s body glows momentarily.";
1856 break;
1857 case 8:
1858 // Set nothing; canned_msg(MSG_NOTHING_HAPPENS) will be taken
1859 // care of elsewhere.
1860 break;
1861 case 9:
1862 if (you.can_smell())
1863 all_msg = "You smell something strange.";
1864 else if (you.species == SP_MUMMY)
1865 you_msg = "Your bandages flutter.";
1866 break;
1867 case 10:
1869 // Player only (for now).
1870 bool plural;
1871 std::string hair = _hair_str(target, plural);
1872 you_msg = make_stringf("Your %s momentarily turn%s into snakes!",
1873 hair.c_str(), plural ? "" : "s");
1876 do_msg();
1877 break;
1879 case 1: // slightly annoying
1880 switch (random2(crawl_state.game_is_arena() ? 1 : 2))
1882 case 0:
1883 you_msg = "Your body is twisted painfully.";
1884 mon_msg_seen = "@The_monster@'s body twists unnaturally.";
1885 _ouch(1 + random2avg(11, 2));
1886 break;
1887 case 1:
1888 random_uselessness();
1889 break;
1891 break;
1893 case 2: // much more annoying
1894 // Last case for players only.
1895 switch (random2(target->atype() == ACT_PLAYER ? 4 : 3))
1897 case 0:
1898 you_msg = "Your body is twisted very painfully!";
1899 mon_msg_seen = "@The_monster@'s body twists and writhes.";
1900 _ouch(3 + random2avg(23, 2));
1901 break;
1902 case 1:
1903 _potion_effect(POT_PARALYSIS, 10);
1904 break;
1905 case 2:
1906 _potion_effect(POT_CONFUSION, 10);
1907 break;
1908 case 3:
1909 contaminate_player(random2avg(19, 3), spell != SPELL_NO_SPELL);
1910 break;
1912 break;
1914 case 3: // even nastier
1915 if (target->atype() == ACT_MONSTER)
1916 target->mutate(); // Polymorph the monster, if possible.
1918 switch (random2(3))
1920 case 0:
1921 you_msg = "Your body is flooded with distortional energies!";
1922 mon_msg = "@The_monster@'s body is flooded with distortional "
1923 "energies!";
1924 if (_ouch(3 + random2avg(18, 2)) && target->alive()
1925 && target->atype() == ACT_PLAYER)
1927 contaminate_player(random2avg(35, 3),
1928 spell != SPELL_NO_SPELL, false);
1930 break;
1932 case 1:
1933 // HACK: Avoid lethality before deleting mutation, since
1934 // afterwards a message would already have been given.
1935 if (lethality_margin > 0
1936 && (you.hp - lethality_margin) <= 27
1937 && avoid_lethal(you.hp))
1939 return;
1942 if (target->atype() == ACT_PLAYER)
1944 you_msg = "You feel very strange.";
1945 delete_mutation(RANDOM_MUTATION, true, false, false, false);
1947 _ouch(5 + random2avg(23, 2));
1948 break;
1950 case 2:
1951 // HACK: Avoid lethality before giving mutation, since
1952 // afterwards a message would already have been given.
1953 if (lethality_margin > 0
1954 && (you.hp - lethality_margin) <= 27
1955 && avoid_lethal(you.hp))
1957 return;
1960 if (target->atype() == ACT_PLAYER)
1962 you_msg = "Your body is distorted in a weirdly horrible way!";
1963 // We don't need messages when the mutation fails,
1964 // because we give our own (which is justified anyway as
1965 // you take damage).
1966 give_bad_mutation(false, false);
1967 if (coinflip())
1968 give_bad_mutation(false, false);
1970 _ouch(5 + random2avg(23, 2));
1971 break;
1973 break;
1977 void MiscastEffect::_fire(int severity)
1979 switch (severity)
1981 case 0: // just a harmless message
1982 switch (random2(10))
1984 case 0:
1985 you_msg = "Sparks fly from your @hands@!";
1986 mon_msg_seen = "Sparks fly from @the_monster@'s @hands@!";
1987 break;
1988 case 1:
1989 you_msg = "The air around you burns with energy!";
1990 mon_msg_seen = "The air around @the_monster@ burns with energy!";
1991 break;
1992 case 2:
1993 you_msg = "Wisps of smoke drift from your @hands@.";
1994 mon_msg_seen = "Wisps of smoke drift from @the_monster@'s @hands@.";
1995 break;
1996 case 3:
1997 you_msg = "You feel a strange surge of energy!";
1998 // Monster messages needed.
1999 break;
2000 case 4:
2001 if (you.can_smell())
2002 all_msg = "You smell smoke.";
2003 else if (you.species == SP_MUMMY)
2004 you_msg = "Your bandages flutter.";
2005 break;
2006 case 5:
2007 you_msg = "Heat runs through your body.";
2008 // Monster messages needed.
2009 break;
2010 case 6:
2011 you_msg = "You feel uncomfortably hot.";
2012 // Monster messages needed.
2013 break;
2014 case 7:
2015 you_msg = "Lukewarm flames ripple over your body.";
2016 mon_msg_seen = "Dim flames ripple over @the_monster@'s body.";
2017 break;
2018 case 8:
2019 // Set nothing; canned_msg(MSG_NOTHING_HAPPENS) will be taken
2020 // care of elsewhere.
2021 break;
2022 case 9:
2023 if (neither_end_silenced())
2025 all_msg = "You hear a sizzling sound.";
2026 msg_ch = MSGCH_SOUND;
2027 sound_loudness = 2;
2029 else if (target->atype() == ACT_PLAYER)
2030 you_msg = "You feel like you have heartburn.";
2031 break;
2033 do_msg();
2034 break;
2036 case 1: // a bit less harmless stuff
2037 switch (random2(2))
2039 case 0:
2040 you_msg = "Smoke pours from your @hands@!";
2041 mon_msg_seen = "Smoke pours from @the_monster@'s @hands@!";
2042 mon_msg_unseen = "Smoke appears out of nowhere!";
2044 _big_cloud(random_smoke_type(), 20, 7 + random2(7));
2045 break;
2047 case 1:
2048 you_msg = "Flames sear your flesh.";
2049 mon_msg_seen = "Flames sear @the_monster@.";
2050 if (target->res_fire() < 0)
2052 if (!_ouch(2 + random2avg(13, 2)))
2053 return;
2055 else
2056 do_msg();
2057 if (target->alive())
2058 target->expose_to_element(BEAM_FIRE, 3);
2059 break;
2061 break;
2063 case 2: // rather less harmless stuff
2064 switch (random2(2))
2066 case 0:
2067 you_msg = "You are blasted with fire.";
2068 mon_msg_seen = "@The_monster@ is blasted with fire.";
2069 mon_msg_unseen = "A flame briefly burns in thin air.";
2070 if (_ouch(5 + random2avg(29, 2), BEAM_FIRE) && target->alive())
2071 target->expose_to_element(BEAM_FIRE, 5);
2072 break;
2074 case 1:
2075 you_msg = "You are caught in a fiery explosion!";
2076 mon_msg_seen = "@The_monster@ is caught in a fiery explosion!";
2077 mon_msg_unseen = "Fire explodes from out of thin air!";
2079 beam.flavour = BEAM_FIRE;
2080 beam.glyph = dchar_glyph(DCHAR_FIRED_BURST);
2081 beam.damage = dice_def(3, 14);
2082 beam.name = "explosion";
2083 beam.colour = RED;
2085 _explosion();
2086 break;
2088 break;
2090 case 3: // considerably less harmless stuff
2091 switch (random2(3))
2093 case 0:
2094 you_msg = "You are blasted with searing flames!";
2095 mon_msg_seen = "@The_monster@ is blasted with searing flames!";
2096 mon_msg_unseen = "A large flame burns hotly for a moment in the "
2097 "thin air.";
2098 if (_ouch(9 + random2avg(33, 2), BEAM_FIRE) && target->alive())
2099 target->expose_to_element(BEAM_FIRE, 10);
2100 break;
2101 case 1:
2102 all_msg = "There is a sudden and violent explosion of flames!";
2104 beam.flavour = BEAM_FIRE;
2105 beam.glyph = dchar_glyph(DCHAR_FIRED_BURST);
2106 beam.damage = dice_def(3, 20);
2107 beam.name = "fireball";
2108 beam.colour = RED;
2109 beam.ex_size = coinflip() ? 1 : 2;
2111 _explosion();
2112 break;
2114 case 2:
2116 you_msg = "You are covered in liquid flames!";
2117 mon_msg_seen = "@The_monster@ is covered in liquid flames!";
2118 do_msg();
2120 if (target->atype() == ACT_PLAYER)
2121 napalm_player(random2avg(7,3) + 1);
2122 else
2124 monster* mon_target = target_as_monster();
2125 mon_target->add_ench(mon_enchant(ENCH_STICKY_FLAME,
2126 std::min(4, 1 + random2(mon_target->hit_dice) / 2), kc));
2128 break;
2131 break;
2135 void MiscastEffect::_ice(int severity)
2137 const dungeon_feature_type feat = grd(target->pos());
2139 const bool frostable_feat =
2140 (feat == DNGN_FLOOR || feat_altar_god(feat) != GOD_NO_GOD
2141 || feat_is_staircase(feat) || feat_is_water(feat));
2143 const std::string feat_name = (feat == DNGN_FLOOR ? "the " : "") +
2144 feature_description(target->pos(), false, DESC_NOCAP_THE);
2146 int num;
2147 switch (severity)
2149 case 0: // just a harmless message
2150 num = 10 + (frostable_feat ? 1 : 0);
2151 switch (random2(num))
2153 case 0:
2154 you_msg = "You shiver with cold.";
2155 mon_msg_seen = "@The_monster@ shivers with cold.";
2156 break;
2157 case 1:
2158 you_msg = "A chill runs through your body.";
2159 // Monster messages needed.
2160 break;
2161 case 2:
2162 you_msg = "Wisps of condensation drift from your @hands@.";
2163 mon_msg_seen = "Wisps of condensation drift from @the_monster@'s "
2164 "@hands@.";
2165 mon_msg_unseen = "Wisps of condensation drift in the air.";
2166 break;
2167 case 3:
2168 you_msg = "You feel a strange surge of energy!";
2169 // Monster messages needed.
2170 break;
2171 case 4:
2172 you_msg = "Your @hands@ feel@hand_conj@ numb with cold.";
2173 // Monster messages needed.
2174 break;
2175 case 5:
2176 you_msg = "A chill runs through your body.";
2177 // Monster messages needed.
2178 break;
2179 case 6:
2180 you_msg = "You feel uncomfortably cold.";
2181 // Monster messages needed.
2182 break;
2183 case 7:
2184 you_msg = "Frost covers your body.";
2185 mon_msg_seen = "Frost covers @the_monster@'s body.";
2186 break;
2187 case 8:
2188 // Set nothing; canned_msg(MSG_NOTHING_HAPPENS) will be taken
2189 // care of elsewhere.
2190 break;
2191 case 9:
2192 if (neither_end_silenced())
2194 all_msg = "You hear a crackling sound.";
2195 msg_ch = MSGCH_SOUND;
2196 sound_loudness = 2;
2198 else if (target->atype() == ACT_PLAYER)
2199 you_msg = "A snowflake lands on your nose.";
2200 break;
2201 case 10:
2202 if (feat_is_water(feat))
2203 all_msg = "A thin layer of ice forms on " + feat_name;
2204 else
2205 all_msg = "Frost spreads across " + feat_name;
2206 break;
2208 do_msg();
2209 break;
2211 case 1: // a bit less harmless stuff
2212 switch (random2(2))
2214 case 0:
2215 mpr("You feel extremely cold.");
2216 // Monster messages needed.
2217 break;
2218 case 1:
2219 you_msg = "You are covered in a thin layer of ice.";
2220 mon_msg_seen = "@The_monster@ is covered in a thin layer of ice.";
2221 if (target->res_cold() < 0)
2223 if (!_ouch(4 + random2avg(5, 2)))
2224 return;
2226 else
2227 do_msg();
2228 if (target->alive())
2229 target->expose_to_element(BEAM_COLD, 2);
2230 break;
2232 break;
2234 case 2: // rather less harmless stuff
2235 switch (random2(2))
2237 case 0:
2238 you_msg = "Heat is drained from your body.";
2239 // Monster messages needed.
2240 if (_ouch(5 + random2(6) + random2(7), BEAM_COLD) && target->alive())
2241 target->expose_to_element(BEAM_COLD, 4);
2242 break;
2244 case 1:
2245 you_msg = "You are caught in an explosion of ice and frost!";
2246 mon_msg_seen = "@The_monster@ is caught in an explosion of "
2247 "ice and frost!";
2248 mon_msg_unseen = "Ice and frost explode from out of thin air!";
2250 beam.flavour = BEAM_COLD;
2251 beam.glyph = dchar_glyph(DCHAR_FIRED_BURST);
2252 beam.damage = dice_def(3, 11);
2253 beam.name = "explosion";
2254 beam.colour = WHITE;
2256 _explosion();
2257 break;
2259 break;
2261 case 3: // less harmless stuff
2262 switch (random2(2))
2264 case 0:
2265 you_msg = "You are blasted with ice!";
2266 mon_msg_seen = "@The_monster@ is blasted with ice!";
2267 if (_ouch(9 + random2avg(23, 2), BEAM_ICE) && target->alive())
2268 target->expose_to_element(BEAM_COLD, 9);
2269 break;
2270 case 1:
2271 you_msg = "Freezing gasses pour from your @hands@!";
2272 mon_msg_seen = "Freezing gasses pour from @the_monster@'s "
2273 "@hands@!";
2275 _big_cloud(CLOUD_COLD, 20, 8 + random2(4));
2276 break;
2278 break;
2282 static bool _on_floor(actor* target)
2284 return (target->ground_level() && grd(target->pos()) == DNGN_FLOOR);
2287 void MiscastEffect::_earth(int severity)
2289 int num;
2290 switch (severity)
2292 case 0: // just a harmless message
2293 case 1:
2294 num = 11 + (_on_floor(target) ? 2 : 0);
2295 switch (random2(num))
2297 case 0:
2298 you_msg = "You feel earthy.";
2299 // Monster messages needed.
2300 break;
2301 case 1:
2302 you_msg = "You are showered with tiny particles of grit.";
2303 mon_msg_seen = "@The_monster@ is showered with tiny particles "
2304 "of grit.";
2305 mon_msg_unseen = "Tiny particles of grit hang in the air for a "
2306 "moment.";
2307 break;
2308 case 2:
2309 you_msg = "Sand pours from your @hands@.";
2310 mon_msg_seen = "Sand pours from @the_monster@'s @hands@.";
2311 mon_msg_unseen = "Sand pours from out of thin air.";
2312 break;
2313 case 3:
2314 you_msg = "You feel a surge of energy from the ground.";
2315 // Monster messages needed.
2316 break;
2317 case 4:
2318 if (neither_end_silenced())
2320 all_msg = "You hear a distant rumble.";
2321 msg_ch = MSGCH_SOUND;
2322 sound_loudness = 2;
2324 else if (target->atype() == ACT_PLAYER)
2325 you_msg = "You sympathise with the stones.";
2326 break;
2327 case 5:
2328 you_msg = "You feel gritty.";
2329 // Monster messages needed.
2330 break;
2331 case 6:
2332 you_msg = "You feel momentarily lethargic.";
2333 mon_msg_seen = "@The_monster@ looks momentarily listless.";
2334 break;
2335 case 7:
2336 you_msg = "Motes of dust swirl before your eyes.";
2337 mon_msg_seen = "Motes of dust swirl around @the_monster@.";
2338 mon_msg_unseen = "Motes of dust swirl around in the air.";
2339 break;
2340 case 8:
2341 // Set nothing; canned_msg(MSG_NOTHING_HAPPENS) will be taken
2342 // care of elsewhere.
2343 break;
2344 case 9:
2346 bool pluralised = true;
2347 std::string feet = you.foot_name(true, &pluralised);
2348 std::ostringstream str;
2350 str << "Your " << feet << (pluralised ? " feel" : " feels")
2351 << " warm.";
2353 you_msg = str.str();
2354 // Monster messages needed.
2355 break;
2357 case 10:
2358 if (target->cannot_move())
2360 you_msg = "You briefly vibrate.";
2361 mon_msg_seen = "@The_monster@ briefly vibrates.";
2363 else
2365 you_msg = "You momentarily stiffen.";
2366 mon_msg_seen = "@The_monster@ momentarily stiffens.";
2368 break;
2369 case 11:
2370 all_msg = "The floor vibrates.";
2371 break;
2372 case 12:
2373 all_msg = "The floor shifts beneath you alarmingly!";
2374 break;
2376 do_msg();
2377 break;
2379 case 2: // slightly less harmless stuff
2380 switch (random2(1))
2382 case 0:
2383 switch (random2(3))
2385 case 0:
2386 you_msg = "You are hit by flying rocks!";
2387 mon_msg_seen = "@The_monster@ is hit by flying rocks!";
2388 mon_msg_unseen = "Flying rocks appear out of thin air!";
2389 break;
2390 case 1:
2391 you_msg = "You are blasted with sand!";
2392 mon_msg_seen = "@The_monster@ is blasted with sand!";
2393 mon_msg_unseen = "A miniature sandstorm briefly appears!";
2394 break;
2395 case 2:
2396 you_msg = "Rocks fall onto you out of nowhere!";
2397 mon_msg_seen = "Rocks fall onto @the_monster@ out of "
2398 "nowhere!";
2399 mon_msg_unseen = "Rocks fall out of nowhere!";
2400 break;
2402 _ouch(random2avg(13, 2) + 10 - random2(1 + target->armour_class()));
2403 break;
2405 break;
2407 case 3: // less harmless stuff
2408 switch (random2(1))
2410 case 0:
2411 you_msg = "You are caught in an explosion of flying "
2412 "shrapnel!";
2413 mon_msg_seen = "@The_monster@ is caught in an explosion of "
2414 "flying shrapnel!";
2415 mon_msg_unseen = "Flying shrapnel explodes from thin air!";
2417 beam.flavour = BEAM_FRAG;
2418 beam.glyph = dchar_glyph(DCHAR_FIRED_BURST);
2419 beam.damage = dice_def(3, 15);
2420 beam.name = "explosion";
2421 beam.colour = CYAN;
2423 if (one_chance_in(5))
2424 beam.colour = BROWN;
2425 if (one_chance_in(5))
2426 beam.colour = LIGHTCYAN;
2428 _explosion();
2429 break;
2431 break;
2435 void MiscastEffect::_air(int severity)
2437 int num;
2438 switch (severity)
2440 case 0: // just a harmless message
2441 num = 9;
2442 if (target == &you)
2443 num += 3 + _has_hair(target);
2444 switch (random2(num))
2446 case 0:
2447 you_msg = "You feel momentarily weightless.";
2448 mon_msg_seen = "@The_monster@ bobs in the air for a moment.";
2449 break;
2450 case 1:
2451 you_msg = "Wisps of vapour drift from your @hands@.";
2452 mon_msg_seen = "Wisps of vapour drift from @the_monster@'s "
2453 "@hands@.";
2454 break;
2455 case 2:
2457 bool pluralised = true;
2458 if (!hand_str.empty())
2459 pluralised = can_plural_hand;
2460 else
2461 target->hand_name(true, &pluralised);
2463 if (pluralised)
2465 you_msg = "Sparks of electricity dance between your "
2466 "@hands@.";
2467 mon_msg_seen = "Sparks of electricity dance between "
2468 "@the_monster@'s @hands@.";
2470 else
2472 you_msg = "Sparks of electricity dance over your "
2473 "@hand@.";
2474 mon_msg_seen = "Sparks of electricity dance over "
2475 "@the_monster@'s @hand@.";
2477 break;
2479 case 3:
2480 you_msg = "You are blasted with air!";
2481 mon_msg_seen = "@The_monster@ is blasted with air!";
2482 break;
2483 case 4:
2484 if (neither_end_silenced())
2486 all_msg = "You hear a whooshing sound.";
2487 msg_ch = MSGCH_SOUND;
2488 sound_loudness = 2;
2490 else if (you.can_smell())
2491 all_msg = "You smell ozone.";
2492 else if (you.species == SP_MUMMY)
2493 you_msg = "Your bandages flutter.";
2494 break;
2495 case 5:
2496 // Set nothing; canned_msg(MSG_NOTHING_HAPPENS) will be taken
2497 // care of elsewhere.
2498 break;
2499 case 6:
2500 if (neither_end_silenced())
2502 all_msg = "You hear a crackling sound.";
2503 msg_ch = MSGCH_SOUND;
2504 sound_loudness = 2;
2506 else if (you.can_smell())
2507 all_msg = "You smell something musty.";
2508 else if (you.species == SP_MUMMY)
2509 you_msg = "Your bandages flutter.";
2510 break;
2511 case 7:
2512 you_msg = "There is a short, sharp shower of sparks.";
2513 mon_msg_seen = "@The_monster@ is briefly showered in sparks.";
2514 break;
2515 case 8:
2516 if (silenced(you.pos()))
2518 you_msg = "The wind whips around you!";
2519 mon_msg_seen = "The wind whips around @the_monster@!";
2520 mon_msg_unseen = "The wind whips!";
2522 else
2524 you_msg = "The wind howls around you!";
2525 mon_msg_seen = "The wind howls around @the_monster@!";
2526 mon_msg_unseen = "The wind howls!";
2528 break;
2529 case 9:
2530 you_msg = "Ouch! You gave yourself an electric shock.";
2531 // Monster messages needed.
2532 break;
2533 case 10:
2534 you_msg = "You feel a strange surge of energy!";
2535 // Monster messages needed.
2536 break;
2537 case 11:
2538 you_msg = "You feel electric!";
2539 // Monster messages needed.
2540 break;
2541 case 12:
2543 // Player only (for now).
2544 bool plural;
2545 std::string hair = _hair_str(target, plural);
2546 you_msg = make_stringf("Your %s stand%s on end.", hair.c_str(),
2547 plural ? "" : "s");
2548 break;
2551 do_msg();
2552 break;
2554 case 1: // rather less harmless stuff
2555 switch (random2(3))
2557 case 0:
2558 you_msg = "Electricity courses through your body.";
2559 mon_msg_seen = "@The_monster@ is jolted!";
2560 mon_msg_unseen = "Something invisible sparkles with electricity.";
2561 _ouch(4 + random2avg(9, 2), BEAM_ELECTRICITY);
2562 break;
2563 case 1:
2564 you_msg = "Noxious gasses pour from your @hands@!";
2565 mon_msg_seen = "Noxious gasses pour from @the_monster@'s "
2566 "@hands@!";
2567 mon_msg_unseen = "Noxious gasses appear from out of thin air!";
2569 _big_cloud(CLOUD_STINK, 20, 9 + random2(4));
2570 break;
2571 case 2:
2572 you_msg = "You are under the weather.";
2573 mon_msg_seen = "@The_monster@ looks under the weather.";
2574 mon_msg_unseen = "Inclement weather forms around a spot in thin air.";
2576 _big_cloud(CLOUD_RAIN, 20, 20 + random2(20));
2577 break;
2579 break;
2581 case 2: // much less harmless stuff
2582 switch (random2(2))
2584 case 0:
2585 you_msg = "You are caught in an explosion of electrical "
2586 "discharges!";
2587 mon_msg_seen = "@The_monster@ is caught in an explosion of "
2588 "electrical discharges!";
2589 mon_msg_unseen = "Electrical discharges explode from out of "
2590 "thin air!";
2592 beam.flavour = BEAM_ELECTRICITY;
2593 beam.glyph = dchar_glyph(DCHAR_FIRED_BURST);
2594 beam.damage = dice_def(3, 8);
2595 beam.name = "explosion";
2596 beam.colour = LIGHTBLUE;
2597 beam.ex_size = one_chance_in(4) ? 1 : 2;
2599 _explosion();
2600 break;
2601 case 1:
2602 you_msg = "Venomous gasses pour from your @hands@!";
2603 mon_msg_seen = "Venomous gasses pour from @the_monster@'s "
2604 "@hands@!";
2605 mon_msg_unseen = "Venomous gasses pour forth from the thin air!";
2607 _big_cloud(CLOUD_POISON, 20, 8 + random2(5));
2608 break;
2610 break;
2612 case 3: // even less harmless stuff
2613 switch (random2(3))
2615 case 0:
2616 if (_create_monster(MONS_BALL_LIGHTNING, 3))
2617 all_msg = "A ball of electricity appears!";
2618 do_msg();
2619 break;
2620 case 1:
2621 you_msg = "The air twists around and strikes you!";
2622 mon_msg_seen = "@The_monster@ is struck by twisting air!";
2623 mon_msg_unseen = "The air madly twists around a spot.";
2624 _ouch(12 + random2avg(29, 2), BEAM_AIR);
2625 break;
2626 case 2:
2627 if (_create_monster(MONS_TWISTER, 1))
2628 all_msg = "A huge vortex of air appears!";
2629 do_msg();
2630 break;
2632 break;
2636 void MiscastEffect::_poison(int severity)
2638 switch (severity)
2640 case 0: // just a harmless message
2641 switch (random2(10))
2643 case 0:
2644 you_msg = "You feel mildly nauseous.";
2645 mon_msg_seen = "@The_monster@ briefly looks nauseous.";
2646 break;
2647 case 1:
2648 you_msg = "You feel slightly ill.";
2649 mon_msg_seen = "@The_monster@ briefly looks sick.";
2650 break;
2651 case 2:
2652 you_msg = "Wisps of poison gas drift from your @hands@.";
2653 mon_msg_seen = "Wisps of poison gas drift from @the_monster@'s "
2654 "@hands@.";
2655 break;
2656 case 3:
2657 you_msg = "You feel a strange surge of energy!";
2658 // Monster messages needed.
2659 break;
2660 case 4:
2661 you_msg = "You feel faint for a moment.";
2662 mon_msg_seen = "@The_monster@ looks faint for a moment.";
2663 break;
2664 case 5:
2665 you_msg = "You feel sick.";
2666 mon_msg_seen = "@The_monster@ looks sick.";
2667 break;
2668 case 6:
2669 you_msg = "You feel odd.";
2670 mon_msg_seen = "@The_monster@ has an odd expression for a "
2671 "moment.";
2672 break;
2673 case 7:
2674 you_msg = "You feel weak for a moment.";
2675 mon_msg_seen = "@The_monster@ looks weak for a moment.";
2676 break;
2677 case 8:
2678 // Set nothing; canned_msg(MSG_NOTHING_HAPPENS) will be taken
2679 // care of elsewhere.
2680 break;
2681 case 9:
2682 you_msg = "Your vision is briefly tinged with green.";
2683 mon_msg_seen = "@The_monster@ is briefly tinged with green.";
2684 mon_msg_unseen = "The air has a green tinge for a moment.";
2685 break;
2687 do_msg();
2688 break;
2690 case 1: // a bit less harmless stuff
2691 switch (random2(2))
2693 case 0:
2694 if (target->res_poison() <= 0)
2696 you_msg = "You feel sick.";
2697 mon_msg_seen = "@The_monster@ looks sick.";
2698 _do_poison(2 + random2(3));
2700 do_msg();
2701 break;
2703 case 1:
2704 you_msg = "Noxious gasses pour from your @hands@!";
2705 mon_msg_seen = "Noxious gasses pour from @the_monster@'s "
2706 "@hands@!";
2707 mon_msg_unseen = "Noxious gasses pour forth from the thin air!";
2708 place_cloud(CLOUD_STINK, target->pos(), 2 + random2(4), guilty);
2709 break;
2711 break;
2713 case 2: // rather less harmless stuff
2714 // Don't use last case for monsters.
2715 switch (random2(target->atype() == ACT_PLAYER ? 3 : 2))
2717 case 0:
2718 if (target->res_poison() <= 0)
2720 you_msg = "You feel very sick.";
2721 mon_msg_seen = "@The_monster@ looks very sick.";
2722 _do_poison(3 + random2avg(9, 2));
2724 do_msg();
2725 break;
2727 case 1:
2728 you_msg = "Noxious gasses pour from your @hands@!";
2729 mon_msg_seen = "Noxious gasses pour from @the_monster@'s "
2730 "@hands@!";
2731 mon_msg_unseen = "Noxious gasses pour forth from the thin air!";
2733 _big_cloud(CLOUD_STINK, 20, 8 + random2(5));
2734 break;
2736 case 2:
2737 if (player_res_poison())
2738 canned_msg(MSG_NOTHING_HAPPENS);
2739 else
2740 _lose_stat(STAT_RANDOM, 1);
2741 break;
2743 break;
2745 case 3: // less harmless stuff
2746 // Don't use last case for monsters.
2747 switch (random2(target->atype() == ACT_PLAYER ? 3 : 2))
2749 case 0:
2750 if (target->res_poison() <= 0)
2752 you_msg = "You feel incredibly sick.";
2753 mon_msg_seen = "@The_monster@ looks incredibly sick.";
2754 _do_poison(10 + random2avg(19, 2));
2756 do_msg();
2757 break;
2758 case 1:
2759 you_msg = "Venomous gasses pour from your @hands@!";
2760 mon_msg_seen = "Venomous gasses pour from @the_monster@'s "
2761 "@hands@!";
2762 mon_msg_unseen = "Venomous gasses pour forth from the thin air!";
2764 _big_cloud(CLOUD_POISON, 20, 7 + random2(7));
2765 break;
2766 case 2:
2767 if (player_res_poison())
2768 canned_msg(MSG_NOTHING_HAPPENS);
2769 else
2770 _lose_stat(STAT_RANDOM, 1 + random2avg(5, 2));
2771 break;
2773 break;
2777 void MiscastEffect::_do_poison(int amount)
2779 if (target->atype() == ACT_PLAYER)
2780 poison_player(amount, cause, "residual poison");
2781 else
2782 target->poison(act_source, amount);