some time, though. I added a new prefix "related" if the player character has the same genus as the monster. My new prefix additions (hostile, related and religion) can now be skipped in the speech lookup, which fixes a couple of problems where several monsters were forced silent because of lookup problems. Also clean up the lookup process for silence, allow charmed monsters to sometimes speak (if rarely) and added several debugging statements that are also mentioned in monster_speech.txt that is now clearer than ever before (I hope).
Fixed a couple of bugs in the monster shape calculation where the old glyphs were still being used. Also, a Draconian character eating any type of Draconian will now count as cannibalism.
Also: FR 1894060: Level annotations now prompt for confirmation if they contain an exclamation mark (rather than "WARN"). Fix 1859443: Arriving on a square via staircase now calls request_autopickup and will describe items on the square.
Oh, and fix init.txt to really allow reading in macros from external files.
git-svn-id: https://crawl-ref.svn.sourceforge.net/svnroot/crawl-ref/trunk@3604 c06c8d41-db1a-0410-9941-cceddc491573
6GSGCC5JQJ5NOKX36UHRNOCXNHDBS2A2TDMAR34UBOGWE2DORXIQC HEEAPXAXYJORP7NEYLG62OD6QUCM2AZUWGK6EMWMZY6DPHWK6RGAC PQ3SLWFD5CF33ZHBG2V7YJEKAL6HTSDYOV25OKUTBCW2QF7TL4AAC TVRAEEYYHT3XGS25RTGXX4RVJM35JW3YOENR6M4XKQYBX3TLY5KAC JDM5R3HYGXKQKZWY35QZ2KOB24TFZ3FW2PCNXCRCMWG72AZC5ZXQC 64RZSOR4B4T5QO3FAERBTH2QJIQFSCIFHI4WYK3MDAEAZVAHRLVQC 2VDLCWQOJPOXPJQ7XYGOWZG5P2AE44DGFHC76WI4GBOOK4B7FQTQC M5ZDZJBTOJ7SWQPZZQPC24JYZKP26MWSRDHXBWQE2MPPL6WCXOIQC 2H32CFFM2FNS63JJPNM2S6HMO543EX72GMPOU5GI6HTMQYPL6I3AC K2CS6TCX2NDVL2ASEHGP4J4K4IJ6FP3ANNKTSIWVG43HPYSBX6ZQC 3QLM46S44Z7GDLWPH3VHBMW2RSWZAOLGJMG2BDKNGUOZIM4IX6WAC J6APXOT4QOGQFONWB7G546VTVF6QG42HVOROMHF7YBDJPR4K26OAC AIIVH43Z5X3GTPFY4FXQRZPG6Y7QPH2KJ47VM2Q43PCGGD5MTMOAC KZIHM6RUX43HHKXG6HGJHVEEYUPVVNBFIWMT4SKPD2GAH5ZMA3KAC 4UXFU3FZOCBSLDQ4S7MJKAE2H7VUHCNRDQMIY6NJ3PHYXWNGISDQC X5WLJCJVW55SXZVP7IKP7ADCJIGNKN4PKAXFECVR6TNK7XSMZR7QC YM3U5YZEFIYLRJVDWQCSP75JL56WC36XLQSL5ZBT4IWSXYJRBCBAC G5WLU3B4MR3ZDJLGR6OHNIMLZXGQS2EWBJ5YYY5J2GWM6DTD44BAC D4MYPHZGUOL7HPS53DUUM4QSPIR5W3227DENDB4OBNDVQ4BU5VDAC G7CTMQ3VNTAB73ZI3LNZHKTAJ5LEQEGG772MVFQQ5XXLCMJVORTQC AVCMVFA3MKCXHO6H44UK5KJNIHTGQV7UA7GYXM26VI6TXXU5ZN6QC SDLKLUNFGVKDS55DDJZCBAVIB7NL3RRYPTACAY65SCUQKV6APFSAC RPOZZWKG5GLPHVZZ7ZKMKS64ZMV2LDCQSARBJFJ6FZOTOKCQO7FAC CGYTZT5QWIEGYKUOLOK7MFXSLJKLYRZONER5ZCDZO5XYWSLG475QC XX3TYGTDZY7AT53JJDTMKQXOYL4TUPVXXE2WY53UKZZOZ4UXDTQQC Y56C5OMUQ5XF2G6DKDV4R5MED44UOIUPTBBQVWQBUHYIXYA5MOZAC BMHUBADDGIOZRVN4P3O5QKIDUYD4RFWBS7MP5X6LZWAYHUBRVD2QC O3I7TURGIE6BXI6VXLWVTITPWNP3N5X4EEOBXLIZMDIKDIKPKUVQC WL5WZXFJ6TONUQRSHUY4GQ5USU47ILWNN5X2JDQZO4CRJJZSRQIAC RVST2QHYJ757ZHK4AUJ5NGPDZ44AD6RVFVXYPKQIBJXZBDNUCHXQC FYD4A5TIETIV2ZLFYWGHXANU6WQFKMVREHM7OZY2TAXSBMMCDLJAC if (transform){switch (you.attribute[ATTR_TRANSFORMATION]){case TRAN_AIR:return (false);// unique monsterscase TRAN_BAT:return (mon == MONS_GIANT_BAT);case TRAN_ICE_BEAST:return (mon == MONS_ICE_BEAST);case TRAN_SERPENT_OF_HELL:return (mon == MONS_SERPENT_OF_HELL);// compare with monster *species*case TRAN_LICH:return (mons_species(mon) == MONS_LICH);// compare with monster *genus*case TRAN_SPIDER:return (mons_genus(mon) == MONS_WOLF_SPIDER);case TRAN_DRAGON:return (mons_genus(mon) == MONS_DRAGON); // includes all drakesdefault:break; // check real (non-transformed) form}}
static std::string get_speak_string(const std::vector<std::string> prefixes,
// Try the exact key lookup along with the entire prefix list.// If that fails, start ignoring hostile/religion/silence, in that order,// first skipping hostile, then hostile *and* religion, then all three.static std::string try_exact_string(const std::vector<std::string> prefixes,
if (prefixes[i] == "silenced"){if (ignore_silenced)continue;silenced = true;}prefix += prefixes[i];prefix += " ";
if (prefixes[i] == "hostile"){if (ignore_hostile)continue;hostile = true;}else if (prefixes[i] == "related"){if (ignore_related)continue;related = true;}else if (prefixes[i] == "silenced"){if (ignore_silenced)continue;silenced = true;}else if (prefixes[i] == "beogh" || prefixes[i] == "good god"|| prefixes[i] == "evil god"){if (ignore_religion)continue;religion = true;}prefix += prefixes[i];prefix += " ";}msg = getSpeakString(prefix + key);if (msg.empty()){if (hostile)msg = try_exact_string(prefixes, key, true);else if (related)msg = try_exact_string(prefixes, key, true, true);else if (religion)msg = try_exact_string(prefixes, key, true, true, true);// 50% use non-verbal monster speech,// 50% try for more general silenced monster message insteadelse if (silenced && coinflip())msg = try_exact_string(prefixes, key, true, true, true, true);
// charmed monsters aren't too expressiveif (monster->has_ench(ENCH_CHARM))return false;
// results in wizard mode.)if (you.religion == GOD_BEOGH && mons_genus(monster->type) == MONS_ORC)
// results in wizard mode.) Don't count charmed orcs.if (you.religion == GOD_BEOGH && mons_genus(monster->type) == MONS_ORC&& !monster->has_ench(ENCH_CHARM)){
#ifdef DEBUG_MONSPEAK{std::string prefix = "";const int size = prefixes.size();for (int i = 0; i < size; i++){prefix += prefixes[i];prefix += " ";}mprf(MSGCH_DIAGNOSTICS, "monster speech lookup for %s: prefix = %s",monster->name(DESC_PLAIN).c_str(), prefix.c_str());}#endif
if (mons_species(monster->type) != monster->type){msg = get_speak_string(prefixes,mons_type_name(mons_species(monster->type), DESC_PLAIN),
msg = get_speak_string(prefixes,mons_type_name(mons_genus(monster->type), DESC_PLAIN),
}// Still nothing found? Try monster genus!if ((msg.empty() || msg == "__NEXT")&& mons_genus(monster->type) != monster->type){msg = get_speak_string(prefixes,mons_type_name(mons_genus(monster->type), DESC_PLAIN),monster);}
}static std::string pluralise_player_genus(){std::string sp = species_name(you.species, 1, true);if (player_genus(GENPC_ELVEN, you.species)|| player_genus(GENPC_DWARVEN, you.species)){sp = sp.substr(0, sp.find("f"));sp += "ves";}else if (you.species != SP_DEMONSPAWN)sp += "s";return (sp);
msg = replace_all(msg, "@species_insult_adj1@", get_species_insult("adj1"));msg = replace_all(msg, "@species_insult_adj2@", get_species_insult("adj2"));msg = replace_all(msg, "@species_insult_noun@", get_species_insult("noun"));
if (msg.find("@species_insult_") != std::string::npos){msg = replace_all(msg, "@species_insult_adj1@", get_species_insult("adj1"));msg = replace_all(msg, "@species_insult_adj2@", get_species_insult("adj2"));msg = replace_all(msg, "@species_insult_noun@", get_species_insult("noun"));}
case 'm': // minotaurs, manticores, and snails/slugs/etcif (type == MONS_MINOTAUR)return(MON_SHAPE_HUMANOID);else if (type == MONS_MANTICORE)return(MON_SHAPE_QUADRUPED);elsereturn(MON_SHAPE_SNAIL);
case 'm': // merfolkreturn(MON_SHAPE_HUMANOID);
if (you.religion == GOD_ZIN && mons_intel(item.plus) >= I_NORMAL)simple_god_message(" expects more respect for this departed ""soul.");else if (is_good_god(you.religion) && is_player_same_species(item.plus))
if (is_good_god(you.religion) && is_player_same_species(item.plus))
%%%%friendly_family@The_monster@ says, "I like you, cousin!"@The_monster@ says, "Family always sticks together, @player_name@!"@The_monster@ says, "@player_genus@kind's got to stick together!"@The_monster@ shouts, "@player_genus_plural@ are the best!"@The_monster@ says happily, "You and me, we're family."
# Not currently used:#Thou @generic_insult@!%%%%body_or_spiritual_partw:3@important_body_part@w:1@important_spiritual_part@%%%%will_or_shallwillshall%%%%feast_or_devourfeast ondevour%%%%######################################################## generic insults consists of three random parts#######################################################generic_insult@insult_adjective1@ @insult_adjective2@ @insult_noun@
important_body_partheadbrainheartvisceraeyeslungsliverthroatneckskullspine%%%%important_spiritual_partsoulspiritinner lighthopefaithwillheartmindsanityfortitudelife force%%%%mealmealbreakfastlunchdinnersupperrepastsnackvictualsrefectionjunketluncheonsnacklingcurdlesnackletmouthful%%%%
mealmealbreakfastlunchdinnersupperrepastsnackvictualsrefectionjunketluncheonsnacklingcurdlesnackletmouthful%%%%######################################################## generic insults consist of three random parts#######################################################generic_insult@insult_adjective1@ @insult_adjective2@ @insult_noun@%%%%
insult.txt handles insults thrown at you by imps and demons.
Monster speech probabilities============================Not all monsters are equally likely to speak. Rather there aredifferent chances involved depending on several attributes, and most ofthe time the database lookup stage isn't even reached.The player will only ever hear monsters speak if they are nearby, andmonsters will only speak if they are not asleep, not submerged inwater, air or lava, and not wandering around aimlessly (unless neutral).Berserk monsters are too busy killing and maiming to speak. Also, invisiblemonsters the player can't see (for lack of see invisible) will always staysilent, unless confused.Monsters capable of speech (i.e. all intelligent humanoid monsters, aswell as all uniques and some non-unique demons) have a base chance of1/21 of speaking, while humanoid monsters incapable of speech willnever communicate with the player in any form.Non-humanoid monsters get a 1/84 probability of "speaking" per turn(non-verbal actions, more like). This chance is divided by another 10,if the monster in question was generated as a member of a group.Chances are again doubled if this non-humanoid monster is fleeing, anddoubled again if confused.
wpnnoise.txt handles randart weapons with the noises property.
Neutral monsters only speak half as often, and for charmed monsters theprobability is divided by 3. The same applies to silenced monsters, i.e.monsters that are not naturally silent will only get to even attempt to speak inone out of three tries where the above chances hold.Note that the definition of which monsters are capable of speech isentirely hardcoded. We think we made this apply to all sensiblemonsters, i.e. all intelligent humanoid monsters, but of course it ispossible we've overlooked something, so if you find that yourcarefully constructed monster speech never gets printed, and thisdocumentation also doesn't help you solve the problem, you might wantto post a bug report on Dungeon Crawl's SourceForge site [1].
If you have a look at these files, you'll see that all entries havebasically the same structure: a key, followed by one or more values.
If you have a look at some of the speech files, you'll see that allentries have basically the same structure: a key, followed by one ormore values.
the game generally treats neutral monsters like hostiles as they stillpose a danger to players.
the game generally treats neutral monsters like hostiles since theystill pose a danger to players.The prefix "related" is added if the player and the monster share thesame genus, e.g. if you're playing a Sludge Elf, and the monster inquestion is a deep elf blademaster, you both are Elves and the monsterspeech may reflect that. It's currently only used for friendlyhumanoids who will now sometimes mention that you're family, if youare.
added to the list. If you worship one of the good gods (Zin, TheShining One, or Elyvilon) the prefix "good god" is used instead.Conversely, worshippers of one of the evil gods (Yredelemnul,Kikubaaqudgha, Makhleb, Lugonu, Xom, Beogh, or Vehumet) will use theprefix "evil god".
added to the list. If you worship one of the good gods (Zin, Elyvilon,or The Shining One) the prefix "good god" is used instead.Conversely, worshippers of one of the evil gods (Yredelemnul, Makhleb,Kikubaaqudgha, Lugonu, Xom, Beogh, or Vehumet) will use the prefix"evil god".
First we search for the whole database string in combination with themonster name. If that didn't yield any results, reading from left toright, combinations are tested, beginning at three prefixes and endingat none. At this stage the list of prefixes is always prefixed itselfwith "default". This ensures that, for example, fleeing uniques won'toutput their normal menacing speech but rather the default speechdefined for fleeing humanoids in general.
First we search for the complete prefix string in combination with themonster name. Then we try omitting some very specific prefixes thatmight not be so important, first skipping on "hostile", then alsoignoring "related", then religion status, and finally "silenced", whereapplicable.If all of that didn't yield any results, next we'll take the completeprefix list again, then, reading from left to right, combinations aretested, beginning at three prefixes and ending at none. At this stagethe list of prefixes is always prepended with "default". This ensuresthat, for example, fleeing uniques won't output their normal menacingspeech but rather the default speech defined for fleeing humanoids ingeneral.In practice this means that database keys starting with "default" arethe fallback solution if the exact look-up has failed. As such, themessages should be generic enough to allow for all the possibly skippedprefixes, or else those cases should be caught earlier, e.g. if youhave "default friendly humanoid", you should also define "defaultfriendly fleeing humanoid" and "default friendly confused humanoid"(and possibly both combined) even if only with "__NONE" (stay silent),as the general friendly messages may look odd for a monster suchafflicted.
humanoid, winged humanoid, tailed humanoid, winged tailed humanoid,centaur, naga, quadruped, tailless quadruped, winged quadruped,bat, snake, fish, insect, winged insect, arachnid, centipede, snail,plant, fungus, orb, and blob.
humanoid, winged humanoid (angels), tailed humanoid (draconians),winged tailed humanoid (gargoyles), centaur, naga, quadruped,tailless quadruped (frogs), winged quadruped (hippogriff), bat,snake (also eels and worms), fish, insect, winged insect, arachnid,centipede, snail, plant, fungus, orb (eyes), and blob (jellies).
database, so one after another, we first check for "default friendlyfleeing beogh orc wizard", "default friendly fleeing orc wizard","default friendly beogh orc wizard", "default fleeing beogh orcwizard", "default friendly orc wizard", "default fleeing orc wizard","default beogh orc wizard" and "default orc wizard", none of which issuccessful.Both species and genus of the orc wizard is "orc", so we retry theabove using "orc" instead of "orc wizard". The same is repeated for"friendly fleeing beogh 'o'", and we still haven't found anything.
database, so first we try to remove the less important prefixes,something that in this case only applies to "beogh". Unfortunately,"friendly fleeing orc wizard" also has no corresponding entry in thedatabase, so that, one after another, we now check for "defaultfriendly fleeing beogh orc wizard", "default friendly fleeing orcwizard", "default friendly beogh orc wizard", "default fleeing beoghorc wizard", "default friendly orc wizard", "default fleeing orcwizard", "default beogh orc wizard" and "default orc wizard", none ofwhich is successful.The genus of orc wizards is "orc", so we retry the above using "orc"instead of "orc wizard". The same is repeated for "friendly fleeingbeogh 'o'", and we still haven't found anything.
doesn't exist. Still, we haven't yet tried the prefix combinations:"default friendly fleeing beogh humanoid" is still unsuccessful, butwith "default friendly fleeing humanoid" we finally strike gold:
doesn't exist. Annoyingly enough, neither does "friendly fleeinghumanoid".Still, we haven't yet tried the prefix combinations: "defaultfriendly fleeing beogh humanoid" is still unsuccessful, but with"default friendly fleeing humanoid" we finally strike gold:
shout.txt, monspeak.txt or one of the other files, in which case theyare replaced with a random value from the entry; or they may havehardcoded expansions defined by the game.
shout.txt for the shouting database, or monspeak.txt or one of theother files for the speech database, in which case they are replacedwith a random value from the entry; or they may have hardcodedexpansions defined by the game.
Note, though, that these only will take effect if a VISUAL message justhappens to be chosen. As stated above, the database search doesn'treally care whether a monster is supposed to be silent, so it may pickany noisy monster speech, but the message output will care and refuseto print such nonsense, so that in this case the monster will actuallystay silent after all.All in all, chances of silent "speech" are lower (as is intended) butonly VISUAL messages even have a chance to be printed under these circumstances.
Note, though, that these only will take effect if the "silenced" prefixhasn't been defined for this monster, or at least not in combinationwith the other applying prefixes. In the case of silenced monsters,first the database is searched for the monster key along with all itsprefixes including "silenced", and only if no message has been found,the search will repeat ignoring the "silenced" prefix and only thenthese special VISUAL cases can apply.This will actually double the amount of rounds the database searchgoes through, so you might expect chances for speaking to be higher.In fact, though, the opposite is the case: once a matching message hasbeen found, the database search stops, and if this randomly chosenspeech message doesn't happen to be VISUAL it will simply not beprinted, so the monster stays silent after all. All in all, chancesare lower (as is intended) but only VISUAL messages even have a chanceto be printed under these circumstances.
As explained earlier, "silenced" is one of the prefixes that areregarded as "less important" and can be ignored in the exact stringsearch. So that both specially defined silenced messages for aparticular monster and its normal VISUAL messages can sometimes takeeffect, chances for actually skipping on silenced in the direct stringmatching are 50:50.Example 3:The player has just cast Silence when a Killer Klown wanders intoview. (Uh oh!) This "silenced Killer Klown" is now attempting to saysomething. The exact look-up is unsuccessful, but now there's a 50%chance of skipping on the "silenced" prefix. If this route is chosenwe may get results such as%%%%Killer Klown@The_monster@ giggles crazily.@The_monster@ laughs merrily....none of which, if chosen, would actually be printed, but luckily the"Killer Klown" entry also contains VISUAL statements like thefollowing:...VISUAL:@The_monster@ beckons to you.VISUAL:@The_monster@ does a flip....If one of these is chosen, we get a non-verbal "speech" statement ofthis silenced monster.However, what happens if the other 50% take effect and we will *not*ignore the "silenced" prefix? In this case, we'll simply continuelike in the earlier examples above, get no results for either of"default silenced Killer Klown" or "default Killer Klown", and trythe genus next: human, which cannot be found in the database,silenced or no. Neither will we find anything for the monster glyph'@'. Now all that remains is to check the monster shape, which is"humanoid" again. "silenced humanoid" won't get us any results, norwill simply "humanoid", but "default silenced humanoid" has somestatements defined.%%%%default silenced humanoidw:30VISUAL:@The_monster@ says something but you don't hear anything.w:30VISUAL:@The_monster@ gestures....All of the statements in these predefined "silenced" entries have tobe of the type VISUAL; otherwise they'll never get printed.
Note that the definition of which monsters are capable of speech isentirely hardcoded. We think we made this apply to all sensiblemonsters, i.e. all intelligent humanoid monsters, but of course it ispossible we've overlooked something, so if you find that yourcarefully constructed monster speech never gets printed, and thisdocumentation also doesn't help you solve the problem, you might wantto post a bug report on Dungeon Crawl's SourceForge site [1].
If you successfully got Crawl compiled, you can easily enable moredetailed debug information. All you need to do is add#define DEBUG_MONSPEAKsomewhere in AppHdr.h, for example at the beginning of the sectionentitled "Debugging Defines", and then compile the game anew, firstusing "make clean", then "make wizard".If you play with DEBUG_MONSPEAK compiled in, whenever the game issearching the monspeak database you'll get extensive information on allkeys and prefixes tried. Once you're done testing don't forget toremove (or comment out) the DEBUG_MONSPEAK setting as trying toactually play that way would sure be annoying.
If you feel that your additions add something to the game and wouldlike to make them available to the general public, you can post them(in the form of a diff file, or in plain text) as a feature request onsourceforge.net [1] or in the newsgroup [2].
If you feel that your additions really add something to the game andwould like to make them available to the general public, you can postthem (in the form of a diff file, or in plain text) as a featurerequest on sourceforge.net [1] or in the newsgroup [2].