git-svn-id: https://crawl-ref.svn.sourceforge.net/svnroot/crawl-ref/trunk@9600 c06c8d41-db1a-0410-9941-cceddc491573
IFYZSFWJRTV6JM46H6U4CMTQX46VT562EAM64Y6UYU3F6RDWRRYQC
E5QW4MGLHCPXY3SLW5RWJGOSSVELCQZOFE336BXUM7IRYDJ6PGWAC
PVIRCYXVGCHO4J2Q7P5S6PIYAGUE3D74FNB5PXMEDYUAJEW2YRHAC
FL5OQVX5UXHYHPKC2YZ3PSD4QQ6OHRYXBIVSSKR4RIPUJNC3TORAC
R6YKWD4UXOQ3ULO6VISUMJURT3XHOHYQILKKSASLWEBL7MQP2UCQC
CDEJUVHMOT2SRPKWBB5IUPAXPGX6TUTGRBFLSPTR4XNZABDLSNUQC
5BJPWUPLJFS34FUTFJVKA4A52YMIGV6EWDXLNSDCWBJWBGVSQFGQC
TYAUNNAVB4GEKXYSR447JXRDKRJJZHAVV7XLWGU7RXEP5JMJCQKAC
GYOKKBVTZ6HRW2NYC3EMGSB6ULBX24L5DLDZNEP2F6UTA4KPU3CAC
KFULGQQOHWUTXOM3BXCCYPGGVGGY4Z6265XUFRCBPNLTZAEHJZSQC
QF5LILALY55UNUHCZE22D6FGPJOJJKNJQFLBMRACMBWJBSO7PMCQC
542WW2UJM6XF22442ZD5NFMTS6HTDM74JKJ7GQHBLQ3D6C6T4C3AC
HGVNTG4FUR6CXYG6NFUGEC7LYGHUTJZBVLYOYNDNYKGXDYEIQVEAC
7GCM5WFIKX5N2PQ5UCVNMFJEKTZTBCUVZH5RZ7CPDL3Z6GB26KAQC
PUY2VWZJ3G7HNCLIHZP5VGT2DAGHI436ETDJQTPEBFPRSEHOM2NQC
43XCHFXZ34FDVT2QG23RZ65V6NRBY6PE3ENQEEDXFYKRR7IRFHCAC
TPJYUAKSEZMCCCJANJ5EQ7F67QVTPFEOWBD7WYK33NLRN657Y5VQC
TRBDS4IKHBASW2CTAQ2YHMBMBMRB6QEBQ4ZE7GRSR3U2VJXA7TJQC
FYSQ7HXDIKXZXDGYVKZMODW7HYQQLRZO52Q2HVM3PYBD37UT5B4AC
HCVH2CWL32UD66O6Z7ZYDUASWN3RF5TW6FSWURGMD7MELKB772FAC
2NVJIPJ5NMHUI2J4WOR6KE4XZOCJIVWHQK4M2M6KG7PL24PGBDGAC
ERS7DYNAVCC7QUVG5FXJJRONYESLZU22CQGKCA5HLLLG6DMXYRLQC
XYQFJLTMLSU7LC7VODUJVN5F2P47STH2KVSP7Q3BSCUUDRHROW7QC
6DNNPEMZGBQDMA7YG4LCTQUVZ7LYPC3R4A2XBYT5SDQ65GYOLJVAC
PTJJ6D52LDVJN7WA7NMYV2WHH3WJMWWLRGF3D7ZSBUNLAACFRJHAC
SVY2PTCLXR3KNPQAWXVXTTGCC5DR334HOAKHYO3VDDRWM2BWMALAC
GSQRBVGYRLPXA34WXHXF5HNKDC4YEJ3XGKPVO4T3LKNEZHRGXQIAC
SIDH2P7NBIG5KEOE27XHD3ZT2NQ2OJZFN6VZXWNWYFFY5YVXSSVQC
K2CS6TCX2NDVL2ASEHGP4J4K4IJ6FP3ANNKTSIWVG43HPYSBX6ZQC
7NDXS36TE7QVXTXJWMYSVG5UHCCLPIO4VL6NXFGTDK3ZNKE3A2IAC
QSRRV725GCNDOMIDS36NYAA65MOLDMAZSENVSZ3PNOLBFSGHH7BQC
JR2RAQ523LOWNDYJNK6AZVKI6WVMI622PIV72XWOVZYPXPUKSQWAC
DKRSOHZXL6EPSLKOKHF7GJXSZEJVY7CXGACSHWLM5B5FTRETWWCAC
VBZ7XKM6PIJA6CGSHSE7E3Q5GFJ2DUWYGWIOBYJXTPI5NCY7FNAAC
LXVO45D6K6HCT2LOHMCQIT76VFKX6OFQOQSUAEHR3U32G43TPEBQC
4UXFU3FZOCBSLDQ4S7MJKAE2H7VUHCNRDQMIY6NJ3PHYXWNGISDQC
3RNRFLMD2X4RUFTDVITLXAP377YB6F6YMQLL3DAXSUZDZBTWSLRQC
JWJGOMVBPZRSP2VSHLFFFDIF2CS6UPBA6AHL7DAJWGBCHAV3PJDQC
ZEFGFQHN6J2S6EIPX7EPDG22C5YXTI6DMKQHHRCLWN5MQC44KY3AC
RPOZZWKG5GLPHVZZ7ZKMKS64ZMV2LDCQSARBJFJ6FZOTOKCQO7FAC
OO5PVQJ7B3HMIV46B5BIEKJNBZHQSXL3DJOGINRLLSTGSM67KYZAC
VEPHAIXR3GSPHBLOW5DWFFU4ULEMVWRQG4G5PKSKRA2I6RHYROUAC
CB7U6IEEN2Z74672EYQQHWTB4GXVNNMAYDRQYAGY6K3QSDYYEHYAC
MDAJYB6STTZPNHRQ2X66MMMSONMKXTESLHJSFPGN7H3D3TOVBAVAC
QLEBDRVUQ3BMCT7LV4EBPG7T5X4KMQJAVLMLHHB7DRCNNGDQBRNQC
5FBOE2QNRLKUNOP54CZD6LFAMM7LX6NNLHJRJHRDDIUTQ7J723DQC
VEHHZZFWDG5M4IXTCXXMKH3S2FSXTZ4CD23J6AYVFEPY7PBZ7GWQC
3ZWALZFSTSIVYXY4BAY6ANGINTDACZC6RSSJTEMQSTSUIE66YOBQC
NQIXUYGUIQTKZUB2IQDII7BBDMZ4VN4NUUTGT2ARQBZTDJUMPKRQC
E3D6MYCPSZJ64PQY4QLRJ2XCMKHHF3AOXM6I7JUEI5T2HMXCI7HQC
4HLF6Q3OBOOHCCJ76L2BXVIYI6EMJ2G7O4XXZPFTLFP6BQGSUZNAC
PHBACPMH3F34GODHVDKNCMXWU373RJQGVTDLBFCCDLLWDXVYOLTAC
AZ2RCXNVULJUSCBDBK3VARTUCTPEJXHTA7ALP73S4EXLJB6YYB5QC
2YM5FZ7I6XD6P3VUL4ALJKNEHHX2VIRONLRDX2QPXZOLCP3FNBTQC
YCL3W2PFE6ILTGBFODCSXNPDIA46KVSZP2TI7HDMYAOEJT65RIEAC
RQ24Y25QDO2GY65XESEVBCP6VXCB7BDTWXO42IPPI6UPRJQ5XYDAC
HIRKGUMNJPWKSVTR6TVBPD3MWNA63CEHCLCIPWEMGDFHVB3NPLDQC
ENOQQ6DEA6ECRNTBGYYNK7G3DFEILMKQBNKP4SUQIZW2L6HWVR7QC
TO43FWKHNIA5MVDOFXYHQODTLBQYEZKX5UIUGID57436UF7G2EXQC
TGJZXTUIAKCFZQJ54ZQEBGFBVZSJCAX6AWDRSH3TP7UJRLGUM5SAC
HB27XKFYVYIEQZGBCEZ6LKPUBMXLIPDAAS636GJ5TULIQ7KND5KQC
7DHFQM7MCCELAZL3YR53E263WMSQHQECCI5D7MCPQEF7B56IB2EAC
GP7RUHLNB4KISSZAENEYVNY3MB5YRCFRWRWYAROBZIQ5MR4DXB7QC
NMZFCCM6O3KO2GJWKOSULN27B3QIZKWPBOB62PAILXMRQD4JMIMAC
SDLKLUNFGVKDS55DDJZCBAVIB7NL3RRYPTACAY65SCUQKV6APFSAC
DINIHMHQWCV7UKXHNIA2TLT2ZOO5IYJJE7GMI3XUAWYIR37AKD2QC
RVST2QHYJ757ZHK4AUJ5NGPDZ44AD6RVFVXYPKQIBJXZBDNUCHXQC
CRQ3WJCOA5X7MWZYVUDQMO4N5BU6NSCMPFTO3ENLNRCT5U3ONBPAC
QK7YLIH7SWBSL3OEBQJYVFNTW4XT5FF6U3GPKW7PEGHBLPV3TVQAC
return (you.gift_timeout > 0 && you.piety >= random2(MAX_PIETY+1));
if (you.gift_timeout == 0)
return (false);
// At high tension Xom is more likely to be nice.
int tension_bonus = (tension <= 0 ? 0 : random2(tension));
// Whether Xom is nice depends largely on his mood (== piety).
return (x_chance_in_y(you.piety + tension_bonus, MAX_PIETY + 1));
// Make sure there's at least one enemy within the lightning radius.
bool found_hostile = false;
for (radius_iterator ri(you.pos(), 2, true, true, true); ri; ++ri)
{
if (monsters* mon = monster_at(*ri))
{
if (!mons_wont_attack(mon))
{
found_hostile = true;
break;
}
}
}
// No hostiles within radius.
if (!found_hostile)
return (false);
bool protection = false;
take_note(Note(NOTE_MESSAGE, 0, 0, "XOM: divine lightning"), true);
static char lightning_buf[80];
snprintf(lightning_buf, sizeof(lightning_buf),
"XOM: divine lightning%s", protection ? " (protected)" : "");
take_note(Note(NOTE_MESSAGE, 0, 0, lightning_buf), true);
static bool _move_stair(coord_def stair_pos, bool away)
{
dungeon_feature_type feat = grd(stair_pos);
ASSERT(grid_stair_direction(feat) != CMD_NO_CMD);
coord_def begin, towards;
bool stairs_moved = false;
if (away)
{
// If the staircase starts out under the player first shove it onto
// a neighbouring grid.
if (stair_pos == you.pos())
{
coord_def new_pos(stair_pos);
int adj_count = 0;
for (adjacent_iterator ai(stair_pos); ai; ++ai)
if (grid_stair_direction(grd(*ai)) == CMD_NO_CMD
&& one_chance_in(++adj_count))
{
new_pos = *ai;
}
if (new_pos == stair_pos)
return (false);
if (!slide_feature_over(stair_pos, new_pos))
return (false);
stair_pos = new_pos;
stairs_moved = true;
}
begin = you.pos();
towards = stair_pos;
}
else
{
// Can't move towards player if it's already adjacent.
if (adjacent(you.pos(), stair_pos))
return (false);
begin = stair_pos;
towards = you.pos();
}
ray_def ray;
if (!find_ray(begin, towards, true, ray, 0, true))
{
mpr("Couldn't find ray between player and stairs.", MSGCH_ERROR);
return (stairs_moved);
}
// Don't start off under the player.
if (away)
ray.advance();
bool found_stairs = false;
int past_stairs = 0;
while (in_bounds(ray.pos()) && see_grid(ray.pos())
&& !grid_is_solid(ray.pos()) && ray.pos() != you.pos())
{
if (ray.pos() == stair_pos)
found_stairs = true;
if (found_stairs)
past_stairs++;
ray.advance();
}
past_stairs--;
if (!away && grid_is_solid(ray.pos()))
{
// Transparent wall between stair and player.
return (stairs_moved);
}
if (away && !found_stairs)
{
if (grid_is_solid(ray.pos()))
{
// Transparent wall between stair and player.
return (stairs_moved);
}
mpr("Ray didn't cross stairs.", MSGCH_ERROR);
}
if (away && past_stairs <= 0)
{
// Stairs already at edge, can't move further away.
return (stairs_moved);
}
if (!in_bounds(ray.pos()) || ray.pos() == you.pos())
ray.regress();
while (!see_grid(ray.pos()) || grd(ray.pos()) != DNGN_FLOOR)
{
ray.regress();
if (!in_bounds(ray.pos()) || ray.pos() == you.pos()
|| ray.pos() == stair_pos)
{
// No squares in path are a plain floor.
return (stairs_moved);
}
}
ASSERT(stair_pos != ray.pos());
std::string stair_str =
feature_description(stair_pos, false, DESC_CAP_THE, false);
mprf("%s slides %s you!", stair_str.c_str(),
away ? "away from" : "towards");
// Animate stair moving.
const feature_def &feat_def = get_feature_def(feat);
bolt beam;
beam.range = INFINITE_DISTANCE;
beam.flavour = BEAM_VISUAL;
beam.type = feat_def.symbol;
beam.colour = feat_def.colour;
beam.source = stair_pos;
beam.target = ray.pos();
beam.name = "STAIR BEAM";
beam.draw_delay = 50; // Make beam animation slower than normal.
beam.aimed_at_spot = true;
beam.fire();
// Clear out "missile trails"
viewwindow(true, false);
if (!swap_features(stair_pos, ray.pos(), false, false))
{
mprf(MSGCH_ERROR, "_move_stair(): failed to move %s",
stair_str.c_str());
return (stairs_moved);
}
return (true);
}
static bool _repel_stairs()
{
// Repeating the effect while it's still active is boring.
if (you.duration[DUR_REPEL_STAIRS_MOVE]
|| you.duration[DUR_REPEL_STAIRS_CLIMB])
{
return (false);
}
std::vector<coord_def> stairs_avail;
for (radius_iterator ri(you.pos(), LOS_RADIUS, false, true); ri; ++ri)
{
dungeon_feature_type feat = grd(*ri);
if (grid_stair_direction(feat) != CMD_NO_CMD
&& feat != DNGN_ENTER_SHOP)
{
stairs_avail.push_back(*ri);
}
}
// Should only happen if there are stairs in view.
if (stairs_avail.empty())
{
mpr("No stairs found!");
return (false);
}
god_speaks(GOD_XOM,
_get_xom_speech("repel stairs").c_str());
you.duration[DUR_REPEL_STAIRS_MOVE] = 1000;
if (one_chance_in(5)
|| grid_stair_direction(grd(you.pos())) != CMD_NO_CMD
&& grd(you.pos()) != DNGN_ENTER_SHOP)
{
you.duration[DUR_REPEL_STAIRS_CLIMB] = 500;
}
std::random_shuffle(stairs_avail.begin(), stairs_avail.end());
int count_moved = 0;
for (unsigned int i = 0; i < stairs_avail.size(); i++)
if (_move_stair(stairs_avail[i], true))
count_moved++;
if (!count_moved)
{
if (one_chance_in(8))
mpr("Nothing appears to happen... Ominous!");
else
canned_msg(MSG_NOTHING_HAPPENS);
}
#ifdef NOTE_DEBUG_XOM
take_note(Note(NOTE_MESSAGE, 0, 0, "XOM: repel stairs"), true);
#endif
return (true);
}
if (niceness && !one_chance_in(20))
#ifdef DEBUG_XOM
static char xom_buf[100];
snprintf(xom_buf, sizeof(xom_buf), "xom_acts(%s, %d, %d), mood: %d",
(niceness ? "true" : "false"), sever, tension, you.piety);
take_note(Note(NOTE_MESSAGE, 0, 0, xom_buf), true);
#endif
if (niceness && !one_chance_in(15))
if (you.religion != GOD_NO_GOD)
if (you.religion == GOD_XOM)
{
snprintf(god_colour_tag, sizeof god_colour_tag, "<%s>",
colour_to_str(god_colour(you.religion)).c_str());
if (you.gift_timeout == 0)
godpowers += " - BORED";
else if (you.gift_timeout == 1)
godpowers += " - getting BORED";
}
else if (you.religion != GOD_NO_GOD)
if (!quiet)
{
mprf("Your %s glows black for a moment.",
item.name(DESC_PLAIN).c_str());
// If we get the message, we know the item is cursed now.
item.flags |= ISFLAG_KNOW_CURSE;
}
item.flags |= ISFLAG_CURSED;
if (wpn.base_type != OBJ_WEAPONS && wpn.base_type != OBJ_MISSILES
|| !is_cursed
&& !is_enchantable_weapon(wpn, true, true)
&& !is_enchantable_weapon(wpn, true, false))
{
canned_msg(MSG_NOTHING_HAPPENS);
id_the_scroll = false;
break;
}
// It's a weapon or stack of missiles that is not an artefact
// and not fully enchanted, or at least needs to be uncursed.
_handle_enchant_weapon(ENCHANT_TO_HIT, true);
if (coinflip())
_handle_enchant_weapon(ENCHANT_TO_HIT, true);
if (is_cursed)
do_uncurse_item(wpn);
}
else
{
canned_msg(MSG_NOTHING_HAPPENS);
id_the_scroll = false;
mprf("%s slides away from you right after you %s through it!",
stair_str.c_str(), verb.c_str());
if (coinflip()
&& slide_feature_over(you.pos(), coord_def(-1, -1), false))
{
mprf("%s slides away from you right after you %s through "
"it!", stair_str.c_str(), verb.c_str());
}
if (coinflip())
{
// Stairs stop fleeing from you now you actually caught one.
mprf("%s settles down.", stair_str.c_str(), verb.c_str());
you.duration[DUR_REPEL_STAIRS_MOVE] = 0;
you.duration[DUR_REPEL_STAIRS_CLIMB] = 0;
}