QAD5QRQDRHBP2SKJXPYAHIJOUUBXQTJEAMJUU274I3UY2WW7FEXQC
GBH23XC4IIUSUXO2AWVWZP5SUBIVLH2JEP7BXZQW7JPFQQ356SUAC
WJV5GC6EYV5NAVSRHUWT7KDDCC46SGT3ZFNZBAHHK5HVOGAWACCAC
UZTXJW3EW3N63K7GSC4EMPGHEHDHBW2P3HMINLGXS4UPGZHRWKLAC
4NDJLMFFC7YF7NARAT64ZBWRE5QEFEOL34KDSHFWFXACI7NE2F4QC
SXPQSJIWN6G642ROHGHG22XOOJL2DKJOJIT4MFQFFWFWIP4SG2VAC
EPX5ZPJEARQ6Z3DW7M6GMPND3ZNZUN2OWXIJCXVH7TJFZXA2VIZAC
VXT2KCTUSBREZLVJGINL2XY2P766DY57W44XTW4KANJH2A4WFPHAC
QSUB43KOJG5ZN5JYY2IJ4TGNGVY6LI5OAO6OASYYOMYTGXQWUAYAC
H4WYMTARHB33JNRKJGZZYL22RKWTBFLHX2PUC6DQSGZBV6JMIYIAC
CQR54KQDXP6KE37UR4V3T4ZI2UKPWYXOUU4D4RASGKOFVGBJGTGQC
ZTGL6NBMDI5FA7C3JFLH6DUQNK47EQIOIRKOEYMRCSA7S3TQESIQC
5DVMFDTDCWKGQ372J5WGN4FDYUQWZZV6NJKW4VDD4QLCPZET5L5QC
WZ5INX2BYTC3FPVA2SDPX3FGTFWKO27G5GJL62GKSHEYVFAV24GAC
G7DNYFW745Q567EF3TPR2FCQ4ATPN236ON7X5TLYC7TEPZW3BAFAC
JROZ5XCAQKPXFV242IO3OACFTD6KC4SNSWIXPI5WO4FQ5APRLC4QC
E76RRHMXEPJCNDNKMI3AP7OI7IOMXXRHVYWRIYA75BQMMIST2XRAC
Y6YXZ7CF7TJ5WIYFGQA7OFF52P3V5YHKTMUOSBIPAFCRCMNPGSZQC
RBAGQ2PB7V5YAM5KSHSZR2E3MLKDSRVM5XYGI2TIXP5QMVBOQHDQC
K2CS6TCX2NDVL2ASEHGP4J4K4IJ6FP3ANNKTSIWVG43HPYSBX6ZQC
QEEJFAETO6B2J4IWDIDCJ5UNIFNNHHG22IWF2CUJRTJJBNE47CWQC
SVY2PTCLXR3KNPQAWXVXTTGCC5DR334HOAKHYO3VDDRWM2BWMALAC
U6HLBU2OIMKVNWWZ55SERG56WKAW3GSFFEGUJBP4SQVYSESGXC2QC
FDMKFGCTWKKSBP3B5VE4BSVFHUVNX5BSDFRVD6E735DHPVYEQFGQC
2XSNHF7JXHEKABVMXDAU25QKFHJHH256GR4WLYAHKSPF4XLBJW4QC
NVD2HSEW2ONWNYDDCTOMZZOUP6NG4DCXI4LNYYIY4BQEBDMJQK5AC
OFPZBHMZ6DZ6NZ2NJTLRHPEDIQ4FVRASXBTA7TVQKFZ4CIKDDCNAC
TJ544OJG4CFFMGMAQ2B7UJT432EIBUV5HOHDAQ7GMKZZKSDBFXZQC
IP4STBRVFU5OPNAPM2XZWU77PXHKLOPBW5EGLGB4ZHYNZS7QKTKAC
GQQ6ASWTYODIHG7X32JNUUHP5NMOVZJIHWGS3F3MKRYZGAHP6NVQC
5WVUTEZLEZEML54CKPR6GACQBYY3EMVNXMLJOREN6SSEUZGC47AQC
UNXGLYIYBZMWR6GX3LRNAA2UPZD7MNBH7TYGYQTTFHPCJRDZXWPQC
27JI3J23EXDY2G4X7NHTFTSHSEUDGDPFOYPG6P53UNSSJP3DDQTAC
ODQ7LIJ2UROGGENIORRXZFWII3ZM2N45YD53FKWDQB7LLRXR4PHAC
J6ILYHNWEDUHAP44NSA66DYGFXZAD7KKO3PHVG44IWB3KWMMNTHQC
PUO3U5MM6BGXC7BO4PKI77KWEOAWOFF3ZYSVDZJBG2XO7JT3II3AC
BEPZL7D7JJHJUUDCVLGJRKKWM7NUAC7X2SU5XJMEASE6YTB53P3AC
BNRY5YIXLFE2TDNU2JQHWWXJQVWNSEWQ52DU7XUWIT5DZWKGBDDAC
L2CVX5VYQC3XVCEADQEWQYQT4IGJIZJM3XAEAVT3GCY3EF7JINUQC
ZPINQTMG4J532QWU6RW7534UNC73ZT3Y3WFDDHJQQFJ6P4IXC62AC
GGDX26OLH2EBB2ZBJCBIE3UDPHWEMTMSOEJBJIWCBLUK3HEY3PKQC
QSSBY2L2FO3QV77ODEFPGZ63NSE7KACQ5SKCH2WGFB7DXKUHT7EQC
LM764EO6YIFOKMRXWZ5S4GYZB4BHZQDTEFP7MEVYO4NN4EDOFGNQC
SZLYZGHTB6IVHF4NG3Y7UQMRIH5GIBT65NDOOJAHLAELVMKTMSBQC
T3R2D5M4YSC6NFZ6YO3AEG4VWORECX72CHUM5UBADV4UPAAZG7WQC
VY2RJLJQMUOVIJOYPTA7AEXPURIV3H6VF7O5QQ7LF44ZS36RTFYAC
XJZXBPVEV3HQIWKQ5UYSEMQQ26C4N7QYW23ZIIXMUR2I2S73LUYAC
FWNNTOEERPUKXPE4OC52UABFZLKIU3O5GRNNLDK4QI4HR2IOU36QC
4GYZYBY7FFORRNPIEFTV4ZM2C7Z6D2KTQOM537ZCC2YBXT2TNSHAC
4LSDVTTNEK7LTLUCGP5SUVXJBUFF457AKWA7CEUQURWXGGLHRGCQC
KVMJCPD4RM6YUWIMO4LDHEIB5W62MTOCGBWAEFBHNOUDYLGKXQ3QC
QO5ZJWQ3JK3PEGBPTQSAYIPEJEHG2M2KTD74227G5VG7DVXUL3BQC
RIGGVFYNCRFDUUCMIAN7SDEOUL4VMMZI6OYXZW72BVNI4WXJQXWQC
WXZQJUZXMYS7R6ORNB7DWE5KEUXT262GXWMRPOJYYB4I3BFGYLLAC
JEWRZ3AI42QDS32KLPVYQZIXLS3GYOOU64IR4IPPKZNF4JYUL7TAC
5FMXUX2ZFIF6NQZCS54W7ZOCVSH7XR6UIMQ5FW2UZLEN4EWP5PSAC
R6OIKZAWLEAS6COYSOHY37CINPIOTSOVJ5OLJISPUCP64IJAGSGQC
FW3PIRSTFPX7VNUAVASCBB7VPYJHGPRSHXC4S6RXCLSLJMGWS6QQC
62CWUC7WKYRODVOOUFHRPDZXGTBUIU7XPR3EHJWESPG2XVUM7SDAC
2KJ6VEN4TXT3L77WRJJ2ZU2QSJV73YQDPJD4WI7UCMSRXXILXHSAC
S34LKQDIQJLIWVIPASOJBBZ6ZCXDHP5KPS7TRBZJSCDRVNCLK6UAC
V4F3SDV2H4HBH6G6W5M3REN3BDSSE4IDF2RNM7PJMKRW3IDJ7PNAC
VIQYG6MPI5YOCGDYTUNKGC7SUTNDRMWKT463CHZARVZXQIABGWKAC
V4DWL5WBO2JCODVS5QQNWXDH4DAYZN3D5V3UDCHM2KKOMADOTEDQC
WZNB427K3EUNV3FMVXLQTM4UIHER4FIKQXWLUUXRNQC3OQ33VQYAC
WNDCC2WZEUQ2SHRQZUAAK3A4QF5JGLDJ5D3WLKLNXYSCK4TZ7KZAC
B3HWU2BEQQ4E6WKVTW3JQQJFMWTVW3XWKY6BHFNBRHSZPRCF2OTQC
IQGGFC563RBS7GDOACKCLXK752EE5RC3T6G5L6H446SXTMSA7T2AC
43IJZIJEQREN63MUKMO2WB5SJI4AXVVA4HORZPMOAFEATHCUHS6AC
AXRXY7RSEN3QHQRK6SFEH2OZAAYJRR5RBBBFF4YJF756V2FPFJ3AC
XDHIIBQZLHLXAHIPJMXWH3FJ2X5PO7IB7HXQMVZDWM5JZFAG3HAQC
FS4MVTH4EEEECLEAO2FTNK5CLF2PHFYO2JZHC2YEOKYLWXRDRU6AC
C7Q5QY7S5TTMJ3XO2SIO3FY5ZENWYYETS4NKEKCAJMENEHJC6Y2AC
NFXK75IVZIF2JRTVQYLSR7NRD3OV4H24EZT33OBOIDGYYBNJGCKQC
MDFQRJ6QZNFUBVSFWLXUJ6EBXOU47T3CVDI2XKBGNNRF4DXDKESQC
KYVZGUJXV23ELA4CKPVQZO3NTJCODXMCWYAZJYWVWJVLPETNHLGQC
JBZ7NU4BB5PGQWCOSZHD5OQUHQIVOD4XGJLSJQ7BUGQEGPRTVGZQC
3DQXSE4YGFBBDUWK4YEOFWW4UPWILWELFSLP37SL6BERGAZJC5YAC
H7GMWXGBKDNFSKIDR5IWTS6UYPRHPBBSAFMVXHZQOZTCZ7OMNVKQC
TGJZXTUIAKCFZQJ54ZQEBGFBVZSJCAX6AWDRSH3TP7UJRLGUM5SAC
P2OYYNPHIBGOLT4CRLNTTIXDN34EU2QCMFQJNLAMUAHQXZTEDPXQC
IGNQ3YSGMW6NG7GPYYXWXW6XPM4YWKNUJ5IU55QCWZ2AEHHO3L3QC
KZ362RP6C7HRFQB66QL3PBRG7MBEPLRKTFMJYK7DFJQKERFGNFXQC
BWHU47MJ7KAVKMKMRBVYLOHUCASSNVCGPC3SPMNBAC7DLI6XX2YQC
5PNVRKZFGGUKPYADIXIJSBTBGX26NDGSNGYS6WGSBP3JGT5NCCKAC
SS6MUIJYTGIVBYU356Z563QJWLJ47QNHSJWS7GJTS7EATZH2ESJQC
CQ24AVAI6SW3AHTIDMLPSTRRBEU6FHRF5I5FD6G5QIYE6PO4BQMQC
2RJUPYKEDZZCW4GDG6WLEDVYF32ADC4W5I42KSKHN3MWEBCWSAHQC
VVMQW3SQYNMFSMLK7WAXWOXOEDLFLN6W44UOVIJMBMF5AOPYM6FQC
TNKSIEURZ6WZTNL5XYNWFENONDAPHJY6VYUHH2AGUGV2WXCEISAAC
6KCBR34M2QLZOQ6WQC4L6Z2MCH4DFV5BZ4QRGQSYRQLKG7WZGHFAC
4I62MHXSS7OWDF2QU7AYXCRB2ZAGHNCZQN24MENLXJFRSGMXXFLAC
EODUVLUYJAJFRQAKFIMDYCOI4666SL2JHJDH3NWS452WNCVOI7LAC
SDK3Q2BC3R4WJ2TJTJQTAKF6XYBAS2S44C6RZE3FCRMK2UEBDOVAC
MG2J6HQGH4DWFH3PC2SZB45NGKK5ISPBADQD24GWAZCZTDLOA33AC
BR6HF3PWCXUG24OBIWTCZ64DDVBA2G6BQBDJ5V5WMARRQBG2CLGQC
RMZCWOVH2IPIOCGCS7EQQIO7Y5HQ3XPY52K2B6SAPWKYYSJ6EUIAC
3PPH2RAOMAQGDPQKUKMMA3RC5M3VUSEJ7WKGZNVJ7UBFE75K574QC
XII3RPTU6PPAY7U7TE4MTVPSOFZTOPF7ZKHMBGG2GHLAWPUFOKCQC
JXO53C3SJ5KPLXVEBFGFWCBI4EFY6TCA6QQVH5NII5NP5BC4EWUAC
MG6LLF3XYCOEBQRX7TJ4MUTKM3IROYWUMZGCMYVW4TGDG36CJMJQC
NLQNXH3SVJ52CWXEV35FSSZP32VHC4QFGN3HINF4KO5GZHZMOBKQC
L5YS6SNTQW7YRR5LGCDSLHLNFJ73IWHU4A7S3MY6KYLG67N2KPGAC
5JS3QSE3EIXSBVI4DATH2EIFD7QN3POAFEUM7MK4NRMPH5JOPAAQC
F7QFSXE22UPQTBLYJLY26HJ3QPHFNBJMUOFJRV35R5YCHSGKTBYQC
PJWXE2ZLK4YCJM77CENEMB5XKVFTXFPMJEWC3TAMOTPZ5HSD3JZAC
KNW37MRIU72X4LPXSA4AUPW3VJMOXKWY2XFTV67KW2ZXTCSYMMNAC
5YQ53FYWPSONG3EOUAEMII2ECVAO6SRDUBVICH7JFGFS2Q5L4HYQC
4SWAT5KCKQV527NKELAXFQ5XA4Q5HONQXD4VBXMUZNPVPQKPCPNAC
NNQPJEMQAJC6V45OOHEX7OA54DE5IEQI73SJTS5O6PPU3KMHF4WQC
EMOBSWJHHB4V6WVMZL7JCF2V3KZN454Z6NS346OKFPMBNO24EJDQC
LYEMFS2OCCXSYOZKIQURQDXL64CB5BFP2P3MW3JDCEUIYVWX745QC
TR6F3WVSL6TS5SZVGJBGDK54FKAXYWRWXFRNMQ2AYYKHADSHR2EQC
FZ3VCF24YWNHTLVHBZYWX37X4FI2SNCXGZGTV2UFGFGAWMOKFIUAC
PC6K5OQF3BWPMWTIN5JXAKHTZF453JQOELDWRUOSBZXR256FTUYQC
SIDH2P7NBIG5KEOE27XHD3ZT2NQ2OJZFN6VZXWNWYFFY5YVXSSVQC
6UEKO6GLZNCAGVJRMRBVX6XSLS7H3SFUOUZRPECEOA5TV2DC2QIQC
RT4UZQXFGZCMWEP553GYPQKMYIKQHRJO7EZ73N76HJI45AW5O3DQC
RPOZZWKG5GLPHVZZ7ZKMKS64ZMV2LDCQSARBJFJ6FZOTOKCQO7FAC
R22TTMI6WXWULC7ODKFF3QCB7MOTETQQ6IR4BUCUPOCQKQNCTT5AC
SDLKLUNFGVKDS55DDJZCBAVIB7NL3RRYPTACAY65SCUQKV6APFSAC
43ZTEB57FU7KE5EVMYWZONNVJBZCGF3JEAJZIY25LC4LGE65PG5QC
PR42BCP5BPRFD2MP5H6CIJP7E57Q6TKL6SOXZWFKMFVR2OZWHT7AC
BK6MGPSEAEMU4URBAPKY3VTKK6JC6IZVN5CNOSN2UPTIOWQYEWLQC
TV3ZC6WOZKSQQJQN26JIVKCHK6UK7WMDBYZDUYRWEAZ4JB4YVNAAC
7AMQN7MITMXBNVDAK5VOXTQ4TZIAOD6ZLOFJG7GQMBTY23Y2BKSAC
MQ62OAMLGJVRW2QIL4PAZRAU6PC52ZVGY2FCOBIY6IWGQIHMU5CAC
UL7XFKMUX3WIU4O2LZANK4ECJ654UZPDBFGNXUEYZYOLKBYBCG6AC
bool zin_sustenance(bool actual = true);
bool zin_remove_all_mutations();
bool yred_injury_mirror(bool actual = true);
bool jiyva_grant_jelly(bool actual = true);
bool jiyva_remove_bad_mutation();
void yred_make_enslaved_soul(monsters *mon, bool force_hostile = false,
bool quiet = false, bool unrestricted = false);
void beogh_convert_orc(monsters *orc, bool emergency,
bool converted_by_follower = false);
void jiyva_convert_slime(monsters* slime);
void feawn_neutralise_plant(monsters *plant);
bool feawn_passthrough(const monsters * target);
bool vehumet_supports_spell(spell_type spell);
bool trog_burn_spellbooks();
}
bool yred_injury_mirror(bool actual)
{
return (you.religion == GOD_YREDELEMNUL && !player_under_penance()
&& you.piety >= piety_breakpoint(1)
&& (!actual || you.duration[DUR_PRAYER]));
bool beogh_water_walk()
{
return (you.religion == GOD_BEOGH && !player_under_penance()
&& you.piety >= piety_breakpoint(4));
}
bool jiyva_remove_bad_mutation()
{
if (!how_mutated())
{
mpr("You have no bad mutations to be cured!");
return (false);
}
// Ensure that only bad mutations are removed.
if (!delete_mutation(RANDOM_BAD_MUTATION, true, false, true, true))
{
canned_msg(MSG_NOTHING_HAPPENS);
return (false);
}
mpr("You feel cleansed.");
return (true);
}
return (true);
return (false);
}
bool vehumet_supports_spell(spell_type spell)
{
if (spell_typematch(spell, SPTYP_CONJURATION | SPTYP_SUMMONING))
return (true);
if (spell == SPELL_SHATTER
|| spell == SPELL_FRAGMENTATION
|| spell == SPELL_SANDBLAST)
{
}
// Returns false if the invocation fails (no spellbooks in sight, etc.).
bool trog_burn_spellbooks()
{
if (you.religion != GOD_TROG)
return (false);
god_acting gdact;
for (stack_iterator si(you.pos()); si; ++si)
{
if (si->base_type == OBJ_BOOKS
&& si->sub_type != BOOK_MANUAL
&& si->sub_type != BOOK_DESTRUCTION)
{
mpr("Burning your own feet might not be such a smart idea!");
return (false);
}
}
int totalpiety = 0;
for (radius_iterator ri(you.pos(), LOS_RADIUS, true, true, true); ri; ++ri)
{
// If a grid is blocked, books lying there will be ignored.
// Allow bombing of monsters.
const unsigned short cloud = env.cgrid(*ri);
if (feat_is_solid(grd(*ri))
|| cloud != EMPTY_CLOUD && env.cloud[cloud].type != CLOUD_FIRE)
{
continue;
}
int count = 0;
int rarity = 0;
for (stack_iterator si(*ri); si; ++si)
{
if (si->base_type != OBJ_BOOKS
|| si->sub_type == BOOK_MANUAL
|| si->sub_type == BOOK_DESTRUCTION)
{
continue;
}
// Ignore {!D} inscribed books.
if (!check_warning_inscriptions(*si, OPER_DESTROY))
{
mpr("Won't ignite {!D} inscribed book.");
continue;
}
rarity += book_rarity(si->sub_type);
// Piety increases by 2 for books never cracked open, else 1.
// Conversely, rarity influences the duration of the pyre.
if (!item_type_known(*si))
totalpiety += 2;
else
totalpiety++;
#ifdef DEBUG_DIAGNOSTICS
mprf(MSGCH_DIAGNOSTICS, "Burned book rarity: %d", rarity);
#endif
destroy_item(si.link());
count++;
}
if (count)
{
if (cloud != EMPTY_CLOUD)
{
// Reinforce the cloud.
mpr("The fire roars with new energy!");
const int extra_dur = count + random2(rarity / 2);
env.cloud[cloud].decay += extra_dur * 5;
env.cloud[cloud].set_whose(KC_YOU);
continue;
}
const int duration = std::min(4 + count + random2(rarity/2), 23);
place_cloud(CLOUD_FIRE, *ri, duration, KC_YOU);
mprf(MSGCH_GOD, "The book%s burst%s into flames.",
count == 1 ? "" : "s",
count == 1 ? "s" : "");
}
}
if (!totalpiety)
{
mpr("You cannot see a spellbook to ignite!");
return (false);
}
else
{
simple_god_message(" is delighted!", GOD_TROG);
gain_piety(totalpiety);
}
return (true);
}
static bool _yred_enslaved_souls_on_level_disappear()
{
bool success = false;
for (int i = 0; i < MAX_MONSTERS; ++i)
{
monsters *monster = &menv[i];
if (_is_yred_enslaved_soul(monster))
{
#ifdef DEBUG_DIAGNOSTICS
mprf(MSGCH_DIAGNOSTICS, "Undead soul disappearing: %s on level %d, branch %d",
monster->name(DESC_PLAIN).c_str(),
static_cast<int>(you.your_level),
static_cast<int>(you.where_are_you));
#endif
simple_monster_message(monster, " is freed.");
// The monster disappears.
monster_die(monster, KILL_DISMISSED, NON_MONSTER);
success = true;
}
}
return (success);
}
void yred_make_enslaved_soul(monsters *mon, bool force_hostile,
bool quiet, bool unrestricted)
{
if (!unrestricted)
_yred_souls_disappear();
const int type = mon->type;
monster_type soul_type = mons_species(type);
const std::string whose =
you.can_see(mon) ? apostrophise(mon->name(DESC_CAP_THE))
: mon->pronoun(PRONOUN_CAP_POSSESSIVE);
const bool twisted =
!unrestricted ? !x_chance_in_y(you.skills[SK_INVOCATIONS] * 20 / 9 + 20,
100)
: false;
int corps = -1;
// If the monster's held in a net, get it out.
mons_clear_trapping_net(mon);
const monsters orig = *mon;
if (twisted)
{
mon->type = mons_zombie_size(soul_type) == Z_BIG ?
MONS_ABOMINATION_LARGE : MONS_ABOMINATION_SMALL;
mon->base_monster = MONS_PROGRAM_BUG;
}
else
{
// Drop the monster's corpse, so that it can be properly
// re-equipped below.
corps = place_monster_corpse(mon, true, true);
}
// Drop the monster's equipment.
monster_drop_ething(mon);
// Recreate the monster as an abomination, or as itself before
// turning it into a spectral thing below.
define_monster(*mon);
mon->colour = ETC_UNHOLY;
mon->flags |= MF_CREATED_FRIENDLY;
mon->flags |= MF_ENSLAVED_SOUL;
if (twisted)
// Mark abominations as undead.
mon->flags |= MF_HONORARY_UNDEAD;
else if (corps != -1)
{
// Turn the monster into a spectral thing, minus the usual
// adjustments for zombified monsters.
mon->type = MONS_SPECTRAL_THING;
mon->base_monster = soul_type;
// Re-equip the spectral thing.
equip_undead(mon->pos(), corps, monster_index(mon),
mon->base_monster);
// Destroy the monster's corpse, as it's no longer needed.
destroy_item(corps);
}
name_zombie(mon, &orig);
mons_make_god_gift(mon, GOD_YREDELEMNUL);
mon->attitude = !force_hostile ? ATT_FRIENDLY : ATT_HOSTILE;
behaviour_event(mon, ME_ALERT, !force_hostile ? MHITNOT : MHITYOU);
if (!quiet)
{
mprf("%s soul %s, and %s.", whose.c_str(),
twisted ? "becomes twisted" : "remains intact",
!force_hostile ? "is now yours" : "fights you");
}
}
static void _print_converted_orc_speech(const std::string key,
monsters *mon,
msg_channel_type channel)
{
std::string msg = getSpeakString("beogh_converted_orc_" + key);
if (!msg.empty())
{
msg = do_mon_str_replacements(msg, mon);
mpr(msg.c_str(), channel);
}
}
// Orcs may turn friendly when encountering followers of Beogh, and be
// made gifts of Beogh.
void beogh_convert_orc(monsters *orc, bool emergency,
bool converted_by_follower)
{
ASSERT(mons_species(orc->type) == MONS_ORC);
if (you.can_see(orc)) // show reaction
{
if (emergency || !orc->alive())
{
if (converted_by_follower)
{
_print_converted_orc_speech("reaction_battle_follower", orc,
MSGCH_FRIEND_ENCHANT);
_print_converted_orc_speech("speech_battle_follower", orc,
MSGCH_TALK);
}
else
{
_print_converted_orc_speech("reaction_battle", orc,
MSGCH_FRIEND_ENCHANT);
_print_converted_orc_speech("speech_battle", orc, MSGCH_TALK);
}
}
else
{
_print_converted_orc_speech("reaction_sight", orc,
MSGCH_FRIEND_ENCHANT);
if (!one_chance_in(3))
_print_converted_orc_speech("speech_sight", orc, MSGCH_TALK);
}
}
orc->attitude = ATT_FRIENDLY;
// The monster is not really *created* friendly, but should it
// become hostile later on, it won't count as a good kill.
orc->flags |= MF_CREATED_FRIENDLY;
// Prevent assertion if the orc was previously worshipping a
// different god, rather than already worshipping Beogh or being an
// atheist.
orc->god = GOD_NO_GOD;
mons_make_god_gift(orc, GOD_BEOGH);
if (orc->is_patrolling())
{
// Make orcs stop patrolling and forget their patrol point,
// they're supposed to follow you now.
orc->patrol_point = coord_def(0, 0);
}
if (!orc->alive())
orc->hit_points = std::min(random_range(1, 4), orc->max_hit_points);
// Avoid immobile "followers".
behaviour_event(orc, ME_ALERT, MHITNOT);
}
void feawn_neutralise_plant(monsters *plant)
{
if (!plant
|| !feawn_neutralises(plant)
|| plant->attitude != ATT_HOSTILE
|| testbits(plant->flags, MF_ATT_CHANGE_ATTEMPT))
{
return;
}
plant->attitude = ATT_GOOD_NEUTRAL;
plant->flags |= MF_WAS_NEUTRAL;
}
// During prayer feawn allows worshipers to walk on top of stationary plants
// and fungi.
bool feawn_passthrough(const monsters * target)
{
return (target && you.religion == GOD_FEAWN
&& you.duration[DUR_PRAYER]
&& mons_is_plant(target)
&& mons_is_stationary(target));
if (you.can_see(slime))
{
if (mons_genus(slime->type) == MONS_GIANT_EYEBALL)
{
mprf(MSGCH_GOD, "%s stares at you suspiciously for a moment, "
"then relaxes.",
slime->name(DESC_CAP_THE).c_str());
}
else
{
mprf(MSGCH_GOD, "%s trembles before you.",
slime->name(DESC_CAP_THE).c_str());
}
}
slime->attitude = ATT_STRICT_NEUTRAL;
slime->flags |= MF_WAS_NEUTRAL;
if (!mons_eats_items(slime))
{
slime->add_ench(ENCH_EAT_ITEMS);
mprf(MSGCH_MONSTER_ENCHANT, "%s looks hungrier.",
slime->name(DESC_CAP_THE).c_str());
}
// Prevent assertion if the slime was previously worshipping a
// different god, rather than already worshipping Jiyva or being an
// atheist.
slime->god = GOD_NO_GOD;
mons_make_god_gift(slime, GOD_JIYVA);
}
}
bool ponderousify_armour(){
int item_slot = -1;
do
{
if (item_slot == -1)
{
item_slot = prompt_invent_item("Make which item ponderous?",
MT_INVLIST, OSEL_ENCH_ARM, true, true, false);
}
if (prompt_failed(item_slot))
return (false);
item_def& arm(you.inv[item_slot]);
if (!is_enchantable_armour(arm, true, true)
|| get_armour_ego_type(arm) != SPARM_NORMAL)
{
mpr("Choose some type of armour to enchant, or Esc to abort.");
if (Options.auto_list)
more();
item_slot = -1;
mpr("You can't enchant that."); //does not appear
continue;
}
//make item desc runed if desc was vanilla?
set_item_ego_type(arm, OBJ_ARMOUR, SPARM_PONDEROUSNESS);
you.redraw_armour_class = true;
you.redraw_evasion = true;
simple_god_message(" says: Dude, use this wisely!");
return (true);
}
while (true);
return true;
static int _slouch_monsters(coord_def where, int pow, int, actor* agent)
{
monsters* mon = monster_at(where);
if (mon == NULL)
return (0);
int dmg = (mon->speed - player_movement_speed());
dmg = (dmg > 0 ? dmg * dmg : 0);
mon->hurt(agent, dmg, BEAM_MMISSILE, true);
return (1);
}
int chronos_slouch(int pow)
{
return (apply_area_visible(_slouch_monsters, pow));
}
/*
* File: godabil.h
* Summary: God-granted abilities.
*/
#ifndef GODABIL_H
#define GODABILN_H
#include "enum.h"
#include "externs.h"
bool ponderousify_armour();
int chronos_slouch(int);
bool zin_sustenance(bool actual = true);
bool zin_remove_all_mutations();
bool yred_injury_mirror(bool actual = true);
bool jiyva_grant_jelly(bool actual = true);
bool jiyva_remove_bad_mutation();
bool beogh_water_walk();
void yred_make_enslaved_soul(monsters *mon, bool force_hostile = false,
bool quiet = false, bool unrestricted = false);
void beogh_convert_orc(monsters *orc, bool emergency,
bool converted_by_follower = false);
void jiyva_convert_slime(monsters* slime);
void feawn_neutralise_plant(monsters *plant);
bool feawn_passthrough(const monsters * target);
bool vehumet_supports_spell(spell_type spell);
bool trog_burn_spellbooks();
#endif
/*
* File: godabil.cc
* Summary: God-granted abilities.
*/
#include "AppHdr.h"
#include "cloud.h"
#include "database.h"
#include "files.h"
#include "godabil.h"
#include "invent.h"
#include "items.h"
#include "kills.h"
#include "message.h"
#include "mon-util.h"
#include "monstuff.h"
#include "mstuff2.h"
#include "mutation.h"
#include "religion.h"
#include "shopping.h"
#include "spells3.h"
#include "spl-book.h"
#include "spl-util.h"
#include "stuff.h"
#include "terrain.h"
#include "view.h"
bool yred_injury_mirror(bool actual)
{
return (you.religion == GOD_YREDELEMNUL && !player_under_penance()
&& you.piety >= piety_breakpoint(1)
&& (!actual || you.duration[DUR_PRAYER]));
}
bool beogh_water_walk()
{
return (you.religion == GOD_BEOGH && !player_under_penance()
&& you.piety >= piety_breakpoint(4));
}
bool jiyva_grant_jelly(bool actual)
{
return (you.religion == GOD_JIYVA && !player_under_penance()
&& you.piety >= piety_breakpoint(2)
&& (!actual || you.duration[DUR_PRAYER]));
}
bool jiyva_remove_bad_mutation()
{
if (!how_mutated())
{
mpr("You have no bad mutations to be cured!");
return (false);
}
// Ensure that only bad mutations are removed.
if (!delete_mutation(RANDOM_BAD_MUTATION, true, false, true, true))
{
canned_msg(MSG_NOTHING_HAPPENS);
return (false);
}
mpr("You feel cleansed.");
return (true);
}
bool vehumet_supports_spell(spell_type spell)
{
if (spell_typematch(spell, SPTYP_CONJURATION | SPTYP_SUMMONING))
return (true);
if (spell == SPELL_SHATTER
|| spell == SPELL_FRAGMENTATION
|| spell == SPELL_SANDBLAST)
{
return (true);
}
return (false);
}
// Returns false if the invocation fails (no spellbooks in sight, etc.).
bool trog_burn_spellbooks()
{
if (you.religion != GOD_TROG)
return (false);
god_acting gdact;
for (stack_iterator si(you.pos()); si; ++si)
{
if (si->base_type == OBJ_BOOKS
&& si->sub_type != BOOK_MANUAL
&& si->sub_type != BOOK_DESTRUCTION)
{
mpr("Burning your own feet might not be such a smart idea!");
return (false);
}
}
int totalpiety = 0;
for (radius_iterator ri(you.pos(), LOS_RADIUS, true, true, true); ri; ++ri)
{
// If a grid is blocked, books lying there will be ignored.
// Allow bombing of monsters.
const unsigned short cloud = env.cgrid(*ri);
if (feat_is_solid(grd(*ri))
|| cloud != EMPTY_CLOUD && env.cloud[cloud].type != CLOUD_FIRE)
{
continue;
}
int count = 0;
int rarity = 0;
for (stack_iterator si(*ri); si; ++si)
{
if (si->base_type != OBJ_BOOKS
|| si->sub_type == BOOK_MANUAL
|| si->sub_type == BOOK_DESTRUCTION)
{
continue;
}
// Ignore {!D} inscribed books.
if (!check_warning_inscriptions(*si, OPER_DESTROY))
{
mpr("Won't ignite {!D} inscribed book.");
continue;
}
rarity += book_rarity(si->sub_type);
// Piety increases by 2 for books never cracked open, else 1.
// Conversely, rarity influences the duration of the pyre.
if (!item_type_known(*si))
totalpiety += 2;
else
totalpiety++;
#ifdef DEBUG_DIAGNOSTICS
mprf(MSGCH_DIAGNOSTICS, "Burned book rarity: %d", rarity);
#endif
destroy_item(si.link());
count++;
}
if (count)
{
if (cloud != EMPTY_CLOUD)
{
// Reinforce the cloud.
mpr("The fire roars with new energy!");
const int extra_dur = count + random2(rarity / 2);
env.cloud[cloud].decay += extra_dur * 5;
env.cloud[cloud].set_whose(KC_YOU);
continue;
}
const int duration = std::min(4 + count + random2(rarity/2), 23);
place_cloud(CLOUD_FIRE, *ri, duration, KC_YOU);
mprf(MSGCH_GOD, "The book%s burst%s into flames.",
count == 1 ? "" : "s",
count == 1 ? "s" : "");
}
}
if (!totalpiety)
{
mpr("You cannot see a spellbook to ignite!");
return (false);
}
else
{
simple_god_message(" is delighted!", GOD_TROG);
gain_piety(totalpiety);
}
return (true);
}
static bool _is_yred_enslaved_soul(const monsters* mon)
{
return (mon->alive() && mons_enslaved_soul(mon));
}
static bool _yred_enslaved_souls_on_level_disappear()
{
bool success = false;
for (int i = 0; i < MAX_MONSTERS; ++i)
{
monsters *monster = &menv[i];
if (_is_yred_enslaved_soul(monster))
{
#ifdef DEBUG_DIAGNOSTICS
mprf(MSGCH_DIAGNOSTICS, "Undead soul disappearing: %s on level %d, branch %d",
monster->name(DESC_PLAIN).c_str(),
static_cast<int>(you.your_level),
static_cast<int>(you.where_are_you));
#endif
simple_monster_message(monster, " is freed.");
// The monster disappears.
monster_die(monster, KILL_DISMISSED, NON_MONSTER);
success = true;
}
}
return (success);
}
static bool _yred_souls_disappear()
{
return (apply_to_all_dungeons(_yred_enslaved_souls_on_level_disappear));
}
void yred_make_enslaved_soul(monsters *mon, bool force_hostile,
bool quiet, bool unrestricted)
{
if (!unrestricted)
_yred_souls_disappear();
const int type = mon->type;
monster_type soul_type = mons_species(type);
const std::string whose =
you.can_see(mon) ? apostrophise(mon->name(DESC_CAP_THE))
: mon->pronoun(PRONOUN_CAP_POSSESSIVE);
const bool twisted =
!unrestricted ? !x_chance_in_y(you.skills[SK_INVOCATIONS] * 20 / 9 + 20,
100)
: false;
int corps = -1;
// If the monster's held in a net, get it out.
mons_clear_trapping_net(mon);
const monsters orig = *mon;
if (twisted)
{
mon->type = mons_zombie_size(soul_type) == Z_BIG ?
MONS_ABOMINATION_LARGE : MONS_ABOMINATION_SMALL;
mon->base_monster = MONS_PROGRAM_BUG;
}
else
{
// Drop the monster's corpse, so that it can be properly
// re-equipped below.
corps = place_monster_corpse(mon, true, true);
}
// Drop the monster's equipment.
monster_drop_ething(mon);
// Recreate the monster as an abomination, or as itself before
// turning it into a spectral thing below.
define_monster(*mon);
mon->colour = ETC_UNHOLY;
mon->flags |= MF_CREATED_FRIENDLY;
mon->flags |= MF_ENSLAVED_SOUL;
if (twisted)
// Mark abominations as undead.
mon->flags |= MF_HONORARY_UNDEAD;
else if (corps != -1)
{
// Turn the monster into a spectral thing, minus the usual
// adjustments for zombified monsters.
mon->type = MONS_SPECTRAL_THING;
mon->base_monster = soul_type;
// Re-equip the spectral thing.
equip_undead(mon->pos(), corps, monster_index(mon),
mon->base_monster);
// Destroy the monster's corpse, as it's no longer needed.
destroy_item(corps);
}
name_zombie(mon, &orig);
mons_make_god_gift(mon, GOD_YREDELEMNUL);
mon->attitude = !force_hostile ? ATT_FRIENDLY : ATT_HOSTILE;
behaviour_event(mon, ME_ALERT, !force_hostile ? MHITNOT : MHITYOU);
if (!quiet)
{
mprf("%s soul %s, and %s.", whose.c_str(),
twisted ? "becomes twisted" : "remains intact",
!force_hostile ? "is now yours" : "fights you");
}
}
static void _print_converted_orc_speech(const std::string key,
monsters *mon,
msg_channel_type channel)
{
std::string msg = getSpeakString("beogh_converted_orc_" + key);
if (!msg.empty())
{
msg = do_mon_str_replacements(msg, mon);
mpr(msg.c_str(), channel);
}
}
// Orcs may turn friendly when encountering followers of Beogh, and be
// made gifts of Beogh.
void beogh_convert_orc(monsters *orc, bool emergency,
bool converted_by_follower)
{
ASSERT(mons_species(orc->type) == MONS_ORC);
if (you.can_see(orc)) // show reaction
{
if (emergency || !orc->alive())
{
if (converted_by_follower)
{
_print_converted_orc_speech("reaction_battle_follower", orc,
MSGCH_FRIEND_ENCHANT);
_print_converted_orc_speech("speech_battle_follower", orc,
MSGCH_TALK);
}
else
{
_print_converted_orc_speech("reaction_battle", orc,
MSGCH_FRIEND_ENCHANT);
_print_converted_orc_speech("speech_battle", orc, MSGCH_TALK);
}
}
else
{
_print_converted_orc_speech("reaction_sight", orc,
MSGCH_FRIEND_ENCHANT);
if (!one_chance_in(3))
_print_converted_orc_speech("speech_sight", orc, MSGCH_TALK);
}
}
orc->attitude = ATT_FRIENDLY;
// The monster is not really *created* friendly, but should it
// become hostile later on, it won't count as a good kill.
orc->flags |= MF_CREATED_FRIENDLY;
// Prevent assertion if the orc was previously worshipping a
// different god, rather than already worshipping Beogh or being an
// atheist.
orc->god = GOD_NO_GOD;
mons_make_god_gift(orc, GOD_BEOGH);
if (orc->is_patrolling())
{
// Make orcs stop patrolling and forget their patrol point,
// they're supposed to follow you now.
orc->patrol_point = coord_def(0, 0);
}
if (!orc->alive())
orc->hit_points = std::min(random_range(1, 4), orc->max_hit_points);
// Avoid immobile "followers".
behaviour_event(orc, ME_ALERT, MHITNOT);
}
void feawn_neutralise_plant(monsters *plant)
{
if (!plant
|| !feawn_neutralises(plant)
|| plant->attitude != ATT_HOSTILE
|| testbits(plant->flags, MF_ATT_CHANGE_ATTEMPT))
{
return;
}
plant->attitude = ATT_GOOD_NEUTRAL;
plant->flags |= MF_WAS_NEUTRAL;
}
// During prayer feawn allows worshipers to walk on top of stationary plants
// and fungi.
bool feawn_passthrough(const monsters * target)
{
return (target && you.religion == GOD_FEAWN
&& you.duration[DUR_PRAYER]
&& mons_is_plant(target)
&& mons_is_stationary(target));
}
void jiyva_convert_slime(monsters* slime)
{
ASSERT(mons_is_slime(slime));
if (you.can_see(slime))
{
if (mons_genus(slime->type) == MONS_GIANT_EYEBALL)
{
mprf(MSGCH_GOD, "%s stares at you suspiciously for a moment, "
"then relaxes.",
slime->name(DESC_CAP_THE).c_str());
}
else
{
mprf(MSGCH_GOD, "%s trembles before you.",
slime->name(DESC_CAP_THE).c_str());
}
}
slime->attitude = ATT_STRICT_NEUTRAL;
slime->flags |= MF_WAS_NEUTRAL;
if (!mons_eats_items(slime))
{
slime->add_ench(ENCH_EAT_ITEMS);
mprf(MSGCH_MONSTER_ENCHANT, "%s looks hungrier.",
slime->name(DESC_CAP_THE).c_str());
}
// Prevent assertion if the slime was previously worshipping a
// different god, rather than already worshipping Jiyva or being an
// atheist.
slime->god = GOD_NO_GOD;
mons_make_god_gift(slime, GOD_JIYVA);
}
bool ponderousify_armour()
{
int item_slot = -1;
do
{
if (item_slot == -1)
{
item_slot = prompt_invent_item("Make which item ponderous?",
MT_INVLIST, OSEL_ENCH_ARM, true, true, false);
}
if (prompt_failed(item_slot))
return (false);
item_def& arm(you.inv[item_slot]);
if (!is_enchantable_armour(arm, true, true)
|| get_armour_ego_type(arm) != SPARM_NORMAL)
{
mpr("Choose some type of armour to enchant, or Esc to abort.");
if (Options.auto_list)
more();
item_slot = -1;
mpr("You can't enchant that."); //does not appear
continue;
}
//make item desc runed if desc was vanilla?
set_item_ego_type(arm, OBJ_ARMOUR, SPARM_PONDEROUSNESS);
you.redraw_armour_class = true;
you.redraw_evasion = true;
simple_god_message(" says: Dude, use this wisely!");
return (true);
}
while (true);
return true;
}
static int _slouch_monsters(coord_def where, int pow, int, actor* agent)
{
monsters* mon = monster_at(where);
if (mon == NULL)
return (0);
int dmg = (mon->speed - player_movement_speed());
dmg = (dmg > 0 ? dmg * dmg : 0);
mon->hurt(agent, dmg, BEAM_MMISSILE, true);
return (1);
}
int chronos_slouch(int pow)
{
return (apply_area_visible(_slouch_monsters, pow));
}