wizard/priest monsters now make noise, with the loudness depending upon level and spell disciplines: conjuration spells have a loudness equal to their level, spells containing only air and/or poison equal to 50% of their level (rounded up), and everything else to 75% of the level (rounded up). This undoudedtly needs rebalancing, and a better level+disciplines -> loudness formula. Also, each spell can have it's loudness tweaked from the default via the noise_mod field of the spell_desc field in spl-data.h, for those spells whose desired loudness don't quite fit into whatever formula is used.
The messages used to announce a spell have been moved out to source/dat/database/monspell.txt, which uses the same format and conventions as monspeak.txt. So far this has just been used to make invisible wizard/priest monsters give a message to the player if the player can hear them cast, and also to make curse skulls and Murray not "gesture wildly". However, it could be used to give a greater variety of spell announcement messages based upon the spell used or the monster's type/species/genus, and/or to give multi-part messages.
git-svn-id: https://crawl-ref.svn.sourceforge.net/svnroot/crawl-ref/trunk@7820 c06c8d41-db1a-0410-9941-cceddc491573
ZEFGFQHN6J2S6EIPX7EPDG22C5YXTI6DMKQHHRCLWN5MQC44KY3AC SUWIERONPDATHPDMZRYO6GYIXSW6XIS5V5MK5IV23DWQH2LL7VIAC 53BVN4ZHKGUAJE53HM6FC6GKUGXOU5QBUT7CLXV2ONS6S5NPW55AC SVY2PTCLXR3KNPQAWXVXTTGCC5DR334HOAKHYO3VDDRWM2BWMALAC K2CS6TCX2NDVL2ASEHGP4J4K4IJ6FP3ANNKTSIWVG43HPYSBX6ZQC DDU4A3JGN5IUIPP5IASOODKPR2WBHSDSV4FITZ6HNXNSXXQACWAQC PR2XIEELO6UJWT3EXDHWCJZGIZCCF3D6KF6LC67R6RWWAVNWEHWAC NQMXQ6OQVUSC7Y7F7IL252QW4A5JED224EECNHWAM4ZZYVNY745AC 7KVPF74ACO6Q5FXS2YBBJTJT4Y4YN2M3ZNIPXFI3QSQNGNTHD7AAC CHO4U5JC3RNTLXVIDXXJYZMOBZJ4VXW2GVJWDOTBRKK3AJ36LDLQC KHVK7HH7OIYOBZY52WQGGLC2O4SXTWQS2XAHNJZZ7JZ3QTOUTLNAC JI4NDSOXGGZ7QHXXFB3ZTHAKHABXYBZXPDGLUFV5SKYEOL5FT7JQC PMODADA7C3BWOFCPU37626DKMWENG6FAR5I6TOIQU5OBJBUJTSAQC WG6O475IOLZFMUQSLVR2KHM7XTBF5HH276L2KDGF7UOSESDOAILQC 64LQALS66EFDRQUEN3NRAWD2PWE7VMNRSEUTMRKQSEQTS55ZRZXAC 4SWAT5KCKQV527NKELAXFQ5XA4Q5HONQXD4VBXMUZNPVPQKPCPNAC TGJZXTUIAKCFZQJ54ZQEBGFBVZSJCAX6AWDRSH3TP7UJRLGUM5SAC UAJN2CFA2QHYDHW2UFAVPPHDQFCD54RKM6V2UC4AMEDJUBBLNWIQC WLMMF4LM4KVLTRFJCM57UYLN6DS37L6UR7TS6TA3EYDGRCQGOUIAC WQIEW3O4MANA2KKYRUWEZP44KHVJ4RRHEZTDXSF4EDELX66LO26QC 5JS3QSE3EIXSBVI4DATH2EIFD7QN3POAFEUM7MK4NRMPH5JOPAAQC RPOZZWKG5GLPHVZZ7ZKMKS64ZMV2LDCQSARBJFJ6FZOTOKCQO7FAC G2IBQUJ2V2OGM4TR6VKC4CLNVLALTDLB5STOBN7637GOUX2SH4ZAC KAOE5HB3THUKVGFZRO5EZESHEB3Q34WUO5DFMLWIKOBF47LZTIYAC 542UIZKI65UDRNEMGFFDBWYD5XC7AYLTZ3JZQRR2GHYJALD3YY6QC XOYDYIYKWQZIA5ZWV6FS5DCU2PDIANTIJFEAONEJOXHZJRMADBZQC QV6FWOWE22V4GIDHNV5MJ36G5ETDCFBQSHGUHZLKIXQXMFOS35YAC NVSFIV2ZKP44XHCSCXG6OZVGL67OIFINC34J2EMKTA4KULCERUEAC SG76BPJKTQGDFNP5QFMAVR6H72FMMAYCECVGSWWSCLMAVQX7E3FQC 3QLM46S44Z7GDLWPH3VHBMW2RSWZAOLGJMG2BDKNGUOZIM4IX6WAC J6APXOT4QOGQFONWB7G546VTVF6QG42HVOROMHF7YBDJPR4K26OAC AIIVH43Z5X3GTPFY4FXQRZPG6Y7QPH2KJ47VM2Q43PCGGD5MTMOAC S34LKQDIQJLIWVIPASOJBBZ6ZCXDHP5KPS7TRBZJSCDRVNCLK6UAC 3WHI3KM43ZCN4ITJLFQQBQBC4OJPRS7QTBPIQ6QBCUVKRSK476SAC 7C62IQ3PLAE7RLZ2ZNA3G6Z7LPXWAMK2OEHSBNY4WEKJ42BPZYQAC Y56C5OMUQ5XF2G6DKDV4R5MED44UOIUPTBBQVWQBUHYIXYA5MOZAC EJKHYV2Z6UPRVYUAL4WRW33GBNHYBFPMPA57HMBX2LQKXHIUO5VQC struct spell_desc{int id;const char *title;unsigned int disciplines; // bitfieldunsigned int flags; // bitfieldunsigned int level;int power_cap;// At power 0, you get min_range. At power power_cap, you get max_range.int min_range;int max_range;const char *target_prompt;
// If a monster is casting this, does it need a tracer?bool ms_needs_tracer;// The spell can be used no matter what the monster's foe is.bool ms_utility;};
struct spell_desc{int id;const char *title;unsigned int disciplines; // bitfieldunsigned int flags; // bitfieldunsigned int level;int power_cap;// At power 0, you get min_range. At power power_cap, you get max_range.int min_range;int max_range;// How much louder or quieter the spell is than the default.int noise_mod;const char *target_prompt;// If a monster is casting this, does it need a tracer?bool ms_needs_tracer;// The spell can be used no matter what the monster's foe is.bool ms_utility;};
}int spell_noise(spell_type spell){const spell_desc *desc = _seekspell(spell);return desc->noise_mod + spell_noise(desc->disciplines, desc->level);}int spell_noise(unsigned int disciplines, int level){if (disciplines == SPTYP_NONE)return (0);else if (disciplines & SPTYP_CONJURATION)return (level);else if (disciplines && !(disciplines & (SPTYP_POISON | SPTYP_AIR)))return div_round_up(level * 3, 4);elsereturn div_round_up(level, 2);
void mons_cast(monsters *monster, bolt &pbolt, spell_type spell_cast);
void mons_cast(monsters *monster, bolt &pbolt, spell_type spell_cast,bool do_noise = true);void mons_cast_noise(monsters *monster, bolt &pbolt, spell_type spell_cast);
}void mons_cast_noise(monsters *monster, bolt &pbolt, spell_type spell_cast){const bool unseen = !you.can_see(monster);const bool silent = silenced(monster->pos());if (unseen && silent)return;const bool priest = mons_class_flag(monster->type, M_PRIEST);const bool wizard = mons_class_flag(monster->type, M_ACTUAL_SPELLS);const bool innate = !(priest || wizard);int noise;if(silent || innate)noise = 0;elsenoise = spell_noise(spell_cast);const std::string cast_str = " cast";std::string suffix;if (silent)suffix = " silent";else if (unseen)suffix = " unseen";std::string key;// First try the individual spell.key = spell_title(spell_cast) + cast_str;std::string msg = getSpeakString(key + suffix);if (msg.empty() && silent)msg = getSpeakString(key);// Second, try the individual monster.if (msg.empty()){key = mons_type_name(monster->type, DESC_PLAIN);key += cast_str;msg = getSpeakString(key + suffix);if (msg.empty() && silent)msg = getSpeakString(key);}// Third, try generic priest or wizard messages.if (msg.empty() && !innate){if (priest)key = "priest";elsekey = "wizard";key += cast_str;msg = getSpeakString(key + suffix);if (msg.empty() && silent)msg = getSpeakString(key);}// Fourth, try the monster's species.if (msg.empty()){key = mons_type_name(mons_species(monster->type), DESC_PLAIN);key += cast_str;msg = getSpeakString(key + suffix);if (msg.empty() && silent)msg = getSpeakString(key);}// Fifth, try the monster's genus.if (msg.empty()){key = mons_type_name(mons_genus(monster->type), DESC_PLAIN);key += cast_str;msg = getSpeakString(key + suffix);if (msg.empty() && silent)msg = getSpeakString(key);}// Lastly, maybe it's a demon.if (msg.empty() && mons_is_demon(monster->type)){key = "demon";key += cast_str;msg = getSpeakString(key + suffix);if (msg.empty() && silent)msg = getSpeakString(key);}if (msg.empty()){if (silent)return;noisy(noise, monster->pos());return;}const msg_channel_type chan =(unseen ? MSGCH_SOUND :mons_friendly(monster) ? MSGCH_FRIEND_SPELL :MSGCH_MONSTER_SPELL);if (silent){mons_speaks_msg(monster, msg, chan, true);return;}if (msg.find(" roar") != std::string::npos)noise = get_shout_noise_level(S_ROAR);else if (msg.find(" breathes") != std::string::npos){shout_type type = mons_shouts(monster->type);if(type == S_SILENT)type = S_ROAR;noise = get_shout_noise_level(type);}// noisy() returns true if the player heard the noise.if (noisy(noise, monster->pos()) || !unseen)mons_speaks_msg(monster, msg, chan);
}static const char *_orb_of_fire_glow(){static const char *orb_glows[] ={" glows yellow."," glows bright magenta."," glows deep purple.", // Smoke on the Water" glows red."," emits a lurid red light.",};return RANDOM_ELEMENT(orb_glows);
if (silenced(monster->pos()))return (false);simple_monster_message( monster, " winds a great silver horn.",spl );}else if (mons_is_demon( monster->type )){simple_monster_message( monster, " gestures.", spl );}else{switch (monster->type)
if (simple_monster_message(monster, " breathes.", spl))return (true);else
default:if (spell_cast == draco_breath){if (!simple_monster_message(monster, " breathes.", spl)){if (!silenced(monster->pos())&& !silenced(you.pos())){mpr("You hear a roar.", MSGCH_SOUND);}}break;}if (silenced(monster->pos()))return (false);if (mons_class_flag(monster->type, M_PRIEST)){switch (random2(3)){case 0:simple_monster_message(monster, " prays.", spl);break;case 1:simple_monster_message(monster," mumbles some strange prayers.",spl);break;case 2:default:simple_monster_message(monster," utters an invocation.", spl);break;}}else // not a priest{switch (random2(3)){case 0:// XXX: could be better, chosen to match the// ones in monspeak.cc... has the problem// that it doesn't suggest a vocal component. -- bwrif (player_monster_visible(monster)){simple_monster_message(monster," gestures wildly.", spl );}break;case 1:simple_monster_message(monster," mumbles some strange words.",spl);break;case 2:default:simple_monster_message(monster, " casts a spell.", spl);break;}}break;case MONS_BALL_LIGHTNING:monster->hit_points = -1;break;case MONS_STEAM_DRAGON:case MONS_MOTTLED_DRAGON:case MONS_STORM_DRAGON:case MONS_GOLDEN_DRAGON:case MONS_SHADOW_DRAGON:case MONS_SWAMP_DRAGON:case MONS_SWAMP_DRAKE:case MONS_DEATH_DRAKE:case MONS_HELL_HOG:case MONS_SERPENT_OF_HELL:case MONS_QUICKSILVER_DRAGON:case MONS_IRON_DRAGON:if (!simple_monster_message(monster, " breathes.", spl))
if (!silenced(monster->pos())&& !silenced(you.pos()))
break;case MONS_VAPOUR:monster->add_ench(ENCH_SUBMERGED);break;case MONS_BRAIN_WORM:case MONS_ELECTRIC_GOLEM:case MONS_ICE_STATUE:// These don't show any signs that they're casting a spell.break;case MONS_GREAT_ORB_OF_EYES:case MONS_SHINING_EYE:case MONS_EYE_OF_DEVASTATION:simple_monster_message(monster, " gazes.", spl);break;case MONS_GIANT_ORANGE_BRAIN:simple_monster_message(monster, " pulsates.", spl);break;case MONS_NAGA:case MONS_NAGA_WARRIOR:simple_monster_message(monster, " spits poison.", spl);break;case MONS_ORB_OF_FIRE:simple_monster_message(monster, _orb_of_fire_glow(), spl);break;
}}else{// Handle far-away monsters.if (monster->type == MONS_GERYON&& !silenced(you.pos())){mpr("You hear a weird and mournful sound.", MSGCH_SOUND);
// Geryon can't summon beasts if he's silenced since he uses a horn,// and we have to check for him explicitly since he's neither a priest// nor a wizard.if (silenced(monster->pos())&& (monster->type == MONS_GERYON|| mons_class_flag(monster->type, M_PRIEST | M_ACTUAL_SPELLS))){return (false);}
if (!_mons_announce_cast(monster, monsterNearby,spell_cast, draco_breath)){return (false);}
const bool did_noise =_mons_announce_cast(monster, monsterNearby,spell_cast, draco_breath);
###################################################### Individual spells.#####################################################%%%%Poison Splash cast@The_monster@ spits poison.%%%%Poison Splash cast unseenYou hear a spitting sound.%%%%Symbol of Torment cast@The_monster@ calls on the powers of Hell!%%%%Symbol of Torment cast unseen@The_something@ calls on the powers of Hell!###################################################### Priest and wizard casting messages.#####################################################%%%%priest cast@The_monster@ prays.@The_monster@ mumbles some strange prayers.@The_monster@ utters an invocation.%%%%priest cast unseenYou hear some strange, mumbled prayers.%%%%wizard cast@The_monster@ gestures wildly.@The_monster@ mumbles some strange words.@The_monster@ casts a spell.%%%%wizard cast unseenYou hear some strange, mumbled words.######################################################################### Monster genus and species messages.########################################################################%%%%demon cast@The_monster@ gestures.%%%%dragon cast@The_monster@ breaths.%%%%dragon cast unseenYou hear a roar.%%%%curse skull cast@The_monster@ rattles @possessive@ jaw.@The_monster@ casts a spell.%%%%curse skull cast unseenYou hear the clattering of teeth.%%%%giant eyeball cast@The_monster@ gazes.######################################################################### Individual monsters########################################################################%%%%Geryon cast@The_monster@ winds a great silver horn.%%%%Geryon cast unseenYou hear a weird and mournful sound.%%%%giant orange brain cast@The_monster@ pulsates.%%%%orb of fire cast@The_monster@ glows yellow.@The_monster@ glows bright magenta.@The_monster@ glows deep purple.@The_monster@ glows red.@The_monster@ emits a lurid red light.%%%%