zelgadis. Currently, shout.txt and speak.txt share in with the .des files in /dat. That should be changed, but I've no idea how to do this.
Also implementing a bug fix by ennewalker (1787428).
git-svn-id: https://crawl-ref.svn.sourceforge.net/svnroot/crawl-ref/trunk@2052 c06c8d41-db1a-0410-9941-cceddc491573
J6APXOT4QOGQFONWB7G546VTVF6QG42HVOROMHF7YBDJPR4K26OAC
FDODUDJBCF5LLARJNKBS65WDCHWE3TJY57X6LQDDMGRXMFFKG6WQC
VORPJHCEZKAOM3NHZSGHS2TT5X5AVR4WZFTA4PPZHS2NF5O6K2OQC
6STQOVN7PAYN5Y7PISP7PFCV4SDZUMHVOI7DQGUN5GM2SLLA5CPAC
HSRRNAU5UAYC6B6IQWGJPFROMZBTJICPCH6DJVZDHDTAGOQ6IOYAC
RCPQNIRPR3NQXEMVLBAQW6657UJFIP43N54UJVEZHJH22OH4UQIQC
54QO7QZXN6HFLXHLBLZK3QVXMX3JWBFS4WKS4WWCYVBK3KUZPQFAC
I7QLYOTE6DLQZM7YWUWYLKHRJRB2A3STQ42ALSRGQICEWKD2QTEQC
RGY2525RQH7SSGM6ZVI7CZL4WMNFZK2WRABOSIWRKQYYOU2RWN4QC
BW3XFNOS6LDAQLHOZ6RXARCMKCY5JVLVDSXDSSAX4DSYM3FANQBAC
UWMN4HLG6YA2YFQEVIVMDISD6APKEPIZXMMPMNUYCBQDSAUYSXPQC
SDLKLUNFGVKDS55DDJZCBAVIB7NL3RRYPTACAY65SCUQKV6APFSAC
K2CS6TCX2NDVL2ASEHGP4J4K4IJ6FP3ANNKTSIWVG43HPYSBX6ZQC
RPOZZWKG5GLPHVZZ7ZKMKS64ZMV2LDCQSARBJFJ6FZOTOKCQO7FAC
PFEJ4LMDNEKLMGRCMWQ7EIRVU4JMYGICI4G7X4WVWOROVXQCBZ7QC
WT66JDIRTLLP37SHTV4GI3V64JFJ4D25LNRLGCHFG6CLEFKJ3QGQC
UQFNR6PCRYPSUWMFF7KHITOVE4DZJ4CEAHFSXO7NG6GYZRF5JKUAC
3QLM46S44Z7GDLWPH3VHBMW2RSWZAOLGJMG2BDKNGUOZIM4IX6WAC
4UXFU3FZOCBSLDQ4S7MJKAE2H7VUHCNRDQMIY6NJ3PHYXWNGISDQC
E5DMZFW6WCFAKTKKOQPYTQXZ2CGLWMVH64LRXDUI2UIG4VYUHIVQC
RSIUBEQUGNU4LO6KH4PKVROWQS33DAKSY4XFVGN7T3CEKSXABCSAC
X5WLJCJVW55SXZVP7IKP7ADCJIGNKN4PKAXFECVR6TNK7XSMZR7QC
OP6CTAKWCAU64JXQ3USQYR5E5IFHQHNCACII5UMVRXUTZXJQOAZAC
2XG4UYEUFFZV4ARZJXQ36KQBK3XEAY77KEJOJ4X27NP5IBSF27YQC
D4MYPHZGUOL7HPS53DUUM4QSPIR5W3227DENDB4OBNDVQ4BU5VDAC
DYBB7LISQQKT734KRIQZCO67OGDQWLZ2KSTDZUY4BZFCCOIDTUWAC
MTM3ZU5KREJPXEMV3VVPDYWA5JZJISUBYDVEWCPBWNCKJF67CHWAC
7Y5HSDFKA5TPLS2TWTRFMQVX6UXUDHXU5MUMXQSDFAIY4THQ3BIQC
5V47S4NNTHWTSAHV3YLO2VGH7JTUIYJ3GBPDN5ZM4UQALT2ZEXDQC
5XSXMOBGXFLTIQE6WDXWWFVDOTUPZSIQ2FWT3YI5QMVU6D76IUYQC
DDU4A3JGN5IUIPP5IASOODKPR2WBHSDSV4FITZ6HNXNSXXQACWAQC
YCL3W2PFE6ILTGBFODCSXNPDIA46KVSZP2TI7HDMYAOEJT65RIEAC
BNTPYSO6ECZ76CHHLDP3ASSPDSEUH4Y3E3LETKNXVWAWJRFL3YEQC
LW4N5EHKL776DURXZMAM6JEW3JPWWX5BSNP7TCZHTLCDOQTTGFCAC
QDWDUURSNLMT6AXNNJ3DEQCWAKCAIHV6MP5F7QGIBGXOG2BI2NPQC
7KWDC7XFNMBLSUO2HISIROBINZBX5T67LJEEXTAORXW2YZ7VWFGAC
DODCHP2S4I6VZKQAVXX6D76OPNFI2YWZ4XH3HZTMAJZXA2RJ3XRQC
CQ24AVAI6SW3AHTIDMLPSTRRBEU6FHRF5I5FD6G5QIYE6PO4BQMQC
UZ6N6HOUPGVSPC5NQROEEDWMEGJA5XUWUY2AKH5QG65AZ25PVXDAC
TJRYL3NXPW5IUGEV3YOC7JYWEXCZDBFPLT4AUG4P227WVKVB72ZAC
WLX2RQMMOMP2PYPAGJRM4VFD2WTLJTOAZZPPY3MV76FU2EGEJ54QC
DTO3EUKWHZ5RJNGNCFYXSOVTIPVXPP637F2W7WFGYKJ7JK7VNKNQC
3C2VE43SHCSBY4LTRTFYFLIPRWFUN6DXU6D34QVWDQTSNRBUFG7AC
Y56C5OMUQ5XF2G6DKDV4R5MED44UOIUPTBBQVWQBUHYIXYA5MOZAC
KR655YT3I3U5DMN5NS3FPUGMDNT4BI56K3SFF2FNJ77C45NFKL5AC
5SFYYTKXTWLSBXB4PUB6G3E47W6DNROQNDLN3UJZQ4FN7ML3MADQC
X2FMEN4E345XD26Z2X7JMJ7VGHOGCGIELMHQRE2ITLVNQACP3NOQC
TZ643KHSE5CUPXFSQ7VYVOCM5MTQ7F4SENEYQX2RNFHGHLQVS3RQC
M47QBURKKRV2JFK6U7GQNVWK7RUTBVPBJ5FHURC55SKQSXAUFSBAC
if (you.turn_is_over
&& mons_shouts(monster->type) != S_SILENT
&& random2(30) >= you.skills[SK_STEALTH])
if (!force
&& (!you.turn_is_over || random2(30) < you.skills[SK_STEALTH]))
return;
// Get it once, since monster might be S_RANDOM, in which case
// mons_shouts() will return a different value every time.
shout_type type = mons_shouts(monster->type);
// Silent monsters can give noiseless "visual shouts" if the
// player can see them, in which case silence isn't checked for.
if (mons_friendly(monster)
|| (type == S_SILENT && !player_monster_visible(monster))
|| (type != S_SILENT && (silenced(you.x_pos, you.y_pos)
|| silenced(monster->x, monster->y))))
return;
int noise_level = 8;
std::string default_msg_key;
switch (type)
{
case NUM_SHOUTS:
case S_RANDOM:
default_msg_key = "__BUGGY";
break;
case S_SILENT:
default_msg_key = "";
noise_level = 0;
break;
case S_SHOUT:
default_msg_key = "__SHOUT";
break;
case S_BARK:
default_msg_key = "__BARK";
break;
case S_SHOUT2:
default_msg_key = "__TWO_SHOUTS";
noise_level = 12;
break;
case S_ROAR:
default_msg_key = "__ROAR";
noise_level = 12;
break;
case S_SCREAM:
default_msg_key = "__SCREAM";
break;
case S_BELLOW:
default_msg_key = "__BELLOW";
break;
case S_SCREECH:
default_msg_key = "__SCREECH";
break;
case S_BUZZ:
default_msg_key = "__BUZZ";
break;
case S_MOAN:
default_msg_key = "__MOAN";
break;
case S_WHINE:
default_msg_key = "__WHINE";
break;
case S_CROAK:
default_msg_key = "__CROAK";
break;
case S_GROWL:
default_msg_key = "__GROWL";
break;
case S_HISS:
default_msg_key = "__HISS";
noise_level = 4; // not very loud -- bwr
break;
// Loudness setting for shouts that are only defined in dat/shout.txt
case S_VERY_SOFT:
default_msg_key = "";
noise_level = 4;
break;
case S_SOFT:
default_msg_key = "";
noise_level = 6;
break;
case S_NORMAL:
default_msg_key = "";
noise_level = 8;
break;
case S_LOUD:
default_msg_key = "";
noise_level = 10;
break;
case S_VERY_LOUD:
default_msg_key = "";
noise_level = 12;
break;
}
// Use get_monster_data(monster->type) to bypass mon_shouts()
// replacing S_RANDOM with a random value.
if (mons_is_demon( monster->type ) && coinflip()
&& (type != S_SILENT ||
get_monster_data(monster->type)->shouts == S_RANDOM))
{
noise_level = 8;
default_msg_key = "__DEMON_TAUNT";
}
std::string msg, suffix;
std::string key = mons_type_name(monster->type, DESC_PLAIN);
// Pandemonium demons have random names, so use "pandemonium lord"
if (monster->type == MONS_PANDEMONIUM_DEMON)
key = "pandemonium lord";
// Search for player ghost shout by the ghost's class.
else if (monster->type == MONS_PLAYER_GHOST)
{
const ghost_demon &ghost = *(monster->ghost);
std::string ghost_class = get_class_name(ghost.values[GVAL_CLASS]);
key = ghost_class + " player ghost";
default_msg_key = "player ghost";
}
// Tries to find an entry for "name seen" or "name unseen",
// and if no such entry exists then looks simply for "name".
if (player_monster_visible(monster))
suffix = " seen";
else
suffix = " unseen";
msg = getShoutString(key, suffix);
if (msg == "__DEFAULT" || msg == "__NEXT")
msg = getShoutString(default_msg_key, suffix);
else if (msg == "")
if (!mons_friendly(monster)
&& (!silenced(you.x_pos, you.y_pos)
&& !silenced(monster->x, monster->y)))
{
if (mons_is_demon( monster->type ) && coinflip())
{
if (monster->type == MONS_IMP
|| monster->type == MONS_WHITE_IMP
|| monster->type == MONS_SHADOW_IMP)
{
imp_taunt( monster );
}
else
{
demon_taunt( monster );
}
}
else
{
std::string msg = "You hear ";
switch (mons_shouts(monster->type))
{
case S_SILENT:
case NUM_SHOUTS:
case S_RANDOM:
msg += "buggy behaviour!";
break;
case S_SHOUT:
msg += "a shout!";
break;
case S_BARK:
msg += "a bark!";
break;
case S_SHOUT2:
msg += "two shouts!";
noise_level = 12;
break;
case S_ROAR:
msg += "a roar!";
noise_level = 12;
break;
case S_SCREAM:
msg += "a hideous shriek!";
break;
case S_BELLOW:
msg += "a bellow!";
break;
case S_SCREECH:
msg += "a screech!";
break;
case S_BUZZ:
msg += "an angry buzzing noise.";
break;
case S_MOAN:
msg += "a chilling moan.";
break;
case S_WHINE:
msg += "an irritating high-pitched whine.";
break;
case S_CROAK:
if (coinflip())
msg += "a loud, deep croak!";
else
msg += "a croak.";
break;
case S_GROWL:
msg += "an angry growl!";
break;
case S_HISS:
msg += "an angry hiss!";
noise_level = 4; // not very loud -- bwr
break;
}
msg::streams(MSGCH_SOUND) << msg << std::endl;
}
}
// Database keys are case-insensitve.
if (isupper(mons_char(monster->type)))
glyph_key += "cap-";
noisy( noise_level, monster->x, monster->y );
glyph_key += mons_char(monster->type);
glyph_key += "'";
msg = getShoutString(glyph_key, suffix);
if (msg == "" || msg == "__DEFAULT")
msg = getShoutString(default_msg_key, suffix);
}
if (default_msg_key == "__BUGGY")
msg::streams(MSGCH_SOUND) << "You hear something buggy!"
<< std::endl;
else if ((msg == "" || msg == "__NONE")
&& mons_shouts(monster->type) == S_SILENT)
; // No "visual shout" defined for silent monster, do nothing
else if (msg == "")
{
msg::streams(MSGCH_DIAGNOSTICS)
<< "No shout entry for default shout type '"
<< default_msg_key << "'" << std::endl;
msg::streams(MSGCH_SOUND) << "You hear something buggy!"
<< std::endl;
}
else if (msg == "__NONE")
{
msg::streams(MSGCH_DIAGNOSTICS)
<< "__NONE returned as shout for non-silent monster '"
<< default_msg_key << "'" << std::endl;
msg::streams(MSGCH_SOUND) << "You hear something buggy!"
<< std::endl;
}
else
{
msg = do_mon_str_replacements(msg, monster);
if (mons_shouts(monster->type) == S_SILENT)
msg::streams(MSGCH_TALK) << msg << std::endl;
else
msg::streams(MSGCH_SOUND) << msg << std::endl;
// Band members are a lot less likely to speak, since there's
// a lot of them.
if (testbits(monster->flags, MF_BAND_MEMBER))
chance *= 10;
// However, confused and fleeing monsters are more interesting.
if (monster->behaviour == BEH_FLEE)
chance /= 2;
if (monster->has_ench(ENCH_CONFUSION))
chance /= 2;
if (one_chance_in(chance))
mons_speaks(monster);
}
monster_type speaker;
const char **silenced;
const char **confused;
const char **confused_friend;
const char **fleeing;
const char **fleeing_friend;
const char **friendly;
const char **hostile; // Most common.
};
std::string prefix = "";
const int size = prefixes.size();
for (int i = 0; i < size; i++)
{
prefix += prefixes[i];
prefix += " ";
}
static const char *murray_silenced[] =
{
"%s rolls in a circle.",
"%s rolls around.",
"%s spins like a top.",
"%s grins evilly.",
"%s seems to say something.",
"%s says something you can't hear. It was probably not a compliment.",
NULL
};
std::string msg = "";
msg = getSpeakString(prefix + key);
if (msg != "")
return msg;
static const char *murray_hostile[] =
{
"%s rolls in a circle.",
"%s rolls around.",
"%s spins like a top.",
"%s grins evilly.",
"%s laughs evilly.",
"%s cackles, \"I will rule the world!\"",
"%s shouts, \"Give me your head, so I can impale it on a pike!\"",
"%s's teeth chatter loudly.",
"%s yells, \"I'm a mighty demonic power!\"",
"%s asks, \"How could you choose the Orb over me, your best friend?\"",
"%s shouts, \"Let the forces of evil and voodoo overcome you!\"",
"%s screams, \"If I had legs, you would be dead twenty times over!\"",
"%s yells, \"My visage is famous all over the dungeon!\"",
"%s says, \"You're the second biggest fool I've ever met!\"",
NULL
};
// Combinations of prefixes by threes
if (size >= 3)
{
for (int i = 0; i < (size - 2); i++)
for (int j = i + 1; j < (size - 1); j++)
for (int k = j + 1; k < size; k++)
{
prefix = prefixes[i] + " ";
prefix += prefixes[j] + " ";
prefix += prefixes[k] + " ";
static mon_dialogue vox_populi[] =
{
{ MONS_MURRAY, murray_silenced, NULL, NULL, NULL, NULL, NULL,
murray_hostile },
};
static const mon_dialogue *find_dialogue(const monsters *monster)
{
for (unsigned i = 0; i < sizeof(vox_populi) / sizeof(*vox_populi); ++i)
if (vox_populi[i].speaker == monster->type)
return (&vox_populi[i]);
return (NULL);
}
static bool say_dialogue(const monsters *monster,
const char **dialogue)
{
if (!dialogue)
return (false);
msg = getSpeakString("default " + prefix + key);
if (msg != "")
return msg;
}
}
int nitems = 0;
for (const char **run = dialogue; *run; ++run, ++nitems)
;
// Combinations of prefixes by twos
if (size >= 2)
{
for (int i = 0; i < (size - 1); i++)
for (int j = i + 1; j < size; j++)
{
prefix = prefixes[i] + " ";
prefix += prefixes[j] + " ";
static bool say_specific_dialogue(const monsters *monster,
const mon_dialogue *dialogue)
// Player ghosts with different classes can potentially speak different
// things.
static std::string player_ghost_speak_str(const monsters *monster,
const std::vector<std::string> prefixes)
int temp_rand; // probability determination
// This function is a little bit of a problem for the message channels
// since some of the messages it generates are "fake" warning to
// scare the player. In order to accomidate this intent, we're
// falsely categorizing various things in the function as spells and
// danger warning... everything else just goes into the talk channel -- bwr
msg_channel_type msg_type = MSGCH_TALK;
const std::string m_name = monster->name(DESC_CAP_THE);
strcpy(info, m_name.c_str());
// Invisible monster tries to remain unnoticed. Unless they're
// confused, since then they're too confused to realize they
// should stay silent, but only if the player can see them, so as
// to not have to deal with cases of speaking monsters which the
// player can't see.
if (monster->invisible() && !(player_monster_visible(monster)
&& monster->has_ench(ENCH_CONFUSION)))
return false;
if (monster->invisible())
// Dealing with the monster not being silenced while the player
// *is* silenced, and is hence able to see the monsters' gestures
// and such but not hear any sounds it makes, would be a big
// headache to deal with, so skip it.
if (!silenced(monster->x, monster->y)
&& silenced(you.x_pos, you.y_pos))
const mon_dialogue *dialogue = find_dialogue(monster);
if (dialogue)
return (say_specific_dialogue(monster, dialogue));
//mv: if it's also invisible, program never gets here
if (silenced(monster->x, monster->y))
{
// Silenced monsters only "speak" 1/3 as often as non-silenced,
// unless they're normally silent (S_SILENT). Use
// get_monster_data(monster->type) to bypass mon_shouts()
// replacing S_RANDOM with a random value.
if (silenced(monster->x, monster->y)
&& get_monster_data(monster->type)->shouts != S_SILENT)
if (monster->has_ench(ENCH_CONFUSION))
{
temp_rand = random2(10);
strcat(info, (temp_rand < 4) ? " gestures wildly." :
(temp_rand == 4) ? " looks confused." :
(temp_rand == 5) ? " grins evilly." :
(temp_rand == 6) ? " smiles happily." :
(temp_rand == 7) ? " cries."
: " says something but you don't hear anything.");
}
else if (monster->behaviour == BEH_FLEE)
{
temp_rand = random2(10);
strcat(info,
(temp_rand < 3) ? " glances furtively about." :
(temp_rand == 3) ? " opens its mouth, as if shouting." :
(temp_rand == 4) ? " looks around." :
(temp_rand == 5) ? " appears indecisive." :
(temp_rand == 6) ? " ponders the situation."
: " seems to say something.");
}
// disregard charmed critters.. they're not too expressive
else if (monster->attitude == ATT_FRIENDLY)
{
temp_rand = random2(10);
strcat(info, (temp_rand < 3) ? " gives you a thumbs up." :
(temp_rand == 3) ? " looks at you." :
(temp_rand == 4) ? " waves at you." :
(temp_rand == 5) ? " smiles happily.":
(temp_rand == 6) ? " winks at you."
: " says something you can't hear.");
}
else
{
temp_rand = random2(10);
strcat(info, (temp_rand < 3) ? " gestures." :
(temp_rand == 3) ? " gestures obscenely." :
(temp_rand == 4) ? " grins." :
(temp_rand == 5) ? " looks angry." :
(temp_rand == 6) ? " seems to be listening."
: " says something but you don't hear anything.");
} //end switch silenced monster's behaviour
mpr(info, MSGCH_TALK);
return true;
} // end silenced monster
prefixes.push_back("confused");
std::string msg;
// __NONE means to be silent, and __NEXT means to try the next,
// less exact method of describing the monster to find a speech
// string.
// First, try its exact name
if (monster->type == MONS_PLAYER_GHOST)
// Player ghosts are treated differently.
msg = player_ghost_speak_str(monster, prefixes);
else if (monster->type == MONS_PANDEMONIUM_DEMON)
// Pandemonium demons have randomly generated names,
// so use "pandemonium lord" instead.
msg = get_speak_string(prefixes, "pandemonium lord", monster);
else
msg = get_speak_string(prefixes, monster->name(DESC_PLAIN), monster);
if (msg == "__NONE")
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,
// so try the monster's glyph/symbol.
if (msg == "" || msg == "__NEXT")
if (mons_friendly(monster))
{
switch (random2(18)) // speaks for friendly confused monsters
{
case 0:
strcat(info, " prays for help.");
break;
case 1:
strcat(info, " screams, \"Help!\"");
break;
case 2:
strcat(info, " shouts, \"I'm losing control!\"");
break;
case 3:
strcat(info, " shouts, \"What's happening?\"");
break;
case 4:
case 5:
strcat(info, " gestures wildly.");
break;
case 6:
strcat(info, " cries.");
break;
case 7:
strcat(info, " shouts, \"Yeah!\"");
break;
case 8:
strcat(info, " sings.");
break;
case 9:
strcat(info, " laughs crazily.");
break;
case 10:
strcat(info, " ponders the situation.");
break;
case 11:
strcat(info, " grins madly.");
break;
case 12:
strcat(info, " looks very confused.");
break;
case 13:
strcat(info, " mumbles something.");
break;
case 14:
strcat(info, " giggles crazily.");
break;
case 15:
strcat(info, " screams, \"");
strcat(info, you.your_name);
strcat(info, "! Help!\"");
break;
case 16:
strcat(info, " screams, \"");
strcat(info, you.your_name);
strcat(info, "! What's going on?\"");
break;
case 17:
strcat(info, " says, \"");
strcat(info, you.your_name);
strcat(info, ", I'm a little confused.\"");
break;
}
}
else
{
switch (random2(23)) // speaks for unfriendly confused monsters
{
case 0:
strcat(info, " yells, \"Get them off me!\"");
break;
case 1:
strcat(info, " screams, \"I will kill you anyway!\"");
break;
case 2:
strcat(info, " shouts, \"What's happening?\"");
break;
case 3:
case 4:
case 5:
strcat(info, " gestures wildly.");
break;
case 6:
strcat(info, " cries.");
break;
case 7:
strcat(info, " shouts, \"NO!\"");
break;
case 8:
strcat(info, " shouts, \"YES!\"");
break;
case 9:
strcat(info, " laughs crazily.");
break;
case 10:
strcat(info, " ponders the situation.");
break;
case 11:
strcat(info, " grins madly.");
break;
case 12:
strcat(info, " looks very confused.");
break;
case 13:
strcat(info, " mumbles something.");
break;
case 14:
strcat(info, " says, \"I'm a little confused.\"");
break;
case 15:
strcat(info, " asks, \"Where am I?\"");
break;
case 16:
strcat(info, " shakes.");
break;
case 17:
strcat(info, " asks, \"Who are you?\"");
break;
case 18:
strcat(info, " asks, \"What the hell are we doing here? Mmm, I see...\"");
break;
case 19:
strcat(info, " cries, \"My head! MY HEAD!!!\"");
break;
case 20:
strcat(info, " says, \"Why is everything spinning?\"");
break;
case 21:
strcat(info, " screams, \"NO! I can't bear that much noise!\"");
break;
case 22:
strcat(info, " is trying to cover his eyes.");
break;
}
}
// Database keys are case-insensitve.
if (isupper(mons_char(monster->type)))
key += "cap-";
else if (monster->has_ench(ENCH_HELD))
if (msg == "__NONE")
return false;
// Monster symbol didn't work, try monster shape. Since we're
// dealing with just the monster shape, change the prefix to
// include info on if the monster's intelligence is at odds with
// its shape.
mon_body_shape shape = get_mon_shape(monster);
mon_intel_type intel = mons_intel(monster->type);
if (shape >= MON_SHAPE_HUMANOID && shape <= MON_SHAPE_NAGA
&& intel < I_NORMAL)
prefixes.insert(prefixes.begin(), "stupid");
else if (shape >= MON_SHAPE_QUADRUPED && shape <= MON_SHAPE_FISH)
switch(random2(8))
{
case 0:
strcat(info, " says, \"Help me, ");
strcat(info, you.your_name);
strcat(info, ", please!\"");
break;
case 1:
strcat(info, " cries, \"MUMMY!\"");
break;
case 2:
strcat(info, " shouts, \"");
strcat(info, you.your_name);
strcat(info, "! Can't you see I need your help?\"");
break;
case 3:
strcat(info, " shouts, \"I could do with a little help here, you know.\"");
break;
case 4:
strcat(info, " mumbles something.");
break;
case 5:
strcat(info, " says, \"Umm, ");
strcat(info, you.your_name);
strcat(info, "? Help?\"");
break;
case 6:
strcat(info, " cries.");
break;
case 7:
strcat(info, " cries, \"Why me?");
break;
}
if (intel > I_INSECT)
prefixes.insert(prefixes.begin(), "smart");
else if (intel < I_INSECT)
prefixes.insert(prefixes.begin(), "stupid");
switch(random2(12))
{
case 0:
strcat(info, " screams, \"HEY! This isn't fair!\"");
break;
case 1:
strcat(info, " screams, \"Help! Get me out of here!\"");
break;
case 2:
strcat(info, " begs, \"Could you help me? I swear I won't hurt you.\"");
break;
case 3:
strcat(info, " yells, \"LEMME GO!\"");
break;
case 4:
strcat(info, " cries, \"Please! I'll never do it again!\"");
break;
case 5:
strcat(info, " mutters, \"Just what did I do to deserve this?\"");
break;
case 6:
strcat(info, " asks, \"Hey, want to switch places?\"");
break;
case 7:
strcat(info, " cries, \"I hate you!\"");
break;
case 8:
strcat(info, " snarls, \"This is all your fault!\"");
break;
case 9:
strcat(info, " says, \"I meant to do this, just so you know.\"");
break;
case 10:
strcat(info, " shouts, \"This is all a huge misunderstanding!");
break;
case 11:
strcat(info, " cries, \"Why me?\"");
break;
}
if (intel > I_ANIMAL)
prefixes.insert(prefixes.begin(), "smart");
else if (intel < I_ANIMAL)
prefixes.insert(prefixes.begin(), "stupid");
if (mons_holiness( monster ) == MH_DEMONIC
&& monster->type != MONS_IMP)
{
return (false);
}
if (mons_friendly(monster))
{
switch (random2(11))
{
case 0:
snprintf( info, INFO_SIZE, "%s %s, \"WAIT FOR ME!\"",
m_name.c_str(), coinflip() ? "shouts" : "yells");
strcat(info, you.your_name);
strcat(info, ", could you help me?\"");
break;
case 1:
strcat(info, " screams, \"Help!\"");
break;
case 2:
strcat(info, " shouts, \"Cover me!\"");
break;
case 3:
strcat(info, " screams, \"");
strcat(info, you.your_name);
strcat(info, "! Help me!\"");
break;
case 4:
case 5:
case 6:
strcat(info, " tries to hide somewhere.");
break;
case 7:
strcat(info, " prays for help.");
break;
case 8:
strcat(info, " looks at you beseechingly.");
break;
case 9:
strcat(info, " shouts, \"Protect me!\"");
break;
case 10:
strcat(info, " cries, \"Don't forget your friends!\"");
break;
}
}
else
{
switch (random2(20)) // speaks for unfriendly fleeing monsters
{
case 0:
snprintf( info, INFO_SIZE, "%s %s, \"Help!\"", m_name.c_str(),
coinflip()? "yells" : "wails");
break;
case 1:
snprintf( info, INFO_SIZE, "%s %s, \"Help!\"", m_name.c_str(),
coinflip() ? "cries" : "screams"); break;
case 2:
snprintf( info, INFO_SIZE, "%s %s, \"Why can't we all just get along?\"",
m_name.c_str(), coinflip() ? "begs" : "pleads");
break;
case 3:
snprintf( info, INFO_SIZE, "%s %s trips in trying to escape.", m_name.c_str(),
coinflip() ? "nearly" : "almost");
break;
case 4:
snprintf( info, INFO_SIZE, "%s %s, \"Of all the rotten luck!\"", m_name.c_str(),
coinflip() ? "mutters" : "mumbles");
break;
case 5:
snprintf( info, INFO_SIZE, "%s %s, \"Oh dear! Oh dear!\"", m_name.c_str(),
coinflip() ? "moans" : "wails");
case 6:
snprintf( info, INFO_SIZE, "%s %s, \"Damn and blast!\"", m_name.c_str(),
coinflip() ? "mutters" : "mumbles");
break;
case 7:
strcat(info, " prays for help.");
break;
case 8:
strcat(info, " shouts, \"No! I'll never do that again!\"");
break;
case 9:
snprintf( info, INFO_SIZE, "%s %s", m_name.c_str(),
coinflip() ? "begs for mercy." : "cries, \"Mercy!\"");
break;
case 10:
snprintf( info, INFO_SIZE, "%s %s, \"%s!\"", m_name.c_str(),
coinflip() ? "blubbers" : "cries",
coinflip() ? "Mommeee" : "Daddeee");
break;
case 11:
snprintf( info, INFO_SIZE, "%s %s, \"Please don't kill me!\"", m_name.c_str(),
coinflip() ? "begs" : "pleads");
break;
case 12:
snprintf( info, INFO_SIZE, "%s %s, \"Please don't hurt me!\"", m_name.c_str(),
coinflip() ? "begs" : "pleads");
break;
case 13:
snprintf( info, INFO_SIZE, "%s %s, \"Please, I have a lot of children...\"",
m_name.c_str(), coinflip() ? "begs" : "pleads");
break;
case 14:
strcat(info, " tries to recover lost courage.");
break;
case 15:
case 16:
case 17:
strcat(info, " gives up.");
break;
case 19:
snprintf( info, INFO_SIZE, "%s looks really %s.",
m_name.c_str(),
coinflip() ? "scared stiff" : "rattled");
break;
}
}
if (intel > I_INSECT)
prefixes.insert(prefixes.begin(), "smart");
else if (intel < I_INSECT)
prefixes.insert(prefixes.begin(), "stupid");
else if (mons_friendly(monster))
else if (shape >= MON_SHAPE_PLANT && shape <= MON_SHAPE_BLOB
&& intel > I_PLANT)
prefixes.insert(prefixes.begin(), "smart");
if (msg == "" || msg == "__NEXT")
msg = get_speak_string(prefixes, get_mon_shape_str(shape), monster);
if (msg == "__NONE")
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
&& shape <= MON_SHAPE_NAGA)
if (mons_holiness( monster ) == MH_DEMONIC
&& monster->type != MONS_IMP)
// If a humanoid monster has both wings and a tail, try
// removing one and then the other to see if we get any
// results.
if (shape == MON_SHAPE_HUMANOID_WINGED_TAILED)
// friendly imps are too common so they speak very very rarely
if (monster->type == MONS_IMP)
{
if (!one_chance_in(10))
return (false);
switch (random2(12))
// Only be silent if both tailed and winged return __NONE
if (msg == "" || msg == "__NONE" || msg == "__NEXT")
case 0:
strcat(info, " says, \"Just tell me who NOT to kill.\"");
break;
case 1:
strcat(info, " says, \"OK Boss!\"");
break;
case 2:
strcat(info, " grins impishly at you.");
break;
case 3:
strcat(info, " picks up some beetles from the floor "
"and offers them to you.");
break;
case 4:
strcat(info, " blows smoke rings.");
break;
case 5:
strcat(info, " shouts, \"Over here! I found it!\"");
break;
case 6:
strcat(info, " says, \"The Orb is all yours.\"");
break;
case 7:
strcat(info, " says, \"Isn't this more fun with friends?\"");
break;
case 8:
strcat(info, " says, \"Uh-oh! Wait. OK.\"");
break;
case 9:
strcat(info, " shouts, \"Stay back! It could be a trick.\"");
break;
case 10:
strcat(info, " says, \"You're so much nicer than "
"my last boss.\"");
break;
case 11:
strcat(info, " jumps up and down with excitement.\"");
break;
}
}
else
{
switch (random2(18))
{
case 0:
strcat(info, " yells, \"Run! I'll cover you!\"");
break;
case 1:
strcat(info, " shouts, \"Die, monster!\"");
break;
case 2:
strcat(info, " says, \"It's nice to have friends.\"");
break;
shape = MON_SHAPE_HUMANOID_WINGED;
std::string msg2;
msg2 = get_speak_string(prefixes,
get_mon_shape_str(shape),
monster);
if (msg == "__NONE" && msg2 == "__NONE")
return false;
case 3:
strcat(info, " looks at you.");
break;
case 4:
strcat(info, " smiles at you.");
break;
case 5:
strcat(info, " says, \"");
strcat(info, you.your_name);
strcat(info, ", you are my only friend.\"");
break;
case 6:
strcat(info, " says, \"");
strcat(info, you.your_name);
strcat(info, ", I like you.\"");
break;
if (msg2 == "__NONE")
msg2 = "";
case 7:
strcat(info, " waves at you.");
break;
case 8:
strcat(info, " says, \"Be careful!\"");
break;
case 9:
strcat(info, " says, \"Don't worry. I'm here with you.\"");
break;
case 10:
strcat(info, " smiles happily.");
break;
case 11:
strcat(info, " shouts, \"No mercy! Kill them all!");
break;
case 12:
strcat(info, " winks at you.");
break;
case 13:
strcat(info, " says, \"Me and you. It sounds cool.\"");
break;
case 14:
strcat(info, " says, \"I'll never leave you.\"");
break;
case 15:
strcat(info, " says, \"I would die for you.\"");
break;
case 16:
strcat(info, " shouts, \"Beware of monsters!\"");
break;
case 17:
strcat(info, " looks friendly.");
break;
msg = msg2;
switch (monster->type)
{
case MONS_TERENCE: // fighter who likes to kill
switch (random2(15))
{
case 0:
strcat(info, " screams, \"I'm going to kill you! \"");
break;
case 1:
strcat(info, " shouts, \"Now you die.\"");
break;
case 2:
strcat(info, " says, \"Rest in peace.\"");
break;
case 3:
snprintf( info, INFO_SIZE, "%s shouts, \"%s!!!\"",
m_name.c_str(), coinflip() ? "ATTACK" : "DIE");
break;
case 4:
strcat(info, " says, \"How do you enjoy it?\"");
break;
case 5:
strcat(info, " shouts, \"Get ready for death!\"");
break;
case 6:
strcat(info, " says, \"You are history.\"");
break;
case 7:
strcat(info, " says, \"Do you want it fast or slow?.\"");
break;
case 8:
strcat(info, " says, \"Did you write a testament? You should...\"");
break;
case 9:
strcat(info, " says, \"Time to say good-bye...\"");
break;
case 10:
snprintf( info, INFO_SIZE, "%s says, \"Don't try to defend, it's %s.\"",
m_name.c_str(), coinflip() ? "pointless" : "senseless");
break;
case 11:
strcat(info, " bares his teeth.");
break;
case 12:
snprintf( info, INFO_SIZE, "%s says, \"I'll show you few %s.\"",
m_name.c_str(), coinflip() ? "tricks" : "ploys.");
break;
case 13:
strcat(info, " screams, \"I want your blood.\"");
break;
case 14:
strcat(info, " looks scornfully at you.");
break;
}
break; // end Terence
msg::streams(MSGCH_DIAGNOSTICS)
<< "__NEXT used by shape-based speech string for monster '"
<< monster->name(DESC_PLAIN) << "'" << std::endl;
return false;
}
case MONS_EDMUND: // mercenaries guarding dungeon
case MONS_LOUISE:
case MONS_FRANCES:
case MONS_DUANE:
case MONS_FREDERICK:
switch (random2(17))
{
case 0:
strcat(info, " screams, \"I'm going to kill you! Now!\"");
break;
case 1:
strcat(info,
" shouts, \"Return immediately or I'll kill you!\"");
break;
case 2:
strcat(info,
" says, \"Now you've reached the end of your journey!\"");
break;
case 3:
strcat(info,
" screams, \"One false step and I'll kill you!\"");
break;
case 4:
strcat(info, " says, \"Drop everything you've found here and return home.\"");
break;
case 5:
strcat(info, " shouts, \"You will never get the Orb.\"");
break;
case 6:
strcat(info, " looks very unfriendly.");
break;
case 7:
strcat(info, " looks very cold.");
break;
case 8:
strcat(info, " shouts, \"It's the end of the party!\"");
break;
case 9:
strcat(info, " says, \"Return every stolen item!\"");
break;
case 10:
strcat(info, " says, \"No trespassing is allowed here.\"");
break;
case 11:
strcat(info, " grins evilly.");
break;
case 12:
strcat(info, " screams, \"You must be punished!\"");
break;
case 13:
strcat(info, " says, \"It's nothing personal...\"");
break;
case 14:
strcat(info, " says, \"A dead adventurer is a good adventurer.\"");
break;
case 15:
strcat(info, " says, \"Coming here was your last mistake.\"");
break;
case 16:
strcat(info, " shouts, \"Intruder!\"");
break;
}
break; // end Edmund & Co
// We have a speech string, now parse and act on it.
msg = do_mon_str_replacements(msg, monster);
case MONS_JOSEPH:
switch (random2(16))
{
case 0:
strcat(info, " smiles happily.");
break;
case 1:
strcat(info, " says, \"I'm happy to see you. And I'll be happy to kill you.\"");
break;
case 2:
strcat(info, " says, \"I've waited for this moment for such a long time.\"");
break;
case 3:
strcat(info,
" says, \"It's nothing personal, but I have to kill you.\"");
break;
case 5:
strcat(info, " says, \"You will never get the Orb, sorry.\"");
break;
case 9:
strcat(info, " shouts, \"I love to fight! I love killing!\"");
break;
case 10:
strcat(info,
" says, \"I'm here to kill trespassers. I like my job.\"");
break;
case 11:
strcat(info, " tries to grin evilly.");
break;
case 12:
strcat(info,
" says, \"You must be punished! Or... I want to punish you!\"");
break;
case 13:
strcat(info,
" sighs, \"Being a guard is usually so boring...\"");
break;
case 14:
strcat(info, " shouts, \"At last some action!\"");
break;
case 15:
strcat(info, " shouts, \"Wow!\"");
break;
}
break; // end Joseph
std::vector<std::string> lines = split_string("\n", msg);
case MONS_ORC_HIGH_PRIEST: // priest, servants of dark ancient god
case MONS_DEEP_ELF_HIGH_PRIEST:
switch (random2(12))
{
case 0:
case 1:
strcat(info, " prays.");
msg_type = MSGCH_MONSTER_SPELL;
break;
for (int i = 0, size = lines.size(); i < size; i++)
{
std::string line = lines[i];
case 2:
strcat(info, " mumbles some strange prayers.");
msg_type = MSGCH_MONSTER_SPELL;
break;
if (line == "__YOU_RESIST")
{
canned_msg( MSG_YOU_RESIST );
continue;
}
else if (line == "__NOTHING_HAPPENS")
{
canned_msg( MSG_NOTHING_HAPPENS );
continue;
}
else if (line == "__MORE")
{
more();
continue;
}
case 3:
strcat(info,
" shouts, \"You are a heretic and must be destroyed.\"");
break;
case 4:
strcat(info, " says, \"All sinners must die.\"");
break;
// This function is a little bit of a problem for the message
// channels since some of the messages it generates are "fake"
// warning to scare the player. In order to accomidate this
// intent, we're falsely categorizing various things in the
// function as spells and danger warning... everything else
// just goes into the talk channel -- bwr
msg_channel_type msg_type = MSGCH_TALK;
case 5:
strcat(info, " looks excited.");
break;
case 6:
strcat(info, " says, \"You will make a fine sacrifice.\"");
break;
case 7:
strcat(info, " starts to sing a prayer.");
break;
case 8:
strcat(info, " shouts, \"You must be punished.\"");
break;
case 9:
strcat(info, " intones a terrible prayer.");
msg_type = MSGCH_MONSTER_SPELL;
break;
case 10:
strcat(info, " says, \" Right in the middle of my "
"sermon, too.\"");
break;
case 11:
strcat(info, " says, \"The wages of sin are death, "
"you know.\"");
break;
}
break; // end priests
case MONS_ORC_SORCERER: // hateful wizards, using strange powers
case MONS_DEEP_ELF_SORCERER:
case MONS_WIZARD:
switch (random2(19))
{
case 0:
case 1:
case 2:
strcat(info, " wildly gestures.");
mpr( info, MSGCH_MONSTER_SPELL );
if (coinflip())
canned_msg( MSG_NOTHING_HAPPENS );
else
canned_msg( MSG_YOU_RESIST );
return (true);
std::string::size_type pos = line.find(":");
case 3:
case 4:
case 5:
strcat(info, " mumbles some strange words.");
mpr( info, MSGCH_MONSTER_SPELL );
if (coinflip())
canned_msg( MSG_NOTHING_HAPPENS );
else
canned_msg( MSG_YOU_RESIST );
return (true);
case 6:
strcat(info, " shouts, \"You can't withstand my power!\"");
break;
case 7:
strcat(info, " shouts, \"You are history.\"");
break;
case 8:
simple_monster_message( monster, " casts a spell.",
MSGCH_MONSTER_SPELL );
strcat(info, " becomes transparent for a moment.");
msg_type = MSGCH_MONSTER_ENCHANT;
break;
case 9:
strcat(info, " throws some strange powder towards you.");
msg_type = MSGCH_MONSTER_SPELL;
break;
case 10:
simple_monster_message( monster, " casts a spell.",
MSGCH_MONSTER_SPELL );
strcat(info, " glows brightly for a moment.");
msg_type = MSGCH_MONSTER_ENCHANT;
break;
case 11:
strcat(info, " says, \"argatax netranoch dertex\"");
msg_type = MSGCH_MONSTER_SPELL;
break;
case 12:
strcat(info, " says, \"dogrw nutew berg\"");
msg_type = MSGCH_MONSTER_SPELL;
break;
if (pos != std::string::npos)
{
std::string param = line.substr(0, pos);
bool match = true;
break;
case 14:
strcat(info, " casts a spell.");
mpr(info, MSGCH_MONSTER_SPELL);
strcpy(info, m_name.c_str());
strcat(info, " becomes larger for a moment.");
msg_type = MSGCH_MONSTER_ENCHANT;
break;
case 15:
strcat(info, " casts a spell.");
mpr(info, MSGCH_MONSTER_SPELL);
strcpy(info, m_name.c_str());
strcat(info, "'s fingertips start to glow.");
else if (param == "ENCHANT")
break;
case 16:
strcat(info, "'s eyes start to glow.");
msg_type = MSGCH_MONSTER_SPELL;
break;
case 17:
strcat(info, " tries to paralyze you with his gaze.");
msg_type = MSGCH_MONSTER_SPELL;
break;
case 18:
strcat(info, " casts a spell.");
mpr(info, MSGCH_MONSTER_SPELL);
canned_msg( MSG_YOU_RESIST );
return (true);
}
break; // end wizards
case MONS_JESSICA: // sorceress disturbed by player
switch (random2(10))
{
case 0:
strcat(info, " grins evilly.");
break;
case 1:
strcat(info, " says, \"I'm really upset.\"");
break;
case 2:
strcat(info, " shouts, \"I don't like beings like you.\"");
break;
case 3:
strcat(info,
" shouts, \"Stop bothering me, or I'll kill you!\"");
break;
case 4:
strcat(info, " very coldly says, \"I hate your company.\"");
break;
case 5:
strcat(info, " mumbles something strange.");
msg_type = MSGCH_MONSTER_SPELL;
break;
case 6:
strcat(info, " looks very angry.");
break;
case 7:
strcat(info,
" shouts, \"You're disturbing me. I'll have to kill you.\"");
break;
case 8:
strcat(info, " screams, \"You are a ghastly nuisance!\"");
break;
case 9:
strcat(info, " gestures wildly.");
msg_type = MSGCH_MONSTER_SPELL;
break;
}
break; // end Jessica
case MONS_SIGMUND: // mad old wizard
switch (random2(19))
{
case 0:
case 1:
case 2:
strcat(info, " laughs crazily.");
break;
case 3:
strcat(info, " says, \"Don't worry, I'll kill you fast.\"");
break;
case 4:
strcat(info, " grinds his teeth.");
break;
case 5:
strcat(info, " asks, \"Do you like me?\"");
break;
case 6:
strcat(info, " screams, \"Die, monster!\"");
break;
case 7:
strcat(info, " says, \"You will soon forget everything.\"");
break;
case 8:
strcat(info, " screams, \"You will never... NEVER!\"");
break;
case 9:
simple_monster_message( monster, " casts a spell.",
MSGCH_MONSTER_SPELL );
strcat(info, "'s eyes start to glow with a red light. ");
msg_type = MSGCH_MONSTER_ENCHANT;
break;
case 10:
strcat(info, " says, \"Look into my eyes.\"");
break;
case 11:
strcat(info, " says, \"I'm your fate.\"");
break;
case 12:
simple_monster_message( monster, " casts a spell.",
MSGCH_MONSTER_SPELL );
strcat(info, " is suddenly surrounded by pale blue light.");
msg_type = MSGCH_MONSTER_ENCHANT;
break;
case 13:
strcat(info, " tries to bite you.");
break;
case 14:
simple_monster_message( monster, " casts a spell.",
MSGCH_MONSTER_SPELL );
strcat(info, " is suddenly surrounded by pale green light.");
msg_type = MSGCH_MONSTER_ENCHANT;
break;
case 15:
strcat(info, " screams, \"I am the angel of Death!\"");
break;
case 16:
strcat(info, " screams, \"Only death can liberate you!\"");
break;
case 17:
strcat(info, " whispers, \"You'll know eternity soon...\"");
break;
case 18:
strcat(info, " screams, \"Don't try to resist!\"");
break;
}
break; // end Sigmund
case MONS_IMP: // small demon
case MONS_WHITE_IMP:
case MONS_SHADOW_IMP:
if (one_chance_in(3))
{
imp_taunt( monster );
return (true);
}
else if (param == "PLAIN")
msg_type = MSGCH_PLAIN;
{
switch (random2(11))
{
case 0:
strcat(info, " laughs crazily.");
break;
case 1:
strcat(info, " grins evilly.");
break;
case 2:
strcat(info, " breathes smoke at you.");
break;
case 3:
strcat(info, " lashes his tail.");
break;
case 4:
strcat(info, " grinds his teeth.");
break;
case 5:
strcat(info, " sputters.");
break;
case 6:
strcat(info, " breathes steam at you.");
break;
case 7:
strcat(info, " spits at you.");
break;
case 8:
strcat(info, " disappears for a moment.");
break;
case 9:
strcat(info, " summons a swarm of flies.");
break;
case 10:
strcat(info, " picks up a beetle and eats it.");
break;
}
}
break; // end imp
match = false;
case MONS_TORMENTOR: // cruel devil
if (one_chance_in(10))
{
demon_taunt( monster );
return (true);
}
else
{
switch (random2(18))
{
case 0:
strcat(info, " laughs crazily.");
break;
case 1:
strcat(info, " grins evilly.");
break;
case 2:
strcat(info, " says, \"I am all your nightmares come true.\"");
break;
case 3:
strcat(info, " says, \"I will show you what pain is.\"");
break;
case 4:
strcat(info, " shouts, \"I'll tear you apart.\"");
break;
case 5:
strcat(info,
" says, \"You will wish to die when I get to you.\"");
break;
case 6:
strcat(info, " says, \"I will drown you in your own blood.\"");
break;
case 7:
strcat(info,
" screams, \"You will die horribly!\"");
break;
case 8:
strcat(info, " says, \"I will eat your liver.\"");
break;
case 9:
strcat(info, " grins madly.");
break;
case 10:
strcat(info, " shouts, \"Prepare for my thousand needles of pain!\"");
break;
case 11:
strcat(info,
" says, \"I know a thousand and one ways to kill you.\"");
break;
case 12:
strcat(info,
" says, \"I'll show you my torture chamber!\"");
break;
case 13:
case 14:
strcat(info,
" says, \"I'll crush your bones, one by one.\"");
break;
case 15:
strcat(info, " says, \"I know your fate. It's pain.\"");
break;
case 16:
strcat(info, " says, \"Get ready! Throes await you.\"");
break;
case 17:
strcat(info, " grins malevolently.");
break;
}
}
break; // end tormentor
case MONS_PANDEMONIUM_DEMON: // named demons
case MONS_GERYON:
case MONS_ASMODEUS:
case MONS_DISPATER:
case MONS_ANTAEUS:
case MONS_ERESHKIGAL:
case MONS_MNOLEG:
case MONS_LOM_LOBON:
case MONS_CEREBOV:
case MONS_GLOORX_VLOQ:
demon_taunt( monster );
return (true);
case MONS_PLAYER_GHOST: // ghost of unsuccesful player
switch (random2(29))
{
case 0:
strcat(info, " laughs crazily.");
break;
case 1:
strcat(info, " grins evilly.");
break;
case 2:
strcat(info, " shouts, \"You will never get the ORB!\"");
break;
case 3: // mv: ghosts are usually wailing, aren't ?
strcat(info, " says, \"I have seen your future. "
"And it's all used up.\"");
break;
case 4:
strcat(info, " makes a sound of rattling chains.");
break;
case 5:
strcat(info, " says, \"They lied to you. "
"The Dungeon just goes down and down forever.\"");
break;
case 6:
strcat(info, " says, \"Do you think the gods "
"will protect you?\"");
break;
case 7:
strcat(info, " says, \"I was like you once.\"");
break;
case 8:
strcat(info, " says, \"Very impressive. But it won't help. "
"Nothing will.\"");
break;
case 9:
strcat(info, " whispers, \"They're coming for you...\"");
break;
case 10:
strcat(info, " says, \"What have you got "
"that I didn't have?\"");
break;
case 11:
strcat(info, " wails.");
break;
case 12:
strcat(info, " stares at you.");
mpr(info, MSGCH_MONSTER_SPELL);
mpr("You feel cold.", MSGCH_WARN);
return (true);
case 13:
strcat(info, " screams, \"You will join me soon!\"");
break;
case 14:
strcat(info, " wails, \"To die, to sleep, no more.\"");
break; //Hamlet
case 15:
strcat(info,
" screams, \"You must not succeed where I failed.\"");
break;
case 16:
strcat(info,
" screams, \"I'll kill anyone who wants the ORB.\"");
break;
case 17:
strcat(info, " whispers, \"Meet emptiness of death!\"");
break;
case 18:
strcat(info, " whispers, \"Death is liberation.\"");
break;
case 19:
strcat(info,
" whispers, \"Everlasting silence awaits you.\"");
break;
case 20:
strcat(info,
" screams, \"Don't try to defend. You have no chance!\"");
break;
case 21:
strcat(info,
" whispers, \"Death doesn't hurt. What you feel is life.\"");
break;
case 22:
strcat(info, " whispers, \"The ORB doesn't exist.\"");
break;
case 23:
strcat(info, " wails, \"Death is your only future.\"");
break;
case 24:
strcat(info, " says, \"The more you struggle now, "
"the more you'll suffer later.\"");
break;
case 25:
strcat(info, " whispers, \"Trust me. Just give in.\"");
break;
case 26:
strcat(info, " says very slowly, \"There's no hope.\"");
break;
case 27:
strcat(info, " lets out a mournful wail.");
break;
case 28:
strcat(info, " keens inconsolably.");
break;
}
break; // end players ghost
case MONS_PSYCHE: // insane girl
switch (random2(20))
{
case 0:
strcat(info, " smiles happily.");
break;
case 1:
strcat(info, " giggles crazily.");
break;
case 2:
strcat(info, " cries.");
break;
case 3:
strcat(info, " stares at you for a moment.");
break;
case 4:
strcat(info, " sings.");
break;
case 5:
strcat(info,
" says, \"Please, could you die a little faster?\"");
break;
case 6:
strcat(info,
" says, \"I'm a bad girl. But I can't do anything about it.\"");
break;
case 7:
strcat(info,
" screams, \"YOU ARE VIOLATING AREA SECURITY!\"");
break;
case 8:
strcat(info, " cries, \"I hate blood and violence.\"");
break;
case 9:
strcat(info,
" screams, \"Peace! Flowers! Freedom! Dead adventurers!\"");
break;
case 10:
strcat(info,
" says, \"I'm so lonely. Only corpses are my friends.\"");
break;
case 11:
strcat(info, " cries, \"You've killed my pet.\"");
break;
case 12:
strcat(info,
" cries, \"You want to steal my orb collection?!\"");
break;
case 13:
strcat(info, " sings a strange song.");
break;
case 14:
strcat(info, " bursts into tears.");
break;
case 15:
strcat(info, " sucks her thumb.");
break;
case 16:
strcat(info,
" whispers, \"Hold me, thrill me, kiss me, kill me.\"");
break; //(c) U2 ?
case 17:
strcat(info, " says, \"I'll kill you and take you home.\"");
break;
case 18:
strcat(info,
" shouts, \"Well, maybe I'm nutty, but who cares?\"");
break;
case 19:
strcat(info,
" shouts, \"I hope that you are sorry for that.\"");
break;
}
break; // end Psyche
case MONS_DONALD: // adventurers hating competition
case MONS_WAYNE:
switch (random2(11))
{
case 0:
strcat(info, " screams, \"Return home!\"");
break;
case 1:
strcat(info, " screams, \"The Orb is mine!\"");
break;
case 2:
strcat(info, " screams, \"Give me all your treasure!\"");
break;
case 3:
strcat(info, " screams, \"You will never get the Orb!\"");
break;
case 4:
strcat(info, " screams, \"I was here first!\"");
break;
case 5:
strcat(info, " frowns.");
break;
case 6:
strcat(info, " looks very upset.");
break;
case 7:
strcat(info, " screams, \"Get away or die!\"");
break;
case 8:
strcat(info, " screams, \"Die!\"");
break;
case 9:
strcat(info, " screams, \"First you have to pass me!\"");
break;
case 10:
strcat(info, " screams, \"I hate you!\"");
break;
}
break; // end Donald
case MONS_MICHAEL: // spellcaster who wanted to be alone
switch (random2(11))
{
case 0:
strcat(info, " looks very angry.");
break;
case 1:
strcat(info, " frowns.");
break;
case 2:
strcat(info, " screams, \"I want to be alone!\"");
break;
case 3:
strcat(info, " says, \"You are really a nuisance.\"");
break;
case 4:
strcat(info,
" screams, \"I wanted to be alone. And you...\"");
break;
case 5:
strcat(info, " screams, \"Get away! Or better yet, die!\"");
break;
case 6:
strcat(info, " mumbles some strange words.");
msg_type = MSGCH_MONSTER_SPELL;
break;
case 7:
strcat(info, " points at you.");
mpr(info, MSGCH_MONSTER_SPELL);
canned_msg(MSG_YOU_RESIST);
return (true);
case 8:
strcat(info, " shakes with wrath.");
break;
case 9:
strcat(info, " drinks a potion.");
break;
case 10:
strcat(info, " gestures wildly.");
msg_type = MSGCH_MONSTER_SPELL;
break;
}
break; // end Michael
case MONS_ERICA: // wild tempered adventuress
switch (random2(12))
{
case 0:
strcat(info, " screams, \"Die!\"");
break;
case 1:
strcat(info, " screams, \"Do you want it fast or slow?\"");
break;
case 2:
strcat(info, " looks angry.");
break;
case 3:
strcat(info, " drinks a potion.");
break;
case 4:
strcat(info, " says, \"I'm so much better than you.\"");
break;
case 5:
strcat(info,
" says, \"Fast and perfect. Such is my way of killing.\"");
break;
case 6:
strcat(info, " screams, \"Hurry! Death awaits!\"");
break;
case 7:
strcat(info, " laughs wildly.");
break;
case 8:
strcat(info, " screams, \"I'll never tell where it is!\"");
break;
case 9:
strcat(info, " screams, \"You'll never get it!\"");
break;
case 10:
strcat(info, " screams, \"Coming here was suicide!\"");
break;
case 11:
strcat(info,
" says, \"I love to fight, but killing is better.\"");
break;
}
break; // end Erica
case MONS_JOSEPHINE: // ugly old witch looking for somone to kill
switch (random2(13))
{
case 0:
case 1:
case 2:
strcat(info, " grins evilly.");
break;
case 3:
case 4:
strcat(info, " screams, \"I will kill you!\"");
break;
case 5:
strcat(info, " grinds her teeth.");
break;
case 6:
strcat(info, " grins malevolently.");
break;
case 7:
strcat(info, " laughs insanely.");
break;
case 8:
strcat(info, " screams, \"Die!\"");
break;
case 9:
strcat(info,
" screams, \"I have something special for you!\"");
break;
case 10:
strcat(info,
" screams, \"I'll use your head as decoration in my hut!\"");
break;
case 11:
strcat(info, " says, \"I'll make a rug of your skin.\"");
break;
case 12:
strcat(info, " says, \"How about some decapitation?\"");
break;
}
break; // end Josephine
case MONS_HAROLD: // middle aged man, hired to kill you. He is in a hurry.
switch (random2(11))
{
case 0:
strcat(info, " looks nervous.");
break;
case 1:
strcat(info, " screams, \"Hurry up!\"");
break;
case 2:
strcat(info, " screams, \"Could you die faster?\"");
break;
case 3:
strcat(info,
" says, \"Stand still. I'm trying to kill you.\"");
break;
case 4:
strcat(info, " screams, \"Die!\"");
break;
case 5:
strcat(info, " says, \"I hope you die soon!\"");
break;
case 6:
strcat(info,
" says, \"Only a few hits and it's over.\".");
break;
case 7:
strcat(info, " says, \"You know, I'm in a hurry.\"");
break;
case 8:
strcat(info, " screams, \"I'll finish you soon!\"");
break;
case 9:
strcat(info, " screams, \"Don't delay it.\"");
break;
case 11:
strcat(info, " says, \"Mine is not to reason why. Mine's to do, yours to die.\"" );
}
break; // end Harold
// skilled warrior looking for some fame. More deads = more fame
case MONS_NORBERT:
switch (random2(13))
{
case 0:
strcat(info, " smiles happily.");
break;
case 1:
strcat(info, " screams, \"Die, monster!\"");
break;
case 2:
strcat(info, " screams, \"I'm a hero!\"");
break;
case 3:
strcat(info, " shouts, \"YES! Another notch!\"");
break;
case 4:
strcat(info, " says, \"A pity your head will make such an ugly trophy.\"");
break;
case 5:
strcat(info,
" screams, \"Pray, because you'll die soon!\"");
break;
case 6:
strcat(info,
" asks \"Did you write a will? You should.\".");
break;
case 7:
strcat(info,
" says, \"I love killing ugly monsters like you.\"");
break;
case 8:
strcat(info, " screams, \"Blood and destruction!\"");
break;
case 9:
strcat(info, " says, \"You know, it's an honour to die by my hand.\"");
break;
case 10:
strcat(info, " shouts, \"Your time has come!\"");
break;
case 11:
strcat(info,
" says, \"I'm sorry but you don't have a chance.\"");
break;
case 12:
strcat(info,
" says, \"Another dead monster... It must be my lucky day!\"");
break;
}
break; // end Norbert
case MONS_JOZEF: // bounty hunter
switch (random2(14))
{
case 0:
strcat(info, " looks satisfied.");
break;
case 1:
strcat(info, " screams, \"Die!\"");
break;
case 2:
strcat(info, " screams, \"At last I found you!\"");
break;
case 3:
strcat(info, " shouts, \"I'll get 500 for your head!\"");
break;
case 4:
strcat(info,
" says, \"You don't look worth it for that money.\"");
break;
case 5:
strcat(info,
" says, \"It's nothing personal. I'm paid for it!\"");
break;
case 6:
strcat(info,
" asks \"Did you write a testament? You should.\"");
break;
case 7:
strcat(info, " says, \"You are ");
strcat(info, you.your_name);
strcat(info, ", aren't you?.\"");
break;
case 8:
strcat(info, " says, \"I suppose that you are ");
strcat(info, you.your_name);
strcat(info, ". Sorry, if I'm wrong.\"");
break;
case 9:
strcat(info, " says, \"One dead ");
strcat(info, you.your_name);
strcat(info, ", 500 gold pieces. It's in my contract.\"");
break;
case 10:
strcat(info, " shouts, \"Your time has come!\"");
break;
case 11:
strcat(info,
" says, \"My job is sometimes very exciting. Sometimes...\"");
break;
case 12:
strcat(info, " says, \"I think I deserve my money.\"");
break;
case 13:
strcat(info,
" screams, \"Die! I've got more contracts today.\"");
break;
}
break; // end Jozef
case MONS_AGNES: // she is trying to get money and treasure
switch (random2(10))
{
case 0:
strcat(info, " screams, \"Give me all your money!\"");
break;
case 1:
strcat(info, " screams, \"All treasure is mine!\"");
break;
case 2:
strcat(info, " screams, \"You'll never get my money!\"");
break;
case 3:
strcat(info, " grins evilly.");
break;
case 4:
strcat(info,
" screams, \"Give me everything and get away!\"");
break;
case 5:
strcat(info,
" says, \"I need a new robe. I'll buy it with your money.\"");
break;
case 6:
strcat(info,
" screams, \"I want your rings! And amulets! And... EVERYTHING!\"");
break;
case 7:
strcat(info,
" screams, \"I hate dirty adventurers like you.\"");
break;
case 8:
strcat(info, " says, \"How can you wear that ugly dress?\"");
break;
case 9:
strcat(info, " screams, \"Die, beast!\"");
break;
}
break; // end Agnes
case MONS_MAUD: // warrior princess looking for sword "Entarex"
switch (random2(11))
{
case 0:
strcat(info, " screams, \"Submit or die!\"");
break;
case 1:
strcat(info, " screams, \"Give me \"Entarex\"!\"");
break;
case 2:
strcat(info,
" screams, \"If you give me \"Entarex\", I'll let you live!\"");
break;
case 3:
strcat(info, " frowns.");
break;
case 4:
strcat(info, " looks upset.");
break;
case 5:
strcat(info, " screams, \"You can't face my power!\"");
break;
case 6:
strcat(info,
" screams, \"Give me that sword! Immediately!\"");
break;
case 7:
strcat(info,
" screams, \"Your life or \"Entarex\"! You must choose.\"");
break;
case 8:
strcat(info, " screams, \"I want it!\"");
break;
case 9:
strcat(info, " screams, \"Die, you thief!\"");
break;
case 10:
// needed at least one in here to tie to the amnesia
// scroll reference -- bwr
strcat(info, " asks \"Will you think of me as you die?\"");
break;
}
break; // end Maud
// wizard looking for bodyparts as spell components
case MONS_FRANCIS:
switch (random2(15))
{
case 0:
strcat(info,
" says, \"You've nice eyes. I could use them.\"");
break;
case 1:
strcat(info, " says, \"Excuse me, but I need your head.\"");
break;
case 2:
strcat(info, " says, \"I only need a few of your organs!\"");
break;
case 3:
strcat(info, " ponders the situation.");
break;
case 4:
strcat(info, " looks for a scalpel.");
break;
case 5:
simple_monster_message( monster, " casts a spell",
MSGCH_MONSTER_SPELL );
strcat(info, "'s hands start to glow with a soft light.");
msg_type = MSGCH_MONSTER_ENCHANT;
break;
case 6:
strcat(info, " says, \"This won't hurt a bit.\"");
break;
case 7:
strcat(info, " throws something at you.");
break;
case 8:
strcat(info, " says, \"I want you in my laboratory!\"");
break;
case 9:
strcat(info, " says, \"What about a little dissection?\"");
break;
case 10:
strcat(info,
" says, \"I have something special for you.\"");
break;
case 11:
strcat(info,
" screams, \"Don't move! I want to cut off your ear!\"");
break;
case 12:
strcat(info,
" says, \"What about your heart? Do you need it?\"");
break;
case 13:
strcat(info,
" says, \"Did you know that corpses are an important natural resource?\"");
break;
case 14:
strcat(info,
" says, \"Don't worry, I'll only take what I need.\"");
break;
}
break; // end Francis
case MONS_RUPERT: // crazy adventurer
switch (random2(11))
{
case 0:
strcat(info, " says, \"You are a monster, aren't you?\"");
break;
case 1:
strcat(info, " screams, \"Die, monster!\"");
break;
case 2:
strcat(info, " screams, \"Give me the Holy Grail!\"");
break;
case 3:
strcat(info, " screams, \"Red! No, blue!\"");
break;
case 4:
strcat(info, " looks confused.");
break;
case 5:
strcat(info, " looks excited.");
break;
case 6:
strcat(info, " shouts, \"I'm a great and powerful hero!\"");
break;
case 7:
strcat(info,
" screams, \"Get ready! I'll kill you! Or something like it...\"");
break;
case 8:
strcat(info,
" says, \"My Mom always said, kill them all.\"");
break;
case 9:
strcat(info,
" screams, \"You killed all those lovely monsters, you murderer!\"");
break;
case 10:
strcat(info, " screams, \"Hurray!\"");
break;
}
break; // end Rupert
case MONS_NORRIS: // enlighten but crazy man
switch (random2(24))
{
case 0:
strcat(info, " sings \"Hare Rama, Hare Krishna!\"");
break;
case 1:
strcat(info, " smiles at you.");
break;
case 2:
strcat(info,
" says, \"After death you'll find inner peace.\"");
break;
case 3:
strcat(info,
" says, \"Life is just suffering. I'll help you.\"");
break;
case 4:
strcat(info, " is surrounded with aura of peace.");
break;
case 5:
strcat(info, " looks very balanced.");
break;
case 6:
strcat(info, " says, \"Don't resist. I'll do it for you.\"");
break;
case 7:
strcat(info, " screams, \"Enter NIRVANA! Now!\"");
break;
case 8:
strcat(info, " says, \"Death is just a liberation!\"");
break;
case 9:
strcat(info,
" says, \"Feel free to die. It's great thing.\"");
break;
case 10:
strcat(info, " says, \"OHM MANI PADME HUM!\"");
break;
case 11:
strcat(info, " mumbles some mantras.");
msg_type = MSGCH_MONSTER_SPELL;
break;
case 12:
strcat(info, " says, \"Breathe deeply.\"");
break;
case 13:
strcat(info, " screams, \"Love! Eternal love!\"");
break;
case 14:
strcat(info,
" screams, \"Peace! I bring you eternal peace!\"");
break;
case 15:
strcat(info,
" sighs \"Enlightenment is such responsibility.\"");
break;
case 16:
strcat(info, " looks relaxed.");
break;
case 17:
strcat(info, " screams, \"Free your soul! Die!\"");
break;
case 18:
strcat(info, " screams, \"Blow your mind!\"");
break;
case 19:
strcat(info,
" says, \"The Orb is only a myth. Forget about it.\"");
break;
case 20:
strcat(info, " says, \"It's all maya.\"");
break;
case 21:
strcat(info, " says, \"Drop out!\"");
break;
case 22:
strcat(info,
" sings, \"Peace now, freedom now! Peace now, freedom now!\"");
break;
case 23:
strcat(info, " says, \"This is called Combat Meditation.\"");
break;
}
break; // end Norris
case MONS_MARGERY: // powerful sorceress, guarding the ORB
switch (random2(22))
{
case 0:
strcat(info, " says, \"You are dead.\"");
break;
case 1:
strcat(info, " looks very self-confident.");
break;
case 2:
strcat(info, " screams, \"You must be punished!\"");
break;
case 3:
strcat(info, " screams, \"You can't withstand my power!\"");
break;
case 4:
simple_monster_message( monster, " casts a spell.",
MSGCH_MONSTER_SPELL );
strcat(info, " is surrounded with aura of power.");
msg_type = MSGCH_MONSTER_ENCHANT;
break;
case 5:
strcat(info, "'s eyes start to glow with a red light.");
break;
case 6:
strcat(info,
"'s eyes start to glow with a green light.");
break;
case 7:
strcat(info, "'s eyes start to glow with a blue light.");
break;
case 8:
strcat(info, " screams, \"All trespassers must die!\"");
break;
case 9:
strcat(info, " says, \"Die!\"");
break;
case 10:
strcat(info, " screams, \"You'll have to get past me!\"");
break;
case 11:
simple_monster_message( monster, " casts a spell.",
MSGCH_MONSTER_SPELL );
strcat(info, " becomes transparent for a moment.");
msg_type = MSGCH_MONSTER_ENCHANT;
break;
case 12:
strcat(info, " gestures.");
msg_type = MSGCH_MONSTER_SPELL;
break;
case 13:
simple_monster_message( monster, " casts a spell.",
MSGCH_MONSTER_SPELL );
strcat(info, "'s hands start to glow.");
msg_type = MSGCH_MONSTER_ENCHANT;
break;
case 14:
strcat(info, " screams, \"Ergichanteg reztahaw!\"");
mpr(info, MSGCH_MONSTER_SPELL);
mpr("You feel really bad.", MSGCH_WARN);
return (true);
if (match)
line = line.substr(pos + 1);
}
case 15:
strcat(info, " screams, \"You are doomed!\"");
break;
case 16:
strcat(info, " screams, \"Nothing can help you.\"");
break;
case 17:
strcat(info, " screams, \"Death is my middle name!\"");
break;
case 18:
strcat(info, " gestures.");
mpr(info, MSGCH_MONSTER_SPELL);
mpr("You feel doomed.", MSGCH_WARN);
return (true);
case 19:
strcat(info, " gestures.");
mpr(info, MSGCH_MONSTER_SPELL);
mpr("You feel weakened.", MSGCH_WARN);
return (true);
case 20:
strcat(info, " throws some purple powder towards you.");
mpr(info, MSGCH_MONSTER_SPELL);
mpr("You feel cursed.", MSGCH_WARN);
return (true);
case 21:
strcat(info,
" screams, \"The ORB is only a tale, but I will kill you anyway!");
break;
}
break; // end Margery
case MONS_IJYB: // twisted goblin
switch (random2(14))
{
case 0:
strcat(info, " screams, \"Die!\"");
break;
case 1:
strcat(info, " screams, \"Me kill you!\"");
break;
case 2:
strcat(info, " screams, \"Me stronger than you!\"");
break;
case 3:
case 4:
strcat(info, " grins evilly.");
break;
case 5:
strcat(info, " screams, \"It's all mine!\"");
break;
case 6:
strcat(info, " screams, \"Get away!\"");
break;
case 7:
strcat(info, " screams, \"Level is mine! All mine!\"");
break;
case 8:
strcat(info, " screams, \"I cut your head off!\"");
break;
case 9:
strcat(info, " screams, \"I dance on your bones!\"");
break;
case 10:
strcat(info, " screams, \"Me very upset!\"");
break;
case 11:
strcat(info, " screams, \"You nasty! Big nasty!\"");
break;
case 12:
strcat(info, " screams, \"No! No, no, no, no!\"");
break;
case 13:
strcat(info, " screams, \"I no like you!\"");
break;
}
break; // end IJYB
mpr(line.c_str(), msg_type);
}
case MONS_BLORK_THE_ORC: // unfriendly orc
switch (random2(21))
{
case 0:
strcat(info, " screams, \"I don't like you!\"");
break;
case 1:
strcat(info, " screams, \"I'm going to kill you!\"");
break;
case 2:
strcat(info,
" screams, \"I'm much stronger than you!\"");
break;
case 3:
case 4:
strcat(info, " grins evilly.");
break;
case 5:
strcat(info, " frowns.");
break;
case 6:
case 7:
case 8:
case 9:
strcat(info, " looks angry.");
break;
case 10:
strcat(info,
" screams, \"I'll eat your brain! And then I'll vomit it back up!\"");
break;
case 11:
strcat(info,
" screams, \"You are the ugliest creature I've ever seen!\"");
break;
case 12:
strcat(info, " screams, \"I'll cut your head off!\"");
break;
case 13:
strcat(info, " screams, \"I'll break your legs!\"");
break;
case 14:
strcat(info, " screams, \"I'll break your arms!\"");
break;
case 15:
strcat(info,
" screams, \"I'll crush all your ribs! One by one!\"");
break;
case 16:
strcat(info,
" screams, \"I'll make a cloak from your skin!\"");
break;
case 17:
strcat(info,
" screams, \"I'll decorate my home with your organs!\"");
break;
case 18:
strcat(info, " screams, \"Die!\"");
break;
case 19:
strcat(info,
" screams, \"I'll cover the dungeon with your blood!\"");
break;
case 20:
strcat(info, " screams, \"I'll drink your blood! Soon!\"");
break;
}
break; // end Blork
case MONS_EROLCHA: // ugly ogre
switch (random2(11))
{
case 0:
strcat(info, " tries to grin evilly.");
break;
case 1:
strcat(info, " screams, \"Eat!\"");
break;
case 2:
strcat(info, " screams, \"Stand! Erolcha hit you!\"");
break;
case 3:
strcat(info, " screams, \"Blood!\"");
break;
case 4:
strcat(info, " screams, \"Erolcha kill you!\"");
break;
case 5:
strcat(info,
" screams, \"Erolcha crush your head!\"");
break;
case 6:
strcat(info, " roars.");
break;
case 7:
strcat(info, " growls.");
break;
case 8:
strcat(info, " screams, \"Lunch!\"");
break;
case 9:
strcat(info, " screams, \"Erolcha happy to kill you!\"");
break;
case 10:
strcat(info, " screams, \"Erolcha angry!\"");
break;
}
break; // end Erolcha
case MONS_URUG: // orc hired to kill you
switch (random2(11))
{
case 0:
strcat(info, " grins evilly.");
break;
case 1:
strcat(info, " screams, \"Die!\"");
break;
case 2:
strcat(info, " screams, \"I'm going to kill you! Now!\"");
break;
case 3:
strcat(info, " screams, \"Blood and destruction!\"");
break;
case 4:
strcat(info,
" sneers, \"Innocent? I'll kill you anyway.\"");
break;
case 5:
strcat(info,
" screams, \"I'll get 30 silver pieces for your head!\"");
break;
case 6:
strcat(info, " roars.");
break;
case 7:
strcat(info, " howls with blood-lust.");
break;
case 8:
strcat(info, " screams, \"You are already dead.\"");
break;
case 9:
strcat(info, " says, \"Maybe you aren't ");
strcat(info, you.your_name);
strcat(info, ". It doesn't matter.\"");
break;
case 10:
strcat(info, " screams, \"I love blood!\"");
break;
}
break; // end Urug
case MONS_SNORG: // troll
switch (random2(16))
{
case 0:
strcat(info, " grins.");
break;
case 1:
case 2:
case 3:
strcat(info, " smells terrible.");
break;
case 4:
case 5:
case 6:
strcat(info, " looks very hungry.");
break;
case 7:
strcat(info, " screams, \"Snack!\"");
break;
case 8:
strcat(info, " roars.");
break;
case 9:
strcat(info, " says, \"Food!\"");
break;
case 10:
strcat(info, " screams, \"Snorg hungry!\"");
break;
case 11:
strcat(info, " screams, \"Snorg very, very hungry!\"");
case 12:
strcat(info, " says, \"Snorg eat you.\"");
break;
case 13:
strcat(info, " says, \"You food?\"");
break;
case 14:
strcat(info, " says, \"Yum, yum.\"");
break;
case 15:
strcat(info, " burps.");
break;
}
break; // end Snorg
case MONS_XTAHUA: // ancient dragon
switch (random2(13))
{
case 0:
strcat(info, " roars, \"DIE, PUNY ONE!\"");
break;
case 1:
strcat(info, " growls, \"YOU BORE ME SO.\"");
break;
case 2:
strcat(info, " rumbles, \"YOU'RE BARELY A SNACK.\"");
break;
case 3:
strcat(info, " roars, \"I HATE BEING BOTHERED!\"");
break;
case 4:
strcat(info, " roars, \"I HOPE YOU'RE TASTY!\"");
break;
case 5:
strcat(info, " roars, \"BAH! BLOODY ADVENTURERS.\"");
break;
case 6:
strcat(info, " roars, \"FACE MY WRATH!\"");
break;
case 7:
strcat(info, " glares at you.");
break;
case 8:
strcat(info,
" roars, \"COMING HERE WAS YOUR LAST MISTAKE!\"");
break;
case 9:
strcat(info,
" roars, \"I'VE KILLED HUNDREDS OF ADVENTURERS!\"");
break;
case 10:
case 11:
case 12:
strcat(info, " roars horribly.");
mpr(info, MSGCH_TALK);
mpr("You are afraid.", MSGCH_WARN);
return (true);
}
break; // end Xtahua
case MONS_BORIS: // ancient lich
switch (random2(24))
{
case 0:
strcat(info, " says, \"I didn't invite you.\"");
break;
case 1:
strcat(info, " says, \"You can't imagine my power.\"");
break;
case 2:
strcat(info,
" says, \"Orb? You want the Orb? You'll never get it.\"");
break;
case 3:
strcat(info, " says, \"The world, the flesh, and the devil.\"");
break;
case 4:
strcat(info, " gestures.");
break;
case 5:
strcat(info, " stares at you.");
mpr(info, MSGCH_MONSTER_SPELL);
mpr("You feel drained.", MSGCH_WARN);
return (true);
case 6:
strcat(info, " stares at you.");
mpr(info, MSGCH_MONSTER_SPELL);
mpr("You feel weakened.", MSGCH_WARN);
return (true);
case 7:
strcat(info, " stares at you.");
mpr(info, MSGCH_MONSTER_SPELL);
mpr("You feel troubled.", MSGCH_WARN);
return (true);
case 8:
strcat(info, " says \"Magic. You know nothing about it.\"");
break;
case 9:
strcat(info, " says, \"My power is unlimited.\"");
break;
case 10:
strcat(info, " says, \"You can't kill me. I'm immortal.\"");
break;
case 11:
strcat(info, " casts a spell.");
mpr(info, MSGCH_MONSTER_SPELL);
mpr("Your equipment suddenly seems to weigh more.", MSGCH_WARN);
return (true);
case 12:
strcat(info,
" says, \"I know the secret of eternal life. Do you?\"");
break;
case 13:
strcat(info, " says, \"I'll be back.\"");
break;
case 14:
strcat(info, " casts a spell.");
mpr(info, MSGCH_MONSTER_SPELL);
canned_msg( MSG_YOU_RESIST );
return (true);
case 15:
strcat(info, " casts a spell.");
mpr(info, MSGCH_MONSTER_SPELL);
mpr("Suddenly you are surrounded with a pale green light.", MSGCH_WARN);
return (true);
case 16:
strcat(info, " casts a spell.");
mpr(info, MSGCH_MONSTER_SPELL);
mpr("You have a terrible headache.", MSGCH_WARN);
return (true);
case 17:
strcat(info,
" says, \"I know your future. Your future is death.\"");
break;
case 18:
strcat(info, " says, \"Who wants to live forever? Me.\"");
break;
case 19:
strcat(info, " laughs.");
break;
case 20:
strcat(info, " says, \"Join the legion of my servants.\"");
break;
case 21:
strcat(info, " says, \"There's only one solution for you. To die.\"");
break;
case 22:
strcat(info, " says, \"You can never win.\"");
break;
case 23:
simple_monster_message( monster, " casts a spell.",
MSGCH_MONSTER_SPELL );
strcat( info, " speeds up." );
msg_type = MSGCH_MONSTER_ENCHANT;
break;
}
break; // end BORIS
case MONS_DEATH_COB:
if (one_chance_in(2000))
{
mpr("The death cob makes a corny joke.", MSGCH_TALK);
return (true);
}
return (false);
case MONS_KILLER_KLOWN: // Killer Klown - guess!
switch (random2(10))
{
case 0:
strcat(info, " giggles crazily.");
break;
case 1:
strcat(info, " laughs merrily.");
break;
case 2:
strcat(info, " beckons to you.");
break;
case 3:
strcat(info, " does a flip.");
break;
case 4:
strcat(info, " does a somersault.");
break;
case 5:
strcat(info, " smiles at you.");
break;
case 6:
strcat(info, " grins with merry abandon.");
break;
case 7:
strcat(info, " howls with blood-lust!");
break;
case 8:
strcat(info, " pokes out its tongue.");
break;
case 9:
strcat(info, " says, \"Come and play with me!\"");
break;
}
break; // end Killer Klown
default:
strcat(info,
" says, \"I don't know what to say. It's a bug.\"");
break;
} // end monster->type - monster type switch
} // end default
mpr(info, msg_type);
place_monster_aux( band_monsters[i], behaviour, target, px, py,
lev_mons, extra, false, dur);
id = place_monster_aux( band_monsters[i], behaviour, target, px, py,
lev_mons, extra, false, dur);
menv[id].flags |= MF_BAND_MEMBER;
std::string do_mon_str_replacements(const std::string msg,
const monsters* monster);
enum mon_body_shape {
MON_SHAPE_HUMANOID,
MON_SHAPE_HUMANOID_WINGED,
MON_SHAPE_HUMANOID_TAILED,
MON_SHAPE_HUMANOID_WINGED_TAILED,
MON_SHAPE_CENTAUR,
MON_SHAPE_NAGA,
MON_SHAPE_QUADRUPED,
MON_SHAPE_QUADRUPED_TAILLESS,
MON_SHAPE_QUADRUPED_WINGED,
MON_SHAPE_BAT,
MON_SHAPE_SNAKE, // Including eels and worms
MON_SHAPE_FISH,
MON_SHAPE_INSECT,
MON_SHAPE_INSECT_WINGED,
MON_SHAPE_ARACHNID,
MON_SHAPE_CENTIPEDE,
MON_SHAPE_SNAIL,
MON_SHAPE_PLANT,
MON_SHAPE_FUNGUS,
MON_SHAPE_ORB,
MON_SHAPE_BLOB,
MON_SHAPE_MISC
};
mon_body_shape get_mon_shape(const monsters *mon);
mon_body_shape get_mon_shape(const int type);
std::string get_mon_shape_str(const monsters *mon);
std::string get_mon_shape_str(const int type);
std::string get_mon_shape_str(const mon_body_shape shape);
// Replaces the "@foo@" strings in monster shout and monster speak
// definitions.
std::string do_mon_str_replacements(const std::string in_msg,
const monsters* monster)
{
std::string msg = in_msg;
description_level_type nocap, cap;
if (monster->attitude == ATT_FRIENDLY && player_monster_visible(monster))
{
nocap = DESC_PLAIN;
cap = DESC_PLAIN;
msg = replace_all(msg, "@the_something@", "your @the_something@");
msg = replace_all(msg, "@The_something@", "Your @The_something@");
msg = replace_all(msg, "@the_monster@", "your @the_monster@");
msg = replace_all(msg, "@The_monster@", "Your @the_monster@");
}
else
{
nocap = DESC_NOCAP_THE;
cap = DESC_CAP_THE;
}
if (see_grid(monster->x, monster->y))
{
dungeon_feature_type feat = grd[monster->x][monster->y];
if (feat < MINMOVE || feat >= NUM_REAL_FEATURES)
msg = replace_all(msg, "@surface@", "buggy surface");
else if (feat == DNGN_LAVA)
msg = replace_all(msg, "@surface@", "lava");
else if (feat == DNGN_DEEP_WATER || feat == DNGN_SHALLOW_WATER)
msg = replace_all(msg, "@surface@", "water");
else if (feat >= DNGN_ALTAR_ZIN && feat < DNGN_BLUE_FOUNTAIN)
msg = replace_all(msg, "@surface@", "altar");
else
msg = replace_all(msg, "@surface@", "ground");
msg = replace_all(msg, "@feature@", raw_feature_description(feat));
}
else
{
msg = replace_all(msg, "@surface@", "buggy unseen surface");
msg = replace_all(msg, "@feature@", "buggy unseen feature");
}
msg = replace_all(msg, "@player_name@", you.your_name);
if (player_monster_visible(monster))
{
std::string something = monster->name(DESC_PLAIN);
msg = replace_all(msg, "@something@", something);
msg = replace_all(msg, "@a_something@", monster->name(DESC_NOCAP_A));
msg = replace_all(msg, "@the_something@", monster->name(nocap));
something[0] = toupper(something[0]);
msg = replace_all(msg, "@Something@", something);
msg = replace_all(msg, "@A_something@", monster->name(DESC_CAP_A));
msg = replace_all(msg, "@The_something@", monster->name(cap));
}
else
{
msg = replace_all(msg, "@something@", "something");
msg = replace_all(msg, "@a_something@", "something");
msg = replace_all(msg, "@the_something@", "something");
msg = replace_all(msg, "@Something@", "Something");
msg = replace_all(msg, "@A_something@", "Something");
msg = replace_all(msg, "@The_something@", "Something");
}
std::string plain = monster->name(DESC_PLAIN);
msg = replace_all(msg, "@monster@", plain);
msg = replace_all(msg, "@a_monster@", monster->name(DESC_NOCAP_A));
msg = replace_all(msg, "@the_monster@", monster->name(nocap));
plain[0] = toupper(plain[0]);
msg = replace_all(msg, "@Monster@", plain);
msg = replace_all(msg, "@A_monster@", monster->name(DESC_CAP_A));
msg = replace_all(msg, "@The_monster@", monster->name(cap));
msg = replace_all(msg, "@possessive@",
mons_pronoun(monster->type, 3));
msg = replace_all(msg, "@pronoun@",
mons_pronoun(monster->type, 0));
msg = replace_all(msg, "@imp_taunt@", imp_taunt_str());
msg = replace_all(msg, "@demon_taunt@", demon_taunt_str());
static const char * sound_list[] =
{
"says", // actually S_SILENT
"shouts",
"barks",
"shouts",
"roars",
"screams",
"bellows",
"screeches",
"buzzes",
"moans",
"whines",
"croaks",
"growls",
"hisses",
"breathes", // S_VERY_SOFT
"whispers", // S_SOFT
"says", // S_NORMAL
"shouts", // S_LOUD
"screams" // S_VERY_LOUD
};
if (mons_shouts(monster->type) >= NUM_SHOUTS)
{
mpr("Invalid @says@ type.", MSGCH_DIAGNOSTICS);
msg = replace_all(msg, "@says@", "bugilly says");
}
else
msg = replace_all(msg, "@says@",
sound_list[mons_shouts(monster->type)]);
// The proper possessive for a word ending in an "s" is to
// put an appostraphe after the "s": "Chris" -> "Chris'",
// not "Chris" -> "Chris's". Stupid English language...
msg = replace_all(msg, "s's", "s'");
return msg;
}
static mon_body_shape get_ghost_shape(const monsters *mon)
{
const ghost_demon &ghost = *(mon->ghost);
switch(ghost.values[GVAL_SPECIES])
{
case SP_NAGA:
return (MON_SHAPE_NAGA);
case SP_CENTAUR:
return (MON_SHAPE_CENTAUR);
case SP_KENKU:
return (MON_SHAPE_HUMANOID_WINGED);
case SP_RED_DRACONIAN:
case SP_WHITE_DRACONIAN:
case SP_GREEN_DRACONIAN:
case SP_GOLDEN_DRACONIAN:
case SP_GREY_DRACONIAN:
case SP_BLACK_DRACONIAN:
case SP_PURPLE_DRACONIAN:
case SP_MOTTLED_DRACONIAN:
case SP_PALE_DRACONIAN:
case SP_UNK0_DRACONIAN:
case SP_UNK1_DRACONIAN:
case SP_BASE_DRACONIAN:
return (MON_SHAPE_HUMANOID_TAILED);
}
return (MON_SHAPE_HUMANOID);
}
mon_body_shape get_mon_shape(const monsters *mon)
{
if (mon->type == MONS_PLAYER_GHOST)
return get_ghost_shape(mon);
else if (mons_is_zombified(mon))
return get_mon_shape(mon->number);
else
return get_mon_shape(mon->type);
}
mon_body_shape get_mon_shape(const int type)
{
switch(mons_char(type))
{
case 'a': // ants and cockroaches
return(MON_SHAPE_INSECT);
case 'b': // bats and butterflys
if (type == MONS_BUTTERFLY)
return(MON_SHAPE_INSECT_WINGED);
else
return(MON_SHAPE_BAT);
case 'c': // centaurs
return(MON_SHAPE_CENTAUR);
case 'd': // draconions and drakes
if (mons_genus(type) == MONS_DRACONIAN ||
mons_class_flag(type, M_HUMANOID))
{
if (mons_class_flag(type, M_FLIES))
return(MON_SHAPE_HUMANOID_WINGED_TAILED);
else
return(MON_SHAPE_HUMANOID_TAILED);
}
else if (mons_class_flag(type, M_FLIES))
return(MON_SHAPE_QUADRUPED_WINGED);
else
return(MON_SHAPE_QUADRUPED);
case 'e': // elves
return(MON_SHAPE_HUMANOID);
case 'f': // fungi
return(MON_SHAPE_FUNGUS);
case 'g': // gargoyles, gnolls, goblins and hobgoblins
if (type == MONS_GARGOYLE)
return(MON_SHAPE_HUMANOID_WINGED_TAILED);
else
return(MON_SHAPE_HUMANOID);
case 'h': // hounds
case 'j': // jackals
return(MON_SHAPE_QUADRUPED);
case 'k': // killer bees
return(MON_SHAPE_INSECT_WINGED);
case 'l': // lizards
return(MON_SHAPE_QUADRUPED);
case 'm': // minotaurs, manticores, and snails/slugs/etc
if (type == MONS_MINOTAUR)
return(MON_SHAPE_HUMANOID);
else if (type == MONS_MANTICORE)
return(MON_SHAPE_QUADRUPED);
else
return(MON_SHAPE_SNAIL);
case 'n': // necrophages and ghouls
return(MON_SHAPE_HUMANOID);
case 'o': // orcs
return(MON_SHAPE_HUMANOID);
case 'p': // ghosts
if (type != MONS_INSUBSTANTIAL_WISP &&
type != MONS_PLAYER_GHOST)
return(MON_SHAPE_HUMANOID);
case 'q': // quasists
return(MON_SHAPE_HUMANOID_TAILED);
case 'r': // rodents
return(MON_SHAPE_QUADRUPED);
case 's': // arachnids and centidpeds
if (type == MONS_GIANT_CENTIPEDE)
return(MON_SHAPE_CENTIPEDE);
else
return(MON_SHAPE_ARACHNID);
case 'u': // ugly things are humanoid???
return(MON_SHAPE_HUMANOID);
case 'v': // vortices and elementals
return(MON_SHAPE_MISC);
case 'w': // worms
return(MON_SHAPE_SNAKE);
case 'x': // small abominations
return(MON_SHAPE_MISC);
case 'y': // winged insects
return(MON_SHAPE_INSECT_WINGED);
case 'z': // small skeletons
if (type == MONS_SKELETAL_WARRIOR)
return(MON_SHAPE_HUMANOID);
else
// constructed type, not enough info to determine shape
return(MON_SHAPE_MISC);
case 'A': // angelic beings
return(MON_SHAPE_HUMANOID_WINGED);
case 'B': // beetles
return(MON_SHAPE_INSECT);
case 'C': // giants
return(MON_SHAPE_HUMANOID);
case 'D': // dragons
if (mons_class_flag(type, M_FLIES))
return(MON_SHAPE_QUADRUPED_WINGED);
else
return(MON_SHAPE_QUADRUPED);
case 'E': // effreets
return(MON_SHAPE_HUMANOID);
case 'F': // frogs
return(MON_SHAPE_QUADRUPED_TAILLESS);
case 'G': // floating eyeballs and orbs
return(MON_SHAPE_ORB);
case 'H': // hippogriffs and griffns
return(MON_SHAPE_QUADRUPED_WINGED);
case 'I': // ice beasts
return(MON_SHAPE_QUADRUPED);
case 'J': // jellies and jellyfish
return(MON_SHAPE_BLOB);
case 'K': // kobolds
return(MON_SHAPE_HUMANOID);
case 'L': // liches
return(MON_SHAPE_HUMANOID);
case 'M': // mummies
return(MON_SHAPE_HUMANOID);
case 'N': // nagas
return(MON_SHAPE_NAGA);
case 'O': // ogres
return(MON_SHAPE_HUMANOID);
case 'P': // plants
return(MON_SHAPE_PLANT);
case 'Q': // queen insects
if (type == MONS_QUEEN_BEE)
return(MON_SHAPE_INSECT_WINGED);
else
return(MON_SHAPE_INSECT);
case 'R': // rakshasa; humanoid?
return(MON_SHAPE_HUMANOID);
case 'S': // snakes
return(MON_SHAPE_SNAKE);
case 'T': // trolls
return(MON_SHAPE_HUMANOID);
case 'U': // bears
return(MON_SHAPE_QUADRUPED_TAILLESS);
case 'V': // vampires
return(MON_SHAPE_HUMANOID);
case 'W': // wraiths, humanoid if not a spectral thing
if (type == MONS_SPECTRAL_THING)
// constructed type, not enough info to determine shape
return(MON_SHAPE_MISC);
else
return(MON_SHAPE_HUMANOID);
case 'X': // large abominations
return(MON_SHAPE_MISC);
case 'Y': // yaks and sheep
if (type == MONS_SHEEP)
return(MON_SHAPE_QUADRUPED_TAILLESS);
else
return(MON_SHAPE_QUADRUPED);
case 'Z': // constructed type, not enough info to determine shape
return(MON_SHAPE_MISC);
case ';': // Fish and eels
if (type == MONS_ELECTRICAL_EEL)
return(MON_SHAPE_SNAKE);
else
return (MON_SHAPE_FISH);
// The various demons, plus some golems and statues. And humanoids.
case '1':
case '2':
case '3':
case '4':
case '5':
case '&':
case '8':
case '@':
// Assume demon has wings if it can fly.
bool flies = mons_class_flag(type, M_FLIES);
// Assume demon has a tail if it has a sting attack or a
// tail slap attack.
monsterentry *mon_data = get_monster_data(type);
bool tailed = false;
for (int i = 0; i < 4; i++)
if (mon_data->attack[i].type == AT_STING ||
mon_data->attack[i].type == AT_TAIL_SLAP)
{
tailed = true;
break;
}
if (flies && tailed)
return(MON_SHAPE_HUMANOID_WINGED_TAILED);
else if (flies && !tailed)
return(MON_SHAPE_HUMANOID_WINGED);
else if (!flies && tailed)
return(MON_SHAPE_HUMANOID_TAILED);
else
return(MON_SHAPE_HUMANOID);
}
return(MON_SHAPE_MISC);
}
std::string get_mon_shape_str(const monsters *mon)
{
return get_mon_shape_str(get_mon_shape(mon));
}
std::string get_mon_shape_str(const int type)
{
return get_mon_shape_str(get_mon_shape(type));
}
std::string get_mon_shape_str(const mon_body_shape shape)
{
ASSERT(shape >= MON_SHAPE_HUMANOID && shape <= MON_SHAPE_MISC);
if (shape < MON_SHAPE_HUMANOID || shape > MON_SHAPE_MISC)
return("buggy shape");
static const char *shape_names[] =
{
"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",
"blob", "misc"
};
return (shape_names[shape]);
}
void demon_taunt( const monsters *mons )
{
std::string str = demon_taunt_str();
const std::string mon_name = mons->name(DESC_CAP_THE);
static const char * sound_list[] =
{
"says", // actually S_SILENT
"shouts",
"barks",
"shouts",
"roars",
"screams",
"bellows",
"screeches",
"buzzes",
"moans",
"whines",
"croaks",
"growls",
"hisses",
"breathes", // S_VERY_SOFT
"whispers", // S_SOFT
"says", // S_NORMAL
"shouts", // S_LOUD
"screams" // S_VERY_LOUD
};
const char *voice = sound_list[ mons_shouts(mons->type) ];
MF_CREATED_FRIENDLY = 0x01, // no benefit from killing
MF_GOD_GIFT = 0x02, // player not penalized by its death
MF_BATTY = 0x04, // flutters like a bat
MF_JUST_SUMMONED = 0x08, // monster skips next available action
MF_TAKING_STAIRS = 0x10, // is following player through stairs
MF_CREATED_FRIENDLY = 0x01, // no benefit from killing
MF_GOD_GIFT = 0x02, // player not penalized by its death
MF_BATTY = 0x04, // flutters like a bat
MF_JUST_SUMMONED = 0x08, // monster skips next available action
MF_TAKING_STAIRS = 0x10, // is following player through stairs
MF_INTERESTING = 0x20, // Player finds monster interesting
MF_SEEN = 0x40, // Player already seen monster
MF_DIVINE_PROTECTION = 0x80, // Monster has divine protection.
MF_INTERESTING = 0x20, // Player finds monster interesting
MF_SEEN = 0x40, // Player already seen monster
MF_DIVINE_PROTECTION = 0x80, // Monster has divine protection.
MF_KNOWN_MIMIC = 0x100, // Mimic that has taken a swing at the PC,
// or that the player has inspected with ?
MF_BANISHED = 0x200, // Monster that has been banished.
MF_HARD_RESET = 0x400, // Summoned, should not drop gear on reset
MF_CONVERT_ATTEMPT = 0x800, // Orcs only: seen player and was converted
// (or not)
MF_WAS_IN_VIEW = 0x1000 // Was in view during previous turn
MF_KNOWN_MIMIC = 0x100, // Mimic that has taken a swing at the PC,
// or that the player has inspected with ?
MF_BANISHED = 0x200, // Monster that has been banished.
MF_HARD_RESET = 0x400, // Summoned, should not drop gear on reset
MF_CONVERT_ATTEMPT = 0x800, // Orcs only: seen player and was converted
// (or not)
MF_WAS_IN_VIEW = 0x1000, // Was in view during previous turn
MF_BAND_MEMBER = 0x2000 // Created as a member of a band
break;
case CMD_TARGET_WIZARD_MAKE_SHOUT:
// Maybe we can skip this check...but it can't hurt
if (!you.wizard || !in_bounds(moves.tx, moves.ty))
break;
mid = mgrd[moves.tx][moves.ty];
if (mid == NON_MONSTER) // can put in terrain description here
break;
debug_make_monster_shout(&menv[mid]);
// Only one ghost allowed per level
if (mspec.mid == MONS_PLAYER_GHOST)
{
for (int i = 0; i < MAX_MONSTERS; i++)
if (menv[i].type == MONS_PLAYER_GHOST
&& menv[i].alive())
{
mpr("Only one player ghost per level allowed, "
"and this level already has one.");
return;
}
}
// Only one pandemonium lord allowed per level as well.
else if (mspec.mid == MONS_PANDEMONIUM_DEMON)
{
for (int i = 0; i < MAX_MONSTERS; i++)
if (menv[i].type == MONS_PANDEMONIUM_DEMON
&& menv[i].alive())
{
mpr("Only one Pandemonium lord per level allowed, "
"and this level already has one.");
return;
}
}
dgn_place_monster(mspec, you.your_level, x, y, false);
if (!dgn_place_monster(mspec, you.your_level, x, y, false))
{
mpr("Unable to place monster");
return;
}
// Need to set a name for the player ghost
if (mspec.mid == MONS_PLAYER_GHOST)
{
unsigned char mid = mgrd[x][y];
if (mid >= MAX_MONSTERS || menv[mid].type != MONS_PLAYER_GHOST)
{
for (mid = 0; mid < MAX_MONSTERS; mid++)
if (menv[mid].type == MONS_PLAYER_GHOST
&& menv[mid].alive())
break;
}
if (mid >= MAX_MONSTERS)
{
mpr("Couldn't find player ghost, probably going to crash.");
more();
return;
}
monsters &mon = menv[mid];
ghost_demon ghost;
ghost.name = "John Doe";
ghost.values.init(0);
char class_str[80];
mpr( "Make player ghost which class? ", MSGCH_PROMPT );
get_input_line( class_str, sizeof( class_str ) );
int class_id = get_class_index_by_abbrev(class_str);
if (class_id == -1)
class_id = get_class_index_by_name(class_str);
if (class_id == -1)
{
mpr("No such class, making it a Fighter.");
class_id = JOB_FIGHTER;
}
ghost.values[GVAL_CLASS] = class_id;
mon.set_ghost(ghost);
ghosts.push_back(ghost);
}
#ifdef WIZARD
extern void force_monster_shout(monsters* monster);
void debug_make_monster_shout(monsters* mon)
{
mpr("Make the monster (S)hout or (T)alk?", MSGCH_PROMPT);
char type = (char) getchm(KC_DEFAULT);
type = tolower(type);
if (type != 's' && type != 't')
{
canned_msg( MSG_OK );
return;
}
int num_times = debug_prompt_for_int("How many times? ", false);
if (num_times <= 0)
{
canned_msg( MSG_OK );
return;
}
if (type == 's')
{
if (silenced(mon->x, mon->y))
mpr("The monster is silenced and likely won't give any shouts.");
if (silenced(you.x_pos, you.y_pos))
mpr("You are silenced and likely won't hear any shouts.");
for (int i = 0; i < num_times; i++)
force_monster_shout(mon);
}
else
{
if (mon->invisible())
mpr("The monster is invisble and likely won't speak.");
if (silenced(you.x_pos, you.y_pos) && !silenced(mon->x, mon->y))
mpr("You are silenced but the monster isn't; you will "
"probably hear/see nothing.");
else if (!silenced(you.x_pos, you.y_pos) && silenced(mon->x, mon->y))
mpr("The monster is silenced and likely won't say anything.");
else if (silenced(you.x_pos, you.y_pos) && silenced(mon->x, mon->y))
mpr("Both you and the monster are silenced, so you likely "
"won't hear anything.");
for (int i = 0; i< num_times; i++)
mons_speaks(mon);
}
mpr("== Done ==");
}
#endif
if (!shoutDB)
{
std::string shoutPath = get_savedir_path(SHOUT_DB);
std::string shoutText = datafile_path(SHOUT_TXT);
check_newer(shoutPath, shoutText, generate_shout_db);
shoutPath.erase(shoutPath.length() - 3);
if (!(shoutDB = openDB(shoutPath.c_str())))
end(1, true, "Failed to open DB: %s", shoutPath.c_str());
}
if (!speakDB)
{
std::string speakPath = get_savedir_path(SPEAK_DB);
std::string speakText = datafile_path(SPEAK_TXT);
check_newer(speakPath, speakText, generate_speak_db);
speakPath.erase(speakPath.length() - 3);
if (!(speakDB = openDB(speakPath.c_str())))
end(1, true, "Failed to open DB: %s", speakPath.c_str());
}
}
std::string getLongDescription(const std::string &key)
{
if (!descriptionDB)
return ("");
// We have to canonicalize the key (in case the user typed it
// in and got the case wrong.)
std::string canonical_key = key;
lowercase(canonical_key);
// Query the DB.
datum result = database_fetch(descriptionDB, canonical_key);
// Cons up a (C++) string to return. The caller must release it.
return std::string((const char *)result.dptr, result.dsize);
static std::vector<std::string> description_txt_paths()
{
std::vector<std::string> txt_file_names;
std::vector<std::string> paths;
txt_file_names.push_back("features");
txt_file_names.push_back("items");
txt_file_names.push_back("monsters");
txt_file_names.push_back("spells");
for (int i = 0, size = txt_file_names.size(); i < size; i++)
{
std::string name = DESC_TXT_DIR;
name += FILE_SEPARATOR;
name += txt_file_names[i];
name += ".txt";
std::string txt_path = datafile_path(name);
paths.push_back(txt_path);
}
return (paths);
}
static void store_descriptions(const std::string &in, const std::string &out);
static void generate_description_db()
{
std::string db_path = get_savedir_path(DESC_BASE_NAME);
std::string full_db_path = get_savedir_path(DESC_DB);
std::vector<std::string> txt_paths = description_txt_paths();
file_lock lock(get_savedir_path(DESC_BASE_NAME ".lk"), "wb");
unlink( full_db_path.c_str() );
for (int i = 0, size = txt_paths.size(); i < size; i++)
store_descriptions(txt_paths[i], db_path);
DO_CHMOD_PRIVATE(full_db_path.c_str());
}
///////////////////////////////////////////////////////////////////////////
// Internal DB utility functions
static std::string chooseStrByWeight(std::string entry)
{
std::vector<std::string> parts;
std::vector<int> weights;
std::vector<std::string> lines = split_string("\n", entry, false, true);
int total_weight = 0;
for (int i = 0, size = lines.size(); i < size; i++)
{
// Skip over multiple blank lines, and leading and trailing
// blank lines.
while (i < size && lines[i] == "")
i++;
if (i == size)
break;
int weight;
std::string part = "";
if (sscanf(lines[i].c_str(), "w:%d", &weight))
{
i++;
if (i == size)
return ("BUG, WEIGHT AT END OF ENTRY");
}
else
weight = 10;
total_weight += weight;
while (i < size && lines[i] != "")
{
part += lines[i++];
part += "\n";
}
trim_string(part);
parts.push_back(part);
weights.push_back(total_weight);
}
if (parts.size() == 0)
return("BUG, EMPTY ENTRY");
int choice = random2(total_weight);
std::string str = "";
for (int i = 0, size = parts.size(); i < size; i++)
if (choice < weights[i])
return(parts[i]);
return("BUG, NO STRING CHOSEN");
}
#define MAX_RECURSION_DEPTH 10
#define MAX_REPLACEMENTS 100
static std::string getRandomizedStr(DBM *database, const std::string &key,
const std::string &suffix,
int &num_replacements,
int recursion_depth = 0)
{
recursion_depth++;
if (recursion_depth > MAX_RECURSION_DEPTH)
{
mpr("Too many nested replacements, bailing.", MSGCH_DIAGNOSTICS);
return "TOO MUCH RECURSION";
}
// We have to canonicalize the key (in case the user typed it
// in and got the case wrong.)
std::string canonical_key = key + suffix;
lowercase(canonical_key);
// Query the DB.
datum result = database_fetch(database, canonical_key);
if (result.dsize <= 0)
{
// Try ignoring the suffix
canonical_key = key;
lowercase(canonical_key);
// Query the DB.
result = database_fetch(database, canonical_key);
if (result.dsize <= 0)
return "";
}
// Cons up a (C++) string to return. The caller must release it.
std::string str = std::string((const char *)result.dptr, result.dsize);
str = chooseStrByWeight(str);
// Replace any "@foo@" markers that can be found in this database;
// those that can't be found are left alone for the caller to deal
// with.
std::string::size_type pos = str.find("@");
while (pos != std::string::npos)
{
num_replacements++;
if (num_replacements > MAX_REPLACEMENTS)
{
mpr("Too many string replacements, bailing.", MSGCH_DIAGNOSTICS);
return "TOO MANY REPLACEMENTS";
}
std::string::size_type end = str.find("@", pos + 1);
if (end == std::string::npos)
{
mpr("Unbalanced @, bailing.", MSGCH_DIAGNOSTICS);
break;
}
std::string marker_full = str.substr(pos, end - pos + 1);
std::string marker = str.substr(pos + 1, end - pos - 1);
std::string replacement =
getRandomizedStr(database, marker, suffix, num_replacements,
recursion_depth);
if (replacement == "")
// Nothing in database, leave it alone and go onto next @foo@
pos = str.find("@", end + 1);
else
{
str.replace(pos, marker_full.length(), replacement);
// Start search from pos rather than end + 1, so that if
// the replacement contains its own @foo@, we can replace
// that too.
pos = str.find("@", pos);
}
} // while (pos != std::string::npos)
return str;
}
/////////////////////////////////////////////////////////////////////////////
// Description DB specific functions.
std::string getLongDescription(const std::string &key)
{
if (!descriptionDB)
return ("");
// We have to canonicalize the key (in case the user typed it
// in and got the case wrong.)
std::string canonical_key = key;
lowercase(canonical_key);
// Query the DB.
datum result = database_fetch(descriptionDB, canonical_key);
// Cons up a (C++) string to return. The caller must release it.
return std::string((const char *)result.dptr, result.dsize);
}
static std::vector<std::string> description_txt_paths()
{
std::vector<std::string> txt_file_names;
std::vector<std::string> paths;
txt_file_names.push_back("features");
txt_file_names.push_back("items");
txt_file_names.push_back("monsters");
txt_file_names.push_back("spells");
/*
txt_file_names.push_back("shout");
txt_file_names.push_back("speak");
*/
for (int i = 0, size = txt_file_names.size(); i < size; i++)
{
std::string name = DESC_TXT_DIR;
name += FILE_SEPARATOR;
name += txt_file_names[i];
name += ".txt";
std::string txt_path = datafile_path(name);
if (!txt_path.empty())
paths.push_back(txt_path);
}
return (paths);
}
static void generate_description_db()
{
std::string db_path = get_savedir_path(DESC_BASE_NAME);
std::string full_db_path = get_savedir_path(DESC_DB);
std::vector<std::string> txt_paths = description_txt_paths();
file_lock lock(get_savedir_path(DESC_BASE_NAME ".lk"), "wb");
unlink( full_db_path.c_str() );
for (int i = 0, size = txt_paths.size(); i < size; i++)
store_text_db(txt_paths[i], db_path);
DO_CHMOD_PRIVATE(full_db_path.c_str());
}
/////////////////////////////////////////////////////////////////////////////
// Shout DB specific functions.
std::string getShoutString(const std::string &monst,
const std::string &suffix)
{
int num_replacements = 0;
return getRandomizedStr(shoutDB, monst, suffix, num_replacements);
}
static void generate_shout_db()
{
std::string db_path = get_savedir_path(SHOUT_BASE_NAME);
std::string full_db_path = get_savedir_path(SHOUT_DB);
std::string txt_path = datafile_path(SHOUT_TXT);
file_lock lock(get_savedir_path(SHOUT_BASE_NAME ".lk"), "wb");
unlink( full_db_path.c_str() );
store_text_db(txt_path, db_path);
DO_CHMOD_PRIVATE(full_db_path.c_str());
}
/////////////////////////////////////////////////////////////////////////////
// Speak DB specific functions.
std::string getSpeakString(const std::string &monst)
{
int num_replacements = 0;
return getRandomizedStr(speakDB, monst, "", num_replacements);
}
static void generate_speak_db()
{
std::string db_path = get_savedir_path(SPEAK_BASE_NAME);
std::string full_db_path = get_savedir_path(SPEAK_DB);
std::string txt_path = datafile_path(SPEAK_TXT);
file_lock lock(get_savedir_path(SPEAK_BASE_NAME ".lk"), "wb");
unlink( full_db_path.c_str() );
store_text_db(txt_path, db_path);
DO_CHMOD_PRIVATE(full_db_path.c_str());
}
"<w>Shift-Dir</w> : shoot straight-line beam\n";
"<w>Shift-Dir</w> : shoot straight-line beam\n"
#ifdef WIZARD
" \n"
"<h>Wizard targeting comands:</h>\n"
"<w>F</w>: make target friendly\n"
"<w>s</w>: force target to shout or speak\n"
#endif
;