on crawl-ref-discuss.
git-svn-id: https://crawl-ref.svn.sourceforge.net/svnroot/crawl-ref/trunk@7263 c06c8d41-db1a-0410-9941-cceddc491573
BNRY5YIXLFE2TDNU2JQHWWXJQVWNSEWQ52DU7XUWIT5DZWKGBDDAC
HOUSHQ4DQK4MVKTCJ56MKYGYPDTF77HJCFVB5PYV7ALNZZJWFYFQC
YPQ24FG2TT6IX454HDF5QT7P6NKDNIZK4LB4YIJPCLQBMEXMCBBQC
FU3BLBSYBDAK6UVFT4EWO5ZTUFCYFPHYNZNFFF27AX7PWHOCHURAC
K7EIE5VJDKRYBAZRDFEEEKST2P2B7HFPH2AJVER5JUUQVTYXZWHQC
MSRJ3N4NX255RVISUOPTTTY2GG4JVVNNM76HWUZ2EKCYESNI6MLQC
TJ72NVTRNJKF55RTH5MRLTHHVPOJ2M5OOYEWF4UFLTO2PPPTU6PQC
QC6O26QFCH75KANQDWNY6X7BYKPKF63NFBBSHDUWZ6AUPIMYRB2QC
FTGL3RHC2ARWUOOMWO6TI2F2HSGCHKET7OHDBWCHARQCPCHHQERQC
EHL7B5UIYYHSFX3KXQ43C4GNFJSEUEXFF7U3IL7XU6E5R675WS7AC
WFMQVPMMOPG5SBJD5LUBOIYWRMXVWK3FXENK7SAEGZ5T6XWFKERQC
ABA7GPRHJ6M5CA2AJSZM2PZCL7CDOBEMM6QZJFRLKLS4CVMEUV6AC
GGDX26OLH2EBB2ZBJCBIE3UDPHWEMTMSOEJBJIWCBLUK3HEY3PKQC
LM764EO6YIFOKMRXWZ5S4GYZB4BHZQDTEFP7MEVYO4NN4EDOFGNQC
K2CS6TCX2NDVL2ASEHGP4J4K4IJ6FP3ANNKTSIWVG43HPYSBX6ZQC
JW2KRJHES33W7UTWZ6NDO4TLMK4EFU4HKZXBWR2UJOMPCCOTR4CQC
NNQPJEMQAJC6V45OOHEX7OA54DE5IEQI73SJTS5O6PPU3KMHF4WQC
62CWUC7WKYRODVOOUFHRPDZXGTBUIU7XPR3EHJWESPG2XVUM7SDAC
IGNQ3YSGMW6NG7GPYYXWXW6XPM4YWKNUJ5IU55QCWZ2AEHHO3L3QC
5PNVRKZFGGUKPYADIXIJSBTBGX26NDGSNGYS6WGSBP3JGT5NCCKAC
2NFFQ4TCADDVDWUNH3YXIPLDQ566TPF5WZ2YAZLDM5UEWPVUKNZQC
B47CVG54WZNP3CQ7HOTKTWQA26GCOIKQADX2EK4ZOEYRRQ4T5W2AC
CQ24AVAI6SW3AHTIDMLPSTRRBEU6FHRF5I5FD6G5QIYE6PO4BQMQC
5FBOE2QNRLKUNOP54CZD6LFAMM7LX6NNLHJRJHRDDIUTQ7J723DQC
KAOE5HB3THUKVGFZRO5EZESHEB3Q34WUO5DFMLWIKOBF47LZTIYAC
T7CUIVICB74342RA32BR37T36FOX4RBSQIB5PNOHTGTGUYGDKSTQC
2YL37AGHLFOMIF3GCTVQGGV2RNNWETWM6ZMUHO3QEWDVBFFSFAKQC
EFWEYIB2R3DPD3JWIPU6LS6SFLPMYN7J7X4GBZR7DJWKHJ3UELSAC
NLQNXH3SVJ52CWXEV35FSSZP32VHC4QFGN3HINF4KO5GZHZMOBKQC
Y2NYY7HWFZ2LQDK3ACSLGS37F2J2IJ5LRGCIMZYXLEOSVPD3A4DAC
YA24HFHVUI2LDWFOZR5QSHRIVTAWGSGPAH5E2FPP6ANCL2MTUSTAC
V7IKAPO5OY7CJTT62GMHQOD3EQW42FTTY3KDBOTJUODPS5WMBCHAC
BLN5LDH5NRRJPBY77A36Q4THEY75N42MVCJMZRUZ2D5YSXTDL4HQC
QDTVLBRGHDTRUVT7I3O72K6TMOYAUSAJBZUHGOEFU2RKJNUPWZSQC
RPOZZWKG5GLPHVZZ7ZKMKS64ZMV2LDCQSARBJFJ6FZOTOKCQO7FAC
5FHWTG7M6FW4B3I33YI7QSM3OZIB6ZGC6TI6JISSLY5Y43HI56VAC
J6APXOT4QOGQFONWB7G546VTVF6QG42HVOROMHF7YBDJPR4K26OAC
4SWAT5KCKQV527NKELAXFQ5XA4Q5HONQXD4VBXMUZNPVPQKPCPNAC
HOPP345EQLSF24XJYE3625VKU23PBKM5ZZKNCXBXUWYYORYPMDAAC
PVLLIAYFIAU4TQFBIP7B4ARIBUX2CVTSBQECEU6VTONJV4ANHVFAC
TN2D3PHU7VSGUND2BDIC2F4U6O2HFSV3JXLF7HMYYMY7GZXM6IFAC
QYQKV4R47PTERXVFQNNWWQVICGSOMBHW6WM5TAZAKLIYOLLPUAJAC
VXWDDKBETFFMU7LMGN4UGB74NNKXW456KFJMWWEVOTWH35NZZZHAC
W2KRIXSCRJPS6WDIYTHVF5IRMF3V5DWECRAWUPVTB7VZ6A2BLD4QC
CK5VYF5GP4KDA7KC3RABE5DAY2E4372TJB5K2A3SCWDM44R2W4XAC
OEHJJ5X5CBOHTXISZLJHVLCAPH77RYSVKKBGW3US2GGXZMZJ5CEQC
N3BRDQWPEHQZWIX2CDM2O2VLD6DJONGILDXVCSCAVWOGIOUU5IGAC
DENP72AB5VYMFLNU3VQULFIAWZAXOK4K554O5GBMZPHMVBUTO53AC
WXSNNK2RXP3DQFAEQGQUZJHFWXJC7ZKG2WURZGL566UDM4YXFSWQC
OYANFNGKCXG2NLQMYW4TNFU3LFK3533XQ3HFGI3LNMY4JGMDMK5QC
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);
}
if (is_yred_undead_slave(monster))
if (_is_yred_enslaved_body_and_soul(monster))
{
#ifdef DEBUG_DIAGNOSTICS
mprf(MSGCH_DIAGNOSTICS, "Undead soul abandoning: %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
yred_make_enslaved_soul(monster, true, true, false);
success = true;
}
else if (is_yred_undead_slave(monster))
monster->attitude = ATT_HOSTILE;
behaviour_event(monster, ME_ALERT, MHITYOU);
// For now CREATED_FRIENDLY stays.
if (_is_yred_enslaved_body_and_soul(monster))
yred_make_enslaved_soul(monster, true, true, false);
else
{
monster->attitude = ATT_HOSTILE;
behaviour_event(monster, ME_ALERT, MHITYOU);
// For now CREATED_FRIENDLY stays.
}
const int type = mon->type;
const std::string name_cap_the = mon->name(DESC_CAP_THE);
const std::string name_plain = mon->name(DESC_PLAIN);
bool twisted = false;
if ((allow_fail || mons_unusable_items(mon) > 0) && coinflip())
twisted = true;
if (!quiet)
{
mprf("%s's soul %s.", name_cap_the.c_str(),
twisted ? "becomes twisted" : "remains intact");
}
if (twisted)
{
mon->type = mons_zombie_size(type) == Z_BIG ?
MONS_ABOMINATION_LARGE : MONS_ABOMINATION_SMALL;
mon->base_monster = mons_species(mon->type);
}
else
{
mon->type = MONS_SPECTRAL_THING;
mon->base_monster = mons_species(type);
}
define_monster(*mon);
if (twisted)
{
// Mark abominations as undead.
mon->flags |= MF_HONORARY_UNDEAD;
monster_drop_ething(mon);
}
mon->flags |= MF_ENSLAVED_SOUL;
if (mons_is_unique(type))
{
mon->mname = name_plain;
// Special case for Blork the orc: shorten his name to "Blork"
// to avoid mentions of "Blork the orc the spectral orc" or
// "Blork the orc the small abomination".
if (type == MONS_BLORK_THE_ORC)
mon->mname = "Blork";
}
// Wow, permanent enslaving!
mon->attitude = !force_hostile ? ATT_FRIENDLY : ATT_HOSTILE;
mon->flags |= MF_CREATED_FRIENDLY;
behaviour_event(mon, ME_ALERT, !force_hostile ? MHITNOT : MHITYOU);
mons_make_god_gift(mon, GOD_YREDELEMNUL);
if (!quiet)
{
mprf("%s's soul %s.", name_cap_the.c_str(),
!force_hostile ? "is now yours" : "fights you");
}
}
static int _scan_mon_inv_items(const monsters *mon,
bool (*item_type)(const item_def&))
{
int ret = 0;
if (mons_itemuse(mon) >= MONUSE_STARTING_EQUIPMENT)
{
const int weapon = mon->inv[MSLOT_WEAPON];
const int second = mon->inv[MSLOT_ALT_WEAPON]; // Two-headed ogres, etc.
const int misc = mon->inv[MSLOT_MISCELLANY];
const int potion = mon->inv[MSLOT_POTION];
const int wand = mon->inv[MSLOT_WAND];
const int scroll = mon->inv[MSLOT_SCROLL];
if (weapon != NON_ITEM && mitm[weapon].base_type == OBJ_WEAPONS
&& item_type(mitm[weapon]))
{
ret++;
}
if (second != NON_ITEM && mitm[second].base_type == OBJ_WEAPONS
&& item_type(mitm[second]))
{
ret++;
}
if (misc != NON_ITEM && mitm[misc].base_type == OBJ_MISCELLANY
&& item_type(mitm[misc]))
{
ret++;
}
if (potion != NON_ITEM && mitm[potion].base_type == OBJ_POTIONS
&& item_type(mitm[potion]))
{
ret++;
}
if (wand != NON_ITEM && mitm[misc].base_type == OBJ_WANDS
&& item_type(mitm[wand]))
{
ret++;
}
if (scroll != NON_ITEM && mitm[scroll].base_type == OBJ_SCROLLS
&& item_type(mitm[scroll]))
{
ret++;
}
}
return (ret);
}
static bool _mons_has_undrinkable_potion(const monsters *mon)
{
bool ret = false;
if (mons_itemuse(mon) >= MONUSE_STARTING_EQUIPMENT)
{
const int potion = mon->inv[MSLOT_POTION];
if (potion != NON_ITEM && mitm[potion].base_type == OBJ_POTIONS)
{
const potion_type ptype =
static_cast<potion_type>(mitm[potion].sub_type);
if (!mon->can_drink_potion(ptype))
ret = true;
}
}
return (ret);
}
int mons_unusable_items(const monsters *mon)
{
int ret = 0;
if (mons_is_holy(mon))
ret += _scan_mon_inv_items(mon, is_evil_item) > 0;
else if (mons_is_unholy(mon))
{
ret += _scan_mon_inv_items(mon, is_holy_item) > 0;
if (mons_holiness(mon) == MH_UNDEAD
&& _mons_has_undrinkable_potion(mon))
{
ret++;
}
}
return (ret);
}
&& !mons_is_summoned(mon));
&& !mons_is_summoned(mon)
&& !mons_enslaved_body_and_soul(mon));
}
bool mons_enslaved_body_and_soul(const monsters *mon)
{
return (testbits(mon->flags, MF_ENSLAVED_SOUL)
&& mons_holiness(mon) == MH_NATURAL);
}
bool mons_enslaved_twisted_soul(const monsters *mon)
{
return (testbits(mon->flags, MF_ENSLAVED_SOUL)
&& (mon->type == MONS_ABOMINATION_SMALL
|| mon->type == MONS_ABOMINATION_LARGE));
}
bool mons_enslaved_intact_soul(const monsters *mon)
{
return (testbits(mon->flags, MF_ENSLAVED_SOUL)
&& mon->type == MONS_SPECTRAL_THING);
}
bool mons_enslaved_soul(const monsters *mon)
{
return (mons_enslaved_twisted_soul(mon)
|| mons_enslaved_intact_soul(mon));
MF_CREATED_FRIENDLY = 0x01, // no benefit from killing
MF_BATTY = 0x02, // flutters like a bat
MF_JUST_SUMMONED = 0x04, // monster skips next available action
MF_TAKING_STAIRS = 0x08, // is following player through stairs
MF_CREATED_FRIENDLY = 0x01, // no benefit from killing
MF_BATTY = 0x02, // flutters like a bat
MF_JUST_SUMMONED = 0x04, // monster skips next available action
MF_TAKING_STAIRS = 0x08, // is following player through stairs
MF_INTERESTING = 0x10, // Player finds monster interesting
MF_SEEN = 0x20, // Player has already seen monster
MF_DIVINE_PROTECTION = 0x40, // Monster has divine protection.
MF_INTERESTING = 0x10, // Player finds monster interesting
MF_SEEN = 0x20, // Player has already seen monster
MF_DIVINE_PROTECTION = 0x40, // Monster has divine protection.
MF_KNOWN_MIMIC = 0x80, // Mimic that has taken a swing at the PC,
// or that the player has inspected with ?
MF_BANISHED = 0x100, // Monster that has been banished.
MF_HARD_RESET = 0x200, // Summoned, should not drop gear on reset
MF_WAS_NEUTRAL = 0x400, // mirror to CREATED_FRIENDLY for neutrals
MF_ATT_CHANGE_ATTEMPT = 0x800, // Saw player and attitude changed (or
// not); currently used for holy beings
// (good god worshippers -> neutral)
// and orcs (Beogh worshippers -> friendly)
MF_WAS_IN_VIEW = 0x1000, // Was in view during previous turn
MF_BAND_MEMBER = 0x2000, // Created as a member of a band
MF_GOT_HALF_XP = 0x4000, // Player already got half xp value earlier
MF_HONORARY_UNDEAD = 0x8000 // Consider this monster to have MH_UNDEAD
// holiness, regardless of its actual type;
// currently used for abominations created
// via Twisted Resurrection
MF_KNOWN_MIMIC = 0x80, // Mimic that has taken a swing at the PC,
// or that the player has inspected with ?
MF_BANISHED = 0x100, // Monster that has been banished.
MF_HARD_RESET = 0x200, // Summoned, should not drop gear on reset
MF_WAS_NEUTRAL = 0x400, // mirror to CREATED_FRIENDLY for neutrals
MF_ATT_CHANGE_ATTEMPT = 0x800, // Saw player and attitude changed (or
// not); currently used for holy beings
// (good god worshippers -> neutral)
// and orcs (Beogh worshippers -> friendly)
MF_WAS_IN_VIEW = 0x1000, // Was in view during previous turn
MF_BAND_MEMBER = 0x2000, // Created as a member of a band
MF_GOT_HALF_XP = 0x4000, // Player already got half xp value earlier
MF_HONORARY_UNDEAD = 0x8000, // Consider this monster to have MH_UNDEAD
// holiness, regardless of its actual type;
// currently used for abominations created
// via Twisted Resurrection
MF_ENSLAVED_SOUL = 0x10000 // An undead monster soul enslaved by
// Yredelemnul's power, or the natural
// monster from whom the soul is taken
Yredelemnul gives you the power to raise corpses to fight on your side, to recall your undead followers to your vicinity, and to drain the life force of living creatures. Eventually, you'll gain the power to sway hostile undead ceatures' loyalties, and make them fight for you instead. Yredelemnul will sporadically gift you with stronger undead servants. Under prayer, with sufficient piety, Yredelemnul will mirror any injury you have to suffer onto the attacker.
Yredelemnul gives you the power to raise corpses to fight on your side, to recall your undead followers to your vicinity, and to drain the life force of living creatures. Eventually, you'll gain the power to bind a monster's soul, and make it fight for you instead. Yredelemnul will sporadically gift you with stronger undead servants. Under prayer, with sufficient piety, Yredelemnul will mirror any injury you have to suffer onto the attacker.
Attempt to temporarily enslave undead monsters around you.
Mark a monster's living soul as yours, once the monster dies. The soul will retain at least some of the monster's faculties, and sometimes even the monster's equipment. However, you can only enslave one soul at any given time.
case BEAM_ENSLAVE_SOUL:
#if DEBUG_DIAGNOSTICS
mprf(MSGCH_DIAGNOSTICS,
"HD: %d; pow: %d", mon->hit_dice, beam.ench_power);
#endif
if (!mons_can_be_zombified(mon) || mons_intel(mon) < I_NORMAL)
{
simple_monster_message(mon, " is unaffected.");
return (MON_OTHER);
}
if (mon->hit_dice >= random2(beam.ench_power / 2))
return (MON_RESIST);
beam.obvious_effect = true;
mon->flags |= MF_ENSLAVED_SOUL;
simple_monster_message(mon, "'s soul is now ripe for the taking.");
return (MON_AFFECTED);
// degeneration / sleep
if (beam.flavour == BEAM_DEGENERATE || beam.flavour == BEAM_SLEEP)
// degeneration / sleep / enslave soul
if (beam.flavour == BEAM_DEGENERATE || beam.flavour == BEAM_SLEEP
|| beam.flavour == BEAM_ENSLAVE_SOUL)
{
case ABIL_YRED_CONTROL_UNDEAD:
mass_enchantment(ENCH_CHARM, you.skills[SK_INVOCATIONS] * 8, MHITYOU);
exercise(SK_INVOCATIONS, 3 + random2(4));
case ABIL_YRED_ENSLAVE_SOUL:
{
god_acting gdact;
if (!spell_direction(spd, beam))
return (false);
if (!zapping(ZAP_ENSLAVE_SOUL, you.skills[SK_INVOCATIONS] * 4, beam,
true))
{
return (false);
}
exercise(SK_INVOCATIONS, 8 + random2(10));