Lots of new things that amuse/stimulate Xom, and a few things which don't amuse him as much anymore. Among the new things is a corpse turning into a skeleton while butchering it; if this is too harsh to do just for Xom's amusement (previously turning into a skeleton while butchering was an ignored case and still produced chunks of flesh) it can be changed back. Also, if a Xom worshiper draws the Blank card, Xom makes it act like a Xom card, since a plain old Blank card is boring.
Keep track of which branch the Orb is in, if the player isn't carrying it.
Keep track of how/why the player ended up in a particular level type (Abyss, Pan, etc).
Changed most "a distortion effect" cause strings for distortion caused tranlsocation miscast effects to something more specific.
Added new wizard commands 'C' to curse or uncruse an item, and 'Ctrl-A' to re-generate the Abyss.
git-svn-id: https://crawl-ref.svn.sourceforge.net/svnroot/crawl-ref/trunk@2256 c06c8d41-db1a-0410-9941-cceddc491573
5BJPWUPLJFS34FUTFJVKA4A52YMIGV6EWDXLNSDCWBJWBGVSQFGQC
5HJJGIOOIIQNCRIL33ZQAY6S57MPTSTG27UETJW3HE3BUUPUKPQAC
7MDPXLMPCFLZS6CLZBN4FN4RDNBW4Z6Q2NNPWD2N3LOW5LQISM3AC
HFCPPPYI366EDKNBDGVNSAW76OGQA2NYTKLSP4LC3VYKHPLWFJ6QC
X7X6JKZXOCG6NVLZLGNCQDFFXW4H3S77BVAJ5LS7ZHZ4GQVLMOMAC
KHHAE5ZK7ITEZVMMUKYROKECLE2RU5ZU5OQ4Z4XSRQXE2R65O67AC
ED62QWGKBPORWVKDFOQRKJXEIWZVNGR3O4KWQBDSRNPT36AYOQYAC
VBG2GGMVC66LQM4OSI67VKXGAQK4GVOEHX3OL6V3IFOO52MQL72QC
IQGGFC563RBS7GDOACKCLXK752EE5RC3T6G5L6H446SXTMSA7T2AC
I67HCZISOEMUYFEUA6VOJOO2L4TYK73IB4FSTY4CHDR7GZD6CS6QC
UL7XFKMUX3WIU4O2LZANK4ECJ654UZPDBFGNXUEYZYOLKBYBCG6AC
KFULGQQOHWUTXOM3BXCCYPGGVGGY4Z6265XUFRCBPNLTZAEHJZSQC
77H4BWWPPGLM3PLZH4QTAJRXIZTSDVNCOKZE223I437FN2UJ34RQC
RPOZZWKG5GLPHVZZ7ZKMKS64ZMV2LDCQSARBJFJ6FZOTOKCQO7FAC
K2CS6TCX2NDVL2ASEHGP4J4K4IJ6FP3ANNKTSIWVG43HPYSBX6ZQC
ANOEQTM6IGCBTESKKQ5PCBSDTZ7VGRCMDIOAFEH4R7DJHKWKDFAAC
UWMN4HLG6YA2YFQEVIVMDISD6APKEPIZXMMPMNUYCBQDSAUYSXPQC
KYGKLJ3SYIIDSHRSFQUZCDHUIFU7D7EB6QIPIWGCWIAWZCLLUAIAC
TLO257LZSB6ZO36STDUEWJBO2LETXFKTFGXELA6Y4BZBVAEIIINAC
JM7UAK777RAVDAVLQLEOBRTGNW2B47S5G55XITJXO243IUNZHVYQC
SDLKLUNFGVKDS55DDJZCBAVIB7NL3RRYPTACAY65SCUQKV6APFSAC
4JNV6RTRY2UR3PZFMCNPRGCBSUAB7QTXYJCSYBIUAFMCCYVGN6PQC
XKAJWK6MPHS3ZCZIPPLTIMOPF6AROGLRDDCS6EFE3IGE4AHT7MYQC
CJ6OSJQPAZOGWC56OYBALICSITGVUEQERE7LWIYJL2AXWRZE523AC
264FLET5STFALEWUDOEFCR273Y5CY2WZDHL56WHZUAQ635RUN6MAC
XUCCWGMXKPIR34BBCCOI67YHI3RST4STDWSDUZTN4B2CJWXQLQ7AC
33ZMPQC6OXTESW7SRW765GRNJUEJRSYONRVZVIEUDAUEJ2PPMB4AC
GQL5SIGBHLU3FMCE54XVGLRY5AZHRM6DUEB722REA2DPLGJSN6EQC
ZJLJGSB2XSBQU42OFQMXL3EG4CXAQGOYAU6YTV2SAWZEJIPFH2CAC
BW3XFNOS6LDAQLHOZ6RXARCMKCY5JVLVDSXDSSAX4DSYM3FANQBAC
SVY2PTCLXR3KNPQAWXVXTTGCC5DR334HOAKHYO3VDDRWM2BWMALAC
DOZORMA366M4HB5JKSS27BMCR6ET7QNZNND2B7KV3NVEEPR5H7EAC
5O7S2U2B5R7HYML3D66557BC56RG6XH66PFYP6NDJZMXOABMEUKQC
DTJNZWOY2ODLIKWXJXEXOABVO2NDU7DM4UZ3NVLHXPQORVNFPTJQC
BDFIS53HAIHOCXQ5BE7WCO2MEOFCUQPFY4JGUWVLWY6JO3IFMEKQC
SGR2P5BGJIJHVSSQYQHWS4ORLVHQBZTDES3D4BFC6SVAQXSKENNQC
VNIAJEGE3PYE6F6EAMCQDWMAS52EQTKJUPAFXK7ARCITZ326WTTQC
34C4U6EQWERY75GZJKUCM5KVGU2OUICETS5LGZF6RMKMZT4R5SQAC
JVSCP4FTW2G57C6YD5HZOZXTODGZH7TR75JQGFJBEPX3LCZH236QC
WT66JDIRTLLP37SHTV4GI3V64JFJ4D25LNRLGCHFG6CLEFKJ3QGQC
QDTVLBRGHDTRUVT7I3O72K6TMOYAUSAJBZUHGOEFU2RKJNUPWZSQC
R22TTMI6WXWULC7ODKFF3QCB7MOTETQQ6IR4BUCUPOCQKQNCTT5AC
W5VEC2PBIM5DMU5233HOWAZUEPTGWJRZZIA3H35YYQQW6BTP6XUAC
RGY2525RQH7SSGM6ZVI7CZL4WMNFZK2WRABOSIWRKQYYOU2RWN4QC
I2B33Z7NZGC33AMDSSK446AZZYWKPHWLAGULVHKKZU4MVB4BNJOAC
L4RYVF46EQKMVOEADGRG4WMPVTQ6NNFGYMU4SHAH6XJIKWVHT77QC
NOB3FIJ2IOGBSK3EKCRS2WORSMTFPFKOQL4V7BTBLENYYTBUPHQQC
ESWIM76FGJL4QFLSHU6AC4D74PT7OPLQ7ZCJYWLZS5UCBAJDXYHAC
ILOED4VB4I6VPAUTR75ZWX6MXDYXB5DO2EDK2UH67O3HNKWV23RQC
OI7JKBFFIMIGWID2EJSMRP2EPEJH5YY42WTEY4QSSL6PFKRU3KJQC
5R4WV4H5SNIM5WU2X33JJ63HIEGKCXN2HELZ6FRRKKANPLMRLF3QC
3KAINFIXO7WNWGUGZB43EUNFRS2ZPBLQZDTY456QACMRHYIJ7WDAC
QKGDOYIYKE6B36ION5O2DRW65DWWPZMYNWJVH7LJJ7FPGGM2MYAQC
2IJDLTWK74ULETLFTIPUIY2MSG6RNONVAFNFE7MADPT6UNYSSBDAC
2ESKXYN266CEMLSL6DNCKG4REDO34FXL4ODVGMWDJTNJRKMXWCRQC
WVFKGV3AMOYUZ53MWH2RWRITRRCPKKNPTO7QASA5WVKWAUGDJ2OQC
KFZYPFHHOWRUZEK2PW26EI73Z6I6DLHW2YEJV2CB5XBWFRRNBFXQC
DBGS3HXMW24VO5GBITT3UI2ZNIISUXUHAEAYUI52QPUT7IO46ITQC
FMBJCM5LJKCG326YRJGOOJU6QNWONXAHK2AB4CP4SAOHKJ5CORXQC
FSD7GIK3YLZXWLEH37BU6KV3IUCFGXPQL6IZ7H65YWNRBEKDBX5AC
5UVDIVD4NSXA52U4QMQIVST3GSZJ2A2YZK3RUEXKPM43YVQ7LI5AC
4UXFU3FZOCBSLDQ4S7MJKAE2H7VUHCNRDQMIY6NJ3PHYXWNGISDQC
BJPPSWEN35BG4KP3XTXPDMAJ2GAUMHXKHCNALAZ4B4OS6B3KDSUQC
UZ6N6HOUPGVSPC5NQROEEDWMEGJA5XUWUY2AKH5QG65AZ25PVXDAC
LOJYD6QZRNLNDDZJKVBMKQIBPTKSRN2ETCYGNVV47M7L3QLUJUJAC
EOMCPVNQLX3IMLC46EAO67DPBH5KEG2FQTPBLGU62HIRWA3UQ7XQC
/*
* File: xom.h
* Summary: Misc Xom related functions.
* Written by: Linley Henzell
*
* Modified for Crawl Reference by $Author$ on $Date$
*
* Change History (most recent first):
*
* <1> 09/28/07 MPC Split from religion.h
*/
#ifndef XOM_H
#define XOM_H
class item_def;
enum xom_message_type
{
XM_NORMAL,
XM_INTRIGUED,
NUM_XOM_MESSAGE_TYPES
};
void xom_is_stimulated(int maxinterestingness,
xom_message_type message_type = XM_NORMAL,
bool force_message = false);
void xom_is_stimulated(int maxinterestingness, std::string message,
bool force_message = false);
bool xom_is_nice();
void xom_acts(bool niceness, int sever);
const char *describe_xom_favour();
inline void xom_acts(int sever)
{
xom_acts(xom_is_nice(), sever);
}
void xom_check_lost_item(item_def& item);
#endif
void xom_is_stimulated(int maxinterestingness)
static const char* xom_message_arrays[NUM_XOM_MESSAGE_TYPES][6] =
{
// XM_NORMAL
{
"Xom roars with laughter!",
"Xom thinks this is hilarious!",
"Xom is highly amused!",
"Xom is amused.",
"Xom is mildly amused.",
"Xom is interested."
},
// XM_INTRIGUED
{
"Xom is fascinated!",
"Xom is very intrigued!",
"Xom is intrigued!",
"Xom is extremely interested.",
"Xom is very interested.",
"Xom is interested."
}
};
static void _xom_is_stimulated(int maxinterestingness,
const char* message_array[],
bool force_message)
god_speaks(GOD_XOM,
((interestingness > 200) ? "Xom roars with laughter!" :
(interestingness > 100) ? "Xom thinks this is hilarious!" :
(interestingness > 75) ? "Xom is highly amused!" :
(interestingness > 50) ? "Xom is amused." :
(interestingness > 25) ? "Xom is mildly amused." :
"Xom is interested."));
was_stimulated = true;
if (was_stimulated || force_message)
god_speaks(GOD_XOM,
((interestingness > 200) ? message_array[5] :
(interestingness > 100) ? message_array[4] :
(interestingness > 75) ? message_array[3] :
(interestingness > 50) ? message_array[2] :
(interestingness > 25) ? message_array[1] :
message_array[0]));
}
void xom_is_stimulated(int maxinterestingness, xom_message_type message_type,
bool force_message)
{
_xom_is_stimulated(maxinterestingness, xom_message_arrays[message_type],
force_message);
}
void xom_is_stimulated(int maxinterestingness, std::string message,
bool force_message)
{
const char* message_array[6];
for (int i = 0; i < 6; i++)
message_array[i] = message.c_str();
_xom_is_stimulated(maxinterestingness, message_array, force_message);
// Nemelex's deck of punishment drawing the Xom card
if (crawl_state.is_god_acting()
&& crawl_state.which_god_acting() != GOD_XOM)
{
god_type which_god = crawl_state.which_god_acting();
if (crawl_state.is_god_retribution())
{
niceness = false;
mprf(MSGCH_GOD, which_god,
"%s asks Xom for help in punishing you, and Xom happily "
"agrees.", god_name(which_god));
}
else
{
niceness = true;
mprf(MSGCH_GOD, which_god,
"%s calls in a favour from Xom.", god_name(which_god));
}
}
}
void xom_check_lost_item(item_def& item)
{
if (item.base_type == OBJ_ORBS)
xom_is_stimulated(255, "Xom laughs nastily.", true);
else if (is_fixed_artefact(item))
xom_is_stimulated(128, "Xom snickers.", true);
else if (is_rune(item))
{
if (is_unique_rune(item))
xom_is_stimulated(255, "Xom snickers loudly.", true);
else if (you.entry_cause == EC_SELF_EXPLICIT &&
!(item.flags & ISFLAG_DROPPED))
{
// Player voluntarily entered Pan or the Abyss looking
// for runes, yet never found it.
if (item.plus == RUNE_ABYSSAL)
{
// Ignore Abyss area shifts.
if (you.level_type != LEVEL_ABYSS)
// Abyssal runes are a lot more trouble to find
// than demonic runes, so it gets twice the
// stimulation.
xom_is_stimulated(128, "Xom snickers.", true);
}
else
xom_is_stimulated(64, "Xom snickers softly.", true);
}
}
// Xom thinks it's hilarious the way the player picks up an ever
// growing entourage of monsters while running through the Abyss.
// To approximate this, if the number of hostile monsters in view
// is greater than it ever was for this particular trip to the
// Abyss, Xom is stimulated in proprotion to the number of
// hostile monsters. Thus if the entourage doesn't grow, then
// Xom becomes bored.
if (you.level_type == LEVEL_ABYSS
&& you.attribute[ATTR_ABYSS_ENTOURAGE] < num_hostile)
{
you.attribute[ATTR_ABYSS_ENTOURAGE] = num_hostile;
xom_is_stimulated(16 * num_hostile);
}
// dangerous place.
if (randtele && player_in_a_dangerous_place())
// dangerous place, unless the player is in the Abyss and
// teleported to escape from all the monsters chasing him/her,
// since in that case the new dangerous area is almost certainly
// *less* dangerous than the old dangerous area.
if (randtele && player_in_a_dangerous_place()
&& you.level_type != LEVEL_ABYSS)
{
bool xom_is_nice();
void xom_is_stimulated(int maxinterestingness);
void xom_acts(bool niceness, int sever);
const char *describe_xom_favour();
if ((death_type != KILLED_BY_MONSTER && death_type != KILLED_BY_BEAM)
|| death_source < 0 || death_source >= MAX_MONSTERS)
if (death_type == KILLED_BY_TARGETTING)
{
// Xom thinks the player hurting him/herself is funny.
xom_is_stimulated(255 * dam / (dam + you.hp));
return;
}
else if (death_type == KILLED_BY_FALLING_DOWN_STAIRS)
{
// Xom thinks falling down the stairs is hilarious
xom_is_stimulated(255);
return;
}
else if ((death_type != KILLED_BY_MONSTER && death_type != KILLED_BY_BEAM)
|| death_source < 0 || death_source >= MAX_MONSTERS)
}
static void set_entry_cause(entry_cause_type default_cause,
level_area_type old_level_type)
{
ASSERT(default_cause != NUM_ENTRY_CAUSE_TYPES);
if (old_level_type == you.level_type)
return;
if (crawl_state.is_god_acting())
{
if (crawl_state.is_god_retribution())
you.entry_cause = EC_GOD_RETRIUBTION;
else
you.entry_cause = EC_GOD_ACT;
you.entry_cause_god = crawl_state.which_god_acting();
}
else if (default_cause != EC_UNKNOWN)
{
you.entry_cause = default_cause;
you.entry_cause_god = GOD_NO_GOD;
}
else
{
you.entry_cause = EC_SELF_EXPLICIT;
you.entry_cause_god = GOD_NO_GOD;
}
void up_stairs(dungeon_feature_type force_stair)
static int runes_in_pack()
{
int num_runes = 0;
for (int i = 0; i < ENDOFPACK; i++)
{
if (is_valid_item( you.inv[i] )
&& you.inv[i].base_type == OBJ_MISCELLANY
&& you.inv[i].sub_type == MISC_RUNE_OF_ZOT)
{
num_runes += you.inv[i].quantity;
}
}
return num_runes;
}
void up_stairs(dungeon_feature_type force_stair,
entry_cause_type entry_cause)
// Left Zot without enough runes to get back in (probably because
// of dropping some runes within Zot), but need to get back in Zot
// to get the Orb? Zom finds that funny.
if (stair_find == DNGN_RETURN_FROM_ZOT
&& runes_in_pack() < NUMBER_OF_RUNES_NEEDED
&& (branches[BRANCH_HALL_OF_ZOT].branch_flags & BFLAG_HAS_ORB))
{
xom_is_stimulated(255, "Xom snickers loudly.", true);
}
xom_is_stimulated(49);
{
switch(you.level_type)
{
case LEVEL_DUNGEON:
xom_is_stimulated(49);
break;
case LEVEL_PORTAL_VAULT:
// Portal vaults aren't as interesting.
xom_is_stimulated(25);
break;
case LEVEL_LABYRINTH:
// Finding the way out of a labyrinth interests Xom.
xom_is_stimulated(98);
break;
case LEVEL_ABYSS:
case LEVEL_PANDEMONIUM:
{
// Paranoia
if (old_level_type == you.level_type)
break;
PlaceInfo &place_info = you.get_place_info();
// Entering voluntarily only stimulates Xom if you've never
// been there before
if ((place_info.num_visits == 1 && place_info.levels_seen == 1)
|| entry_cause != EC_SELF_EXPLICIT)
{
if (crawl_state.is_god_acting())
xom_is_stimulated(256);
else if (entry_cause == EC_SELF_EXPLICIT)
{
// Entering Pandemonium or the Abyss for the first
// time *voluntarily* stimulates Xom much more than
// entering a normal dungeon level for the first time.
xom_is_stimulated(128, XM_INTRIGUED);
}
else if (entry_cause == EC_SELF_RISKY)
xom_is_stimulated(128);
else
xom_is_stimulated(256);
}
break;
}
default:
ASSERT(false);
}
}
return (item.base_type == OBJ_MISCELLANY &&
item.sub_type == MISC_RUNE_OF_ZOT);
return (item.base_type == OBJ_MISCELLANY
&& item.sub_type == MISC_RUNE_OF_ZOT);
}
bool is_unique_rune(const item_def &item)
{
return (item.base_type == OBJ_MISCELLANY
&& item.sub_type == MISC_RUNE_OF_ZOT
&& item.plus != RUNE_DEMONIC
&& item.plus != RUNE_ABYSSAL);
bool item_is_equipped(const item_def &item)
{
if (item.x != -1 || item.y != -1)
return (false);
for (int i = 0; i < NUM_EQUIP; i++)
{
if (you.equip[i] == EQ_NONE)
continue;
item_def& eq(you.inv[you.equip[i]]);
if (!is_valid_item(eq))
continue;
if (eq.slot == item.slot)
return (true);
else if (&eq == &item)
return (true);
}
return (false);
}
// Xom is amused by the player's items being cursed, especially
// if they're worn/equipped.
if (!(item.flags & ISFLAG_CURSED) && item.x == -1 && item.y == -1)
{
int amusement = 64;
if (item_is_equipped(item))
{
amusement *= 2;
// Cursed cloaks prevent you from removing body armour
if (item.base_type == OBJ_ARMOUR
&& get_armour_slot(item) == EQ_CLOAK)
{
amusement *= 2;
}
}
xom_is_stimulated(amusement);
}
const bool artefact = is_random_artefact( item );
const bool identified = fully_identified( item );
const bool artefact = is_random_artefact( item );
const bool identified = fully_identified( item );
const bool known_cursed = item_known_cursed( item );
const bool known_bad = item_type_known( item )
&& (item_value( item ) <= 2);
enum entry_cause_type
{
EC_UNKNOWN,
EC_SELF_EXPLICIT,
EC_SELF_RISKY, // i.e., wielding an id'd distorion weapon
EC_SELF_ACCIDENT, // i.e., wielding an un-id'd distortion weapon
EC_MISCAST,
EC_GOD_RETRIUBTION,
EC_GOD_ACT, // Xom sending the player somewhere for amusement
EC_MONSTER,
NUM_ENTRY_CAUSE_TYPES
};
down_stairs(you.your_level, gate_type); // heh heh
// Now figure out how we got here.
if (who.find("self") != std::string::npos || who == you.your_name
|| who == "you" || who == "You" || crawl_state.is_god_acting())
{
// down_stairs() will take care of setting things.
you.entry_cause = EC_UNKNOWN;
}
else if (who.find("distortion") != std::string::npos)
{
if (who.find("wield") != std::string::npos)
{
if (who.find("unknowing") != std::string::npos)
you.entry_cause = EC_SELF_ACCIDENT;
else
you.entry_cause = EC_SELF_RISKY;
}
else if (who.find("affixation") != std::string::npos)
you.entry_cause = EC_SELF_ACCIDENT;
else if (who.find("branding") != std::string::npos)
you.entry_cause = EC_SELF_RISKY;
else
you.entry_cause = EC_MONSTER;
}
else if (who == "drawing a card")
you.entry_cause = EC_SELF_RISKY;
else if (who.find("miscast") != std::string::npos)
you.entry_cause = EC_MISCAST;
else if (who == "wizard command")
you.entry_cause = EC_SELF_EXPLICIT;
else
you.entry_cause = EC_MONSTER;
mpr("The corpse rots.", MSGCH_ROTTEN_MEAT);
delay.parm2 = 99; // don't give the message twice
mpr("The corpse rots away into a skeleton!");
if (you.species == SP_GHOUL)
xom_check_corpse_waste();
else
xom_is_stimulated(32);
delay.duration = 0;
// mark work done on the corpse in case we stop -- bwr
mitm[ delay.parm1 ].plus2++;
if (you.species != SP_VAMPIRE
&& you.species != SP_MUMMY
&& you.species != SP_GHOUL)
{
xom_check_corpse_waste();
}
}
// mark work done on the corpse in case we stop -- bwr
mitm[ delay.parm1 ].plus2++;
}
xom_is_stimulated(128);
// Cursed cloaks prevent you from removing body armour
int cloak_mult = 1;
if (get_armour_slot(arm) == EQ_CLOAK)
cloak_mult = 2;
if (known_cursed)
xom_is_stimulated(32 * cloak_mult);
else
xom_is_stimulated(64 * cloak_mult);
card_effect( choose_one_card(deck, true), deck_rarity(deck) );
// Could a Xom worshipper ever get a stacked deck in the first
// place?
int amusement = 64;
bool was_oddity = false;
card_type card = choose_one_card(deck, true, was_oddity);
if (!item_type_known(deck))
amusement *= 2;
// Expecting one type of card but got another, real funny.
else if (was_oddity)
amusement = 255;
if (player_in_a_dangerous_place())
amusement *= 2;
switch (card)
{
case CARD_XOM:
// Handled elswehre
amusement = 0;
break;
case CARD_BLANK:
// Boring
amusement = 0;
break;
case CARD_DAMNATION:
// Nothing happened, boring.
if (you.level_type != LEVEL_DUNGEON)
amusement = 0;
break;
if (which_card == CARD_XOM && !crawl_state.is_god_acting())
{
if (you.religion == GOD_XOM)
{
// Being a self-centered diety, Xom *always* finds this
// maximally hilarious.
god_speaks(GOD_XOM, "Xom roars with laughter!");
you.gift_timeout = 255;
}
else if (you.penance[GOD_XOM] > 0)
god_speaks(GOD_XOM, "Xom laughs nastily.");
}
static void update_hurt_or_helped(bolt &beam, monsters *mon)
{
if (beam.attitude != mons_attitude(mon))
{
if (nasty_beam(mon, beam))
beam.foe_hurt++;
else if (nice_beam(mon, beam))
beam.foe_helped++;
}
else
{
if (nasty_beam(mon, beam))
beam.fr_hurt++;
else if (nice_beam(mon, beam))
beam.fr_helped++;
}
}
altars_wanted--;
#if DEBUG_ABYSS
mpr("Placing altar.", MSGCH_DIAGNOSTICS);
#endif
}
}
}
}
static int abyss_exit_nearness()
{
int nearness = INFINITE_DISTANCE;
for (int x = you.x_pos - LOS_RADIUS; x < you.x_pos + LOS_RADIUS; x++)
for (int y = you.y_pos - LOS_RADIUS; y < you.y_pos + LOS_RADIUS; y++)
{
if (!in_bounds(x, y))
continue;
// HACK: Why doesn't is_terrain_known() work here?
if (grd[x][y] == DNGN_EXIT_ABYSS
&& get_screen_glyph(x, y) != '\0')
{
nearness = MIN(nearness,
grid_distance(you.x_pos, you.y_pos,
x, y));
}
}
return (nearness);
}
static int abyss_rune_nearness()
{
int nearness = INFINITE_DISTANCE;
for (int x = you.x_pos - LOS_RADIUS; x < you.x_pos + LOS_RADIUS; x++)
for (int y = you.y_pos - LOS_RADIUS; y < you.y_pos + LOS_RADIUS; y++)
{
if (!in_bounds(x, y))
continue;
// HACK: Why doesn't is_terrain_known() work here?
if (get_screen_glyph(x, y) != '\0')
{
int i = igrd[x][y];
while (i != NON_ITEM)
{
item_def& item(mitm[i]);
if (is_rune(item) && item.plus == RUNE_ABYSSAL)
nearness = MIN(nearness,
grid_distance(you.x_pos, you.y_pos,
x, y));
i = item.link;
}
return (nearness);
}
static int exit_was_near;
static int rune_was_near;
static void xom_check_nearness_setup()
{
exit_was_near = abyss_exit_nearness();
rune_was_near = abyss_rune_nearness();
}
// If the player was almost to the exit when it disppeared, Xom is
// exteremely amused. He's also extremely amused if the player winds
// up right next to an exit when there wasn't one there before. The
// same applies to Abyssal runes.
static void xom_check_nearness()
{
// Update known terrain
viewwindow(true, false);
int exit_is_near = abyss_exit_nearness();
if ((exit_was_near < INFINITE_DISTANCE &&
exit_is_near == INFINITE_DISTANCE)
|| (exit_was_near == INFINITE_DISTANCE &&
exit_is_near < INFINITE_DISTANCE))
{
xom_is_stimulated(255);
}
int rune_is_near = abyss_rune_nearness();
if ((rune_was_near < INFINITE_DISTANCE &&
rune_is_near == INFINITE_DISTANCE)
|| (rune_was_near == INFINITE_DISTANCE &&
rune_is_near < INFINITE_DISTANCE))
{
xom_is_stimulated(255);