1 /**
2 * @file
3 * @brief Functions to handle speaking monsters
4 **/
5
6 #include "AppHdr.h"
7
8 #include "mon-speak.h"
9
10 #include <algorithm>
11 #include <cstdio>
12 #include <cstdlib>
13 #include <cstring>
14
15 #include "areas.h"
16 #include "branch.h"
17 #include "database.h"
18 #include "ghost.h"
19 #include "libutil.h"
20 #include "message.h"
21 #include "mon-death.h"
22 #include "monster.h"
23 #include "mon-util.h"
24 #include "religion.h"
25 #include "skills.h"
26 #include "state.h"
27 #include "stringutil.h"
28 #include "view.h"
29
30 // Try the exact key lookup along with the entire prefix list.
31 // If that fails, start ignoring hostile/religion/branch/silence, in that order,
32 // first skipping hostile, then hostile *and* religion, then hostile, religion
33 // *and* branch, then finally all five.
__try_exact_string(const vector<string> & prefixes,const string & key,bool ignore_hostile=false,bool ignore_related=false,bool ignore_religion=false,bool ignore_branch=false,bool ignore_silenced=false)34 static string __try_exact_string(const vector<string> &prefixes,
35 const string &key,
36 bool ignore_hostile = false,
37 bool ignore_related = false,
38 bool ignore_religion = false,
39 bool ignore_branch = false,
40 bool ignore_silenced = false)
41 {
42 bool hostile = false;
43 bool related = false;
44 bool religion = false;
45 bool branch = false;
46 bool silenced = false;
47
48 string prefix = "";
49 string msg = "";
50 const int size = prefixes.size();
51 for (int i = 0; i < size; i++)
52 {
53 if (prefixes[i] == "hostile")
54 {
55 if (ignore_hostile)
56 continue;
57 hostile = true;
58 }
59 else if (prefixes[i] == "related")
60 {
61 if (ignore_related)
62 continue;
63 related = true;
64 }
65 else if (prefixes[i] == "silenced")
66 {
67 if (ignore_silenced)
68 continue;
69 silenced = true;
70 }
71 else if (prefixes[i] == "Beogh" || prefixes[i] == "good god"
72 || prefixes[i] == "No God"
73 || (str_to_god(prefixes[i]) != GOD_NO_GOD
74 && prefixes[i] != "random"))
75 {
76 if (ignore_religion)
77 continue;
78 religion = true;
79 }
80 else if (branch_by_abbrevname(prefixes[i]) != NUM_BRANCHES)
81 {
82 if (ignore_branch)
83 continue;
84 branch = true;
85 }
86 prefix += prefixes[i];
87 prefix += " ";
88 }
89 msg = getSpeakString(prefix + key);
90
91 if (msg.empty())
92 {
93 if (hostile) // skip hostile
94 msg = __try_exact_string(prefixes, key, true);
95 else if (related)
96 {
97 if (branch) // skip hostile and branch
98 msg = __try_exact_string(prefixes, key, true, false, false, true);
99 else if (religion) // skip hostile and religion
100 {
101 msg = __try_exact_string(prefixes, key, true, false, true,
102 ignore_branch);
103 }
104 else // skip hostile and related
105 msg = __try_exact_string(prefixes, key, true, true);
106 }
107 else if (religion) // skip hostile, related and religion
108 {
109 if (branch && coinflip()) // skip hostile, related and branch
110 msg = __try_exact_string(prefixes, key, true, true, false, true);
111 else // skip hostile, related and religion
112 msg = __try_exact_string(prefixes, key, true, true, true);
113 }
114 else if (branch) // skip hostile, related, religion and branch
115 msg = __try_exact_string(prefixes, key, true, true, true, true);
116 // 50% use non-verbal monster speech,
117 // 50% try for more general silenced monster message instead
118 else if (silenced && coinflip()) // skip all
119 msg = __try_exact_string(prefixes, key, true, true, true, true, true);
120 }
121 return msg;
122 }
123
_invalid_msg(const string & msg,bool no_player,bool no_foe,bool no_foe_name,bool no_god,bool unseen)124 static bool _invalid_msg(const string &msg, bool no_player, bool no_foe,
125 bool no_foe_name, bool no_god, bool unseen)
126 {
127 if (no_player
128 && (msg.find("@player") != string::npos
129 || msg.find("@Player") != string::npos
130 || msg.find(":You") != string::npos))
131 {
132 return true;
133 }
134
135 if (no_player)
136 {
137 for (const string &line : split_string("\n", msg))
138 if (starts_with(line, "You") || ends_with(line, "you."))
139 return true;
140 }
141
142 if (no_foe && (msg.find("@foe") != string::npos
143 || msg.find("@Foe") != string::npos
144 || msg.find("foe@") != string::npos
145 || msg.find("@species") != string::npos))
146 {
147 return true;
148 }
149
150 if (no_god && (msg.find("_god@") != string::npos
151 || msg.find("@god_") != string::npos))
152 {
153 return true;
154 }
155
156 if (no_foe_name && msg.find("@foe_name@") != string::npos)
157 return true;
158
159 if (unseen && msg.find("VISUAL") != string::npos)
160 return true;
161
162 return false;
163 }
164
_try_exact_string(const vector<string> & prefixes,const string & key,bool no_player,bool no_foe,bool no_foe_name,bool no_god,bool unseen,bool ignore_hostile=false,bool ignore_related=false,bool ignore_religion=false,bool ignore_branch=false,bool ignore_silenced=false)165 static string _try_exact_string(const vector<string> &prefixes,
166 const string &key,
167 bool no_player, bool no_foe,
168 bool no_foe_name, bool no_god,
169 bool unseen,
170 bool ignore_hostile = false,
171 bool ignore_related = false,
172 bool ignore_religion = false,
173 bool ignore_branch = false,
174 bool ignore_silenced = false)
175 {
176 string msg;
177 for (int tries = 0; tries < 10; tries++)
178 {
179 msg =
180 __try_exact_string(prefixes, key, ignore_hostile, ignore_related,
181 ignore_religion, ignore_branch, ignore_silenced);
182
183 // If the first message was non-empty and discarded then discard
184 // all subsequent empty messages, so as to not replace an
185 // invalid non-empty message with an empty one.
186 if (msg.empty())
187 {
188 if (tries == 0)
189 return msg;
190 else
191 {
192 tries--;
193 continue;
194 }
195 }
196
197 if (_invalid_msg(msg, no_player, no_foe, no_foe_name, no_god, unseen))
198 {
199 msg = "";
200 continue;
201 }
202 break;
203 }
204
205 return msg;
206 }
207
__get_speak_string(const vector<string> & prefixes,const string & key,bool no_player,bool no_foe,bool no_foe_name,bool no_god,bool unseen)208 static string __get_speak_string(const vector<string> &prefixes,
209 const string &key,
210 bool no_player, bool no_foe,
211 bool no_foe_name, bool no_god,
212 bool unseen)
213 {
214 string msg = _try_exact_string(prefixes, key, no_player, no_foe,
215 no_foe_name, no_god, unseen);
216
217 if (!msg.empty())
218 return msg;
219
220 // Combinations of prefixes by threes
221 const int size = prefixes.size();
222 string prefix = "";
223 if (size >= 3)
224 {
225 for (int i = 0; i < (size - 2); i++)
226 for (int j = i + 1; j < (size - 1); j++)
227 for (int k = j + 1; k < size; k++)
228 {
229 prefix = prefixes[i] + " ";
230 prefix += prefixes[j] + " ";
231 prefix += prefixes[k] + " ";
232
233 msg = getSpeakString("default " + prefix + key);
234
235 if (!msg.empty())
236 return msg;
237 }
238 }
239
240 // Combinations of prefixes by twos
241 if (size >= 2)
242 {
243 for (int i = 0; i < (size - 1); i++)
244 for (int j = i + 1; j < size; j++)
245 {
246 prefix = prefixes[i] + " ";
247 prefix += prefixes[j] + " ";
248
249 msg = getSpeakString("default " + prefix + key);
250
251 if (!msg.empty())
252 return msg;
253 }
254 }
255
256 // Prefixes singly
257 if (size >= 1)
258 {
259 for (int i = 0; i < size; i++)
260 {
261 prefix = prefixes[i] + " ";
262
263 msg = getSpeakString("default " + prefix + key);
264
265 if (!msg.empty())
266 return msg;
267 }
268 }
269
270 // No prefixes
271 msg = getSpeakString("default " + key);
272
273 return msg;
274 }
275
_get_speak_string(const vector<string> & prefixes,string key,const monster * mons,bool no_player,bool no_foe,bool no_foe_name,bool no_god,bool unseen)276 static string _get_speak_string(const vector<string> &prefixes,
277 string key,
278 const monster* mons,
279 bool no_player, bool no_foe,
280 bool no_foe_name, bool no_god,
281 bool unseen)
282 {
283 int duration = 1;
284 if ((mons->flags & MF_BANISHED) && !player_in_branch(BRANCH_ABYSS))
285 key += " banished";
286 else if (mons->hit_points <= 0)
287 {
288 //separate death/permadeath lines for resurrection monsters
289 if (mons_is_mons_class(mons, MONS_NATASHA)
290 && !mons_felid_can_revive(mons)
291 || mons->type == MONS_BENNU
292 && !mons_bennu_can_revive(mons))
293 {
294 key += " permanently";
295 }
296 key += " killed";
297 }
298 else if (mons->is_summoned(&duration) && duration <= 0)
299 key += " unsummoned";
300
301 string msg;
302 for (int tries = 0; tries < 10; tries++)
303 {
304 msg =
305 __get_speak_string(prefixes, key, no_player, no_foe,
306 no_foe_name, no_god, unseen);
307
308 // If the first message was non-empty and discarded then discard
309 // all subsequent empty messages, so as to not replace an
310 // invalid non-empty message with an empty one.
311 if (msg.empty())
312 {
313 if (tries == 0)
314 return msg;
315 else
316 {
317 tries--;
318 continue;
319 }
320 }
321
322 if (_invalid_msg(msg, no_player, no_foe, no_foe_name, no_god, unseen))
323 {
324 msg = "";
325 continue;
326 }
327
328 break;
329 }
330
331 return msg;
332 }
333
334 /**
335 * Rolls a chance for a monster to speak, and calls mons_speaks as necessary.
336 *
337 * @param mons The monster in question.
338 */
maybe_mons_speaks(monster * mons)339 void maybe_mons_speaks(monster* mons)
340 {
341 // Very fast wandering/patrolling monsters might, in one monster turn,
342 // move into the player's LOS and then back out (or the player
343 // might move into their LOS and the monster move back out before
344 // the player's view has a chance to update) so prevent them
345 // from speaking.
346 if (mons->is_patrolling() || mons_is_wandering(*mons))
347 return;
348
349 // per ef44f8a14, this seems to be handled elsewhere?
350 if (mons->attitude == ATT_NEUTRAL)
351 return;
352
353 // too annoying for a permanent companion without more thought put into it
354 if (mons_is_hepliaklqana_ancestor(mons->type))
355 return;
356
357 int chance = 21; // this is a very old number; no idea why it was chosen
358
359 // allies stick around longer, so should probably have longer to say
360 // their piece; no need for them to chatter as much.
361 if (mons->wont_attack())
362 chance *= 15;
363 else if (!mons_is_unique(mons->type)
364 && testbits(mons->flags, MF_BAND_MEMBER))
365 {
366 // Band members are a lot less likely to speak, since there's
367 // a lot of them. Except for uniques.
368 chance *= 10;
369 }
370
371 // Confused and fleeing monsters are more interesting.
372 if (mons_is_fleeing(*mons))
373 chance /= 2;
374 if (mons->has_ench(ENCH_CONFUSION))
375 chance /= 2;
376
377 if ((mons_class_flag(mons->type, M_SPEAKS)
378 || !mons->mname.empty())
379 && one_chance_in(chance))
380 {
381 mons_speaks(mons);
382 }
383 else if ((mons->type == MONS_CRAZY_YIUF || mons->type == MONS_DONALD)
384 && one_chance_in(7))
385 {
386 // Yiuf gets an extra chance to speak!
387 // So does Donald.
388 mons_speaks(mons);
389 }
390 else if (get_mon_shape(*mons) >= MON_SHAPE_QUADRUPED)
391 {
392 // Non-humanoid-ish monsters have a low chance of speaking
393 // without the M_SPEAKS flag, to give the dungeon some
394 // atmosphere/flavour.
395 if (one_chance_in(chance * 4))
396 mons_speaks(mons);
397 }
398 // Okay then, don't speak.
399 }
400
_get_foe(const monster & mon)401 static actor* _get_foe(const monster &mon)
402 {
403 if (!crawl_state.game_is_arena()
404 && mon.wont_attack()
405 && invalid_monster_index(mon.foe))
406 {
407 return &you;
408 }
409 return mon.get_foe();
410 }
411
412 // Returns true if something is said.
mons_speaks(monster * mons)413 bool mons_speaks(monster* mons)
414 {
415 ASSERT(mons); // XXX: change to monster &mons
416 ASSERT(!invalid_monster_type(mons->type));
417
418 // Natasha's death lines aren't physical speech.
419 if ((mons->asleep() || mons->cannot_act() || mons->flags & MF_EXPLODE_KILL)
420 && !(mons->type == MONS_NATASHA && !mons->alive()))
421 {
422 return false;
423 }
424
425 // Monsters talk on death even if invisible/silenced/etc.
426 int duration = 1;
427 const bool force_speak = !mons->alive()
428 || (mons->flags & MF_BANISHED) && !player_in_branch(BRANCH_ABYSS)
429 || (mons->is_summoned(&duration) && duration <= 0)
430 || crawl_state.prev_cmd == CMD_LOOK_AROUND; // Wizard testing
431
432 const bool unseen = !you.can_see(*mons);
433 const bool confused = mons->confused();
434
435 if (!force_speak)
436 {
437 // Invisible monster tries to remain unnoticed. Unless they're
438 // confused, since then they're too confused to realise they
439 // should stay silent, but only if the player can see them, so as
440 // to not have to deal with cases of speaking monsters which the
441 // player can't see.
442 if (unseen && !confused)
443 return false;
444
445 // Silenced monsters only "speak" 1/3 as often as non-silenced,
446 // unless they're normally silent (S_SILENT).
447 if (mons->is_silenced() && mons_can_shout(mons->type)
448 && !one_chance_in(3))
449 {
450 return false;
451 }
452
453 // Berserk monsters just want your hide.
454 if (mons->berserk_or_insane())
455 return false;
456
457 // Rolling beetles shouldn't twitch antennae
458 if (mons->has_ench(ENCH_ROLLING))
459 return false;
460
461 // Charmed monsters aren't too expressive.
462 if (mons->has_ench(ENCH_CHARM) && !one_chance_in(3))
463 return false;
464 }
465
466 vector<string> prefixes;
467 if (mons->neutral())
468 {
469 if (!force_speak && coinflip()) // Neutrals speak half as often.
470 return false;
471
472 prefixes.emplace_back("neutral");
473 }
474 else if (mons->friendly() && !crawl_state.game_is_arena())
475 prefixes.emplace_back("friendly");
476 else
477 prefixes.emplace_back("hostile");
478
479 if (mons_is_fleeing(*mons))
480 prefixes.emplace_back("fleeing");
481
482 bool silence = silenced(you.pos());
483 if (silenced(mons->pos()) || mons->has_ench(ENCH_MUTE))
484 {
485 silence = true;
486 prefixes.emplace_back("silenced");
487 }
488
489 if (confused)
490 prefixes.emplace_back("confused");
491
492 // Allows monster speech to be altered slightly on-the-fly.
493 if (mons->props.exists("speech_prefix"))
494 prefixes.push_back(mons->props["speech_prefix"].get_string());
495
496 const actor* foe = _get_foe(*mons);
497 const monster* m_foe = foe ? foe->as_monster() : nullptr;
498
499 if (!foe || foe->is_player() || mons->wont_attack())
500 {
501 // Animals only look at the current player form, smart monsters at the
502 // actual player genus.
503 if (is_player_same_genus(mons->type))
504 prefixes.emplace_back("related"); // maybe overkill for Beogh?
505 }
506 else
507 {
508 if (mons_genus(mons->mons_species()) ==
509 mons_genus(foe->mons_species()))
510 {
511 prefixes.emplace_back("related");
512 }
513 }
514
515 const god_type god = foe ? foe->deity() :
516 crawl_state.game_is_arena() ? GOD_NO_GOD
517 : you.religion;
518
519 // Add Beogh to list of prefixes for orcs (hostile and friendly) if you
520 // worship Beogh. (This assumes your being an orc, so might have odd
521 // results in wizard mode.) Don't count charmed or summoned orcs.
522 if (you_worship(GOD_BEOGH) && mons_genus(mons->type) == MONS_ORC)
523 {
524 if (!mons->has_ench(ENCH_CHARM) && !mons->is_summoned())
525 {
526 if (mons->god == GOD_BEOGH)
527 prefixes.emplace_back("Beogh");
528 else
529 prefixes.emplace_back("unbeliever");
530 }
531 }
532 else if (mons->type == MONS_PLAYER_GHOST)
533 {
534 // Use the *ghost's* religion, to get speech about its god. Only
535 // sometimes, though, so we can get skill-based messages as well.
536 if (coinflip())
537 prefixes.push_back(god_name(mons->ghost->religion));
538 }
539 else
540 {
541 // Include our current god's name, too. This means that uniques
542 // can have speech that is tailored to your specific god.
543 if (is_good_god(god) && coinflip())
544 prefixes.emplace_back("good god");
545 else
546 prefixes.push_back(god_name(you.religion));
547 }
548
549 // Include our current branch, too. It can make speech vary by branch for
550 // uniques and other monsters! Specifically, Donald.
551 prefixes.emplace_back(branches[you.where_are_you].abbrevname);
552
553 // Include a prefix for the orb run.
554 if (player_has_orb())
555 prefixes.emplace_back("orb");
556
557 #ifdef DEBUG_MONSPEAK
558 {
559 string prefix;
560 const int size = prefixes.size();
561 for (int i = 0; i < size; i++)
562 {
563 prefix += prefixes[i];
564 prefix += " ";
565 }
566 dprf(DIAG_SPEECH, "monster speech lookup for %s: prefix = %s",
567 mons->name(DESC_PLAIN).c_str(), prefix.c_str());
568 }
569 #endif
570
571 const bool no_foe = (foe == nullptr);
572 const bool no_player = crawl_state.game_is_arena()
573 || (!mons->wont_attack()
574 && (!foe || !foe->is_player()));
575 const bool mon_foe = (m_foe != nullptr);
576 const bool no_god = no_foe || (mon_foe && foe->deity() == GOD_NO_GOD);
577 const bool named_foe = !no_foe && (!mon_foe || (m_foe->is_named()
578 && m_foe->type != MONS_ROYAL_JELLY));
579 const bool no_foe_name = !named_foe
580 || (mon_foe && (m_foe->flags & MF_NAME_MASK));
581
582 string msg;
583
584 // First, try its exact name.
585 if (mons->type == MONS_PLAYER_GHOST)
586 {
587 if (one_chance_in(5))
588 {
589 const ghost_demon &ghost = *(mons->ghost);
590 string ghost_skill = skill_name(ghost.best_skill);
591 vector<string> with_skill = prefixes;
592 with_skill.push_back(ghost_skill);
593 msg = _get_speak_string(with_skill, "player ghost", mons,
594 no_player, no_foe, no_foe_name, no_god,
595 unseen);
596 }
597 if (msg.empty())
598 {
599 msg = _get_speak_string(prefixes, "player ghost", mons,
600 no_player, no_foe, no_foe_name, no_god,
601 unseen);
602 }
603 }
604 else if (mons->type == MONS_PANDEMONIUM_LORD)
605 {
606 // Pandemonium demons have randomly generated names, so use
607 // "pandemonium lord" instead.
608 msg = _get_speak_string(prefixes, "pandemonium lord", mons,
609 no_player, no_foe, no_foe_name, no_god,
610 unseen);
611 }
612 else
613 {
614 if (msg.empty() && mons->props.exists("dbname"))
615 {
616 msg = _get_speak_string(prefixes,
617 mons->props["dbname"].get_string(),
618 mons, no_player, no_foe, no_foe_name,
619 no_god, unseen);
620
621 if (msg.empty())
622 {
623 // Try again without the prefixes if the key is empty. Vaults
624 // *really* want monsters to use the key specified, rather than
625 // the key with prefixes.
626 vector<string> faux_prefixes;
627 msg = _get_speak_string(faux_prefixes,
628 mons->props["dbname"].get_string(),
629 mons, no_player, no_foe, no_foe_name,
630 no_god, unseen);
631 }
632 }
633
634 // If the monster was originally a unique which has been polymorphed
635 // into a non-unique, is its current monster type capable of using its
636 // old speech?
637 if (!mons->mname.empty() && mons->can_speak() && msg.empty())
638 {
639 msg = _get_speak_string(prefixes, mons->name(DESC_PLAIN),
640 mons, no_player, no_foe, no_foe_name,
641 no_god, unseen);
642 }
643
644 if (msg.empty())
645 {
646 msg = _get_speak_string(prefixes, mons->base_name(DESC_PLAIN),
647 mons, no_player, no_foe, no_foe_name,
648 no_god, unseen);
649 }
650 }
651
652 // The exact name brought no results, try monster genus.
653 if ((msg.empty() || msg == "__NEXT")
654 && mons_genus(mons->type) != mons->type)
655 {
656 msg = _get_speak_string(prefixes,
657 mons_type_name(mons_genus(mons->type), DESC_PLAIN),
658 mons, no_player, no_foe, no_foe_name, no_god,
659 unseen);
660 }
661
662 // __NONE means to be silent, and __NEXT means to try the next,
663 // less exact method of describing the monster to find a speech
664 // string.
665
666 if (msg == "__NONE")
667 {
668 #ifdef DEBUG_MONSPEAK
669 dprf(DIAG_SPEECH, "result: \"__NONE\"!");
670 #endif
671 return false;
672 }
673
674 // Now that we're not dealing with a specific monster name, include
675 // whether or not it can move in the prefix.
676 if (mons->is_stationary())
677 prefixes.insert(prefixes.begin(), "stationary");
678
679 // Names for the exact monster name and its genus have failed,
680 // so try the monster's glyph/symbol.
681 if (msg.empty() || msg == "__NEXT")
682 {
683 string key = "'";
684
685 // Database keys are case-insensitve.
686 if (isaupper(mons_base_char(mons->type)))
687 key += "cap-";
688
689 key += mons_base_char(mons->type);
690 key += "'";
691 msg = _get_speak_string(prefixes, key, mons, no_player, no_foe,
692 no_foe_name, no_god, unseen);
693 }
694
695 if (msg == "__NONE")
696 {
697 #ifdef DEBUG_MONSPEAK
698 dprf(DIAG_SPEECH, "result: \"__NONE\"!");
699 #endif
700 return false;
701 }
702
703 if (mons_intel(*mons) < I_HUMAN)
704 prefixes.insert(prefixes.begin(), "stupid");
705
706 const mon_body_shape shape = get_mon_shape(*mons);
707 if (msg.empty() || msg == "__NEXT")
708 {
709 msg = _get_speak_string(prefixes, get_mon_shape_str(shape), mons,
710 no_player, no_foe, no_foe_name, no_god,
711 unseen);
712 }
713
714 if (msg == "__NONE")
715 {
716 #ifdef DEBUG_MONSPEAK
717 dprf(DIAG_SPEECH, "result: \"__NONE\"!");
718 #endif
719 return false;
720 }
721
722 // If we failed to get a message with a partial/hybrid humanoid, try moving
723 // closer to plain humanoid.
724 if ((msg.empty() || msg == "__NEXT") && mon_shape_is_humanoid(shape)
725 && shape != MON_SHAPE_HUMANOID)
726 {
727 // If a humanoid monster has both wings and a tail, try removing
728 // one and then the other to see if we get any results.
729 if (shape == MON_SHAPE_HUMANOID_WINGED_TAILED)
730 {
731 msg = _get_speak_string(prefixes,
732 get_mon_shape_str(MON_SHAPE_HUMANOID_TAILED),
733 mons, no_player, no_foe, no_foe_name,
734 no_god, unseen);
735
736 // Only be silent if both tailed and winged return __NONE.
737 if (msg.empty() || msg == "__NONE" || msg == "__NEXT")
738 {
739 string msg2;
740 msg2 = _get_speak_string(prefixes,
741 get_mon_shape_str(MON_SHAPE_HUMANOID_WINGED),
742 mons, no_player, no_foe,
743 no_foe_name, no_god, unseen);
744
745 if (msg == "__NONE" && msg2 == "__NONE")
746 {
747 #ifdef DEBUG_MONSPEAK
748 dprf(DIAG_SPEECH, "result: \"__NONE\"!");
749 #endif
750 return false;
751 }
752
753 if (msg2 == "__NONE")
754 msg2 = "";
755
756 msg = msg2;
757 }
758 }
759
760 if (msg.empty() || msg == "__NONE" || msg == "__NEXT")
761 {
762 msg = _get_speak_string(prefixes,
763 get_mon_shape_str(MON_SHAPE_HUMANOID),
764 mons, no_player, no_foe, no_foe_name,
765 no_god, unseen);
766 }
767 }
768 if (msg.empty() || msg == "__NONE")
769 {
770 #ifdef DEBUG_MONSPEAK
771 dprf(DIAG_SPEECH, "final result: %s!",
772 (msg.empty() ? "empty" : "\"__NONE\""));
773 #endif
774 return false;
775 }
776
777 if (msg == "__NEXT")
778 {
779 msg::streams(MSGCH_DIAGNOSTICS)
780 << "__NEXT used by shape-based speech string for monster '"
781 << mons->name(DESC_PLAIN) << "'" << endl;
782 return false;
783 }
784
785 return mons_speaks_msg(mons, msg, MSGCH_TALK, silence);
786 }
787
invalid_msg(const monster & mon,string msg)788 bool invalid_msg(const monster &mon, string msg)
789 {
790 const actor* foe = _get_foe(mon);
791 const monster* m_foe = foe ? foe->as_monster() : nullptr;
792 // TODO: dedup with mons_speaks()
793 const bool no_foe = (foe == nullptr);
794 const bool no_player = crawl_state.game_is_arena()
795 || (!mon.wont_attack()
796 && (!foe || !foe->is_player()));
797 const bool mon_foe = (m_foe != nullptr);
798 const bool no_god = no_foe || (mon_foe && foe->deity() == GOD_NO_GOD);
799 const bool named_foe = !no_foe && (!mon_foe || (m_foe->is_named()
800 && m_foe->type != MONS_ROYAL_JELLY));
801 const bool no_foe_name = !named_foe
802 || (mon_foe && (m_foe->flags & MF_NAME_MASK));
803 const bool unseen = !you.can_see(mon);
804 return _invalid_msg(msg, no_player, no_foe, no_foe_name, no_god, unseen);
805
806 }
807
mons_speaks_msg(monster * mons,const string & msg,const msg_channel_type def_chan,bool silence)808 bool mons_speaks_msg(monster* mons, const string &msg,
809 const msg_channel_type def_chan, bool silence)
810 {
811 if (!you.see_cell(mons->pos()))
812 return false;
813
814 mon_acting mact(mons);
815
816 // We have a speech string, now parse and act on it.
817 const string _msg = do_mon_str_replacements(msg, *mons);
818 const vector<string> lines = split_string("\n", _msg);
819
820 bool noticed = false; // Any messages actually printed?
821
822 if (mons->has_ench(ENCH_MUTE))
823 silence = true;
824
825 for (string line : lines)
826 {
827 // This function is a little bit of a problem for the message
828 // channels since some of the messages it generates are "fake"
829 // warning to scare the player. In order to accommodate this
830 // intent, we're falsely categorizing various things in the
831 // function as spells and danger warning... everything else
832 // just goes into the talk channel -- bwr
833 // [jpeg] Added MSGCH_TALK_VISUAL for silent "chatter".
834 msg_channel_type msg_type = def_chan;
835
836 if (strip_channel_prefix(line, msg_type, silence))
837 {
838 if (msg_type == MSGCH_MONSTER_SPELL && mons->friendly())
839 msg_type = MSGCH_FRIEND_SPELL;
840 if (msg_type == MSGCH_MONSTER_ENCHANT && mons->friendly())
841 msg_type = MSGCH_FRIEND_ENCHANT;
842 if (line.empty())
843 continue;
844 }
845
846 const bool old_noticed = noticed;
847 noticed = true; // Only one case is different.
848
849 // Except for VISUAL, none of the above influence these.
850 if (msg_type == MSGCH_TALK_VISUAL)
851 silence = false;
852
853 if (msg_type == MSGCH_TALK_VISUAL && !you.can_see(*mons))
854 noticed = old_noticed;
855 else
856 {
857 if (you.can_see(*mons))
858 handle_seen_interrupt(mons);
859 mprf(msg_type, "%s", line.c_str());
860 }
861 }
862 return noticed;
863 }
864