git-svn-id: https://crawl-ref.svn.sourceforge.net/svnroot/crawl-ref/trunk@8549 c06c8d41-db1a-0410-9941-cceddc491573
43XCHFXZ34FDVT2QG23RZ65V6NRBY6PE3ENQEEDXFYKRR7IRFHCAC
M4FZOH6OHMO5ILBBMOBQOXBVSURRPUANJEKWGSFRXVTDJZWDJ66AC
YYGGJB2XHBNYLHPV3V5Q7IO4TR2MZ5CPMHZELOKVRXT46COA4PNQC
YRPFSFBFCP23X6DCROXKIVLLPCMWELAFSQN5XNBPK4SJXEM55U5QC
2EAWKRFSOQQ3ZGPMIRFNY6UWDH4Y5S4H4YKLH4T6RU4CTC7IQE6QC
PUY2VWZJ3G7HNCLIHZP5VGT2DAGHI436ETDJQTPEBFPRSEHOM2NQC
KFULGQQOHWUTXOM3BXCCYPGGVGGY4Z6265XUFRCBPNLTZAEHJZSQC
LUD5XPFLSYPJOYZG6DDV4C5WIQUGZPE7YV6AR75ENCAIISD3LZWQC
IQGGFC563RBS7GDOACKCLXK752EE5RC3T6G5L6H446SXTMSA7T2AC
B3HWU2BEQQ4E6WKVTW3JQQJFMWTVW3XWKY6BHFNBRHSZPRCF2OTQC
64HB7VYSYHQEN5UP7OYJ5GSVA2XMDSLLH647UPWE5NSFF3AVZSSQC
JYEEOUYQ7ZPKOGWUV7VCORBVSOLF2UCBFBH3TR75RGOSS6PNKYUAC
RDOOG5LBE5TCTFYCKJIB7TGGTRFX4HBLMJZYXS5TCFWNCU3QII5QC
TO3JMTZO6ETZWBXPA75JLCFD7ML546WXBRLWHPKL44ZIQ2H5HW6QC
HCVH2CWL32UD66O6Z7ZYDUASWN3RF5TW6FSWURGMD7MELKB772FAC
IBV5MNXWCCOWCI7DPVTPFEEMLX7QWP75EP6YQ3RA2WJOKWSGMPSQC
FYSQ7HXDIKXZXDGYVKZMODW7HYQQLRZO52Q2HVM3PYBD37UT5B4AC
ERS7DYNAVCC7QUVG5FXJJRONYESLZU22CQGKCA5HLLLG6DMXYRLQC
TRBDS4IKHBASW2CTAQ2YHMBMBMRB6QEBQ4ZE7GRSR3U2VJXA7TJQC
2NVJIPJ5NMHUI2J4WOR6KE4XZOCJIVWHQK4M2M6KG7PL24PGBDGAC
5MGUZD2UACJCSG74TEZHI3Z4YL5KL6ZVUCQ3XVZKDOLKM7EMGWJAC
TPO6FNMPNUSWH4NCKO3VLYNAADEPSAXLUITCCACLZZSY53PKA62QC
NMZFCCM6O3KO2GJWKOSULN27B3QIZKWPBOB62PAILXMRQD4JMIMAC
22YVHM74WBJNJE4PA5CBEUTDWM6FAGGGILI26A4LXAURX55TNRKAC
5WHLQTLOJRJ67M4KAJZURHMNQLYHBW4XHQFBXV2LUQ4W6YKTOXVAC
CLIEHAE2PP7ZIGLLIMYCWM4FC54KBOAN5AILOLAZJ5S26GTJM4RQC
BAQJ26USF7KRR6ALYPXUPUFOYLNGBQVQOS53JXJJWZKDVREHFL2QC
5CPP63H7WJ3GLSHJM4Z2YSU2NISLVESEJ3OYMO4MFZEXVOCV4NIAC
XDB2YEWS2WYH4FQZG3CIQ7P5JNS47MDYII2MV2IQ6BCAEPBYO5EQC
2RW7ANB4PPWJC2MP2XCBAWBDGMHJUNNWKMXR74JONERE4X522CNQC
BQ5QKUWLCYSBO4A7EWZN4FXPNSIAR6JPBAZE4PSV6XCUNTV53ERQC
ZR4ALQ5F2ETOD3GXMBYXSN6P75DPDGI3C275A7W5XHYI5TGPHNUQC
LQH6T3DTCDOS5LAJ4PIPHMQY6UYRFWMVVUX32YJAELGIVR5RZTGQC
LPPYA57KUWV53DIXGFMMNJUWBQOH5EDBZFFLYCWXBH347V6OLLCQC
V7KMVXS2DILGLKP5XIKXEK7RFEABZGHHCG24QNSMMUAXRJ66THJQC
QL3UTDJCNTASBU67LD5QODTIH7LCSAOW672CLJCDT4HED6PP5OPAC
53BVN4ZHKGUAJE53HM6FC6GKUGXOU5QBUT7CLXV2ONS6S5NPW55AC
WEAAN2EBCCSUDTVAREPHLT7L7I7JR64F6MEWODY6QUMV3OAIK4WAC
HZF272SANK2AOSUXM4WVKQKK767KCZUDXOQTHKBAHQPOTDEWEAZQC
GTG5BFLJ5GBLJEEWK6AVZSCL5SQ4VSUW6IWEMZM7PAAT7KTSJQ5QC
IOMAHHDYJ6P65ZZK4Q44YX2PEBZWBPB7ZOA3OKXPUBI5BRLRQ5JAC
W3XVTY4C5S3OYK3TY3KDMJP2M7X7RJV33NLGYSEPUPHV2FSVTZCAC
C5YQSTQ76D3OSNKOXBZD5MLX6GISUKXGPXLYZB5VKWZWXRAYPPQAC
25ADVXLZ7BCN6EHSVAZPAX6K75XPJYPG7IVRDY3S5YS5JMQGPMBQC
YCKKYPEEODERLRF5DVJ6IKIXEHLKJQ37COYKGXCEXHMBT5Y2B32QC
NGW2XPEX2XRK3CYC37DNUZSSB5IQLECMKRB6NX257I2X3G35LMPAC
O4ZFDG3AEV3K4NPGCCLB7DXUH5CBETKP5FBKLCIET7JNTNDX5DUAC
RMPMIONAOIYDZ5GWRUT65OVWAIQX7NWQ5QAPU6FSIODAGBAI5BIAC
WHURZ7S6MM5OAEVGAM7ZNYXK3V62HUYYQM4NDB4NRJHG23YK35RAC
MKJ2ORKSFPOPYEB5C36WZTR2QFHQYQ23PCLSC6SA44LJZ2AFBZFQC
DVK4UATWXWXC5WZODCYAEMZM2TQUNC3URSUGMZSFYE6N76NQRK7AC
76XONKEXTJDLNAJCQTPN5MTBBPJZ55WFYX3B5CN5AKII6CW3SDCAC
UHL7ECQOTO3SHFAPV4T6ODJ2HLSMUKVHQJQF3CXM3IUNICR7LACAC
CQE2PS6RJI7QIP5YWGJKM6227HSIP7ZB2CBCJH5S2FN3PUDMLXUQC
PVX27BLN5U3FAKDIGAANLLNJ75HYFB3M2WKQZN5BCNCBZ2OCQ3KQC
KJO5N6UIPKQ6TZNNOWZEHUAWZNUW7CAHLIW2ARX47K4SIE3N5LYAC
3WNSWDDTTPWQ24SUOFU7EL6GODIMVTK4TL3P3AFLNB6AXUIIHFSAC
HSDVFA7GIQ3JG6XK3OLW5UI63VZSBZUZ4VMTKL3XFBJXILYF67RQC
OJXLFQMDM4XF2WSDVMAC3FXG5HJQB3QAQXLZM35RA34YYLTAP2HQC
QME3SNESM4AEPUDL3QUVQUXGGFY7PJ7GQKFWBCHX257NSQU6O5GAC
4SWAT5KCKQV527NKELAXFQ5XA4Q5HONQXD4VBXMUZNPVPQKPCPNAC
45CWQUPQHKUFUJ4MVL5K3KCVCCKLY2Z7RZWZ53UT723RV5STPSRAC
UKBVBVJK23OUOOKQJRGLZWEZYED5KZ4NLODW6U67UEBYCFWGGQOAC
377IO63NX2CXDYLKI2DUH5X6CKU7BJSPWIJYSCJXEAQTKFV53K5QC
GPEJOT73KMACP33IPAKFR5ROGHCOIP22VXZMQNYTGLEA2OSZUM2AC
KPSCSVGHKEQ4ENM3QQU2U3GYMV52NDFO5L6ML7YDPUKV3365OA3QC
AYU5OVG2HZO46KDAPKUWAVHS5HTYFKUWIMIRMTHAXVVFEDJE7YPAC
NYURIMPCM2RADLMIQSN76OPKXQSK4XBLFNXD2OO53KGZI3MA6AQAC
SGJYXCP2TMR2VQNNO2W4HDHOA72LZOULFORRQVOIURH3KGGZPTDAC
OJKUO2UJ2O2MUITGVQNF3BQITGVYE3XK6QTG7XW6OYPJ4YFWCFQQC
56D656WZS2LWVTXGWPR5FFJ7MDHP25XGPTBMYM4NHT4TKSJILX3QC
3XL4DKV7PSWAU3ZBJSKZFJ2VUYABC47I7KKWGIRCJYXULQD453MQC
IE3INS4WUXZOBVXB5VWRBYPVPXADD2U2W5H3TBTOYNWJ3EGRSGQQC
LK4XZLY5I73MFPFDUHPROWVHGEBXPVI6QDU2XMEBOJCNJPRLQLCQC
R4URIVUHLBA4OJFNBWFCDDFOJFHN77DP4YDPL5AAB5TB7CWX2ICQC
BSYEZ767GXLUDAHWF3UBPEZNM7VJNPDCJHID57SF5SP53KYAUQTQC
PSJ7QDBYFBE35ANUDUTNE5VMKOTNVD66AXCCYC45WWJZRTGBJYLQC
FAT7OTV4CYNUPXMS7KE3OSPMOFFIJX62KHPYCVE5TIOQYB4RPH2QC
// Random-type acquirement.
const int r = random2(7);
const object_class_type objtype = (r == 0) ? OBJ_WEAPONS :
(r == 1) ? OBJ_ARMOUR :
(r == 2) ? OBJ_JEWELLERY :
(r == 3) ? OBJ_BOOKS :
(r == 4) ? OBJ_STAVES :
(r == 5) ? OBJ_FOOD :
(r == 6) ? OBJ_MISCELLANY
: OBJ_GOLD;
const object_class_type types[] = {
OBJ_WEAPONS, OBJ_ARMOUR, OBJ_JEWELLERY, OBJ_BOOKS,
OBJ_STAVES, OBJ_FOOD, OBJ_MISCELLANY, OBJ_GOLD
};
// Don't kill the player unless Xom is being nasty.
if (!_xom_feels_nasty())
{
// Make sure not to lower strength so much that the player
// will die once might wears off.
char vals[3] =
{you.strength - (you.duration[DUR_MIGHT] ? 5 : 0),
you.dex, you.intel};
stat_type types[3] = {STAT_STRENGTH, STAT_DEXTERITY,
STAT_INTELLIGENCE};
int tries = 0;
do {
int idx = random2(3);
stat = types[idx];
max = std::min(3, vals[idx] - 1);
} while (max < 2 && (++tries < 30));
if (tries >= 30)
return (false);
}
god_speaks(GOD_XOM, _get_xom_speech("lose stats").c_str());
lose_stat(stat, 1 + random2(max), true, "the vengeance of Xom" );
return (true);
}
static bool _xom_chaos_upgrade_nearby_monster()
{
bool rc = false;
monsters *mon = choose_random_nearby_monster(0, _choose_chaos_upgrade);
if (!mon)
return (false);
god_speaks(GOD_XOM, _get_xom_speech("chaos upgrade").c_str());
mon_inv_type slots[] = {MSLOT_WEAPON, MSLOT_ALT_WEAPON, MSLOT_MISSILE};
for (int i = 0; i < 3 && !rc; ++i)
{
item_def* const item = mon->mslot_item(slots[i]);
if (item && _is_chaos_upgradeable(*item, mon))
{
_do_chaos_upgrade(*item, mon);
rc = true;
}
}
ASSERT(rc);
// Wake the monster up.
behaviour_event(mon, ME_ALERT, MHITYOU);
return (rc);
}
static bool _xom_player_confusion_effect(int sever)
{
bool rc = false;
// Looks like this will *always* succeed?
if (confuse_player(random2(sever)+1, false))
{
// FIXME: Message order is a bit off here.
god_speaks(GOD_XOM, _get_xom_speech("confusion").c_str());
rc = true;
// Sometimes Xom gets carried away and starts confusing
// other creatures too.
if (coinflip())
{
for (unsigned i = 0; i < MAX_MONSTERS; ++i)
{
monsters* const monster = &menv[i];
if (!monster->alive()
|| !mons_near(monster)
|| !mons_class_is_confusable(monster->type)
|| one_chance_in(20))
{
continue;
}
if (monster->add_ench(mon_enchant(ENCH_CONFUSION, 0,
KC_FRIENDLY, random2(sever))))
{
simple_monster_message(monster,
" looks rather confused.");
}
}
}
}
return (rc);
}
static bool _xom_draining_torment_effect(int sever)
{
const std::string speech = _get_xom_speech("draining or torment");
const bool nasty = _xom_feels_nasty();
bool rc = false;
if (one_chance_in(4))
{
// XP drain effect (25%).
if (player_prot_life() < 3 && (nasty || you.experience > 0))
{
god_speaks(GOD_XOM, speech.c_str());
drain_exp();
if (random2(sever) > 3 && (nasty || you.experience > 0))
drain_exp();
if (random2(sever) > 3 && (nasty || you.experience > 0))
drain_exp();
rc = true;
}
}
else
{
// Torment effect (75%).
if (!player_res_torment())
{
god_speaks(GOD_XOM, speech.c_str());
torment_player(0, TORMENT_XOM);
rc = true;
}
}
return (rc);
}
static bool _xom_summon_hostiles(int sever)
{
bool rc = false;
const std::string speech = _get_xom_speech("hostile monster");
// Nasty, but fun.
if (one_chance_in(4))
{
god_speaks(GOD_XOM, speech.c_str());
cast_tukimas_dance(100, GOD_XOM, true);
// FIXME: We should probably only do this if the spell
// succeeded.
rc = true;
}
else
{
// XXX: Can we clean up this ugliness, please?
const int numdemons =
std::min(random2(random2(random2(sever+1)+1)+1)+1, 14);
for (int i = 0; i < numdemons; ++i)
{
if (create_monster(
mgen_data::hostile_at(
_xom_random_demon(sever),
you.pos(), 4, 0, true, GOD_XOM,
MON_SUMM_WRATH)) != -1)
{
rc = true;
}
}
if (rc)
god_speaks(GOD_XOM, speech.c_str());
}
return (rc);
}
// Xom will only directly kill you with a bad effect if you're under
// penance from him, or if he's bored.
const bool nasty = you.penance[GOD_XOM]
|| (you.religion == GOD_XOM && you.gift_timeout == 0);
stat_type stat = STAT_RANDOM;
int max = 3;
// Don't kill the player unless Xom is being nasty.
if (!nasty)
{
// Make sure not to lower strength so much that the player
// will die once might wears off.
char vals[3] =
{you.strength - (you.duration[DUR_MIGHT] ? 5 : 0),
you.dex, you.intel};
stat_type types[3] = {STAT_STRENGTH, STAT_DEXTERITY,
STAT_INTELLIGENCE};
int count = 0;
for (int i = 0; i < 3; ++i)
{
int val = vals[i];
if (val > 1 && one_chance_in(++count))
{
stat = types[i];
max = val - 1;
}
}
if (count == 0)
continue;
}
god_speaks(GOD_XOM, _get_xom_speech("lose stats").c_str());
lose_stat(stat, 1 + random2(max), true, "the vengeance of Xom" );
done = true;
done = _xom_lose_stats();
monsters *mon =
choose_random_nearby_monster(0, _choose_chaos_upgrade);
if (!mon)
continue;
god_speaks(GOD_XOM, _get_xom_speech("chaos upgrade").c_str());
mon_inv_type slots[] = {MSLOT_WEAPON, MSLOT_ALT_WEAPON,
MSLOT_MISSILE};
for (int i = 0; i < 3; ++i)
{
int idx = mon->inv[slots[i]];
if (idx == NON_ITEM)
continue;
item_def &item(mitm[idx]);
if (!_is_chaos_upgradeable(item, mon))
continue;
_do_chaos_upgrade(item, mon);
done = true;
break;
}
ASSERT(done);
// Wake the monster up.
behaviour_event(mon, ME_ALERT, MHITYOU);
done = _xom_chaos_upgrade_nearby_monster();
if (you.can_safely_mutate()
&& player_mutation_level(MUT_MUTATION_RESISTANCE) < 3)
{
god_speaks(GOD_XOM, _get_xom_speech("random mutations").c_str());
mpr("Your body is suffused with distortional energy.");
set_hp(1 + random2(you.hp), false);
deflate_hp(you.hp_max / 2, true);
bool failMsg = true;
for (int i = random2(4); i >= 0; --i)
{
if (mutate(RANDOM_XOM_MUTATION, failMsg, false, true,
false, false, !nasty))
{
done = true;
}
else
failMsg = false;
}
}
done = _xom_give_mutation(false);
if (there_are_monsters_nearby(false, false))
{
monsters *mon =
choose_random_nearby_monster(0, _choose_mutatable_monster);
if (mon)
{
god_speaks(GOD_XOM, _get_xom_speech("bad monster polymorph").c_str());
bool made_shifter = false;
if (one_chance_in(8) && !mons_is_shapeshifter(mon))
{
mon->add_ench(one_chance_in(3) ?
ENCH_GLOWING_SHAPESHIFTER : ENCH_SHAPESHIFTER);
made_shifter = true;
}
monster_polymorph(mon, RANDOM_MONSTER,
mons_wont_attack(mon) ? PPT_LESS : PPT_MORE, made_shifter);
done = true;
}
}
done = _xom_polymorph_nearby_monster(false);
std::string speech = _get_xom_speech("confusion");
if (confuse_player(random2(sever)+1, false))
{
done = true;
// Sometimes Xom gets carried away and starts confusing
// other creatures too.
if (coinflip())
{
monsters* monster;
for (unsigned i = 0; i < MAX_MONSTERS; ++i)
{
monster = &menv[i];
if (monster->type == -1 || !mons_near(monster)
|| !mons_class_is_confusable(monster->type)
|| one_chance_in(20))
{
continue;
}
if (monster->add_ench(mon_enchant(ENCH_CONFUSION, 0,
KC_FRIENDLY, random2(sever))))
{
simple_monster_message(monster,
" looks rather confused.");
}
}
}
}
done = _xom_player_confusion_effect(sever);
std::string speech = _get_xom_speech("draining or torment");
if (one_chance_in(4))
{
if (player_prot_life() < 3 && (nasty || you.experience > 0))
{
god_speaks(GOD_XOM, speech.c_str());
drain_exp();
if (random2(sever) > 3 && (nasty || you.experience > 0))
drain_exp();
if (random2(sever) > 3 && (nasty || you.experience > 0))
drain_exp();
done = true;
}
}
else
{
if (!player_res_torment())
{
god_speaks(GOD_XOM, speech.c_str());
torment_player(0, TORMENT_XOM);
done = true;
}
}
done = _xom_draining_torment_effect(sever);
std::string speech = _get_xom_speech("hostile monster");
// Nasty, but fun.
if (one_chance_in(4))
{
god_speaks(GOD_XOM, speech.c_str());
cast_tukimas_dance(100, GOD_XOM, true);
done = true;
}
else
{
// XXX: Can we clean up this ugliness, please?
const int numdemons =
std::min(random2(random2(random2(sever+1)+1)+1)+1, 14);
bool success = false;
for (int i = 0; i < numdemons; ++i)
{
if (create_monster(
mgen_data::hostile_at(
_xom_random_demon(sever),
you.pos(), 4, 0, true, GOD_XOM,
MON_SUMM_WRATH)) != -1)
{
success = true;
}
}
if (success)
{
god_speaks(GOD_XOM, speech.c_str());
done = true;
}
}
done = _xom_summon_hostiles(sever);