diff options
Diffstat (limited to 'crawl-ref/source/spl-cast.cc')
-rw-r--r-- | crawl-ref/source/spl-cast.cc | 1993 |
1 files changed, 1315 insertions, 678 deletions
diff --git a/crawl-ref/source/spl-cast.cc b/crawl-ref/source/spl-cast.cc index dc0609259e..aebcbba27b 100644 --- a/crawl-ref/source/spl-cast.cc +++ b/crawl-ref/source/spl-cast.cc @@ -54,6 +54,7 @@ #include "spells3.h" #include "spells4.h" #include "spl-book.h" +#include "spl-mis.h" #include "spl-util.h" #include "state.h" #include "stuff.h" @@ -1125,14 +1126,6 @@ spret_type your_spells(spell_type spell, int powc, bool allow_fail) return (SPRET_FAIL); } - unsigned int sptype = 0; - - do - { - sptype = 1 << (random2(SPTYP_LAST_EXPONENT+1)); - } - while (!spell_typematch(spell, sptype)); - // all spell failures give a bit of magical radiation.. // failure is a function of power squared multiplied // by how badly you missed the spell. High power @@ -1146,8 +1139,8 @@ spret_type your_spells(spell_type spell, int powc, bool allow_fail) // miscasts are uncontrolled contaminate_player( cont_points ); - miscast_effect( sptype, spell_mana(spell), - spfail_chance - spfl, 100 ); + MiscastEffect( &you, NON_MONSTER, spell, spell_mana(spell), + spfail_chance - spfl ); return (SPRET_FAIL); } @@ -2214,80 +2207,617 @@ void exercise_spell( spell_type spell, bool spc, bool success ) did_god_conduct( DID_SPELL_PRACTISE, exer_norm ); } -static bool _send_abyss(const char *cause) +MiscastEffect::MiscastEffect(actor* _target, int _source, spell_type _spell, + int _pow, int _fail, std::string _cause, + nothing_happens_when_type _nothing_happens) : + target(_target), source(_source), cause(_cause), spell(_spell), + school(SPTYP_NONE), pow(_pow), fail(_fail), level(-1), kc(KC_NCATEGORIES), + kt(KILL_NONE), mon_target(NULL), mon_source(NULL), + nothing_happens_when(_nothing_happens) +{ + ASSERT(is_valid_spell(_spell)); + unsigned int schools = get_spell_disciplines(_spell); + ASSERT(schools != SPTYP_NONE); + ASSERT(!(schools & SPTYP_HOLY)); + + init(); + do_miscast(); +} + +MiscastEffect::MiscastEffect(actor *_target, int _source, + spschool_flag_type _school, int _level, + std::string _cause, + nothing_happens_when_type _nothing_happens) : + target(_target), source(_source), cause(_cause), spell(SPELL_NO_SPELL), + school(_school), pow(-1), fail(-1), level(_level), kc(KC_NCATEGORIES), + kt(KILL_NONE), mon_target(NULL), mon_source(NULL), + nothing_happens_when(_nothing_happens) +{ + ASSERT(!_cause.empty()); + ASSERT(count_bits(_school) == 1); + ASSERT(_school < SPTYP_HOLY || _school == SPTYP_RANDOM); + ASSERT(level >= 0 && level <= 3); + + init(); + do_miscast(); +} + +MiscastEffect::MiscastEffect(actor *_target, int _source, + spschool_flag_type _school, int _pow, int _fail, + std::string _cause, + nothing_happens_when_type _nothing_happens) : + target(_target), source(_source), cause(_cause), spell(SPELL_NO_SPELL), + school(_school), pow(_pow), fail(_fail), level(-1), kc(KC_NCATEGORIES), + kt(KILL_NONE), mon_target(NULL), mon_source(NULL), + nothing_happens_when(_nothing_happens) +{ + ASSERT(!_cause.empty()); + ASSERT(count_bits(_school) == 1); + ASSERT(_school < SPTYP_HOLY || _school == SPTYP_RANDOM); + + init(); + do_miscast(); +} + +void MiscastEffect::init() { - if (you.level_type != LEVEL_ABYSS) + ASSERT(spell != SPELL_NO_SPELL && school == SPTYP_NONE + || spell == SPELL_NO_SPELL && school != SPTYP_NONE); + ASSERT(pow != -1 && fail != -1 && level == -1 + || pow == -1 && fail == -1 && level >= 0 && level <= 3); + + ASSERT(target != NULL); + // A dead but not-yet-exploded giant spore or ball lightning *might* + // be the target of a miscast effect. + ASSERT(target->alive() || target->id() == MONS_GIANT_SPORE + || target->id() == MONS_BALL_LIGHTNING); + + source_known = target_known = false; + + mon_target = mon_source = NULL; + act_source = NULL; + + const bool death_curse = (cause.find("death curse") != std::string::npos); + + if (target->atype() == ACT_MONSTER) { - you.banish(cause ? cause : ""); - return (true); + mon_target = dynamic_cast<monsters*>(target); + target_known = you.can_see(mon_target); } else + target_known = true; + + kill_source = source; + if (source == WIELD_MISCAST || source == MELEE_MISCAST) { - mpr("The world appears momentarily distorted."); - return (false); + if (target->atype() == ACT_MONSTER) + { + mon_source = dynamic_cast<monsters*>(target); + kill_source = monster_index(mon_source); + } + else + kill_source = NON_MONSTER; + } + + if (kill_source == NON_MONSTER) + { + kc = KC_YOU; + kt = KILL_YOU_MISSILE; + act_source = dynamic_cast<actor*>(&you); + source_known = true; + } + else if (kill_source >= 0 && kill_source < NON_MONSTER) + { + mon_source = &menv[kill_source]; + act_source = dynamic_cast<actor*>(mon_source); + ASSERT(mon_source->type != -1); + + if (death_curse && target->atype() == ACT_MONSTER + && mon_target->confused_by_you()) + { + kt = KILL_YOU_CONF; + } + else if (!death_curse && mon_source->confused_by_you() + && !mons_friendly(mon_source)) + { + kt = KILL_YOU_CONF; + } + else + kt = KILL_MON_MISSILE; + + if (mons_friendly(mon_source)) + kc = KC_FRIENDLY; + else + kc = KC_OTHER; + + source_known = you.can_see(mon_source); + + if (target_known && death_curse) + source_known = true; + } + else + { + ASSERT(source == ZOT_TRAP_MISCAST + || source == MISC_KNOWN_MISCAST + || source == MISC_UNKNOWN_MISCAST + || (source < 0 && -source < NUM_GODS)); + + kc = KC_OTHER; + kt = KILL_MISC; + + if (source == ZOT_TRAP_MISCAST) + { + source_known = target_known; + + if (target->atype() == ACT_MONSTER + && mon_target->confused_by_you()) + { + kt = KILL_YOU_CONF; + } + } + else if (source == MISC_KNOWN_MISCAST) + source_known = true; + else if (source == MISC_UNKNOWN_MISCAST) + source_known = false; + else + source_known = true; + } + + ASSERT(kc != KC_NCATEGORIES && kt != KILL_NONE); + + if (death_curse && !invalid_monster_index(kill_source)) + { + if (starts_with(cause, "a ")) + cause.replace(cause.begin(), cause.begin() + 1, "an indirect"); + if (starts_with(cause, "an ")) + cause.replace(cause.begin(), cause.begin() + 2, "an indirect"); + else + cause = replace_all(cause, "death curse", "indirect death curse"); + } + + // source_known = false for MELEE_MISCAST so that melee miscasts + // won't give a "nothing happens" message. + if (source == MELEE_MISCAST) + source_known = false; + + beam.is_beam = false; + beam.is_explosion = true; + + if (cause.empty()) + cause = get_default_cause(); + beam.aux_source = cause; + beam.beam_source = kill_source; + beam.thrower = kt; +} + +std::string MiscastEffect::get_default_cause() +{ + // This is only for true miscasts, which means both a spell and that + // the source of the miscast is the same as the target of the miscast. + ASSERT(source >= 0 && source <= NON_MONSTER); + ASSERT(spell != SPELL_NO_SPELL); + ASSERT(school == SPTYP_NONE); + + if (source == NON_MONSTER) + { + ASSERT(target->atype() == ACT_PLAYER); + std::string str = "you miscasting "; + str += spell_title(spell); + return str; + } + + ASSERT(mon_source != NULL); + ASSERT(mon_source == mon_target); + + if (you.can_see(mon_source)) + { + std::string str = mon_source->base_name(DESC_PLAIN, false); + + str += "'s spell miscasting"; + str = replace_all(str, "s's", "s'"); + return str; + } + else + return "something's spell miscasting"; +} + +bool MiscastEffect::neither_end_silenced() +{ + return (!silenced(you.pos()) && !silenced(target->pos())); +} + +void MiscastEffect::do_miscast() +{ + // Repeated calls to do_miscast() on a single object instance have + // killed a target which was alive when the object was created, + // or the target is a dead but not-yet-exploded giant spore or + // ball lightning. + if (!target->alive()) + { + mprf(MSGCH_DIAGNOSTICS, "Miscast target '%s' already dead", + target->name(DESC_PLAIN, true).c_str()); + return; + } + + spschool_flag_type sp_type; + int severity; + + if (spell != SPELL_NO_SPELL) + { + std::vector<int> school_list; + for (int i = 0; i < SPTYP_LAST_EXPONENT; i++) + if (spell_typematch(spell, 1 << i)) + school_list.push_back(i); + + unsigned int _school = school_list[random2(school_list.size())]; + sp_type = static_cast<spschool_flag_type>(1 << _school); + } + else + { + sp_type = school; + if (sp_type == SPTYP_RANDOM) + { + int exp = (random2(SPTYP_LAST_EXPONENT)); + sp_type = (spschool_flag_type) (1 << exp); + } + } + + if (level != -1) + severity = level; + else + { + severity = (pow * fail * (10 + pow) / 7 * WILD_MAGIC_NASTINESS) / 100; + +#if DEBUG_DIAGNOSTICS || DEBUG_MISCAT + mprf(MSGCH_DIAGNOSTICS, "'%s' miscast power: %d", + spell != SPELL_NO_SPELL ? spell_title(spell) + : spelltype_short_name(sp_type), + severity); +#endif + + if (random2(40) > severity && random2(40) > severity) + { + if (target->atype() == ACT_PLAYER) + canned_msg(MSG_NOTHING_HAPPENS); + return; + } + + severity /= 100; + severity = random2(severity); + if (severity > 3) + severity = 3; + else if (severity < 0) + severity = 0; + } + +#if DEBUG_DIAGNOSTICS || DEBUG_MISCAT + mprf(MSGCH_DIAGNOSTICS, "Sptype: %u, severity: %d", + spelltype_short_name(sp_type), severity ); +#endif + + beam.ex_size = 1; + beam.name = ""; + beam.damage = dice_def(0, 0); + beam.flavour = BEAM_NONE; + beam.msg_generated = false; + beam.in_explosion_phase = false; + + // Do this here since multiple miscasts (wizmode testing) might move + // the target around. + beam.source_x = target->pos().x; + beam.source_y = target->pos().y; + beam.target_x = target->pos().x; + beam.target_y = target->pos().y; + beam.pos = target->pos(); + + all_msg = you_msg = mon_msg = mon_msg_seen = mon_msg_unseen = ""; + msg_ch = MSGCH_PLAIN; + + switch (sp_type) + { + case SPTYP_CONJURATION: _conjuration(severity); break; + case SPTYP_ENCHANTMENT: _enchantment(severity); break; + case SPTYP_TRANSLOCATION: _translocation(severity); break; + case SPTYP_SUMMONING: _summoning(severity); break; + case SPTYP_NECROMANCY: _necromancy(severity); break; + case SPTYP_TRANSMIGRATION: _transmigration(severity); break; + case SPTYP_FIRE: _fire(severity); break; + case SPTYP_ICE: _ice(severity); break; + case SPTYP_EARTH: _earth(severity); break; + case SPTYP_AIR: _air(severity); break; + case SPTYP_POISON: _poison(severity); break; + case SPTYP_DIVINATION: + // Divination miscasts have nothing in common between the player + // and monsters. + if (target->atype() == ACT_PLAYER) + _divination_you(severity); + else + _divination_mon(severity); + break; + + default: + ASSERT(false); + } + + if (target->atype() == ACT_PLAYER) + xom_is_stimulated(severity * 50); +} + +void MiscastEffect::do_msg(bool suppress_nothing_happnes) +{ + if (mon_target != NULL && !mons_near(mon_target)) + return; + + std::string msg; + + if (!all_msg.empty()) + msg = all_msg; + else if (target->atype() == ACT_PLAYER) + msg = you_msg; + else if (!mon_msg.empty()) + { + msg = mon_msg; + // Monster might be unseen with hands that can't be seen. + ASSERT(msg.find("@hand") == std::string::npos); + } + else + { + if (you.can_see(target)) + msg = mon_msg_seen; + else + { + msg = mon_msg_unseen; + // Can't see the hands of invisible monsters. + ASSERT(msg.find("@hand") == std::string::npos); + } + } + + if (msg.empty()) + { + if (!suppress_nothing_happnes + && (nothing_happens_when == NH_ALWAYS + || (nothing_happens_when == NH_DEFAULT && source_known + && target_known))) + { + canned_msg(MSG_NOTHING_HAPPENS); + } + + return; + } + + msg = replace_all(msg, "@hand@", target->hand_name(false)); + msg = replace_all(msg, "@hands@", target->hand_name(true)); + + if (target->atype() == ACT_MONSTER) + msg = do_mon_str_replacements(msg, mon_target, S_SILENT); + + mpr(msg.c_str(), msg_ch); +} + +void MiscastEffect::_ouch(int dam, beam_type flavour) +{ + do_msg(true); + + if (target->atype() == ACT_MONSTER) + { + bolt beem; + + beem.flavour = flavour; + dam = mons_adjust_flavoured(mon_target, beem, dam, true); + hurt_monster(mon_target, dam); + + if (mon_target->hit_points < 1) + monster_die(mon_target, kt, kill_source); + } + else + { + kill_method_type method; + + if (source == NON_MONSTER && spell != SPELL_NO_SPELL) + method = KILLED_BY_WILD_MAGIC; + else if (source == ZOT_TRAP_MISCAST) + method = KILLED_BY_TRAP; + else if (source < 0 && -source < NUM_GODS) + { + god_type god = static_cast<god_type>(-source); + + if (god == GOD_XOM && you.penance[GOD_XOM] == 0) + method = KILLED_BY_XOM; + else + { + method = KILLED_BY_DIVINE_WRATH; + + if (you.penance[god] == 0) + mpr("God making you miscast, but not under penance.", + MSGCH_DIAGNOSTICS); + } + } + else if (source >= 0 && source < NON_MONSTER) + method = KILLED_BY_MONSTER; + else + method = KILLED_BY_SOMETHING; + + dam = check_your_resists(dam, flavour); + + bool see_source = false; + if (kill_source != NON_MONSTER) + see_source = you.can_see(&menv[kill_source]); + + ouch(dam, kill_source, method, cause.c_str(), see_source); + } +} + +void MiscastEffect::_explosion() +{ + ASSERT(!beam.name.empty()); + ASSERT(beam.damage.num != 0 && beam.damage.size != 0); + ASSERT(beam.flavour != BEAM_NONE); + + do_msg(true); + explosion(beam, false, true); +} + +void MiscastEffect::_potion_effect(int pot_eff, int pot_pow) +{ + if (target->atype() == ACT_PLAYER) + { + potion_effect(static_cast<potion_type>(pot_eff), pot_pow, false); + return; + } + + switch(pot_eff) + { + case POT_LEVITATION: + // There's no levitation enchantment for monsters, and anyways + // it's not nearly as inconveniencing for monsters as for the + // player, so backlight them instead. + mon_target->add_ench( mon_enchant(ENCH_BACKLIGHT, pot_pow, kc) ); + break; + case POT_BERSERK_RAGE: + if (target->can_go_berserk()) + { + target->go_berserk(false); + break; + } + // Intentional fallthrough if that didn't work. + case POT_SLOWING: + target->slow_down(pot_pow); + break; + case POT_PARALYSIS: + target->paralyse(pot_pow); + break; + case POT_CONFUSION: + target->confuse(pot_pow); + break; + + default: + ASSERT(false); + } +} + +void MiscastEffect::send_abyss() +{ + if (you.level_type == LEVEL_ABYSS) + { + you_msg = "The world appears momentarily distorted."; + mon_msg_seen = "@The_monster@ wobbles for a moment."; + mon_msg_unseen = "An empty piece of space momentarily distorts."; + do_msg(); + return; + } + + target->banish(cause); +} + +bool MiscastEffect::_create_monster(monster_type what, int abj_deg, + bool alert) +{ + const god_type god = + (crawl_state.is_god_acting()) ? crawl_state.which_god_acting() + : GOD_NO_GOD; + + mgen_data data = mgen_data::hostile_at(what, target->pos(), + abj_deg, 0, alert, god); + + // hostile_at() assumes the monster is hostile to the player, + // but should be hostile to the target monster unless the miscast + // is a result of either divine wrath or a Zot trap. + if (target->atype() == ACT_MONSTER && you.penance[god] == 0 + && source != ZOT_TRAP_MISCAST) + { + switch(mon_target->temp_attitude()) + { + case ATT_FRIENDLY: data.behaviour = BEH_HOSTILE; break; + case ATT_HOSTILE: data.behaviour = BEH_FRIENDLY; break; + case ATT_GOOD_NEUTRAL: + case ATT_NEUTRAL: + data.behaviour = BEH_NEUTRAL; + break; + } + + if (alert) + data.foe = monster_index(mon_target); + + // No permanent allies from miscasts. + if (data.behaviour == BEH_FRIENDLY && abj_deg == 0) + data.abjuration_duration = 6; } + + return (create_monster(data) != -1); } -static void _miscast_conjuration(int severity, const char* cause) +void MiscastEffect::_conjuration(int severity) { - bolt beam; switch (severity) { case 0: // just a harmless message switch (random2(10)) { case 0: - msg::stream << "Sparks fly from your " << your_hand(true) - << '!' << std::endl; + you_msg = "Sparks fly from your @hands@!"; + mon_msg_seen = "Sparks fly from @the_monster@'s @hands@!"; break; case 1: - mpr("The air around you crackles with energy!"); + you_msg = "The air around you crackles with energy!"; + mon_msg_seen = "The air around @the_monster@ crackles " + "with energy!"; break; case 2: - msg::stream << "Wisps of smoke drift from your " - << your_hand(true) << '.' << std::endl; + you_msg = "Wisps of smoke drift from your @hands@."; + mon_msg_seen = "Wisps of smoke drift from @the_monster@'s " + "@hands@."; break; case 3: - mpr("You feel a strange surge of energy!"); + you_msg = "You feel a strange surge of energy!"; + // Monster messages needed. break; case 4: - mpr("You are momentarily dazzled by a flash of light!"); + you_msg = "You are momentarily dazzled by a flash of light!"; + mon_msg_seen = "@The_monster@ emits a flash of light!"; break; case 5: - mpr("Strange energies run through your body."); + you_msg = "Strange energies run through your body."; + // Monster messages needed. break; case 6: - mpr("Your skin tingles."); + you_msg = "Your skin tingles."; + // Monster messages needed. break; case 7: - mpr("Your skin glows momentarily."); + you_msg = "Your skin glows momentarily."; + mon_msg_seen = "@The_monster@ glows momentarily."; + // A smal glow isn't going to make it past invisibility. break; case 8: - canned_msg(MSG_NOTHING_HAPPENS); + // Set nothing; canned_msg(MSG_NOTHING_HAPPENS) will be taken + // care of elsewhere. break; case 9: if (player_can_smell()) - mpr("You smell something strange."); + all_msg = "You smell something strange."; else if (you.species == SP_MUMMY) - mpr("Your bandages flutter."); - else - canned_msg(MSG_NOTHING_HAPPENS); + you_msg = "Your bandages flutter."; } + do_msg(); break; case 1: // a bit less harmless stuff switch (random2(2)) { case 0: - msg::stream << "Smoke pours from your " << your_hand(true) - << '!' << std::endl; - big_cloud( CLOUD_GREY_SMOKE, (cause ? KC_OTHER : KC_YOU), - you.x_pos, you.y_pos, 20, - 7 + random2(7) ); + you_msg = "Smoke pours from your @hands@!"; + mon_msg_seen = "Smoke pours from @the_monster@'s @hands@!"; + mon_msg_unseen = "Smoke appears from out of nowhere!"; + + do_msg(); + big_cloud( CLOUD_GREY_SMOKE, kc, kt, + target->pos().x, target->pos().y, + 20, 7 + random2(7) ); break; case 1: - mpr("A wave of violent energy washes through your body!"); - ouch(6 + random2avg(7, 2), 0, KILLED_BY_WILD_MAGIC, cause); + you_msg = "A wave of violent energy washes through your body!"; + // Monster messages needed. + _ouch(6 + random2avg(7, 2)); break; } break; @@ -2296,29 +2826,24 @@ static void _miscast_conjuration(int severity, const char* cause) switch (random2(2)) { case 0: - mpr("Energy rips through your body!"); - ouch(9 + random2avg(17, 2), 0, KILLED_BY_WILD_MAGIC, cause); + you_msg = "Energy rips through your body!"; + // Monster messages needed. + _ouch(9 + random2avg(17, 2)); break; case 1: - mpr("You are caught in a violent explosion!"); - beam.type = dchar_glyph(DCHAR_FIRED_BURST); - beam.damage = dice_def( 3, 12 ); + you_msg = "You are caught in a violent explosion!"; + mon_msg_seen = "@The_monster@ is caugh in a violent explosion!"; + mon_msg_unseen = "A violent explosion happens from " + "out of thin air!"; + + beam.damage = dice_def( 3, 12 ); beam.flavour = BEAM_MISSILE; // unsure about this // BEAM_EXPLOSION instead? {dlb} - beam.target_x = you.x_pos; - beam.target_y = you.y_pos; - beam.name = "explosion"; + beam.name = "explosion"; beam.colour = random_colour(); - beam.beam_source = NON_MONSTER; - beam.thrower = (cause) ? KILL_MISC : KILL_YOU; - beam.aux_source.clear(); - if (cause) - beam.aux_source = cause; - beam.ex_size = 1; - beam.is_explosion = true; - explosion(beam); + _explosion(); break; } break; @@ -2327,34 +2852,53 @@ static void _miscast_conjuration(int severity, const char* cause) switch (random2(2)) { case 0: - mpr("You are blasted with magical energy!"); - ouch(12 + random2avg(29, 2), 0, KILLED_BY_WILD_MAGIC, cause); + you_msg = "You are blasted with magical energy!"; + mon_msg_seen = "@The_monster@ is blasted with magical energy!"; + // No message for invis monsters? + _ouch(12 + random2avg(29, 2)); break; case 1: - mpr("There is a sudden explosion of magical energy!"); - beam.type = dchar_glyph(DCHAR_FIRED_BURST); - beam.damage = dice_def( 3, 20 ); + all_msg = "There is a sudden explosion of magical energy!"; + + beam.type = dchar_glyph(DCHAR_FIRED_BURST); + beam.damage = dice_def( 3, 20 ); beam.flavour = BEAM_MISSILE; // unsure about this // BEAM_EXPLOSION instead? {dlb} - beam.target_x = you.x_pos; - beam.target_y = you.y_pos; - beam.name = "explosion"; - beam.colour = random_colour(); - beam.beam_source = NON_MONSTER; - beam.thrower = (cause) ? KILL_MISC : KILL_YOU; - beam.aux_source.clear(); - if (cause) - beam.aux_source = cause; + beam.name = "explosion"; + beam.colour = random_colour(); beam.ex_size = coinflip() ? 1 : 2; - beam.is_explosion = true; - explosion(beam); + _explosion(); break; } } } -static void _miscast_enchantment(int severity, const char* cause) +static void _your_hands_glow(actor* target, std::string& you_msg, + std::string& mon_msg_seen) +{ + you_msg = "Your @hands@ "; + mon_msg_seen = "@The_monster@'s @hands@ "; + // No message for invisible monsters. + + bool pluralized = true; + target->hand_name(true, &pluralized); + + if (pluralized) + { + you_msg += "glow"; + mon_msg_seen += "glow"; + } + else + { + you_msg += "glows"; + mon_msg_seen += "glows"; + } + you_msg += " momentarily."; + mon_msg_seen += " momentarily."; +} + +void MiscastEffect::_enchantment(int severity) { switch (severity) { @@ -2362,51 +2906,67 @@ static void _miscast_enchantment(int severity, const char* cause) switch (random2(10)) { case 0: - msg::stream << "Your " << your_hand(true) - << " glow momentarily." << std::endl; + _your_hands_glow(target, you_msg, mon_msg_seen); break; case 1: - mpr("The air around you crackles with energy!"); + you_msg = "The air around you crackles with energy!"; + mon_msg_seen = "The air around @the_monster@ crackles with" + " energy!"; break; case 2: - mpr("Multicolored lights dance before your eyes!"); + you_msg = "Multicolored lights dance before your eyes!"; + // Monster messages needed. break; case 3: - mpr("You feel a strange surge of energy!"); + you_msg = "You feel a strange surge of energy!"; + // Monster messages needed. break; case 4: - mpr("Waves of light ripple over your body."); + you_msg = "Waves of light ripple over your body."; + mon_msg_seen = "Waves of light ripple over @the_monster@'s body."; break; case 5: - mpr("Strange energies run through your body."); + you_msg = "Strange energies run through your body."; + // Monster messages needed. break; case 6: - mpr("Your skin tingles."); + you_msg = "Your skin tingles."; + // Monster messages needed. break; case 7: - mpr("Your skin glows momentarily."); + you_msg = "Your skin glows momentarily."; + mon_msg_seen = "@The_monster@'s body glows momentarily."; break; case 8: - canned_msg(MSG_NOTHING_HAPPENS); + // Set nothing; canned_msg(MSG_NOTHING_HAPPENS) will be taken + // care of elsewhere. break; case 9: - if (!silenced(you.pos())) - mpr("You hear something strange.", MSGCH_SOUND); - else if (you.attribute[ATTR_TRANSFORMATION] != TRAN_AIR) - mpr("Your skull vibrates slightly."); - else - canned_msg(MSG_NOTHING_HAPPENS); + if (neither_end_silenced()) + { + // XXX: Should use noisy(). + all_msg = "You hear something strange."; + msg_ch = MSGCH_SOUND; + return; + } + else if (target->atype() == ACT_PLAYER + && you.attribute[ATTR_TRANSFORMATION] != TRAN_AIR) + { + you_msg = "Your skull vibrates slightly."; + } break; } + do_msg(); break; case 1: // slightly annoying switch (random2(2)) { case 0: - potion_effect(POT_LEVITATION, 20); + _potion_effect(POT_LEVITATION, 20); break; case 1: + // XXX: Something else for monsters? random_uselessness(); break; } @@ -2418,24 +2978,39 @@ static void _miscast_enchantment(int severity, const char* cause) case 0: case 1: case 2: - mpr("You sense a malignant aura."); - curse_an_item(false); - break; + if (target->atype() == ACT_PLAYER) + { + mpr("You sense a malignant aura."); + curse_an_item(false); + break; + } + // Intentional fall-through for monsters. case 3: case 4: case 5: - potion_effect(POT_SLOWING, 10); + _potion_effect(POT_SLOWING, 10); break; case 6: - potion_effect(POT_BERSERK_RAGE, 10); + _potion_effect(POT_BERSERK_RAGE, 10); break; } break; case 3: // potentially lethal - switch (random2(4)) + // Only use first two cases for monsters. + switch (random2(target->atype() == ACT_PLAYER ? 4 : 2)) { case 0: + _potion_effect(POT_PARALYSIS, 10); + break; + case 1: + _potion_effect(POT_CONFUSION, 10); + break; + case 2: + mpr("You feel saturated with unharnessed energies!"); + you.magic_contamination += random2avg(19,3); + break; + case 3: do { curse_an_item(false); @@ -2444,63 +3019,61 @@ static void _miscast_enchantment(int severity, const char* cause) mpr("You sense an overwhelmingly malignant aura!"); break; - case 1: - potion_effect(POT_PARALYSIS, 10); - break; - case 2: - potion_effect(POT_CONFUSION, 10); - break; - case 3: - mpr("You feel saturated with unharnessed energies!"); - you.magic_contamination += random2avg(19,3); - break; } break; } } -static void _miscast_translocation(int severity, const char* cause) +void MiscastEffect::_translocation(int severity) { - const god_type god = - (crawl_state.is_god_acting()) ? crawl_state.which_god_acting() - : GOD_NO_GOD; - switch (severity) { case 0: // harmless messages only switch (random2(10)) { case 0: - mpr("Space warps around you."); + you_msg = "Space warps around you."; + mon_msg_seen = "Space warps around @the_monster@."; break; case 1: - mpr("The air around you crackles with energy!"); + you_msg = "The air around you crackles with energy!"; + mon_msg_seen = "The air around @the_monster@ crackles with " + "energy!"; break; case 2: - mpr("You feel a wrenching sensation."); + you_msg = "You feel a wrenching sensation."; + // Monster messages needed. break; case 3: - mpr("You feel a strange surge of energy!"); + you_msg = "You feel a strange surge of energy!"; + // Monster messages needed. break; case 4: - mpr("You spin around."); + you_msg = "You spin around."; + mon_msg_seen = "@The_monster@ spins around."; break; case 5: - mpr("Strange energies run through your body."); + you_msg = "Strange energies run through your body."; + // Monster messages needed. break; case 6: - mpr("Your skin tingles."); + you_msg = "Your skin tingles."; + // Monster messages needed. break; case 7: - mpr("The world appears momentarily distorted!"); + you_msg = "The world appears momentarily distorted!"; + mon_msg_seen = "@The_monster@ appears momentarily distorted!"; break; case 8: - canned_msg(MSG_NOTHING_HAPPENS); + // Set nothing; canned_msg(MSG_NOTHING_HAPPENS) will be taken + // care of elsewhere. break; case 9: - mpr("You feel uncomfortable."); + you_msg = "You feel uncomfortable."; + // Monster messages needed. break; } + do_msg(); break; case 1: // mostly harmless @@ -2509,24 +3082,25 @@ static void _miscast_translocation(int severity, const char* cause) case 0: case 1: case 2: - mpr("You are caught in a localised field of spatial distortion."); - ouch(4 + random2avg(9, 2), 0, KILLED_BY_WILD_MAGIC, cause); + you_msg = "You are caught in a localised field of spatial " + "distortion."; + mon_msg_seen = "@The_monster@ is caught in a localised field of " + "spatial distortion."; + mon_msg_unseen = "A piece of empty space twists and distorts."; + _ouch(4 + random2avg(9, 2)); break; case 3: case 4: - mpr("Space bends around you!"); - random_blink(false); - ouch(4 + random2avg(7, 2), 0, KILLED_BY_WILD_MAGIC, cause); + you_msg = "Space bends around you!"; + mon_msg_seen = "Space bends around @the_monster@!"; + mon_msg_unseen = "A piece of empty space twists and distorts."; + _ouch(4 + random2avg(7, 2)); + target->blink(false); break; case 5: - if (create_monster( - mgen_data::hostile_at(MONS_SPATIAL_VORTEX, - you.pos(), 3, 0, false, god)) != -1) - { - mpr("Space twists in upon itself!"); - } - else - canned_msg(MSG_NOTHING_HAPPENS); + if (_create_monster(MONS_SPATIAL_VORTEX, 3)) + all_msg = "Space twists in upon itself!"; + do_msg(); break; } break; @@ -2537,20 +3111,27 @@ static void _miscast_translocation(int severity, const char* cause) case 0: case 1: case 2: - mpr("You are caught in a strong localised spatial distortion."); - ouch(9 + random2avg(23, 2), 0, KILLED_BY_WILD_MAGIC, cause); + you_msg = "You are caught in a strong localised spatial " + "distortion."; + mon_msg_seen = "@The_monster@ is caught in a strong localised " + "spatial distortion."; + mon_msg_unseen = "A piece of empty space twists and writhes."; + _ouch(9 + random2avg(23, 2)); break; case 3: case 4: - mpr("Space warps around you!"); + you_msg = "Space warps around you!"; + mon_msg_seen = "Space warps around @the_monster!"; + mon_msg_unseen = "A piece of empty space twists and writhes."; + + _ouch(5 + random2avg(9, 2)); if (one_chance_in(3)) - you_teleport_now( true ); + target->teleport(true); else - random_blink( false ); + target->blink(false); - ouch(5 + random2avg(9, 2), 0, KILLED_BY_WILD_MAGIC, cause); - potion_effect(POT_CONFUSION, 40); + _potion_effect(POT_CONFUSION, 40); break; case 5: { @@ -2558,42 +3139,43 @@ static void _miscast_translocation(int severity, const char* cause) for (int i = 1 + random2(3); i >= 0; --i) { - if (create_monster( - mgen_data::hostile_at(MONS_SPATIAL_VORTEX, - you.pos(), 3, 0, false, god)) != -1) - { + if (_create_monster(MONS_SPATIAL_VORTEX, 3)) success = true; - } } if (success) - mpr("Space twists in upon itself!"); - else - canned_msg(MSG_NOTHING_HAPPENS); + all_msg = "Space twists in upon itself!"; break; } case 6: - _send_abyss(cause); + send_abyss(); break; } break; case 3: // much less harmless - switch (random2(4)) + // Don't use the last case for monsters. + switch (random2(target->atype() == ACT_PLAYER ? 4 : 3)) { case 0: - mpr("You are caught in an extremely strong localised spatial distortion!"); - ouch(15 + random2avg(29, 2), 0, KILLED_BY_WILD_MAGIC, cause); + you_msg = "You are caught in an extremely strong localised " + "spatial distortion!"; + mon_msg_seen = "@The_monster@ is caught in an extremely strong " + "localised spatial distortion!"; + mon_msg_unseen = "A rift temporarily opens in the fabric of space!"; + _ouch(15 + random2avg(29, 2)); break; case 1: - mpr("Space warps crazily around you!"); - you_teleport_now( true ); + you_msg = "Space warps crazily around you!"; + mon_msg_seen = "Space warps crazily around @the_monster@!"; + mon_msg_unseen = "A rift temporarily opens in the fabric of space!"; - ouch(9 + random2avg(17, 2), 0, KILLED_BY_WILD_MAGIC, cause); + _ouch(9 + random2avg(17, 2)); + you_teleport_now( true ); potion_effect(POT_CONFUSION, 60); break; case 2: - _send_abyss(cause); + send_abyss(); break; case 3: mpr("You feel saturated with unharnessed energies!"); @@ -2604,51 +3186,68 @@ static void _miscast_translocation(int severity, const char* cause) } } -static void _miscast_summoning(int severity, const char* cause) +void MiscastEffect::_summoning(int severity) { - const god_type god = - (crawl_state.is_god_acting()) ? crawl_state.which_god_acting() - : GOD_NO_GOD; - switch (severity) { case 0: // harmless messages only switch (random2(10)) { case 0: - mpr("Shadowy shapes form in the air around you, then vanish."); + you_msg = "Shadowy shapes form in the air around you, " + "then vanish."; + mon_msg_seen = "Shadowy shapes form in the air around " + "@the_monster@, then vanish."; break; case 1: - if (!silenced(you.pos())) - mpr("You hear strange voices.", MSGCH_SOUND); - else - mpr("You feel momentarily dizzy."); + if (neither_end_silenced()) + { + all_msg = "You hear strange voices."; + msg_ch = MSGCH_SOUND; + } + else if (target->atype() == ACT_PLAYER) + you_msg = "You feel momentarily dizzy."; break; case 2: - mpr("Your head hurts."); + you_msg = "Your head hurts."; + // Monster messages needed. break; case 3: - mpr("You feel a strange surge of energy!"); + you_msg = "You feel a strange surge of energy!"; + // Monster messages needed. break; case 4: - mpr("Your brain hurts!"); + you_msg = "Your brain hurts!"; + // Monster messages needed. break; case 5: - mpr("Strange energies run through your body."); + you_msg = "Strange energies run through your body."; + // Monster messages needed. break; case 6: - mpr("The world appears momentarily distorted."); + you_msg = "The world appears momentarily distorted."; + mon_msg_seen = "@The_monster@ appears momentarily distorted."; break; case 7: - mpr("Space warps around you."); + you_msg = "Space warps around you."; + mon_msg_seen = "Space warps around @the_monster@."; break; case 8: - canned_msg(MSG_NOTHING_HAPPENS); + // Set nothing; canned_msg(MSG_NOTHING_HAPPENS) will be taken + // care of elsewhere. break; case 9: - mpr("Distant voices call out to you!"); + if (neither_end_silenced()) + { + you_msg = "Distant voices call out to you!"; + mon_msg_seen = "Distant voices call out to @the_monster@!"; + msg_ch = MSGCH_SOUND; + } + else if (target->atype() == ACT_PLAYER) + you_msg = "You feel watched."; break; } + do_msg(); break; case 1: // a little bad @@ -2657,30 +3256,23 @@ static void _miscast_summoning(int severity, const char* cause) case 0: // identical to translocation case 1: case 2: - mpr("You are caught in a localised spatial distortion."); - ouch(5 + random2avg(9, 2), 0, KILLED_BY_WILD_MAGIC, cause); + you_msg = "You are caught in a localised spatial " + "distortion."; + mon_msg_seen = "@The_monster@ is caught in a localised spatial " + "distortion."; + mon_msg_unseen = "An empty piece of space distorts and twists."; + _ouch(5 + random2avg(9, 2)); break; case 3: - if (create_monster( - mgen_data::hostile_at(MONS_SPATIAL_VORTEX, - you.pos(), 3, 0, false, god)) != -1) - { - mpr("Space twists in upon itself!"); - } - else - canned_msg(MSG_NOTHING_HAPPENS); + if (_create_monster(MONS_SPATIAL_VORTEX, 3)) + all_msg = "Space twists in upon itself!"; + do_msg(); break; case 4: case 5: - if (create_monster( - mgen_data::hostile_at( - summon_any_demon(DEMON_LESSER), - you.pos(), 5, 0, true, god)) != -1) - { - mpr("Something appears in a flash of light!"); - } - else - canned_msg(MSG_NOTHING_HAPPENS); + if (_create_monster(summon_any_demon(DEMON_LESSER), 5, true)) + all_msg = "Something appears in a flash of light!"; + do_msg(); break; } break; @@ -2694,32 +3286,21 @@ static void _miscast_summoning(int severity, const char* cause) for (int i = 1 + random2(3); i >= 0; --i) { - if (create_monster( - mgen_data::hostile_at(MONS_SPATIAL_VORTEX, - you.pos(), 3, 0, false, god)) != -1) - { + if (_create_monster(MONS_SPATIAL_VORTEX, 3)) success = true; - } } if (success) - mpr("Space twists in upon itself!"); - else - canned_msg(MSG_NOTHING_HAPPENS); + all_msg = "Space twists in upon itself!"; + do_msg(); break; } case 1: case 2: - if (create_monster( - mgen_data::hostile_at( - summon_any_demon(DEMON_COMMON), - you.pos(), 5, 0, true, god)) != -1) - { - mpr("Something forms out of thin air!"); - } - else - canned_msg(MSG_NOTHING_HAPPENS); + if (_create_monster(summon_any_demon(DEMON_COMMON), 5, true)) + all_msg = "Something forms from out of thin air!"; + do_msg(); break; case 3: @@ -2730,19 +3311,17 @@ static void _miscast_summoning(int severity, const char* cause) for (int i = 1 + random2(2); i >= 0; --i) { - if (create_monster( - mgen_data::hostile_at( - summon_any_demon(DEMON_LESSER), - you.pos(), 5, 0, true, god)) != -1) - { + if (_create_monster(summon_any_demon(DEMON_LESSER), 5, true)) success = true; - } } - if (success) - mpr("A chorus of chattering voices calls out to you!"); - else - canned_msg(MSG_NOTHING_HAPPENS); + if (success && neither_end_silenced()) + { + you_msg = "A chorus of chattering voices calls out to you!"; + mon_msg = "A chorus of chattering voices calls out!"; + msg_ch = MSGCH_SOUND; + } + do_msg(); break; } } @@ -2752,26 +3331,15 @@ static void _miscast_summoning(int severity, const char* cause) switch (random2(4)) { case 0: - if (create_monster( - mgen_data::hostile_at(MONS_ABOMINATION_SMALL, - you.pos(), 0, 0, true, god)) != -1) - { - mpr("Something forms out of thin air."); - } - else - canned_msg(MSG_NOTHING_HAPPENS); + if (_create_monster(MONS_ABOMINATION_SMALL, 0, true)) + all_msg = "Something forms from out of thin air."; + do_msg(); break; case 1: - if (create_monster( - mgen_data::hostile_at( - summon_any_demon(DEMON_GREATER), - you.pos(), 0, 0, true, god)) != -1) - { - mpr("You sense a hostile presence."); - } - else - canned_msg(MSG_NOTHING_HAPPENS); + if (_create_monster(summon_any_demon(DEMON_GREATER), 0, true)) + all_msg = "You sense a hostile presence."; + do_msg(); break; case 2: @@ -2780,31 +3348,29 @@ static void _miscast_summoning(int severity, const char* cause) for (int i = 1 + random2(2); i >= 0; --i) { - if (create_monster( - mgen_data::hostile_at( - summon_any_demon(DEMON_COMMON), - you.pos(), 3, 0, true, god)) != -1) - { + if (_create_monster(summon_any_demon(DEMON_COMMON), 3, true)) success = true; - } } if (success) - mpr("Something turns its malign attention towards you..."); - else - canned_msg(MSG_NOTHING_HAPPENS); + { + you_msg = "Something turns its malign attention towards " + "you..."; + mon_msg = "You sense a malign presence."; + } + do_msg(); break; } case 3: - _send_abyss(cause); + send_abyss(); break; } break; } } -static void _miscast_divination(int severity, const char* cause) +void MiscastEffect::_divination_you(int severity) { switch (severity) { @@ -2912,9 +3478,14 @@ static void _miscast_divination(int severity, const char* cause) } } -static void _miscast_necromancy(int severity, const char* cause) +// XXX: Monster divination miscasts. +void MiscastEffect::_divination_mon(int severity) +{ +} + +void MiscastEffect::_necromancy(int severity) { - if (you.religion == GOD_KIKUBAAQUDGHA + if (target->atype() == ACT_PLAYER && you.religion == GOD_KIKUBAAQUDGHA && !player_under_penance() && you.piety >= piety_breakpoint(1) && x_chance_in_y(you.piety, 150)) { @@ -2922,10 +3493,6 @@ static void _miscast_necromancy(int severity, const char* cause) return; } - const god_type god = - (crawl_state.is_god_acting()) ? crawl_state.which_god_acting() - : GOD_NO_GOD; - switch (severity) { case 0: @@ -2933,41 +3500,50 @@ static void _miscast_necromancy(int severity, const char* cause) { case 0: if (player_can_smell()) - mpr("You smell decay."); + all_msg = "You smell decay."; else if (you.species == SP_MUMMY) - mpr("Your bandages flutter."); - else - canned_msg(MSG_NOTHING_HAPPENS); + you_msg = "Your bandages flutter."; break; case 1: - if (!silenced(you.pos())) - mpr("You hear strange and distant voices.", MSGCH_SOUND); - else - mpr("You feel homesick."); + if (neither_end_silenced()) + { + all_msg = "You hear strange and distant voices."; + msg_ch = MSGCH_SOUND; + } + else if (target->atype() == ACT_PLAYER) + you_msg = "You feel homesick."; break; case 2: - mpr("Pain shoots through your body."); + you_msg = "Pain shoots through your body."; + // Monster messages needed. break; case 3: - mpr("Your bones ache."); + you_msg = "Your bones ache."; + // Monster messages needed. break; case 4: - mpr("The world around you seems to dim momentarily."); + you_msg = "The world around you seems to dim momentarily."; + mon_msg_seen = "@The_monster@ seems to dim momentarily."; break; case 5: - mpr("Strange energies run through your body."); + you_msg = "Strange energies run through your body."; + // Monster messages needed. break; case 6: - mpr("You shiver with cold."); + you_msg = "You shiver with cold."; + // Monster messages needed. break; case 7: - mpr("You sense a malignant aura."); + you_msg = "You sense a malignant aura."; + // Monster messages needed. break; case 8: - canned_msg(MSG_NOTHING_HAPPENS); + // Set nothing; canned_msg(MSG_NOTHING_HAPPENS) will be taken + // care of elsewhere. break; case 9: - mpr("You feel very uncomfortable."); + you_msg = "You feel very uncomfortable."; + // Monster messages needed. break; } break; @@ -2976,29 +3552,37 @@ static void _miscast_necromancy(int severity, const char* cause) switch (random2(3)) { case 0: - if (player_res_torment()) + // Monster messages needed. + if (target->res_torment()) { - mpr("You feel weird for a moment."); + you_msg = "You feel weird for a moment."; + do_msg(); break; } - mpr("Pain shoots through your body!"); - ouch(5 + random2avg(15, 2), 0, KILLED_BY_WILD_MAGIC, cause); + you_msg = "Pain shoots through your body!"; + _ouch(5 + random2avg(15, 2)); break; case 1: - mpr("You feel horribly lethargic."); - potion_effect(POT_SLOWING, 15); + you_msg = "You feel horribly lethargic."; + // Monster messages needed. + _potion_effect(POT_SLOWING, 15); break; case 2: // josh declares mummies cannot smell {dlb} - if (player_can_smell() && you.res_rotting() == 0) + if (target->res_rotting() == 0) { - mpr("You smell decay."); // identical to a harmless message - you.rotting++; + if (player_can_smell()) + // identical to a harmless message + all_msg = "You smell decay."; + if (target->atype() == ACT_PLAYER) + you.rotting++; + else + mon_target->add_ench( mon_enchant(ENCH_ROT, 1, kc) ); } else if (you.species == SP_MUMMY) - mpr("Your bandages flutter."); - else - canned_msg(MSG_NOTHING_HAPPENS); + // Monster messages needed. + you_msg = "Your bandages flutter."; + do_msg(); break; } break; @@ -3012,97 +3596,100 @@ static void _miscast_necromancy(int severity, const char* cause) for (int i = random2(3); i >= 0; --i) { - if (create_monster( - mgen_data::hostile_at(MONS_SHADOW, - you.pos(), 2, 0, true, god)) != -1) - { + if (_create_monster(MONS_SHADOW, 2, true)) success = true; - } } if (success) - mpr("Flickering shadows surround you."); - else - canned_msg(MSG_NOTHING_HAPPENS); + { + you_msg = "Flickering shadows surround you."; + mon_msg_seen = "Flickering shadows surround @the_monster@."; + mon_msg_unseen = "Shadows flicker in the thin air."; + } + do_msg(); break; } case 1: - if (!player_prot_life() && one_chance_in(3)) + if (target->atype() == ACT_PLAYER && !player_prot_life() + && one_chance_in(3)) { drain_exp(); break; } // otherwise it just flows through... case 2: - if (player_res_torment()) + // Monster messages needed. + if (target->res_torment()) { - mpr("You feel weird for a moment."); + you_msg = "You feel weird for a moment."; + do_msg(); break; } - mpr("You convulse helplessly as pain tears through your body!"); - ouch(15 + random2avg(23, 2), 0, KILLED_BY_WILD_MAGIC, cause); + you_msg = "You convulse helplessly as pain tears through " + "your body!"; + _ouch(15 + random2avg(23, 2)); break; } break; case 3: // even nastier - switch (random2(6)) + // Don't use two last cases for monsters. + switch (random2(target->atype() == ACT_PLAYER ? 6 : 4)) { case 0: - if (you.is_undead) + if (target->holiness() == MH_UNDEAD) { - mpr("Something just walked over your grave. No, really!"); + // Monster messages needed. + you_msg = "Something just walked over your grave. No, really!"; + do_msg(); break; } - torment_monsters(you.pos(), 0, TORMENT_GENERIC); + torment_monsters(target->pos(), 0, TORMENT_GENERIC); break; case 1: - mpr("You are engulfed in negative energy!"); - - if (!player_prot_life()) - { - drain_exp(); - break; - } // otherwise it just flows through... + target->rot(act_source, random2avg(7, 2) + 1, 0); + break; case 2: - lose_stat(STAT_RANDOM, 1 + random2avg(7, 2), false, cause); + if (_create_monster(MONS_SOUL_EATER, 4, true)) + { + // Monster messages needed. + you_msg = "Something reaches out for you..."; + } + do_msg(); break; case 3: - rot_player( random2avg(7, 2) + 1 ); + if (_create_monster(MONS_REAPER, 4, true)) + { + // Monster messages needed. + you_msg = "Death has come for you..."; + } + do_msg(); break; case 4: - if (create_monster( - mgen_data::hostile_at(MONS_SOUL_EATER, - you.pos(), 4, 0, true, god)) != -1) + mpr("You are engulfed in negative energy!"); + + if (!player_prot_life()) { - mpr("Something reaches out for you..."); - } - else - canned_msg(MSG_NOTHING_HAPPENS); - break; + drain_exp(); + break; + } // otherwise it just flows through... case 5: - if (create_monster( - mgen_data::hostile_at(MONS_REAPER, - you.pos(), 4, 0, true, god)) != -1) - { - mpr("Death has come for you..."); - } - else - canned_msg(MSG_NOTHING_HAPPENS); + lose_stat(STAT_RANDOM, 1 + random2avg(7, 2), false, cause); break; + } break; } } -static void _miscast_transmigration(int severity, const char* cause) +void MiscastEffect::_transmigration(int severity) { switch (severity) { @@ -3110,50 +3697,60 @@ static void _miscast_transmigration(int severity, const char* cause) switch (random2(10)) { case 0: - msg::stream << "Your " << your_hand(true) - << " glow momentarily." << std::endl; + _your_hands_glow(target, you_msg, mon_msg_seen); break; case 1: - mpr("The air around you crackles with energy!"); + you_msg = "The air around you crackles with energy!"; + mon_msg_seen = "The air around @the_monster@ crackles with" + " energy!"; + mon_msg_unseen = "The thin air crackles with energy!"; break; case 2: - mpr("Multicolored lights dance before your eyes!"); + you_msg = "Multicolored lights dance before your eyes!"; + // Monster messages needed. break; case 3: - mpr("You feel a strange surge of energy!"); + you_msg = "You feel a strange surge of energy!"; + // Monster messages needed. break; case 4: - mpr("Waves of light ripple over your body."); + you_msg = "Waves of light ripple over your body."; + mon_msg_seen = "Waves of light ripple over @the_monster@'s body."; + mon_msg_unseen = "Waves of light ripple in the air."; break; case 5: - mpr("Strange energies run through your body."); + you_msg = "Strange energies run through your body."; + // Monster messages needed. break; case 6: - mpr("Your skin tingles."); + you_msg = "Your skin tingles."; + // Monster messages needed. break; case 7: - mpr("Your skin glows momentarily."); + you_msg = "Your skin glows momentarily."; + mon_msg_seen = "@The_monster@'s body glows momentarily."; break; case 8: - canned_msg(MSG_NOTHING_HAPPENS); + // Set nothing; canned_msg(MSG_NOTHING_HAPPENS) will be taken + // care of elsewhere. break; case 9: if (player_can_smell()) - mpr("You smell something strange."); + all_msg = "You smell something strange."; else if (you.species == SP_MUMMY) - mpr("Your bandages flutter."); - else - canned_msg(MSG_NOTHING_HAPPENS); + you_msg = "Your bandages flutter."; break; } + do_msg(); break; case 1: // slightly annoying switch (random2(2)) { case 0: - mpr("Your body is twisted painfully."); - ouch(1 + random2avg(11, 2), 0, KILLED_BY_WILD_MAGIC, cause); + you_msg = "Your body is twisted painfully."; + mon_msg_seen = "@The_monster@'s body twists unnaturally."; + _ouch(1 + random2avg(11, 2)); break; case 1: random_uselessness(); @@ -3162,123 +3759,147 @@ static void _miscast_transmigration(int severity, const char* cause) break; case 2: // much more annoying - switch (random2(4)) + // Last case for players only. + switch (random2(target->atype() == ACT_PLAYER ? 4 : 3)) { case 0: - mpr("Your body is twisted very painfully!"); - ouch(3 + random2avg(23, 2), 0, KILLED_BY_WILD_MAGIC, cause); + you_msg = "Your body is twisted very painfully!"; + mon_msg_seen = "@The_monster@'s body twists and writhes."; + _ouch(3 + random2avg(23, 2)); break; case 1: - mpr("You feel saturated with unharnessed energies!"); - you.magic_contamination += random2avg(19,3); + _potion_effect(POT_PARALYSIS, 10); break; case 2: - potion_effect(POT_PARALYSIS, 10); + _potion_effect(POT_CONFUSION, 10); break; case 3: - potion_effect(POT_CONFUSION, 10); + mpr("You feel saturated with unharnessed energies!"); + you.magic_contamination += random2avg(19,3); break; } break; case 3: // even nastier + if (target->atype() == ACT_MONSTER) + target->mutate(); // Polymorph the monster, if possible. switch (random2(3)) { case 0: - mpr("Your body is flooded with distortional energies!"); - you.magic_contamination += random2avg(35, 3); + if (target->atype() == ACT_PLAYER) + { + mpr("Your body is flooded with distortional energies!"); + you.magic_contamination += random2avg(35, 3); + } - ouch(3 + random2avg(18, 2), 0, KILLED_BY_WILD_MAGIC, cause); + _ouch(3 + random2avg(18, 2)); break; case 1: - mpr("You feel very strange."); - delete_mutation(RANDOM_MUTATION); - ouch(5 + random2avg(23, 2), 0, KILLED_BY_WILD_MAGIC, cause); + if (target->atype() == ACT_PLAYER) + { + mpr("You feel very strange."); + delete_mutation(RANDOM_MUTATION); + } + _ouch(5 + random2avg(23, 2)); break; case 2: - mpr("Your body is distorted in a weirdly horrible way!"); + if (target->atype() == ACT_PLAYER) { + mpr("Your body is distorted in a weirdly horrible way!"); const bool failMsg = !give_bad_mutation(); if (coinflip()) give_bad_mutation(failMsg); - ouch(5 + random2avg(23, 2), 0, KILLED_BY_WILD_MAGIC, cause); } + _ouch(5 + random2avg(23, 2)); break; } break; } } -static void _miscast_fire(int severity, const char* cause) +void MiscastEffect::_fire(int severity) { - bolt beam; switch (severity) { case 0: // just a harmless message switch (random2(10)) { case 0: - msg::stream << "Sparks fly from your " << your_hand(true) - << '!' << std::endl; + you_msg = "Sparks fly from your @hands@!"; + mon_msg_seen = "Sparks fly from @the_monster@'s @hands@!"; break; case 1: - mpr("The air around you burns with energy!"); + you_msg = "The air around you burns with energy!"; + mon_msg_seen = "The air around @the_monster@ burns with energy!"; break; case 2: - msg::stream << "Wisps of smoke drift from your " - << your_hand(true) << '.' << std::endl; + you_msg = "Wisps of smoke drift from your @hands@."; + mon_msg_seen = "Wisps of smoke drift from @the_monster@'s @hands@."; break; case 3: - mpr("You feel a strange surge of energy!"); + you_msg = "You feel a strange surge of energy!"; + // Monster messages needed. break; case 4: if (player_can_smell()) - mpr("You smell smoke."); + all_msg = "You smell smoke."; else if (you.species == SP_MUMMY) - mpr("Your bandages flutter."); - else - canned_msg(MSG_NOTHING_HAPPENS); + you_msg = "Your bandages flutter."; break; case 5: - mpr("Heat runs through your body."); + you_msg = "Heat runs through your body."; + // Monster messages needed. break; case 6: - mpr("You feel uncomfortably hot."); + you_msg = "You feel uncomfortably hot."; + // Monster messages needed. break; case 7: - mpr("Lukewarm flames ripple over your body."); + you_msg = "Lukewarm flames ripple over your body."; + mon_msg_seen = "Dim flames ripple over @the_monster@'s body."; break; case 8: - canned_msg(MSG_NOTHING_HAPPENS); + // Set nothing; canned_msg(MSG_NOTHING_HAPPENS) will be taken + // care of elsewhere. break; case 9: - if (!silenced(you.pos())) - mpr("You hear a sizzling sound.", MSGCH_SOUND); - else - mpr("You feel like you have heartburn."); + if (neither_end_silenced()) + { + all_msg = "You hear a sizzling sound."; + msg_ch = MSGCH_SOUND; + } + else if (target->atype() == ACT_PLAYER) + you_msg = "You feel like you have heartburn."; break; } + do_msg(); break; case 1: // a bit less harmless stuff switch (random2(2)) { case 0: - msg::stream << "Smoke pours from your " - << your_hand(true) << "!" << std::endl; - big_cloud( random_smoke_type(), (cause ? KC_OTHER : KC_YOU), - you.x_pos, you.y_pos, 20, 7 + random2(7) ); + you_msg = "Smoke pours from your @hands@!"; + mon_msg_seen = "Smoke pours from @the_monster@'s @hands@!"; + mon_msg_unseen = "Smoke appears out of nowhere!"; + + do_msg(); + big_cloud( random_smoke_type(), kc, kt, + target->pos().x, target->pos().y, 20, 7 + random2(7) ); break; case 1: - mpr("Flames sear your flesh."); - expose_player_to_element(BEAM_FIRE, 3); + you_msg = "Flames sear your flesh."; + mon_msg_seen = "Flames sear @the_monster@."; - if (player_res_fire() < 0) - ouch(2 + random2avg(13, 2), 0, KILLED_BY_WILD_MAGIC, cause); + if (target->res_fire() < 0) + _ouch(2 + random2avg(13, 2)); + else + do_msg(); + target->expose_to_element(BEAM_FIRE, 3); break; } @@ -3288,31 +3909,25 @@ static void _miscast_fire(int severity, const char* cause) switch (random2(2)) { case 0: - mpr("You are blasted with fire."); - - ouch( check_your_resists( 5 + random2avg(29, 2), BEAM_FIRE ), 0, - KILLED_BY_WILD_MAGIC, cause ); + you_msg = "You are blasted with fire."; + mon_msg_seen = "@The_monster@ is blasted with fire."; + mon_msg_unseen = "A flame briefly burns in thin air."; - expose_player_to_element(BEAM_FIRE, 5); + _ouch(5 + random2avg(29, 2), BEAM_FIRE ); + target->expose_to_element(BEAM_FIRE, 5); break; case 1: - mpr("You are caught in a fiery explosion!"); - beam.type = dchar_glyph(DCHAR_FIRED_BURST); - beam.damage = dice_def( 3, 14 ); + you_msg = "You are caught in a fiery explosion!"; + mon_msg_seen = "@The_monster@ is caught in a fiery explosion!"; + mon_msg_unseen = "Fire explodes from out of thin air!"; + + beam.type = dchar_glyph(DCHAR_FIRED_BURST); + beam.damage = dice_def( 3, 14 ); beam.flavour = BEAM_FIRE; - beam.target_x = you.x_pos; - beam.target_y = you.y_pos; - beam.name = "explosion"; - beam.colour = RED; - beam.beam_source = NON_MONSTER; - beam.thrower = (cause) ? KILL_MISC : KILL_YOU; - beam.aux_source.clear(); - if (cause) - beam.aux_source = cause; - beam.ex_size = 1; - beam.is_explosion = true; - explosion(beam); + beam.name = "explosion"; + beam.colour = RED; + _explosion(); break; } break; @@ -3321,85 +3936,100 @@ static void _miscast_fire(int severity, const char* cause) switch (random2(3)) { case 0: - mpr("You are blasted with searing flames!"); + you_msg = "You are blasted with searing flames!"; + mon_msg_seen = "@The_monster@ is blasted with searing flames!"; + mon_msg_unseen = "A large flame burns hotly for a moment in the " + "thin air."; - ouch( check_your_resists( 9 + random2avg(33, 2), BEAM_FIRE ), 0, - KILLED_BY_WILD_MAGIC, cause ); + _ouch(9 + random2avg(33, 2), BEAM_FIRE); - expose_player_to_element(BEAM_FIRE, 10); + target->expose_to_element(BEAM_FIRE, 10); break; case 1: - mpr("There is a sudden and violent explosion of flames!"); - beam.type = dchar_glyph(DCHAR_FIRED_BURST); - beam.damage = dice_def( 3, 20 ); + all_msg = "There is a sudden and violent explosion of flames!"; + + beam.type = dchar_glyph(DCHAR_FIRED_BURST); + beam.damage = dice_def( 3, 20 ); beam.flavour = BEAM_FIRE; - beam.target_x = you.x_pos; - beam.target_y = you.y_pos; - beam.name = "fireball"; - beam.colour = RED; - beam.beam_source = NON_MONSTER; - beam.thrower = (cause) ? KILL_MISC : KILL_YOU; - beam.aux_source.clear(); - if (cause) - beam.aux_source = cause; + beam.name = "fireball"; + beam.colour = RED; beam.ex_size = coinflip()?1:2; - beam.is_explosion = true; - explosion(beam); + _explosion(); break; case 2: - mpr("You are covered in liquid flames!"); - you.duration[DUR_LIQUID_FLAMES] += random2avg(7, 3) + 1; + { + you_msg = "You are covered in liquid flames!"; + mon_msg_seen = "@The_monster@ is covered in liquid flames!"; + do_msg(); + + int dur = random2avg(7, 3) + 1; + if (target->atype() == ACT_PLAYER) + you.duration[DUR_LIQUID_FLAMES] += dur; + else + mon_target->add_ench( mon_enchant(ENCH_STICKY_FLAME, dur, kc) ); break; + } } break; } } -static void _miscast_ice(int severity, const char* cause) +void MiscastEffect::_ice(int severity) { - bolt beam; switch (severity) { case 0: // just a harmless message switch (random2(10)) { case 0: - mpr("You shiver with cold."); + you_msg = "You shiver with cold."; + // Monster messages needed. break; case 1: - mpr("A chill runs through your body."); + you_msg = "A chill runs through your body."; + // Monster messages needed. break; case 2: - msg::stream << "Wisps of condensation drift from your " - << your_hand(true) << "." << std::endl; + you_msg = "Wisps of condensation drift from your @hands@."; + mon_msg_seen = "Wisps of condensation drift from @the_monster@'s " + "@hands@."; break; case 3: - mpr("You feel a strange surge of energy!"); + you_msg = "You feel a strange surge of energy!"; + // Monster messages needed. break; case 4: - msg::stream << "Your " << your_hand(true) - << " feel numb with cold." << std::endl; + you_msg = "Your @hands@ feel numb with cold."; + // Monster messages needed. break; case 5: - mpr("A chill runs through your body."); + you_msg = "A chill runs through your body."; + // Monster messages needed. break; case 6: - mpr("You feel uncomfortably cold."); + you_msg = "You feel uncomfortably cold."; + // Monster messages needed. break; case 7: - mpr("Frost covers your body."); + you_msg = "Frost covers your body."; + mon_msg_seen = "Frost covers @the_monster@'s body."; break; case 8: - canned_msg(MSG_NOTHING_HAPPENS); + // Set nothing; canned_msg(MSG_NOTHING_HAPPENS) will be taken + // care of elsewhere. break; case 9: - if (!silenced(you.pos())) - mpr("You hear a crackling sound.", MSGCH_SOUND); - else - mpr("A snowflake lands on your nose."); + if (neither_end_silenced()) + { + all_msg = "You hear a crackling sound."; + msg_ch = MSGCH_SOUND; + } + else if (target->atype() == ACT_PLAYER) + you_msg = "A snowflake lands on your nose."; break; } + do_msg(); break; case 1: // a bit less harmless stuff @@ -3407,13 +4037,17 @@ static void _miscast_ice(int severity, const char* cause) { case 0: mpr("You feel extremely cold."); + // Monster messages needed. break; case 1: - mpr("You are covered in a thin layer of ice."); - expose_player_to_element(BEAM_COLD, 2); + you_msg = "You are covered in a thin layer of ice."; + mon_msg_seen = "@The_monster@ is covered in a thin layer of ice."; - if (player_res_cold() < 0) - ouch(4 + random2avg(5, 2), 0, KILLED_BY_WILD_MAGIC, cause); + if (target->res_cold() < 0) + _ouch(4 + random2avg(5, 2)); + else + do_msg(); + target->expose_to_element(BEAM_COLD, 2); break; } break; @@ -3422,32 +4056,27 @@ static void _miscast_ice(int severity, const char* cause) switch (random2(2)) { case 0: - mpr("Heat is drained from your body."); + you_msg = "Heat is drained from your body."; + // Monster messages needed. - ouch(check_your_resists(5 + random2(6) + random2(7), BEAM_COLD), 0, - KILLED_BY_WILD_MAGIC, cause); + _ouch(5 + random2(6) + random2(7), BEAM_COLD); - expose_player_to_element(BEAM_COLD, 4); + target->expose_to_element(BEAM_COLD, 4); break; case 1: - mpr("You are caught in an explosion of ice and frost!"); - beam.type = dchar_glyph(DCHAR_FIRED_BURST); - beam.damage = dice_def( 3, 11 ); + you_msg = "You are caught in an explosion of ice and frost!"; + mon_msg_seen = "@The_monster@ is caught in an explosion of " + "ice and frost!"; + mon_msg_unseen = "Ice and frost explode from out of thin air!"; + + beam.type = dchar_glyph(DCHAR_FIRED_BURST); + beam.damage = dice_def( 3, 11 ); beam.flavour = BEAM_COLD; - beam.target_x = you.x_pos; - beam.target_y = you.y_pos; - beam.name = "explosion"; - beam.colour = WHITE; - beam.beam_source = NON_MONSTER; - beam.thrower = (cause) ? KILL_MISC : KILL_YOU; - beam.aux_source.clear(); - if (cause) - beam.aux_source = cause; - beam.ex_size = 1; - beam.is_explosion = true; + beam.name = "explosion"; + beam.colour = WHITE; - explosion(beam); + _explosion(); break; } break; @@ -3456,27 +4085,29 @@ static void _miscast_ice(int severity, const char* cause) switch (random2(2)) { case 0: - mpr("You are blasted with ice!"); + you_msg = "You are blasted with ice!"; + mon_msg_seen = "@The_monster@ is blasted with ice!"; - ouch(check_your_resists(9 + random2avg(23, 2), BEAM_ICE), 0, - KILLED_BY_WILD_MAGIC, cause); + _ouch(9 + random2avg(23, 2), BEAM_ICE); - expose_player_to_element(BEAM_COLD, 9); + target->expose_to_element(BEAM_COLD, 9); break; case 1: - msg::stream << "Freezing gasses pour from your " - << your_hand(true) << "!" << std::endl; - big_cloud(CLOUD_COLD, (cause ? KC_OTHER : KC_YOU), - you.x_pos, you.y_pos, 20, 8 + random2(4)); + you_msg = "Freezing gasses pour from your @hands@!"; + mon_msg_seen = "Freezing gasses pour from @the_monsters@'s " + " @hands@!"; + + do_msg(); + big_cloud(CLOUD_COLD, kc, kt, + target->pos().x, target->pos().y, 20, 8 + random2(4)); break; } break; } } -static void _miscast_earth(int severity, const char* cause) +void MiscastEffect::_earth(int severity) { - bolt beam; switch (severity) { case 0: // just a harmless message @@ -3484,50 +4115,62 @@ static void _miscast_earth(int severity, const char* cause) switch (random2(10)) { case 0: - mpr("You feel earthy."); + you_msg = "You feel earthy."; + // Monster messages needed. break; case 1: - mpr("You are showered with tiny particles of grit."); + you_msg = "You are showered with tiny particles of grit."; + mon_msg_seen = "@The_monster@ is showered with tiny particles " + "of grit."; break; case 2: - msg::stream << "Sand pours from your " - << your_hand(true) << "." << std::endl; + you_msg = "Sand pours from your @hands@."; + mon_msg_seen = "Sand pours from @the_monster@'s @hands@."; break; case 3: - mpr("You feel a surge of energy from the ground."); + you_msg = "You feel a surge of energy from the ground."; + // Monster messages needed. break; case 4: - if (!silenced(you.pos())) - mpr("You hear a distant rumble.", MSGCH_SOUND); - else - mpr("You sympathise with the stones."); + if (neither_end_silenced()) + { + all_msg = "You hear a distant rumble."; + msg_ch = MSGCH_SOUND; + } + else if (target->atype() == ACT_PLAYER) + you_msg = "You sympathise with the stones."; break; case 5: - mpr("You feel gritty."); + you_msg = "You feel gritty."; + // Monster messages needed. break; case 6: - mpr("You feel momentarily lethargic."); + you_msg = "You feel momentarily lethargic."; + // Monster messages needed. break; case 7: - mpr("Motes of dust swirl before your eyes."); + you_msg = "Motes of dust swirl before your eyes."; + // Monster messages needed. break; case 8: - canned_msg(MSG_NOTHING_HAPPENS); + // Set nothing; canned_msg(MSG_NOTHING_HAPPENS) will be taken + // care of elsewhere. break; case 9: - mprf("Your %s warm.", - (you.attribute[ATTR_TRANSFORMATION] == TRAN_AIR) - ? "lowest portion feels" : - (!transform_changed_physiology() ? - (player_mutation_level(MUT_HOOVES)) ? "hooves feel" : - (player_mutation_level(MUT_TALONS)) ? "talons feel" : - (you.species == SP_NAGA) ? "underbelly feels" : - (you.species == SP_MERFOLK - && player_is_swimming()) ? "tail feels" - : "feet feel" - : "feet feel")); + { + bool pluralized = true; + std::string feet = you.foot_name(true, &pluralized); + std::ostringstream str; + + str << "Your " << feet << (pluralized ? " feel" : " feels") + << " warm"; + + you_msg = str.str(); + // Monster messages needed. break; } + } + do_msg(); break; case 2: // slightly less harmless stuff @@ -3537,17 +4180,23 @@ static void _miscast_earth(int severity, const char* cause) switch (random2(3)) { case 0: - mpr("You are hit by flying rocks!"); + you_msg = "You are hit by flying rocks!"; + mon_msg_seen = "@The_monster@ is hit by flying rocks!"; + mon_msg_unseen = "Flying rocks appear out of thin air!"; break; case 1: - mpr("You are blasted with sand!"); + you_msg = "You are blasted with sand!"; + mon_msg_seen = "@The_monster@ is blasted with sand!"; + mon_msg_unseen = "A minature sandstorm briefly appears!"; break; case 2: - mpr("Rocks fall onto you out of nowhere!"); + you_msg = "Rocks fall onto you out of nowhere!"; + mon_msg_seen = "Rocks fall onto @the_monster@ out of " + "nowhere!"; + mon_msg_unseen = "Rocks fall out of nowhere!"; break; } - ouch( random2avg(13,2) + 10 - random2(1 + player_AC()), - 0, KILLED_BY_WILD_MAGIC, cause); + _ouch(random2avg(13,2) + 10 - random2(1 + target->armour_class())); break; } break; @@ -3556,12 +4205,14 @@ static void _miscast_earth(int severity, const char* cause) switch (random2(1)) { case 0: - mpr("You are caught in an explosion of flying shrapnel!"); + you_msg = "You are caught in an explosion of flying " + "shrapnel!"; + mon_msg_seen = "@The_monster@ is caught in an explosion of " + "flying shrapnel!"; + mon_msg_unseen = "Flying shrapnel explodes from the thin air!"; beam.type = dchar_glyph(DCHAR_FIRED_BURST); beam.damage = dice_def( 3, 15 ); beam.flavour = BEAM_FRAG; - beam.target_x = you.x_pos; - beam.target_y = you.y_pos; beam.name = "explosion"; beam.colour = CYAN; @@ -3570,141 +4221,170 @@ static void _miscast_earth(int severity, const char* cause) if (one_chance_in(5)) beam.colour = LIGHTCYAN; - beam.beam_source = NON_MONSTER; - beam.thrower = (cause) ? KILL_MISC : KILL_YOU; - beam.aux_source.clear(); - if (cause) - beam.aux_source = cause; - beam.ex_size = 1; - beam.is_explosion = true; - - explosion(beam); + _explosion(); break; } break; } } -static void _miscast_air(int severity, const char* cause) +void MiscastEffect::_air(int severity) { - bolt beam; switch (severity) { case 0: // just a harmless message switch (random2(10)) { case 0: - mpr("Ouch! You gave yourself an electric shock."); + you_msg = "Ouch! You gave yourself an electric shock."; + // Monster messages needed. break; case 1: - mpr("You feel momentarily weightless."); + you_msg = "You feel momentarily weightless."; + // Monster messages needed. break; case 2: - msg::stream << "Wisps of vapour drift from your " - << your_hand(true) << "." << std::endl; + you_msg = "Wisps of vapour drift from your @hands@."; + mon_msg_seen = "Wisps of vapour drift from @the_monster@'s " + "@hands@."; break; case 3: - mpr("You feel a strange surge of energy!"); + you_msg = "You feel a strange surge of energy!"; + // Monster messages needed. break; case 4: - mpr("You feel electric!"); + you_msg = "You feel electric!"; + // Monster messages needed. break; case 5: - msg::stream << "Sparks of electricity dance between your " - << your_hand(true) << "." << std::endl; + { + bool pluralized = true; + target->hand_name(true, &pluralized); + + if (pluralized) + { + you_msg = "Sparks of electricity dance between your " + "@hands@."; + mon_msg_seen = "Sparks of electricity dance between " + "@the_monster@'s @hands@."; + } + else + { + you_msg = "Sparks of electricity dance over your " + "@hand@."; + mon_msg_seen = "Sparks of electricity dance over " + "@the_monster@'s @hand@."; + } break; + } case 6: - mpr("You are blasted with air!"); + you_msg = "You are blasted with air!"; + // Monster messages needed. break; case 7: - if (!silenced(you.pos())) - mpr("You hear a whooshing sound.", MSGCH_SOUND); + if (neither_end_silenced()) + { + all_msg = "You hear a whooshing sound."; + msg_ch = MSGCH_SOUND; + } else if (player_can_smell()) - mpr("You smell ozone."); + all_msg = "You smell ozone."; else if (you.species == SP_MUMMY) - mpr("Your bandages flutter."); - else - canned_msg(MSG_NOTHING_HAPPENS); + you_msg = "Your bandages flutter."; break; case 8: - canned_msg(MSG_NOTHING_HAPPENS); + // Set nothing; canned_msg(MSG_NOTHING_HAPPENS) will be taken + // care of elsewhere. break; case 9: - if (!silenced(you.pos())) - mpr("You hear a crackling sound.", MSGCH_SOUND); + if (neither_end_silenced()) + { + all_msg = "You hear a crackling sound."; + msg_ch = MSGCH_SOUND; + } else if (player_can_smell()) - mpr("You smell something musty."); + all_msg = "You smell something musty."; else if (you.species == SP_MUMMY) - mpr("Your bandages flutter."); - else - canned_msg(MSG_NOTHING_HAPPENS); + you_msg = "Your bandages flutter."; break; } + do_msg(); break; case 1: // a bit less harmless stuff switch (random2(2)) { case 0: - mpr("There is a short, sharp shower of sparks."); + you_msg = "There is a short, sharp shower of sparks."; + mon_msg_seen = "@The_monster@ is briefly showered in sparks."; break; case 1: - mprf("The wind %s around you!", - silenced(you.pos()) ? "whips" : "howls"); + if (silenced(you.pos())) + all_msg = "The wind whips around you!"; + else + all_msg = "The wind howls around you!"; break; } + do_msg(); break; case 2: // rather less harmless stuff switch (random2(2)) { case 0: - mpr("Electricity courses through your body."); - ouch(check_your_resists(4 + random2avg(9, 2), BEAM_ELECTRICITY), 0, - KILLED_BY_WILD_MAGIC, cause); + you_msg = "Electricity courses through your body."; + // Monster messages needed. + _ouch(4 + random2avg(9, 2), BEAM_ELECTRICITY); break; case 1: - msg::stream << "Noxious gasses pour from your " - << your_hand(true) << "!" << std::endl; - big_cloud(CLOUD_STINK, (cause ? KC_OTHER : KC_YOU), - you.x_pos, you.y_pos, 20, 9 + random2(4)); + you_msg = "Noxious gasses pour from your @hands@!"; + mon_msg_seen = "Noxious gasses pour from @the_monster@'s " + "@hands@!"; + mon_msg_unseen = "Noxious gasses appear from out of thin air!"; + + do_msg(); + big_cloud(CLOUD_STINK, kc, kt, + target->pos().x, target->pos().y, 20, 9 + random2(4)); break; } break; - case 3: // less harmless stuff + case 3: // musch less harmless stuff switch (random2(2)) { case 0: - mpr("You are caught in an explosion of electrical discharges!"); - beam.type = dchar_glyph(DCHAR_FIRED_BURST); - beam.damage = dice_def( 3, 8 ); + you_msg = "You are caught in an explosion of electrical " + "discharges!"; + mon_msg_seen = "@The_monster@ is caught in an explosion of " + "electrical discharges!"; + mon_msg_unseen = "Elecectrical discharges explodes from out of " + "thin air!"; + + beam.type = dchar_glyph(DCHAR_FIRED_BURST); + beam.damage = dice_def( 3, 8 ); beam.flavour = BEAM_ELECTRICITY; - beam.target_x = you.x_pos; - beam.target_y = you.y_pos; - beam.name = "explosion"; - beam.colour = LIGHTBLUE; - beam.beam_source = NON_MONSTER; - beam.thrower = (cause) ? KILL_MISC : KILL_YOU; - beam.aux_source.clear(); - if (cause) - beam.aux_source = cause; + beam.name = "explosion"; + beam.colour = LIGHTBLUE; beam.ex_size = one_chance_in(4)?1:2; - beam.is_explosion = true; - explosion(beam); + _explosion(); break; case 1: - msg::stream << "Venomous gasses pour from your " - << your_hand(true) << "!" << std::endl; - big_cloud( CLOUD_POISON, (cause ? KC_OTHER : KC_YOU), - you.x_pos, you.y_pos, 20, 8 + random2(5) ); + you_msg = "Venomous gasses pour from your @hands@!"; + mon_msg_seen = "Venomous gasses pour from @the_monster@'s " + "@hands@!"; + mon_msg_unseen = "Venomous gasses pour forth from the thin air!"; + + do_msg(); + big_cloud( CLOUD_POISON, kc, kt, + target->pos().x, target->pos().y, 20, 8 + random2(5) ); break; } } } -static void _miscast_poison(int severity, const char* cause) +// XXX MATT +void MiscastEffect::_poison(int severity) { switch (severity) { @@ -3712,83 +4392,101 @@ static void _miscast_poison(int severity, const char* cause) switch (random2(10)) { case 0: - mpr("You feel mildly nauseous."); + you_msg = "You feel mildly nauseous."; + // Monster messages needed. break; case 1: - mpr("You feel slightly ill."); + you_msg = "You feel slightly ill."; + // Monster messages needed. break; case 2: - msg::stream << "Wisps of poison gas drift from your " - << your_hand(true) << "." << std::endl; + you_msg = "Wisps of poison gas drift from your @hands@."; + mon_msg_seen = "Wisps of poison gas drift from @the_monster@'s " + "@hands@."; break; case 3: - mpr("You feel a strange surge of energy!"); + you_msg = "You feel a strange surge of energy!"; + // Monster messages needed. break; case 4: - mpr("You feel faint for a moment."); + you_msg = "You feel faint for a moment."; + // Monster messages needed. break; case 5: - mpr("You feel sick."); + you_msg = "You feel sick."; + // Monster messages needed. break; case 6: - mpr("You feel odd."); + you_msg = "You feel odd."; + // Monster messages needed. break; case 7: - mpr("You feel weak for a moment."); + you_msg = "You feel weak for a moment."; + // Monster messages needed. break; case 8: - canned_msg(MSG_NOTHING_HAPPENS); + // Set nothing; canned_msg(MSG_NOTHING_HAPPENS) will be taken + // care of elsewhere. break; case 9: - if (!silenced(you.pos())) - mpr("You hear a slurping sound.", MSGCH_SOUND); + if (neither_end_silenced()) + { + all_msg = "You hear a slurping sound."; + msg_ch = MSGCH_SOUND; + } else if (you.species != SP_MUMMY) - mpr("You taste almonds."); - else - canned_msg(MSG_NOTHING_HAPPENS); + you_msg = "You taste almonds."; break; } + do_msg(); break; case 1: // a bit less harmless stuff switch (random2(2)) { case 0: - if (player_res_poison()) - canned_msg(MSG_NOTHING_HAPPENS); - else + if (target->res_poison() <= 0) { - mpr("You feel sick."); - poison_player( 2 + random2(3) ); + you_msg = "You feel sick."; + // Monster messages needed. + target->poison( act_source, 2 + random2(3) ); } + do_msg(); break; case 1: - msg::stream << "Noxious gasses pour from your " - << your_hand(true) << "!" << std::endl; - place_cloud(CLOUD_STINK, you.pos(), - 2 + random2(4), (cause ? KC_OTHER : KC_YOU) ); + you_msg = "Noxious gasses pour from your @hands@!"; + mon_msg_seen = "Noxious gasses pour from @the_monster@'s " + "@hands@!"; + mon_msg_unseen = "Noxious gasses pour forth from the thin air!"; + place_cloud(CLOUD_STINK, target->pos(), 2 + random2(4), kc, kt ); break; } break; case 2: // rather less harmless stuff - switch (random2(3)) + // Don't use last case for monsters. + switch (random2(target->atype() == ACT_PLAYER ? 3 : 2)) { case 0: - if (player_res_poison()) - canned_msg(MSG_NOTHING_HAPPENS); - else + if (target->res_poison() <= 0) { - mpr("You feel very sick."); - poison_player( 3 + random2avg(9, 2) ); + you_msg = "You feel very sick."; + // Monster messages needed. + target->poison( act_source, 3 + random2avg(9, 2) ); } + do_msg(); break; case 1: - mpr("Noxious gasses pour from your hands!"); - big_cloud(CLOUD_STINK, (cause ? KC_OTHER : KC_YOU), - you.x_pos, you.y_pos, 20, 8 + random2(5)); + you_msg = "Noxious gasses pour from your @hands@!"; + mon_msg_seen = "Noxious gasses pour from @the_monster@'s " + "@hands@!"; + mon_msg_unseen = "Noxious gasses pour forth from the thin air!"; + + do_msg(); + big_cloud(CLOUD_STINK, kc, kt, + target->pos().x, target->pos().y, 20, 8 + random2(5)); break; case 2: @@ -3801,22 +4499,26 @@ static void _miscast_poison(int severity, const char* cause) break; case 3: // less harmless stuff - switch (random2(3)) + // Don't use last case for monsters. + switch (random2(target->atype() == ACT_PLAYER ? 3 : 2)) { case 0: - if (player_res_poison()) - canned_msg(MSG_NOTHING_HAPPENS); - else + if (target->res_poison() <= 0) { - mpr("You feel incredibly sick."); - poison_player( 10 + random2avg(19, 2) ); + you_msg = "You feel incredibly sick."; + // Monster messages needed. + target->poison( act_source, 10 + random2avg(19, 2) ); } + do_msg(); break; case 1: - msg::stream << "Venomous gasses pour from your " - << your_hand(true) << "!" << std::endl; - big_cloud(CLOUD_POISON, (cause ? KC_OTHER : KC_YOU), - you.x_pos, you.y_pos, 20, 7 + random2(7)); + you_msg = "Venomous gasses pour from your @hands@!"; + mon_msg_seen = "Venomous gasses pour from @the_monster@'s @hands@!"; + mon_msg_unseen = "Venomous gasses pour forth from the thin air!"; + + do_msg(); + big_cloud(CLOUD_POISON, kc, kt, + target->pos().x, target->pos().y, 20, 7 + random2(7)); break; case 2: if (player_res_poison()) @@ -3829,71 +4531,6 @@ static void _miscast_poison(int severity, const char* cause) } } -// sp_type: The type of the spell. -// mag_pow: The overall power of the spell or effect (i.e. its level). -// mag_fail: The degree to which you failed. -// force_effect: This forces a certain severity of effect to occur. It -// can be disabled by being set to 100. -// -// If a god is making you miscast, any monsters produced will count as -// god gifts. -void miscast_effect(unsigned int sp_type, int mag_pow, int mag_fail, - int force_effect, const char *cause) -{ - if (sp_type == SPTYP_RANDOM) - sp_type = 1 << (random2(SPTYP_LAST_EXPONENT)); - - int sever = (mag_pow*mag_fail*(10+mag_pow)/7 * WILD_MAGIC_NASTINESS)/100; - - if (force_effect == 100 && random2(40) > sever && random2(40) > sever) - { - canned_msg(MSG_NOTHING_HAPPENS); - return; - } - - if (cause == NULL || strlen(cause) == 0) - cause = "spell miscasting"; - - sever /= 100; - -#if DEBUG_DIAGNOSTICS - const int old_fail = sever; -#endif - - sever = random2(sever); - - if (sever > 3) - sever = 3; - else if (sever < 0) - sever = 0; - -#if DEBUG_DIAGNOSTICS - mprf(MSGCH_DIAGNOSTICS, "Sptype: %u, failure1: %d, failure2: %d", - sp_type, old_fail, sever ); -#endif - - if (force_effect != 100) - sever = force_effect; - - switch (sp_type) - { - case SPTYP_CONJURATION: _miscast_conjuration(sever, cause); break; - case SPTYP_ENCHANTMENT: _miscast_enchantment(sever, cause); break; - case SPTYP_TRANSLOCATION: _miscast_translocation(sever, cause); break; - case SPTYP_SUMMONING: _miscast_summoning(sever, cause); break; - case SPTYP_DIVINATION: _miscast_divination(sever, cause); break; - case SPTYP_NECROMANCY: _miscast_necromancy(sever, cause); break; - case SPTYP_TRANSMIGRATION: _miscast_transmigration(sever, cause); break; - case SPTYP_FIRE: _miscast_fire(sever, cause); break; - case SPTYP_ICE: _miscast_ice(sever, cause); break; - case SPTYP_EARTH: _miscast_earth(sever, cause); break; - case SPTYP_AIR: _miscast_air(sever, cause); break; - case SPTYP_POISON: _miscast_poison(sever, cause); break; - } - - xom_is_stimulated(sever); -} - const char* failure_rate_to_string( int fail ) { return |