For zero-level (message only) miscasts there's a 1 in 20 chance that a non-standard message will be given, like "Your shield spins", "The scales of your dragon armour briefly wiggle", and so on.
For all other miscasts the string used for "your hands" will be randomized to only sometimes be normal, to get messages like "Your nose glows momentarily" or "Noxious gasses pour from your feet". This can lead to some bizarre messages like "Sparks play between your ears", but then, this is Xom.
git-svn-id: https://crawl-ref.svn.sourceforge.net/svnroot/crawl-ref/trunk@7906 c06c8d41-db1a-0410-9941-cceddc491573
IBV5MNXWCCOWCI7DPVTPFEEMLX7QWP75EP6YQ3RA2WJOKWSGMPSQC
PAQHYOD44BYIKN4NB7EOQJME472Z5ORZPANK7TQBJUUMQW5TSKIQC
FYSQ7HXDIKXZXDGYVKZMODW7HYQQLRZO52Q2HVM3PYBD37UT5B4AC
2NVJIPJ5NMHUI2J4WOR6KE4XZOCJIVWHQK4M2M6KG7PL24PGBDGAC
KFULGQQOHWUTXOM3BXCCYPGGVGGY4Z6265XUFRCBPNLTZAEHJZSQC
ERS7DYNAVCC7QUVG5FXJJRONYESLZU22CQGKCA5HLLLG6DMXYRLQC
TPO6FNMPNUSWH4NCKO3VLYNAADEPSAXLUITCCACLZZSY53PKA62QC
5MGUZD2UACJCSG74TEZHI3Z4YL5KL6ZVUCQ3XVZKDOLKM7EMGWJAC
NMZFCCM6O3KO2GJWKOSULN27B3QIZKWPBOB62PAILXMRQD4JMIMAC
22YVHM74WBJNJE4PA5CBEUTDWM6FAGGGILI26A4LXAURX55TNRKAC
3DQXSE4YGFBBDUWK4YEOFWW4UPWILWELFSLP37SL6BERGAZJC5YAC
ZNDS3LUJYJQJ7GUOHCQUDUAAYNQAOJMC2PTMRF7XXTHOPOFLMP3AC
EWFP6RFDHTEGD6SX36LYRLQB3APIKGAHNBKWPD56RGYBUE4FWJUQC
NVSFIV2ZKP44XHCSCXG6OZVGL67OIFINC34J2EMKTA4KULCERUEAC
K2CS6TCX2NDVL2ASEHGP4J4K4IJ6FP3ANNKTSIWVG43HPYSBX6ZQC
SOCJXX6MMOXLBEWBID4QN5FW2YNYULNNN7K3IRL7RSWK5EUNAZLQC
JJULXW764V5C2HJKZNWQAEWB6QM5YZADD7ZCE35LYTBFEM6PMYCAC
BWAQ3FHBBM6G3K3KYP75CRTR343RDQZJRYX5ZGYUEXYBAC3APDLAC
}
// Is the equipment type usable, and the slot is empty?
static bool _could_wear_eq(equipment_type eq)
{
if (!you_tran_can_wear(eq, true))
return (false);
return (you.slot_item(eq) == NULL);
}
static item_def* _tran_get_eq(equipment_type eq)
{
if (you_tran_can_wear(eq, true))
return you.slot_item(eq);
else
return (NULL);
}
// Which types of dungeon features are in view?
static void _get_in_view(bool in_view[])
{
for (int i = 0; i < NUM_REAL_FEATURES; i++)
in_view[i] = false;
for (radius_iterator ri(you.pos(), LOS_RADIUS); ri; ++ri)
in_view[grd(*ri)] = true;
///////////////////////////////////
// Dungeon feature dependant stuff.
bool in_view[NUM_REAL_FEATURES];
_get_in_view(in_view);
if (in_view[DNGN_LAVA])
messages.push_back("The lava spits out sparks!");
if (in_view[DNGN_DEEP_WATER] || in_view[DNGN_SHALLOW_WATER])
{
messages.push_back("The water briefly bubbles.");
messages.push_back("The water briefly swirls.");
messages.push_back("The water briefly glows.");
}
if (in_view[DNGN_DEEP_WATER])
messages.push_back("From the corner of your eye you spot something "
"lurking in the deep water.");
if (in_view[DNGN_ORCISH_IDOL])
{
if (you.species == SP_HILL_ORC)
priority.push_back("The idol of Beogh turns to glare at you.");
else
priority.push_back("The orish idol turns to glare at you.");
}
if (in_view[DNGN_GRANITE_STATUE])
priority.push_back("The granite statue turns to stare at you.");
if (in_view[DNGN_WAX_WALL])
priority.push_back("The wax wall pulsates ominously.");
if (in_view[DNGN_FOUNTAIN_BLUE] || in_view[DNGN_FOUNTAIN_SPARKLING])
{
priority.push_back("The water in the fountain briefly bubbles.");
priority.push_back("The water in the fountain briefly swirls.");
priority.push_back("The water in the fountain briefly glows.");
}
if (in_view[DNGN_DRY_FOUNTAIN_BLUE]
|| in_view[DNGN_DRY_FOUNTAIN_SPARKLING]
|| in_view[DNGN_PERMADRY_FOUNTAIN])
{
priority.push_back("Water briefly sprays from the dry fountain.");
priority.push_back("Dust puffs up from the dry fountain.");
}
if (in_view[DNGN_STONE_ARCH])
priority.push_back("The stone arch briefly shows a sunny meadow on "
"the other side.");
const dungeon_feature_type feat = grd(you.pos());
if (!grid_is_solid(feat) && grid_stair_direction(feat) == CMD_NO_CMD
&& !grid_is_trap(feat) && feat != DNGN_STONE_ARCH
&& feat != DNGN_OPEN_DOOR && feat != DNGN_ABANDONED_SHOP)
{
const std::string feat_name =
feature_description(you.pos(), false, DESC_CAP_THE, false);
if (you.airborne())
{
// Kenku fly a lot, so don't put airborne messages into the
// priority vector for them.
std::vector<std::string>* vec;
if (you.species == SP_KENKU)
vec = &messages;
else
vec = &priority;
vec->push_back(feat_name
+ " seems to fall away from under you!");
vec->push_back(feat_name
+ " seems to rush up at you!");
if (feat == DNGN_DEEP_WATER || feat == DNGN_SHALLOW_WATER)
priority.push_back("Something invisible splashes into the "
"water beneath you!");
}
else if (feat == DNGN_DEEP_WATER || feat == DNGN_SHALLOW_WATER)
{
priority.push_back("The water briefly recedes away from you.");
priority.push_back("Something invisible splashes into the water "
"beside you!");
}
else if (feat == DNGN_FLOOR)
{
messages.push_back("The floor shifts under you alarmingly!");
messages.push_back("The floor vibrates.");
}
}
if (!grid_destroys_items(feat) && !grid_is_solid(feat))
{
int count = 0;
int idx = -1;
for (int i = 0; i < ENDOFPACK; i++)
{
const item_def &item(you.inv[i]);
if (is_valid_item(item) && !item_is_equipped(item)
&& !item_is_critical(item))
{
if (one_chance_in(++count))
idx = i;
}
}
if (idx != -1)
{
item_def &item(you.inv[idx]);
std::string name;
if (item.quantity == 1)
name = item.name(DESC_CAP_YOUR, false, false, false);
else
{
name = "One of ";
name += item.name(DESC_NOCAP_YOUR, false, false, false);
}
messages.push_back(name + " falls out of your pack, then "
"immediately jumps back in!");
}
}
////////////////////////////////////////////
// Body, player spcies, transformations, etc
const int transform = you.attribute[ATTR_TRANSFORMATION];
if (you.species == SP_MUMMY && you_tran_can_wear(EQ_BODY_ARMOUR))
{
messages.push_back("You briefly get tangled in your bandages.");
if (!you.airborne() && !you.swimming())
messages.push_back("You trip over your bandages.");
}
if (transform != TRAN_SPIDER && transform != TRAN_AIR)
{
std::string str = "A monocle briefly appears over your ";
str += coinflip() ? "right" : "left";
str += " eye.";
messages.push_back(str);
}
if (!player_genus(GENPC_DRACONIAN) && you.species != SP_MUMMY
&& (transform == TRAN_NONE || transform == TRAN_BLADE_HANDS))
{
messages.push_back("Your eyebrows briefly feel very bushy.");
}
///////////////////////////
// Equipment related stuff.
item_def* item;
if (_could_wear_eq(EQ_WEAPON))
{
std::string str = "A fancy cane briefly appears in your ";
str += you.hand_name(true);
str += ".";
messages.push_back(str);
}
if (_tran_get_eq(EQ_CLOAK) != NULL)
messages.push_back("Your cloak billows in an unfelt wind.");
if (item = _tran_get_eq(EQ_HELMET))
{
std::string str = "Your ";
str += item->name(DESC_BASENAME, false, false, false);
str += " leaps into the air, briefly spins, then lands on your "
"head again!";
messages.push_back(str);
}
if ((item = _tran_get_eq(EQ_BOOTS)) && item->sub_type == ARM_BOOTS
&& !you.cannot_act())
{
std::string name = item->name(DESC_BASENAME, false, false, false);
name = replace_all(name, "pair of ", "");
std::string str = "You compulsively click the heels of your ";
str += name;
str += " together three times.";
messages.push_back(str);
}
if (item = _tran_get_eq(EQ_SHIELD))
{
std::string str = "Your ";
str += item->name(DESC_BASENAME, false, false, false);
str += " spins!";
messages.push_back(str);
}
if (item = _tran_get_eq(EQ_BODY_ARMOUR))
{
std::string str;
std::string name = item->name(DESC_BASENAME, false, false, false);
if (name.find("dragon") != std::string::npos)
{
str = "The scales on your ";
str += name;
str += " wiggle briefly.";
}
else if (item->sub_type == ARM_ANIMAL_SKIN)
{
str = "The fur on your ";
str += name;
str += " grows longer at an alarming rate, then retracts back "
"to normal.";
}
else if (item->sub_type == ARM_LEATHER_ARMOUR)
{
str = "Your ";
str += name;
str += " briefly grows fur, then returns to normal.";
}
else if (item->sub_type == ARM_ROBE)
{
str = "You briefly become tangled in your ";
str += pluralise(name);
str += ".";
}
else if (item->sub_type >= ARM_RING_MAIL &&
item->sub_type <= ARM_PLATE_MAIL)
{
str = "Your ";
str += name;
str += " briefly appears rusty.";
}
if (!str.empty())
messages.push_back(str);
}
if (priority.size() > 0 && coinflip())
mpr(priority[random2(priority.size())].c_str());
else
mpr(messages[random2(messages.size())].c_str());
}
static void _get_hand_type(std::string &hand, bool &can_plural)
{
hand = "";
can_plural = true;
const int transform = you.attribute[ATTR_TRANSFORMATION];
if (transform == TRAN_AIR)
return;
std::vector<std::string> hand_vec;
std::vector<bool> plural_vec;
bool plural;
hand_vec.push_back(you.hand_name(false, &plural));
plural_vec.push_back(plural);
if (you.species != SP_NAGA || transform_changed_physiology())
{
item_def* item;
if ((item = _tran_get_eq(EQ_BOOTS)) && item->sub_type == ARM_BOOTS)
{
hand_vec.push_back("boot");
plural = true;
}
else
hand_vec.push_back(you.foot_name(false, &plural));
plural_vec.push_back(plural);
}
if (transform == TRAN_SPIDER)
{
hand_vec.push_back("mandible");
plural_vec.push_back(true);
}
else if (you.species != SP_MUMMY || transform_changed_physiology())
{
hand_vec.push_back("nose");
plural_vec.push_back(false);
}
if (transform == TRAN_BAT
|| you.species != SP_MUMMY && !transform_changed_physiology())
{
hand_vec.push_back("ear");
plural_vec.push_back(true);
}
if (!transform_changed_physiology())
{
hand_vec.push_back("elbow");
plural_vec.push_back(true);
}
ASSERT(hand_vec.size() == plural_vec.size());
ASSERT(hand_vec.size() > 0);
const unsigned int choice = random2(hand_vec.size());
hand = hand_vec[choice];
can_plural = plural_vec[choice];
}
static void _xom_miscast(const int max_level, const bool nasty)
{
ASSERT(max_level >= 0 && max_level <= 3);
const char* speeches[4] = {
"zero miscast effect",
"minor miscast effect",
"medium miscast effect",
"major miscast effect"
};
const char* causes[4] = {
"the mischief of Xom",
"the capriciousness of Xom",
"the capriciousness of Xom",
"the severe capriciousness of Xom"
};
const char* speech_str = speeches[max_level];
const char* cause_str = causes[max_level];
const int level = random2(max_level + 1);
if (level == 0 && one_chance_in(20))
{
god_speaks(GOD_XOM, _get_xom_speech(speech_str).c_str());
_xom_zero_miscast();
return;
}
std::string hand_str;
bool can_plural;
_get_hand_type(hand_str, can_plural);
// If not being nasty then prevent spell miscasts from killing the
// player.
const int lethality_margin = nasty ? 0 : random_range(1, 4);
god_speaks(GOD_XOM, _get_xom_speech(speech_str).c_str());
MiscastEffect(&you, -GOD_XOM, SPTYP_RANDOM, level, cause_str, NH_DEFAULT,
lethality_margin, hand_str, can_plural);
}
god_speaks(GOD_XOM, _get_xom_speech("zero miscast effect").c_str());
MiscastEffect(&you, -GOD_XOM, SPTYP_RANDOM, 0,
"the mischief of Xom");
_xom_miscast(0, nasty);
god_speaks(GOD_XOM, _get_xom_speech("minor miscast effect").c_str());
MiscastEffect(&you, -GOD_XOM, SPTYP_RANDOM, random2(2),
"the capriciousness of Xom", NH_DEFAULT,
lethality_margin);
_xom_miscast(1, nasty);
god_speaks(GOD_XOM, _get_xom_speech("medium miscast effect").c_str());
MiscastEffect(&you, -GOD_XOM, SPTYP_RANDOM, random2(3),
"the capriciousness of Xom", NH_DEFAULT,
lethality_margin);
_xom_miscast(2, nasty);
god_speaks(GOD_XOM, _get_xom_speech("major miscast effect").c_str());
MiscastEffect(&you, -GOD_XOM, SPTYP_RANDOM, random2(4),
"the severe capriciousness of Xom", NH_DEFAULT,
lethality_margin);
_xom_miscast(3, nasty);