3 * Summary: Spell miscast class.
4 * Written by: Matthew Cline
9 #include "spl-miscast.h"
24 #include "mon-place.h"
25 #include "mgen_data.h"
26 #include "mon-stuff.h"
30 #include "player-stats.h"
32 #include "spl-clouds.h"
37 #include "transform.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
,
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
));
71 MiscastEffect::MiscastEffect(actor
* _target
, int _source
,
72 spschool_flag_type _school
, int _level
,
74 nothing_happens_when_type _nothing_happens
,
75 int _lethality_margin
, std::string _hand_str
,
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);
92 MiscastEffect::MiscastEffect(actor
* _target
, int _source
,
93 spschool_flag_type _school
, int _pow
, int _fail
,
95 nothing_happens_when_type _nothing_happens
,
96 int _lethality_margin
, std::string _hand_str
,
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
);
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
);
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
);
142 kill_source
= source
;
143 if (source
== WIELD_MISCAST
|| source
== MELEE_MISCAST
)
145 if (target
->atype() == ACT_MONSTER
)
146 kill_source
= target
->mindex();
148 kill_source
= NON_MONSTER
;
151 if (kill_source
== NON_MONSTER
)
154 kt
= KILL_YOU_MISSILE
;
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())
171 else if (!death_curse
&& mon_source
->confused_by_you()
172 && !mon_source
->friendly())
177 kt
= KILL_MON_MISSILE
;
179 if (mon_source
->friendly())
184 source_known
= you
.can_see(mon_source
);
186 if (target_known
&& death_curse
)
191 ASSERT(source
== ZOT_TRAP_MISCAST
192 || source
== MISC_MISCAST
193 || (source
< 0 && -source
< NUM_GODS
));
200 if (source
== ZOT_TRAP_MISCAST
)
202 source_known
= target_known
;
204 if (target
->atype() == ACT_MONSTER
205 && target_as_monster()->confused_by_you())
210 else if (source
== MISC_MISCAST
)
211 source_known
= true, guilty
= &you
;
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");
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
);
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.
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
;
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
);
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
)
273 + " miscasting " + spell_title(spell
));
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)
293 unwind_var
<int> unwind_depth(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());
305 spschool_flag_type sp_type
;
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
);
321 if (sp_type
== SPTYP_RANDOM
)
323 int exp
= (random2(SPTYP_LAST_EXPONENT
));
324 sp_type
= (spschool_flag_type
) (1 << exp
);
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
),
341 if (random2(40) > severity
&& random2(40) > severity
)
343 if (target
->atype() == ACT_PLAYER
)
344 canned_msg(MSG_NOTHING_HAPPENS
);
349 severity
= random2(severity
);
352 else if (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
);
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
;
380 case SPTYP_CONJURATION
: _conjuration(severity
); break;
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
395 if (target
->atype() == ACT_PLAYER
)
396 _divination_you(severity
);
398 _divination_mon(severity
);
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
)
413 if (target
->atype() == ACT_MONSTER
&& !mons_near(target_as_monster()))
420 if (!all_msg
.empty())
422 else if (target
->atype() == ACT_PLAYER
)
424 else if (!mon_msg
.empty())
427 // Monster might be unseen with hands that can't be seen.
428 ASSERT(msg
.find("@hand") == std::string::npos
);
432 if (you
.can_see(target
))
436 msg
= mon_msg_unseen
;
437 // Can't see the hands of invisible monsters.
438 ASSERT(msg
.find("@hand") == std::string::npos
);
444 if (!suppress_nothing_happens
445 && (nothing_happens_when
== NH_ALWAYS
446 || (nothing_happens_when
== NH_DEFAULT
&& source_known
449 canned_msg(MSG_NOTHING_HAPPENS
);
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));
464 plural
= can_plural_hand
;
465 msg
= replace_all(msg
, "@hand@", hand_str
);
467 msg
= replace_all(msg
, "@hands@", pluralise(hand_str
));
469 msg
= replace_all(msg
, "@hands@", hand_str
);
473 msg
= replace_all(msg
, "@hand_conj@", "");
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()
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();
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
);
517 dam
= check_your_resists(dam
, flavour
, cause
);
519 if (avoid_lethal(dam
))
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
;
537 method
= KILLED_BY_DIVINE_WRATH
;
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
);
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
))
566 bool MiscastEffect::_big_cloud(cloud_type cl_type
, int cloud_pow
, int size
,
569 if (avoid_lethal(2 * max_cloud_damage(cl_type
, cloud_pow
)))
573 big_cloud(cl_type
, guilty
, target
->pos(), cloud_pow
, size
, spread_rate
);
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);
593 case POT_BERSERK_RAGE
:
594 if (target
->can_go_berserk())
596 target
->go_berserk(false);
599 // Intentional fallthrough if that didn't work.
601 target
->slow_down(act_source
, pot_pow
);
604 target
->paralyse(act_source
, pot_pow
);
607 target
->confuse(act_source
, pot_pow
);
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.";
626 target
->banish(cause
);
629 bool MiscastEffect::avoid_lethal(int dam
)
631 if (lethality_margin
<= 0 || (you
.hp
- dam
) > lethality_margin
)
634 if (recursion_depth
== MAX_RECURSE
)
636 #if defined(DEBUG_DIAGNOSTICS) || defined(DEBUG_MISCAST)
637 mpr("Couldn't avoid lethal miscast: too much recursion.",
645 #if defined(DEBUG_DIAGNOSTICS) || defined(DEBUG_MISCAST)
646 mpr("Couldn't avoid lethal miscast: already printed message for this "
647 "miscast.", MSGCH_ERROR
);
652 #if defined(DEBUG_DIAGNOSTICS) || defined(DEBUG_MISCAST)
653 mpr("Avoided lethal miscast.", MSGCH_DIAGNOSTICS
);
661 bool MiscastEffect::_create_monster(monster_type what
, int abj_deg
,
665 (crawl_state
.is_god_acting()) ? crawl_state
.which_god_acting()
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
:
687 case ATT_STRICT_NEUTRAL
:
688 data
.behaviour
= BEH_NEUTRAL
;
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
;
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
)
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
)
741 void MiscastEffect::_conjuration(int severity
)
746 case 0: // just a harmless message
747 num
= 10 + (_has_hair(target
) ? 1 : 0);
748 switch (random2(num
))
751 you_msg
= "Sparks fly from your @hands@!";
752 mon_msg_seen
= "Sparks fly from @the_monster@'s @hands@!";
755 you_msg
= "The air around you crackles with energy!";
756 mon_msg_seen
= "The air around @the_monster@ crackles "
760 you_msg
= "Wisps of smoke drift from your @hands@.";
761 mon_msg_seen
= "Wisps of smoke drift from @the_monster@'s "
765 you_msg
= "You feel a strange surge of energy!";
766 // Monster messages needed.
769 you_msg
= "You are momentarily dazzled by a flash of light!";
770 mon_msg_seen
= "@The_monster@ emits a flash of light!";
773 you_msg
= "Strange energies run through your body.";
774 mon_msg_seen
= "@The_monster@ glows " + weird_glowing_colour() +
778 you_msg
= "Your skin tingles.";
779 mon_msg_seen
= "@The_monster@ twitches.";
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.
787 // Set nothing; canned_msg(MSG_NOTHING_HAPPENS) will be taken
788 // care of elsewhere.
792 all_msg
= "You smell something strange.";
793 else if (you
.species
== SP_MUMMY
)
794 you_msg
= "Your bandages flutter.";
798 // Player only (for now).
800 std::string hair
= _hair_str(target
, plural
);
801 you_msg
= make_stringf("Your %s stand%s on end.", hair
.c_str(),
808 case 1: // a bit less harmless stuff
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));
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));
826 case 2: // rather less harmless stuff
830 you_msg
= "Energy rips through your body!";
831 mon_msg_seen
= "@The_monster@ jerks violently!";
832 _ouch(9 + random2avg(17, 2));
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 "
840 beam
.flavour
= BEAM_MISSILE
;
841 beam
.damage
= dice_def(3, 12);
842 beam
.name
= "explosion";
843 beam
.colour
= random_colour();
850 case 3: // considerably less harmless stuff
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));
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;
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.
885 mon_msg_seen
+= "glow";
890 mon_msg_seen
+= "glows";
893 you_msg
+= " momentarily.";
894 mon_msg_seen
+= " momentarily.";
897 void MiscastEffect::_enchantment(int severity
)
901 case 0: // harmless messages only
905 _your_hands_glow(target
, you_msg
, mon_msg_seen
, can_plural_hand
);
908 you_msg
= "The air around you crackles with energy!";
909 mon_msg_seen
= "The air around @the_monster@ crackles with"
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!";
918 you_msg
= "You feel a strange surge of energy!";
919 // Monster messages needed.
922 you_msg
= "Waves of light ripple over your body.";
923 mon_msg_seen
= "Waves of light ripple over @the_monster@'s body.";
926 you_msg
= "Strange energies run through your body.";
927 mon_msg_seen
= "@The_monster@ glows " + weird_glowing_colour() +
931 you_msg
= "Your skin tingles.";
932 mon_msg_seen
= "@The_monster@ twitches.";
935 you_msg
= "Your skin glows momentarily.";
936 mon_msg_seen
= "@The_monster@'s body glows momentarily.";
939 // Set nothing; canned_msg(MSG_NOTHING_HAPPENS) will be taken
940 // care of elsewhere.
943 if (neither_end_silenced())
945 all_msg
= "You hear something strange.";
946 msg_ch
= MSGCH_SOUND
;
950 else if (target
->atype() == ACT_PLAYER
)
951 you_msg
= "Your skull vibrates slightly.";
957 case 1: // slightly annoying
958 switch (random2(crawl_state
.game_is_arena() ? 1 : 2))
961 if (target
->atype() == ACT_PLAYER
&& !liquefied(you
.pos())
962 && you
.ground_level())
964 you
.attribute
[ATTR_LEV_UNCANCELLABLE
] = 1;
967 else if (target
->atype() == ACT_PLAYER
)
969 // Reasoning: miscasts to get levitation to escape the effects of
970 // liquefaction = cheap.
971 random_uselessness();
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
));
982 // XXX: Something else for monsters?
983 random_uselessness();
988 case 2: // much more annoying
994 if (target
->atype() == ACT_PLAYER
)
996 mpr("You sense a malignant aura.");
997 curse_an_item(false);
1000 // Intentional fall-through for monsters.
1004 _potion_effect(POT_SLOWING
, 10);
1007 _potion_effect(POT_BERSERK_RAGE
, 10);
1012 case 3: // potentially lethal
1013 // Only use first two cases for monsters.
1014 switch (random2(target
->atype() == ACT_PLAYER
? 4 : 2))
1017 _potion_effect(POT_PARALYSIS
, 10);
1020 _potion_effect(POT_CONFUSION
, 10);
1023 contaminate_player(random2avg(19, 3), spell
!= SPELL_NO_SPELL
);
1027 curse_an_item(false);
1028 while (!one_chance_in(3));
1029 mpr("You sense an overwhelmingly malignant aura!");
1036 void MiscastEffect::_translocation(int severity
)
1040 case 0: // harmless messages only
1041 switch (random2(10))
1044 you_msg
= "Space warps around you.";
1045 mon_msg_seen
= "Space warps around @the_monster@.";
1048 you_msg
= "The air around you crackles with energy!";
1049 mon_msg_seen
= "The air around @the_monster@ crackles with "
1053 you_msg
= "You feel a wrenching sensation.";
1054 mon_msg_seen
= "@The_monster@ jerks violently for a moment.";
1057 you_msg
= "You feel a strange surge of energy!";
1058 // Monster messages needed.
1061 you_msg
= "You spin around.";
1062 mon_msg_seen
= "@The_monster@ spins around.";
1065 you_msg
= "Strange energies run through your body.";
1066 mon_msg_seen
= "@The_monster@ glows " + weird_glowing_colour() +
1070 you_msg
= "Your skin tingles.";
1071 mon_msg_seen
= "@The_monster@ twitches.";
1074 you_msg
= "The world appears momentarily distorted!";
1075 mon_msg_seen
= "@The_monster@ appears momentarily distorted!";
1078 // Set nothing; canned_msg(MSG_NOTHING_HAPPENS) will be taken
1079 // care of elsewhere.
1082 you_msg
= "You feel uncomfortable.";
1083 mon_msg_seen
= "@The_monster@ scowls.";
1089 case 1: // mostly harmless
1095 you_msg
= "You are caught in a localised field of spatial "
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));
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);
1111 if (_create_monster(MONS_SPATIAL_VORTEX
, 3))
1112 all_msg
= "Space twists in upon itself!";
1118 case 2: // less harmless
1124 you_msg
= "You are caught in a strong localised spatial "
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));
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);
1141 target
->blink(false);
1142 _potion_effect(POT_CONFUSION
, 40);
1147 bool success
= false;
1149 for (int i
= 1 + random2(3); i
>= 0; --i
)
1151 if (_create_monster(MONS_SPATIAL_VORTEX
, 3))
1156 all_msg
= "Space twists in upon itself!";
1165 case 3: // much less harmless
1166 // Don't use the last case for monsters.
1167 switch (random2(target
->atype() == ACT_PLAYER
? 4 : 3))
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));
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);
1191 contaminate_player(random2avg(19, 3), spell
!= SPELL_NO_SPELL
);
1198 void MiscastEffect::_summoning(int severity
)
1202 case 0: // harmless messages only
1203 switch (random2(10))
1206 you_msg
= "Shadowy shapes form in the air around you, "
1208 mon_msg_seen
= "Shadowy shapes form in the air around "
1209 "@the_monster@, then vanish.";
1212 if (neither_end_silenced())
1214 all_msg
= "You hear strange voices.";
1215 msg_ch
= MSGCH_SOUND
;
1218 else if (target
->atype() == ACT_PLAYER
)
1219 you_msg
= "You feel momentarily dizzy.";
1222 you_msg
= "Your head hurts.";
1223 // Monster messages needed.
1226 you_msg
= "You feel a strange surge of energy!";
1227 // Monster messages needed.
1230 you_msg
= "Your brain hurts!";
1231 // Monster messages needed.
1234 you_msg
= "Strange energies run through your body.";
1235 mon_msg_seen
= "@The_monster@ glows " + weird_glowing_colour() +
1239 you_msg
= "The world appears momentarily distorted.";
1240 mon_msg_seen
= "@The_monster@ appears momentarily distorted.";
1243 you_msg
= "Space warps around you.";
1244 mon_msg_seen
= "Space warps around @the_monster@.";
1247 // Set nothing; canned_msg(MSG_NOTHING_HAPPENS) will be taken
1248 // care of elsewhere.
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
;
1258 else if (target
->atype() == ACT_PLAYER
)
1259 you_msg
= "You feel watched.";
1265 case 1: // a little bad
1268 case 0: // identical to translocation
1271 you_msg
= "You are caught in a localised spatial "
1273 mon_msg_seen
= "@The_monster@ is caught in a localised spatial "
1275 mon_msg_unseen
= "An empty piece of space distorts and twists.";
1276 _ouch(5 + random2avg(9, 2));
1279 if (_create_monster(MONS_SPATIAL_VORTEX
, 3))
1280 all_msg
= "Space twists in upon itself!";
1285 if (_create_monster(summon_any_demon(DEMON_LESSER
), 5, true))
1286 all_msg
= "Something appears in a flash of light!";
1297 bool success
= false;
1299 for (int i
= 1 + random2(3); i
>= 0; --i
)
1301 if (_create_monster(MONS_SPATIAL_VORTEX
, 3))
1306 all_msg
= "Space twists in upon itself!";
1313 if (_create_monster(summon_any_demon(DEMON_COMMON
), 5, true))
1314 all_msg
= "Something forms from out of thin air!";
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))
1330 if (success
&& neither_end_silenced())
1332 you_msg
= "A chorus of chattering voices calls out to"
1334 mon_msg
= "A chorus of chattering voices calls out!";
1335 msg_ch
= MSGCH_SOUND
;
1348 if (_create_monster(MONS_ABOMINATION_SMALL
, 0, true))
1349 all_msg
= "Something forms from out of thin air.";
1354 if (_create_monster(summon_any_demon(DEMON_GREATER
), 0, true))
1355 all_msg
= "You sense a hostile presence.";
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))
1371 you_msg
= "Something turns its malign attention towards "
1373 mon_msg
= "You sense a malign presence.";
1387 void MiscastEffect::_divination_you(int severity
)
1391 case 0: // just a harmless message
1392 switch (random2(10))
1395 mpr("Weird images run through your mind.");
1398 if (!silenced(you
.pos()))
1400 mpr("You hear strange voices.", MSGCH_SOUND
);
1401 noisy(2, you
.pos());
1404 mpr("Your nose twitches.");
1407 mpr("Your head hurts.");
1410 mpr("You feel a strange surge of energy!");
1413 mpr("Your brain hurts!");
1416 mpr("Strange energies run through your body.");
1419 mpr("Everything looks hazy for a moment.");
1422 mpr("You seem to have forgotten something, but you can't remember what it was!");
1425 canned_msg(MSG_NOTHING_HAPPENS
);
1428 mpr("You feel uncomfortable.");
1433 case 1: // more annoying things
1437 mpr("You feel a little dazed.");
1440 potion_effect(POT_CONFUSION
, 10);
1445 case 2: // even more annoying things
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!");
1456 mpr("You have a terrible headache.");
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
);
1468 potion_effect(POT_CONFUSION
, 1); // common to all cases here {dlb}
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
);
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!");
1490 mpr("You have a terrible headache.");
1494 potion_effect(POT_CONFUSION
, 1); // common to all cases here {dlb}
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()))
1508 case 0: // just a harmless message
1509 mon_msg_seen
= "@The_monster@ looks momentarily confused.";
1512 case 1: // more annoying things
1516 mon_msg_seen
= "@The_monster@ looks slightly disoriented.";
1519 mon_msg_seen
= "@The_monster@ looks disoriented.";
1522 1 + random2(3 + act_source
->get_experience_level()));
1527 case 2: // even more annoying things
1528 mon_msg_seen
= "@The_monster@ shudders.";
1531 5 + random2(3 + act_source
->get_experience_level()));
1535 mon_msg_seen
= "@The_monster@ reels.";
1536 if (one_chance_in(7))
1537 target_as_monster()->forget_random_spell();
1540 8 + random2(3 + act_source
->get_experience_level()));
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
);
1563 else if (death_curse
)
1567 simple_god_message(" averts the curse.");
1572 simple_god_message(" partially averts the curse.");
1573 severity
= std::max(severity
- 1, 0);
1581 switch (random2(10))
1584 if (you
.can_smell())
1585 all_msg
= "You smell decay.";
1586 else if (you
.species
== SP_MUMMY
)
1587 you_msg
= "Your bandages flutter.";
1590 if (neither_end_silenced())
1592 all_msg
= "You hear strange and distant voices.";
1593 msg_ch
= MSGCH_SOUND
;
1596 else if (target
->atype() == ACT_PLAYER
)
1597 you_msg
= "You feel homesick.";
1600 you_msg
= "Pain shoots through your body.";
1601 // Monster messages needed.
1604 you_msg
= "Your bones ache.";
1605 // Monster messages needed.
1608 you_msg
= "The world around you seems to dim momentarily.";
1609 mon_msg_seen
= "@The_monster@ seems to dim momentarily.";
1612 you_msg
= "Strange energies run through your body.";
1613 mon_msg_seen
= "@The_monster@ glows " + weird_glowing_colour() +
1617 you_msg
= "You shiver with cold.";
1618 mon_msg_seen
= "@The_monster@ shivers with cold.";
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.
1627 // Set nothing; canned_msg(MSG_NOTHING_HAPPENS) will be taken
1628 // care of elsewhere.
1631 you_msg
= "You feel very uncomfortable.";
1632 mon_msg_seen
= "@The_monster@ scowls horribly.";
1638 case 1: // a bit nasty
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 "
1650 you_msg
= "Pain shoots through your body!";
1651 mon_msg_seen
= "@The_monster@ convulses with pain!";
1652 _ouch(5 + random2avg(15, 2));
1656 you_msg
= "You feel horribly lethargic.";
1657 mon_msg_seen
= "@The_monster@ looks incredibly listless.";
1658 _potion_effect(POT_SLOWING
, 15);
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
)
1672 target_as_monster()->add_ench(mon_enchant(ENCH_ROT
, 1,
1675 else if (you
.species
== SP_MUMMY
)
1677 // Monster messages needed.
1678 you_msg
= "Your bandages flutter.";
1686 case 2: // much nastier
1691 bool success
= false;
1693 for (int i
= random2(3); i
>= 0; --i
)
1695 if (_create_monster(MONS_SHADOW
, 2, true))
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.";
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))
1719 target
->drain_exp(act_source
);
1724 // If we didn't do anything, just flow through...
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 "
1737 you_msg
= "You convulse helplessly as pain tears through "
1739 mon_msg_seen
= "@The_monster@ convulses helplessly with pain!";
1740 _ouch(15 + random2avg(23, 2));
1748 case 3: // even nastier
1749 // Don't use last case for monsters.
1750 switch (random2(target
->atype() == ACT_PLAYER
? 6 : 5))
1753 if (target
->holiness() == MH_UNDEAD
)
1755 you_msg
= "Something just walked over your grave. No, "
1757 mon_msg_seen
= "@The_monster@ seems frightened for a moment.";
1761 torment_monsters(target
->pos(), 0, TORMENT_GENERIC
);
1765 target
->rot(act_source
, random2avg(7, 2) + 1);
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...";
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...";
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
))
1796 target
->drain_exp(act_source
);
1800 // If we didn't do anything, just flow through if it's the player.
1801 if (target
->atype() == ACT_MONSTER
|| did_msg
)
1805 _lose_stat(STAT_RANDOM
, 1 + random2avg(7, 2));
1812 void MiscastEffect::_transmutation(int severity
)
1817 case 0: // just a harmless message
1818 num
= 10 + (_has_hair(target
) ? 1 : 0);
1819 switch (random2(num
))
1822 _your_hands_glow(target
, you_msg
, mon_msg_seen
, can_plural_hand
);
1825 you_msg
= "The air around you crackles with energy!";
1826 mon_msg_seen
= "The air around @the_monster@ crackles with "
1828 mon_msg_unseen
= "The thin air crackles with energy!";
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!";
1836 you_msg
= "You feel a strange surge of energy!";
1837 // Monster messages needed.
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.";
1845 you_msg
= "Strange energies run through your body.";
1846 mon_msg_seen
= "@The_monster@ glows " + weird_glowing_colour() +
1850 you_msg
= "Your skin tingles.";
1851 mon_msg_seen
= "@The_monster@ twitches.";
1854 you_msg
= "Your skin glows momentarily.";
1855 mon_msg_seen
= "@The_monster@'s body glows momentarily.";
1858 // Set nothing; canned_msg(MSG_NOTHING_HAPPENS) will be taken
1859 // care of elsewhere.
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.";
1869 // Player only (for now).
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");
1879 case 1: // slightly annoying
1880 switch (random2(crawl_state
.game_is_arena() ? 1 : 2))
1883 you_msg
= "Your body is twisted painfully.";
1884 mon_msg_seen
= "@The_monster@'s body twists unnaturally.";
1885 _ouch(1 + random2avg(11, 2));
1888 random_uselessness();
1893 case 2: // much more annoying
1894 // Last case for players only.
1895 switch (random2(target
->atype() == ACT_PLAYER
? 4 : 3))
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));
1903 _potion_effect(POT_PARALYSIS
, 10);
1906 _potion_effect(POT_CONFUSION
, 10);
1909 contaminate_player(random2avg(19, 3), spell
!= SPELL_NO_SPELL
);
1914 case 3: // even nastier
1915 if (target
->atype() == ACT_MONSTER
)
1916 target
->mutate(); // Polymorph the monster, if possible.
1921 you_msg
= "Your body is flooded with distortional energies!";
1922 mon_msg
= "@The_monster@'s body is flooded with distortional "
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);
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
))
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));
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
))
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);
1968 give_bad_mutation(false, false);
1970 _ouch(5 + random2avg(23, 2));
1977 void MiscastEffect::_fire(int severity
)
1981 case 0: // just a harmless message
1982 switch (random2(10))
1985 you_msg
= "Sparks fly from your @hands@!";
1986 mon_msg_seen
= "Sparks fly from @the_monster@'s @hands@!";
1989 you_msg
= "The air around you burns with energy!";
1990 mon_msg_seen
= "The air around @the_monster@ burns with energy!";
1993 you_msg
= "Wisps of smoke drift from your @hands@.";
1994 mon_msg_seen
= "Wisps of smoke drift from @the_monster@'s @hands@.";
1997 you_msg
= "You feel a strange surge of energy!";
1998 // Monster messages needed.
2001 if (you
.can_smell())
2002 all_msg
= "You smell smoke.";
2003 else if (you
.species
== SP_MUMMY
)
2004 you_msg
= "Your bandages flutter.";
2007 you_msg
= "Heat runs through your body.";
2008 // Monster messages needed.
2011 you_msg
= "You feel uncomfortably hot.";
2012 // Monster messages needed.
2015 you_msg
= "Lukewarm flames ripple over your body.";
2016 mon_msg_seen
= "Dim flames ripple over @the_monster@'s body.";
2019 // Set nothing; canned_msg(MSG_NOTHING_HAPPENS) will be taken
2020 // care of elsewhere.
2023 if (neither_end_silenced())
2025 all_msg
= "You hear a sizzling sound.";
2026 msg_ch
= MSGCH_SOUND
;
2029 else if (target
->atype() == ACT_PLAYER
)
2030 you_msg
= "You feel like you have heartburn.";
2036 case 1: // a bit less harmless stuff
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));
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)))
2057 if (target
->alive())
2058 target
->expose_to_element(BEAM_FIRE
, 3);
2063 case 2: // rather less harmless stuff
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);
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";
2090 case 3: // considerably less harmless stuff
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 "
2098 if (_ouch(9 + random2avg(33, 2), BEAM_FIRE
) && target
->alive())
2099 target
->expose_to_element(BEAM_FIRE
, 10);
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";
2109 beam
.ex_size
= coinflip() ? 1 : 2;
2116 you_msg
= "You are covered in liquid flames!";
2117 mon_msg_seen
= "@The_monster@ is covered in liquid flames!";
2120 if (target
->atype() == ACT_PLAYER
)
2121 napalm_player(random2avg(7,3) + 1);
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
));
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
);
2149 case 0: // just a harmless message
2150 num
= 10 + (frostable_feat
? 1 : 0);
2151 switch (random2(num
))
2154 you_msg
= "You shiver with cold.";
2155 mon_msg_seen
= "@The_monster@ shivers with cold.";
2158 you_msg
= "A chill runs through your body.";
2159 // Monster messages needed.
2162 you_msg
= "Wisps of condensation drift from your @hands@.";
2163 mon_msg_seen
= "Wisps of condensation drift from @the_monster@'s "
2165 mon_msg_unseen
= "Wisps of condensation drift in the air.";
2168 you_msg
= "You feel a strange surge of energy!";
2169 // Monster messages needed.
2172 you_msg
= "Your @hands@ feel@hand_conj@ numb with cold.";
2173 // Monster messages needed.
2176 you_msg
= "A chill runs through your body.";
2177 // Monster messages needed.
2180 you_msg
= "You feel uncomfortably cold.";
2181 // Monster messages needed.
2184 you_msg
= "Frost covers your body.";
2185 mon_msg_seen
= "Frost covers @the_monster@'s body.";
2188 // Set nothing; canned_msg(MSG_NOTHING_HAPPENS) will be taken
2189 // care of elsewhere.
2192 if (neither_end_silenced())
2194 all_msg
= "You hear a crackling sound.";
2195 msg_ch
= MSGCH_SOUND
;
2198 else if (target
->atype() == ACT_PLAYER
)
2199 you_msg
= "A snowflake lands on your nose.";
2202 if (feat_is_water(feat
))
2203 all_msg
= "A thin layer of ice forms on " + feat_name
;
2205 all_msg
= "Frost spreads across " + feat_name
;
2211 case 1: // a bit less harmless stuff
2215 mpr("You feel extremely cold.");
2216 // Monster messages needed.
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)))
2228 if (target
->alive())
2229 target
->expose_to_element(BEAM_COLD
, 2);
2234 case 2: // rather less harmless stuff
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);
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 "
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
;
2261 case 3: // less harmless stuff
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);
2271 you_msg
= "Freezing gasses pour from your @hands@!";
2272 mon_msg_seen
= "Freezing gasses pour from @the_monster@'s "
2275 _big_cloud(CLOUD_COLD
, 20, 8 + random2(4));
2282 static bool _on_floor(actor
* target
)
2284 return (target
->ground_level() && grd(target
->pos()) == DNGN_FLOOR
);
2287 void MiscastEffect::_earth(int severity
)
2292 case 0: // just a harmless message
2294 num
= 11 + (_on_floor(target
) ? 2 : 0);
2295 switch (random2(num
))
2298 you_msg
= "You feel earthy.";
2299 // Monster messages needed.
2302 you_msg
= "You are showered with tiny particles of grit.";
2303 mon_msg_seen
= "@The_monster@ is showered with tiny particles "
2305 mon_msg_unseen
= "Tiny particles of grit hang in the air for a "
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.";
2314 you_msg
= "You feel a surge of energy from the ground.";
2315 // Monster messages needed.
2318 if (neither_end_silenced())
2320 all_msg
= "You hear a distant rumble.";
2321 msg_ch
= MSGCH_SOUND
;
2324 else if (target
->atype() == ACT_PLAYER
)
2325 you_msg
= "You sympathise with the stones.";
2328 you_msg
= "You feel gritty.";
2329 // Monster messages needed.
2332 you_msg
= "You feel momentarily lethargic.";
2333 mon_msg_seen
= "@The_monster@ looks momentarily listless.";
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.";
2341 // Set nothing; canned_msg(MSG_NOTHING_HAPPENS) will be taken
2342 // care of elsewhere.
2346 bool pluralised
= true;
2347 std::string feet
= you
.foot_name(true, &pluralised
);
2348 std::ostringstream str
;
2350 str
<< "Your " << feet
<< (pluralised
? " feel" : " feels")
2353 you_msg
= str
.str();
2354 // Monster messages needed.
2358 if (target
->cannot_move())
2360 you_msg
= "You briefly vibrate.";
2361 mon_msg_seen
= "@The_monster@ briefly vibrates.";
2365 you_msg
= "You momentarily stiffen.";
2366 mon_msg_seen
= "@The_monster@ momentarily stiffens.";
2370 all_msg
= "The floor vibrates.";
2373 all_msg
= "The floor shifts beneath you alarmingly!";
2379 case 2: // slightly less harmless stuff
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!";
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!";
2396 you_msg
= "Rocks fall onto you out of nowhere!";
2397 mon_msg_seen
= "Rocks fall onto @the_monster@ out of "
2399 mon_msg_unseen
= "Rocks fall out of nowhere!";
2402 _ouch(random2avg(13, 2) + 10 - random2(1 + target
->armour_class()));
2407 case 3: // less harmless stuff
2411 you_msg
= "You are caught in an explosion of flying "
2413 mon_msg_seen
= "@The_monster@ is caught in an explosion of "
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";
2423 if (one_chance_in(5))
2424 beam
.colour
= BROWN
;
2425 if (one_chance_in(5))
2426 beam
.colour
= LIGHTCYAN
;
2435 void MiscastEffect::_air(int severity
)
2440 case 0: // just a harmless message
2443 num
+= 3 + _has_hair(target
);
2444 switch (random2(num
))
2447 you_msg
= "You feel momentarily weightless.";
2448 mon_msg_seen
= "@The_monster@ bobs in the air for a moment.";
2451 you_msg
= "Wisps of vapour drift from your @hands@.";
2452 mon_msg_seen
= "Wisps of vapour drift from @the_monster@'s "
2457 bool pluralised
= true;
2458 if (!hand_str
.empty())
2459 pluralised
= can_plural_hand
;
2461 target
->hand_name(true, &pluralised
);
2465 you_msg
= "Sparks of electricity dance between your "
2467 mon_msg_seen
= "Sparks of electricity dance between "
2468 "@the_monster@'s @hands@.";
2472 you_msg
= "Sparks of electricity dance over your "
2474 mon_msg_seen
= "Sparks of electricity dance over "
2475 "@the_monster@'s @hand@.";
2480 you_msg
= "You are blasted with air!";
2481 mon_msg_seen
= "@The_monster@ is blasted with air!";
2484 if (neither_end_silenced())
2486 all_msg
= "You hear a whooshing sound.";
2487 msg_ch
= MSGCH_SOUND
;
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.";
2496 // Set nothing; canned_msg(MSG_NOTHING_HAPPENS) will be taken
2497 // care of elsewhere.
2500 if (neither_end_silenced())
2502 all_msg
= "You hear a crackling sound.";
2503 msg_ch
= MSGCH_SOUND
;
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.";
2512 you_msg
= "There is a short, sharp shower of sparks.";
2513 mon_msg_seen
= "@The_monster@ is briefly showered in sparks.";
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!";
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!";
2530 you_msg
= "Ouch! You gave yourself an electric shock.";
2531 // Monster messages needed.
2534 you_msg
= "You feel a strange surge of energy!";
2535 // Monster messages needed.
2538 you_msg
= "You feel electric!";
2539 // Monster messages needed.
2543 // Player only (for now).
2545 std::string hair
= _hair_str(target
, plural
);
2546 you_msg
= make_stringf("Your %s stand%s on end.", hair
.c_str(),
2554 case 1: // rather less harmless stuff
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
);
2564 you_msg
= "Noxious gasses pour from your @hands@!";
2565 mon_msg_seen
= "Noxious gasses pour from @the_monster@'s "
2567 mon_msg_unseen
= "Noxious gasses appear from out of thin air!";
2569 _big_cloud(CLOUD_STINK
, 20, 9 + random2(4));
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));
2581 case 2: // much less harmless stuff
2585 you_msg
= "You are caught in an explosion of electrical "
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 "
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;
2602 you_msg
= "Venomous gasses pour from your @hands@!";
2603 mon_msg_seen
= "Venomous gasses pour from @the_monster@'s "
2605 mon_msg_unseen
= "Venomous gasses pour forth from the thin air!";
2607 _big_cloud(CLOUD_POISON
, 20, 8 + random2(5));
2612 case 3: // even less harmless stuff
2616 if (_create_monster(MONS_BALL_LIGHTNING
, 3))
2617 all_msg
= "A ball of electricity appears!";
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
);
2627 if (_create_monster(MONS_TWISTER
, 1))
2628 all_msg
= "A huge vortex of air appears!";
2636 void MiscastEffect::_poison(int severity
)
2640 case 0: // just a harmless message
2641 switch (random2(10))
2644 you_msg
= "You feel mildly nauseous.";
2645 mon_msg_seen
= "@The_monster@ briefly looks nauseous.";
2648 you_msg
= "You feel slightly ill.";
2649 mon_msg_seen
= "@The_monster@ briefly looks sick.";
2652 you_msg
= "Wisps of poison gas drift from your @hands@.";
2653 mon_msg_seen
= "Wisps of poison gas drift from @the_monster@'s "
2657 you_msg
= "You feel a strange surge of energy!";
2658 // Monster messages needed.
2661 you_msg
= "You feel faint for a moment.";
2662 mon_msg_seen
= "@The_monster@ looks faint for a moment.";
2665 you_msg
= "You feel sick.";
2666 mon_msg_seen
= "@The_monster@ looks sick.";
2669 you_msg
= "You feel odd.";
2670 mon_msg_seen
= "@The_monster@ has an odd expression for a "
2674 you_msg
= "You feel weak for a moment.";
2675 mon_msg_seen
= "@The_monster@ looks weak for a moment.";
2678 // Set nothing; canned_msg(MSG_NOTHING_HAPPENS) will be taken
2679 // care of elsewhere.
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.";
2690 case 1: // a bit less harmless stuff
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));
2704 you_msg
= "Noxious gasses pour from your @hands@!";
2705 mon_msg_seen
= "Noxious gasses pour from @the_monster@'s "
2707 mon_msg_unseen
= "Noxious gasses pour forth from the thin air!";
2708 place_cloud(CLOUD_STINK
, target
->pos(), 2 + random2(4), guilty
);
2713 case 2: // rather less harmless stuff
2714 // Don't use last case for monsters.
2715 switch (random2(target
->atype() == ACT_PLAYER
? 3 : 2))
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));
2728 you_msg
= "Noxious gasses pour from your @hands@!";
2729 mon_msg_seen
= "Noxious gasses pour from @the_monster@'s "
2731 mon_msg_unseen
= "Noxious gasses pour forth from the thin air!";
2733 _big_cloud(CLOUD_STINK
, 20, 8 + random2(5));
2737 if (player_res_poison())
2738 canned_msg(MSG_NOTHING_HAPPENS
);
2740 _lose_stat(STAT_RANDOM
, 1);
2745 case 3: // less harmless stuff
2746 // Don't use last case for monsters.
2747 switch (random2(target
->atype() == ACT_PLAYER
? 3 : 2))
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));
2759 you_msg
= "Venomous gasses pour from your @hands@!";
2760 mon_msg_seen
= "Venomous gasses pour from @the_monster@'s "
2762 mon_msg_unseen
= "Venomous gasses pour forth from the thin air!";
2764 _big_cloud(CLOUD_POISON
, 20, 7 + random2(7));
2767 if (player_res_poison())
2768 canned_msg(MSG_NOTHING_HAPPENS
);
2770 _lose_stat(STAT_RANDOM
, 1 + random2avg(5, 2));
2777 void MiscastEffect::_do_poison(int amount
)
2779 if (target
->atype() == ACT_PLAYER
)
2780 poison_player(amount
, cause
, "residual poison");
2782 target
->poison(act_source
, amount
);