diff options
Diffstat (limited to 'crawl-ref/source/monspeak.cc')
-rw-r--r-- | crawl-ref/source/monspeak.cc | 208 |
1 files changed, 150 insertions, 58 deletions
diff --git a/crawl-ref/source/monspeak.cc b/crawl-ref/source/monspeak.cc index ed373e7944..8528276860 100644 --- a/crawl-ref/source/monspeak.cc +++ b/crawl-ref/source/monspeak.cc @@ -42,34 +42,84 @@ #include "stuff.h" #include "view.h" -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, const std::string key, - const monsters *monster, + bool ignore_hostile = false, + bool ignore_related = false, + bool ignore_religion = false, bool ignore_silenced = false) { - std::string prefix = ""; + bool hostile = false; + bool related = false; + bool religion = false; bool silenced = false; + + std::string prefix = ""; + std::string msg = ""; const int size = prefixes.size(); for (int i = 0; i < size; i++) { - 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 instead + else if (silenced && coinflip()) + msg = try_exact_string(prefixes, key, true, true, true, true); } + return msg; +} - std::string msg = ""; +static std::string get_speak_string(const std::vector<std::string> prefixes, + const std::string key, + const monsters *monster) +{ + std::string msg = try_exact_string(prefixes, key); - // try string of all prefixes - msg = getSpeakString(prefix + key); - if (msg != "") + if (!msg.empty()) return msg; // Combinations of prefixes by threes + const int size = prefixes.size(); + std::string prefix = ""; if (size >= 3) { for (int i = 0; i < (size - 2); i++) @@ -81,7 +131,8 @@ static std::string get_speak_string(const std::vector<std::string> prefixes, prefix += prefixes[k] + " "; msg = getSpeakString("default " + prefix + key); - if (msg != "") + + if (!msg.empty()) return msg; } } @@ -96,7 +147,8 @@ static std::string get_speak_string(const std::vector<std::string> prefixes, prefix += prefixes[j] + " "; msg = getSpeakString("default " + prefix + key); - if (msg != "") + + if (!msg.empty()) return msg; } } @@ -109,7 +161,8 @@ static std::string get_speak_string(const std::vector<std::string> prefixes, prefix = prefixes[i] + " "; msg = getSpeakString("default " + prefix + key); - if (msg != "") + + if (!msg.empty()) return msg; } } @@ -117,10 +170,6 @@ static std::string get_speak_string(const std::vector<std::string> prefixes, // No prefixes msg = getSpeakString("default " + key); - // try the same ignoring silence - if (msg == "" && silenced) - return get_speak_string(prefixes, key, monster, true); - return msg; } @@ -139,12 +188,11 @@ static std::string player_ghost_speak_str(const monsters *monster, prefix += " "; } + // first try together with class name std::string msg = getSpeakString(prefix + ghost_class + " player ghost"); - if (msg == "__NONE") - return ""; - - if (msg == "" || msg == "__NEXT") + // else try without class name + if (msg.empty() || msg == "__NEXT") msg = getSpeakString(prefix + "player ghost"); return msg; @@ -173,19 +221,24 @@ bool mons_speaks(const monsters *monster) return false; } - // charmed monsters aren't too expressive - if (monster->has_ench(ENCH_CHARM)) - return false; - // berserk monsters just want your hide. if (monster->has_ench(ENCH_BERSERK)) return false; + // charmed monsters aren't too expressive + if (monster->has_ench(ENCH_CHARM) && !one_chance_in(3)) + return false; + + std::vector<std::string> prefixes; - if (monster->attitude == ATT_FRIENDLY) - prefixes.push_back("friendly"); - else if (monster->attitude == ATT_NEUTRAL) + if (mons_neutral(monster)) + { + if (coinflip()) // neutrals speak half as often + return false; prefixes.push_back("neutral"); + } + else if (mons_friendly(monster)) + prefixes.push_back("friendly"); else prefixes.push_back("hostile"); @@ -201,17 +254,38 @@ bool mons_speaks(const monsters *monster) if (monster->has_ench(ENCH_CONFUSION)) prefixes.push_back("confused"); - + + // only look at the current player form + if (is_player_same_species(monster->type, true)) + prefixes.push_back("related"); + // Add Beogh to list of prefixes for orcs (hostile and friendly) if you // worship Beogh. (This assumes you being a Hill Orc, so might have odd - // 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)) + { prefixes.push_back("beogh"); + } else if (is_good_god(you.religion)) prefixes.push_back("good god"); else if (is_evil_god(you.religion)) prefixes.push_back("evil god"); +#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 + std::string msg; // First, try its exact name @@ -225,23 +299,13 @@ bool mons_speaks(const monsters *monster) else msg = get_speak_string(prefixes, monster->name(DESC_PLAIN), monster); - // The exact name brought no results, try species. - if (msg.empty() || msg == "__NEXT") + // The exact name brought no results, try monster genus. + if ((msg.empty() || msg == "__NEXT") + && mons_genus(monster->type) != monster->type) { - 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), monster); - } - // 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); - } } // __NONE means to be silent, and __NEXT means to try the next, @@ -249,16 +313,21 @@ bool mons_speaks(const monsters *monster) // string. if (msg == "__NONE") + { +#ifdef DEBUG_MONSPEAK + mpr("result: \"__NONE\"!", MSGCH_DIAGNOSTICS); +#endif return false; + } // Now that we're not dealing with a specific monster name, include // whether or not it can move in the prefix if (mons_is_stationary(monster)) prefixes.insert(prefixes.begin(), "stationary"); - // Names for the monster, its species and its genus all failed, + // Names for the exact monster name and its genus have failed, // so try the monster's glyph/symbol. - if (msg == "" || msg == "__NEXT") + if (msg.empty() || msg == "__NEXT") { std::string key = "'"; @@ -271,7 +340,12 @@ bool mons_speaks(const monsters *monster) msg = get_speak_string(prefixes, key, monster); } if (msg == "__NONE") + { +#ifdef DEBUG_MONSPEAK + mpr("result: \"__NONE\"!", MSGCH_DIAGNOSTICS); +#endif return false; + } // Monster symbol didn't work, try monster shape. Since we're // dealing with just the monster shape, change the prefix to @@ -314,14 +388,20 @@ bool mons_speaks(const monsters *monster) prefixes.insert(prefixes.begin(), "smart"); } - if (msg == "" || msg == "__NEXT") + if (msg.empty() || msg == "__NEXT") msg = get_speak_string(prefixes, get_mon_shape_str(shape), monster); + if (msg == "__NONE") + { +#ifdef DEBUG_MONSPEAK + mpr("result: \"__NONE\"!", MSGCH_DIAGNOSTICS); +#endif return false; + } // If we failed to get a message with a winged or tailed humanoid, // or a naga or centaur, try moving closer to plain humanoid - if ((msg == "" || msg == "__NEXT") && shape > MON_SHAPE_HUMANOID + if ((msg.empty() || msg == "__NEXT") && shape > MON_SHAPE_HUMANOID && shape <= MON_SHAPE_NAGA) { // If a humanoid monster has both wings and a tail, try @@ -335,15 +415,21 @@ bool mons_speaks(const monsters *monster) monster); // Only be silent if both tailed and winged return __NONE - if (msg == "" || msg == "__NONE" || msg == "__NEXT") + if (msg.empty() || msg == "__NONE" || msg == "__NEXT") { shape = MON_SHAPE_HUMANOID_WINGED; std::string msg2; msg2 = get_speak_string(prefixes, get_mon_shape_str(shape), monster); + if (msg == "__NONE" && msg2 == "__NONE") + { +#ifdef DEBUG_MONSPEAK + mpr("result: \"__NONE\"!", MSGCH_DIAGNOSTICS); +#endif return false; + } if (msg2 == "__NONE") msg2 = ""; @@ -351,7 +437,7 @@ bool mons_speaks(const monsters *monster) msg = msg2; } } // if (shape == MON_SHAPE_HUMANOID_WINGED_TAILED) - if (msg == "" || msg == "__NONE" || msg == "__NEXT") + if (msg.empty() || msg == "__NONE" || msg == "__NEXT") { shape = MON_SHAPE_HUMANOID; msg = get_speak_string(prefixes, @@ -359,8 +445,14 @@ bool mons_speaks(const monsters *monster) monster); } } - if (msg == "__NONE" || msg == "") + if (msg.empty() || msg == "__NONE") + { +#ifdef DEBUG_MONSPEAK + mprf(MSGCH_DIAGNOSTICS, "final result: %s!", + (msg.empty() ? "empty" : "\"__NONE\"")); +#endif return false; + } if (msg == "__NEXT") { |