there needs to be an invocation that can train Invocations, and Banishment is too costly to use for everyday training.
Corruption is still a first-cut, needs more work and playtesting:
Breaks save compatibility.
git-svn-id: https://crawl-ref.svn.sourceforge.net/svnroot/crawl-ref/trunk@1990 c06c8d41-db1a-0410-9941-cceddc491573
UZ6N6HOUPGVSPC5NQROEEDWMEGJA5XUWUY2AKH5QG65AZ25PVXDAC
JIBXNJPLFXMIBY4BC7PBPFCT33SCOAB7FI24PTLWOKGC5RX2AZOQC
SLDR32H45VDN74AVZ2JDPLNK7AZWXDS2YRTLMGK7E3FYW6OWOFJAC
LDGIQP4A5BWVFQWQ2MGZRM5OY45ZXNNARH4WZPLUTBJVS4CVHISQC
PJ7HBIWAV3H23LXGZAAD2QYJ7HMOFOIR5ZJ4U2UTHI766LOTRRWQC
2E4RV454MTTCKYLKMSHEEAFPNAFVUXXPBZV3XP6V7QMF4BBWE7TAC
RPOZZWKG5GLPHVZZ7ZKMKS64ZMV2LDCQSARBJFJ6FZOTOKCQO7FAC
K2CS6TCX2NDVL2ASEHGP4J4K4IJ6FP3ANNKTSIWVG43HPYSBX6ZQC
PL6I2CMSTHY5ZHWVMIQE5YTM5S5VPKBNZM6QJVHZSSKOJGIJ5W4AC
XHNJ2W4AQHIF32P2ENIMMDLWAIFWP442KJIZC6RKS4HBJNZIHHBAC
R22TTMI6WXWULC7ODKFF3QCB7MOTETQQ6IR4BUCUPOCQKQNCTT5AC
U3KGUJJQWQORJIIFH3ADVNIEEX5HOX6KEOXO7DJSL7L3Z6GG3PAQC
6GT5JAWOIIL4SQ5MWIID6ZVO3KKQFWDQDZNVFHZ6DNK5QCBXJ4UAC
45FTVJJ5FMXBXQ2GVUZVJZU6Y6NUYG2JZIHWVMONA7QYYCZQSM2QC
SDLKLUNFGVKDS55DDJZCBAVIB7NL3RRYPTACAY65SCUQKV6APFSAC
5ASC3STDYCNLZFEBN6UTMUCGDETHBR2OCBZCF5VIAZ5RRWLOTDYQC
KOSAQXB3KF6VAYTG2TOTHGJBB3F7AL6O32EMCXPVZJ5WHQX6XR5AC
AVSWNOP23Z2QCLQGXFDZV7TI4RC3XSXHIX2HDXFHXGKDEZSSIGJQC
WHY6LRRJ5T2NSBE3IUCR4X3TOAH7TTK5NPUPUIFT7TPNJ6J4HBDAC
CQ24AVAI6SW3AHTIDMLPSTRRBEU6FHRF5I5FD6G5QIYE6PO4BQMQC
X7TRUBJTRDVUI53BROBYHF4UDC4I5SUYWBUOGQMZNN2WEZAFVGVQC
NUYXKJP5YXHRDUQW5QW7UC3D5U3VPANIOZAOHFCPWMSRYGMA3GCAC
YZXHBEKWQPY4BTKG5FFGLP3AIRBQSTKQVLJJHWKQEA3HTN4UHDYQC
L5CVPV5IUBSO4EE3WK4O6SQGIMIEPSMQONFBWEVGJBR2HATLPZIAC
QDTVLBRGHDTRUVT7I3O72K6TMOYAUSAJBZUHGOEFU2RKJNUPWZSQC
4MTOLDRVEF5GVPCVVK7LGKUQO6SU5FKOI5D6Y6VPANHNB6XCEL6AC
52W74WXL5XIH6YFJBQRVAO47YHCS3CPMUUZS4Q3AZ3HAPDWMT54AC
VIFRP3HZEONFR6PQRYZYM3YUEJOQ7T4F5CZY4MN4YJMB23FMU7XAC
X5WLJCJVW55SXZVP7IKP7ADCJIGNKN4PKAXFECVR6TNK7XSMZR7QC
MRM4SLSXJTRYJPH2YYTAFTO2CAOXLP2OCMRNYRTIRRYOMWM7NMFAC
QS3ZRS3E6KL3YJHPKYEWCWJYRBJSXD5OOYF6Y25HZVECGPJRDB5QC
JNB3PBPBJHDUHH47ZICB25QENPTMLYK7CXC5BXRVWZ3J3ZZPKCUAC
5UVDIVD4NSXA52U4QMQIVST3GSZJ2A2YZK3RUEXKPM43YVQ7LI5AC
ZP2KE7A2LE7Z2S7AC45WE4CXDSEVDTWIMV2EM4IBUKXYJIDU6R7QC
7VVRO5HMNNOXVRLBLJUCHUJP6MDIRMC2BWCO7MWH4OLQRM3LMTMQC
JDM27QE4HR52AYFSQE763BFF57ANOTF5MXKMO377PP5EXMN7SAOAC
ZJU5Z2WDMI7HN4XJ3NVTVRHIZO2CGFUQ2FSKIRJVTQG47XHNCZFQC
GQL5SIGBHLU3FMCE54XVGLRY5AZHRM6DUEB722REA2DPLGJSN6EQC
AFE345BJ7IX2YYYX3I5I6RYLXNWJCFE4WMH6F5JMIR6X7WUP75CAC
7Y5HSDFKA5TPLS2TWTRFMQVX6UXUDHXU5MUMXQSDFAIY4THQ3BIQC
Y66ZAXN24E3HLIBOSW4OXUTQ4X4PRGNJII4KVDQH4GQJVA6GO3NAC
6GQU5BMORHTHJGGVYPGJZSEIHPOVXDAS23BE7OHU4X6WVDYRC2MAC
T4IH76FA5TWHFOZUJFHLQXQJENJHWTUZZP4EGNA7D4GTZY7D4ZKAC
JM6GKZ6VMX6FNVOZIDXIV22HGX7YESMIFZFE6EEQVCMFJIEA3FNAC
BIZDHHK5LIO57S5AKHEPJFLWV5DAFKZIKYBGOUNGICSWTX7DCXKAC
TLO257LZSB6ZO36STDUEWJBO2LETXFKTFGXELA6Y4BZBVAEIIINAC
R5JKQLY5QE6UBG3RH3Y5ZRSX6H35CHYI2HYNDZF6ZHVRULUORXBQC
MSQI3TH6T62JAXQGLL52QZCWAMC372TGB6ZNNRDGUGMJKBNNV2VAC
LOJYD6QZRNLNDDZJKVBMKQIBPTKSRN2ETCYGNVV47M7L3QLUJUJAC
FSD7GIK3YLZXWLEH37BU6KV3IUCFGXPQL6IZ7H65YWNRBEKDBX5AC
QUYSD2DWCIKAAQJGI43EENAWWPA5W33UT3I5WFRSHU6FPSSXTX2AC
XAFFD52IHN6FWFR2TT5F2KCUS7HAVCBI5CWTFMKPQG77GGTGAHLAC
NDTQUANX3GZ6HZP5FONYNJUYPD3R2P6SGRC3ICKJ7ZWF3KO23LTAC
2YSMM7QMFZOPD5NXAD2OAMDJEY5LOZO4NCYBC7UCQVANKINJRNBAC
KXUQB3WNWC5IFL6VFWADEPQMMU3VV3NDI5FLA666PGOEWFYUHCLQC
L6O4LGZRKBURVWEY7XRVCSQLJ5RULNBEWMQJ6I2UYVWWB66FM3MQC
KCHX2F3JFEWOZT3WMJVZAAQUU2QSZ5Q7RDCD7WUJ7VE65J52JFUQC
2WRXQTGYDBLV46WRNVIUKGNA5QS563XZNNW3N2L6PVOCHIP2YGHQC
BNTPYSO6ECZ76CHHLDP3ASSPDSEUH4Y3E3LETKNXVWAWJRFL3YEQC
RYT42Z6CED4KV5CCJ45CHZ3DQGLFMDCVH6CSQZNXOILULDG4MXVQC
IDTLZ6PEPJP67PO7K5TODLXTBFAEVIE4C3HZCXIQK6OIAQKRVDUQC
7KWDC7XFNMBLSUO2HISIROBINZBX5T67LJEEXTAORXW2YZ7VWFGAC
DTO3EUKWHZ5RJNGNCFYXSOVTIPVXPP637F2W7WFGYKJ7JK7VNKNQC
KW43PGXTTM57DXUGGBQXJ5G5OYYIY3WB76TXIKL2ZCIJGH7GH4LAC
WXSNNK2RXP3DQFAEQGQUZJHFWXJC7ZKG2WURZGL566UDM4YXFSWQC
// Don't clobber with BLACK, because the colour should be
// already set.
if (fdef.colour != BLACK)
*colour = fdef.colour | colmask;
if (object < NUM_REAL_FEATURES && env.grid_colours[x][y])
{
*colour = env.grid_colours[x][y] | colmask;
}
else
{
// Don't clobber with BLACK, because the colour should be
// already set.
if (fdef.colour != BLACK)
*colour = fdef.colour | colmask;
if (fdef.em_colour != fdef.colour && fdef.em_colour)
*colour =
view_emphasised_colour(
x, y, static_cast<dungeon_feature_type>(object),
*colour, fdef.em_colour | colmask);
if (fdef.em_colour != fdef.colour && fdef.em_colour)
*colour =
view_emphasised_colour(
x, y, static_cast<dungeon_feature_type>(object),
*colour, fdef.em_colour | colmask);
}
template <typename marshall, typename grid>
void run_length_encode(tagHeader &th, marshall m, const grid &g,
int width, int height)
{
int last = 0, nlast = 0;
for (int y = 0; y < height; ++y)
{
for (int x = 0; x < width; ++x)
{
if (!nlast)
last = g[x][y];
if (last == g[x][y] && nlast < 255)
{
nlast++;
continue;
}
marshallByte(th, nlast);
m(th, last);
last = g[x][y];
nlast = 1;
}
}
marshallByte(th, nlast);
m(th, last);
}
template <typename unmarshall, typename grid>
void run_length_decode(tagHeader &th, unmarshall um, grid &g,
int width, int height)
{
const int end = width * height;
int offset = 0;
while (offset < end)
{
const int run = (unsigned char) unmarshallByte(th);
const int value = um(th);
for (int i = 0; i < run; ++i)
{
const int y = offset / width;
const int x = offset % width;
g[x][y] = value;
++offset;
}
}
}
}
monster_type pick_random_monster(const level_id &place,
int power,
int &lev_mons)
{
monster_type mon_type = MONS_PROGRAM_BUG;
lev_mons = power;
if (place.branch == BRANCH_MAIN_DUNGEON
&& lev_mons != 51 && one_chance_in(4))
{
lev_mons = random2(power);
}
if (place.branch == BRANCH_MAIN_DUNGEON
&& lev_mons < 28)
{
lev_mons = fuzz_mons_level(lev_mons);
// potentially nasty surprise, but very rare
if (need_super_ood(lev_mons))
lev_mons += random2(12);
// slightly out of depth monsters are more common:
// [ds] Replaced with a fuzz above for a more varied mix.
//if (need_moderate_ood(lev_mons))
// lev_mons += random2(5);
if (lev_mons > 27)
lev_mons = 27;
}
/* Abyss or Pandemonium. Almost never called from Pan;
probably only if a rand demon gets summon anything spell */
if (lev_mons == 51
|| place.level_type == LEVEL_PANDEMONIUM
|| place.level_type == LEVEL_ABYSS)
{
do
{
int count = 0;
do
{
// was: random2(400) {dlb}
mon_type = static_cast<monster_type>( random2(NUM_MONSTERS) );
count++;
}
while (mons_abyss(mon_type) == 0 && count < 2000);
if (count == 2000)
return (MONS_PROGRAM_BUG);
}
while (random2avg(100, 2) > mons_rare_abyss(mon_type)
&& !one_chance_in(100));
}
else
{
int level, diff, chance;
if (lev_mons > 30)
lev_mons = 30;
int i;
for (i = 0; i < 10000; i++)
{
int count = 0;
do
{
mon_type = static_cast<monster_type>(random2(NUM_MONSTERS));
count++;
}
while (mons_rarity(mon_type) == 0 && count < 2000);
if (count == 2000)
return (MONS_PROGRAM_BUG);
level = mons_level( mon_type, place );
diff = level - lev_mons;
chance = mons_rarity( mon_type, place ) - (diff * diff);
if ((lev_mons >= level - 5 && lev_mons <= level + 5)
&& random2avg(100, 2) <= chance)
{
break;
}
}
if (i == 10000)
return (MONS_PROGRAM_BUG);
}
return (mon_type);
if (player_in_branch( BRANCH_MAIN_DUNGEON )
&& lev_mons != 51 && one_chance_in(4))
{
lev_mons = random2(power);
}
if (player_in_branch( BRANCH_MAIN_DUNGEON )
&& lev_mons < 28)
{
lev_mons = fuzz_mons_level(lev_mons);
// potentially nasty surprise, but very rare
if (need_super_ood(lev_mons))
lev_mons += random2(12);
// slightly out of depth monsters are more common:
// [ds] Replaced with a fuzz above for a more varied mix.
//if (need_moderate_ood(lev_mons))
// lev_mons += random2(5);
if (lev_mons > 27)
lev_mons = 27;
}
/* Abyss or Pandemonium. Almost never called from Pan;
probably only if a rand demon gets summon anything spell */
if (lev_mons == 51
|| you.level_type == LEVEL_PANDEMONIUM
|| you.level_type == LEVEL_ABYSS)
{
do
{
count = 0;
do
{
// was: random2(400) {dlb}
mon_type = random2(NUM_MONSTERS);
count++;
}
while (mons_abyss(mon_type) == 0 && count < 2000);
if (count == 2000)
return (false);
}
while (random2avg(100, 2) > mons_rare_abyss(mon_type)
&& !one_chance_in(100));
}
else
{
int level, diff, chance;
if (lev_mons > 30)
lev_mons = 30;
for (i = 0; i < 10000; i++)
{
count = 0;
do
{
mon_type = random2(NUM_MONSTERS);
count++;
}
while (mons_rarity(mon_type) == 0 && count < 2000);
if (count == 2000)
return (false);
level = mons_level( mon_type );
diff = level - lev_mons;
chance = mons_rarity( mon_type ) - (diff * diff);
if ((lev_mons >= level - 5 && lev_mons <= level + 5)
&& random2avg(100, 2) <= chance)
{
break;
}
}
if (i == 10000)
return (false);
}
mon_type = pick_random_monster(level_id::current(), lev_mons,
lev_mons);
if (mon_type == MONS_PROGRAM_BUG)
return (false);
}
static char fix_black_colour(char incol)
{
if ( incol == BLACK )
return LIGHTGREY;
else
return incol;
}
void set_colours_from_monsters()
{
env.floor_colour = fix_black_colour(mcolour[env.mons_alloc[9]]);
env.rock_colour = fix_black_colour(mcolour[env.mons_alloc[8]]);
if (you.level_type == LEVEL_PANDEMONIUM || you.level_type == LEVEL_ABYSS)
{
set_colours_from_monsters();
}
else if (you.level_type == LEVEL_LABYRINTH)
{
env.floor_colour = LIGHTGREY;
env.rock_colour = BROWN;
}
else
{
// level_type == LEVEL_DUNGEON
const int youbranch = you.where_are_you;
env.floor_colour = branches[youbranch].floor_colour;
env.rock_colour = branches[youbranch].rock_colour;
// Zot is multicoloured
if ( you.where_are_you == BRANCH_HALL_OF_ZOT )
{
const char floorcolours_zot[] = { LIGHTGREY, LIGHTGREY, BLUE,
LIGHTBLUE, MAGENTA };
const char rockcolours_zot[] = { LIGHTGREY, BLUE, LIGHTBLUE,
MAGENTA, LIGHTMAGENTA };
const int curr_subdungeon_level = player_branch_depth();
if ( curr_subdungeon_level > 5 || curr_subdungeon_level < 1 )
mpr("Odd colouring!");
else
{
env.floor_colour = floorcolours_zot[curr_subdungeon_level-1];
env.rock_colour = rockcolours_zot[curr_subdungeon_level-1];
}
}
}
dgn_set_floor_colours();
};
class map_corruption_marker : public map_marker
{
public:
map_corruption_marker(const coord_def &pos = coord_def(0, 0),
int dur = 0);
void write(tagHeader &) const;
void read(tagHeader &);
std::string debug_describe() const;
static map_marker *read(tagHeader &, map_marker_type);
public:
int duration, radius;
// map_corruption_marker
map_corruption_marker::map_corruption_marker(const coord_def &p,
int dur)
: map_marker(MAT_CORRUPTION_NEXUS, p), duration(dur), radius(0)
{
}
void map_corruption_marker::write(tagHeader &out) const
{
map_marker::write(out);
marshallShort(out, duration);
marshallShort(out, radius);
}
void map_corruption_marker::read(tagHeader &in)
{
map_marker::read(in);
duration = unmarshallShort(in);
radius = unmarshallShort(in);
}
map_marker *map_corruption_marker::read(tagHeader &th, map_marker_type)
{
map_corruption_marker *mc = new map_corruption_marker();
mc->read(th);
return (mc);
}
std::string map_corruption_marker::debug_describe() const
{
return make_stringf("Lugonu corrupt (%d)", duration);
}
//////////////////////////////////////////////////////////////////////////
// unlink all monsters and items from the grid
for(int x=0; x<GXM; x++)
{
for(int y=0; y<GYM; y++)
{
mgrd[x][y] = NON_MONSTER;
igrd[x][y] = NON_ITEM;
}
}
mgrd.init(NON_MONSTER);
igrd.init(NON_ITEM);
static char fix_black_colour(char incol)
{
if ( incol == BLACK )
return LIGHTGREY;
else
return incol;
}
void dgn_set_colours_from_monsters()
{
env.floor_colour = fix_black_colour(mcolour[env.mons_alloc[9]]);
env.rock_colour = fix_black_colour(mcolour[env.mons_alloc[8]]);
}
void dgn_set_floor_colours()
{
if (you.level_type == LEVEL_PANDEMONIUM || you.level_type == LEVEL_ABYSS)
{
dgn_set_colours_from_monsters();
}
else if (you.level_type == LEVEL_LABYRINTH)
{
env.floor_colour = LIGHTGREY;
env.rock_colour = BROWN;
}
else
{
// level_type == LEVEL_DUNGEON
const int youbranch = you.where_are_you;
env.floor_colour = branches[youbranch].floor_colour;
env.rock_colour = branches[youbranch].rock_colour;
// Zot is multicoloured
if ( you.where_are_you == BRANCH_HALL_OF_ZOT )
{
const char floorcolours_zot[] = { LIGHTGREY, LIGHTGREY, BLUE,
LIGHTBLUE, MAGENTA };
const char rockcolours_zot[] = { LIGHTGREY, BLUE, LIGHTBLUE,
MAGENTA, LIGHTMAGENTA };
const int curr_subdungeon_level = player_branch_depth();
if ( curr_subdungeon_level > 5 || curr_subdungeon_level < 1 )
mpr("Odd colouring!");
else
{
env.floor_colour = floorcolours_zot[curr_subdungeon_level-1];
env.rock_colour = rockcolours_zot[curr_subdungeon_level-1];
}
}
}
}
}
//////////////////////////////////////////////////////////////////////////////
// Abyss effects in other levels, courtesy Lugonu.
static void place_corruption_seed(const coord_def &pos, int duration)
{
env_add_marker(new map_corruption_marker(pos, duration));
}
static void initialise_level_corrupt_seeds(int power)
{
const int low = power / 2, high = power * 3 / 2;
int nseeds = random_range(1, std::min(2 + power / 110, 4));
#ifdef DEBUG_DIAGNOSTICS
mprf(MSGCH_DIAGNOSTICS, "Placing %d corruption seeds", nseeds);
#endif
// The corruption centered on the player is free.
place_corruption_seed(you.pos(), high + 100);
for (int i = 0; i < nseeds; ++i)
{
coord_def where;
do
where = coord_def(random2(GXM), random2(GYM));
while (!in_bounds(where) || grd(where) != DNGN_FLOOR
|| env_find_marker(where, MAT_ANY));
place_corruption_seed(where, random_range(low, high, 2));
}
static bool spawn_corrupted_servant_near(const coord_def &pos)
{
// Thirty tries for a place
for (int i = 0; i < 30; ++i)
{
const coord_def p( pos.x + random2avg(4, 3) + random2(3),
pos.y + random2avg(4, 3) + random2(3) );
if (!in_bounds(p) || p == you.pos() || mgrd(p) != NON_MONSTER
|| !grid_compatible(DNGN_FLOOR, grd(p), true))
continue;
// Got a place, summon the beast.
int level = 51;
monster_type mons =
pick_random_monster(level_id(LEVEL_ABYSS), level, level);
if (mons == MONS_PROGRAM_BUG)
return (false);
const beh_type beh =
one_chance_in(5 + you.skills[SK_INVOCATIONS] / 4)?
BEH_HOSTILE : BEH_NEUTRAL;
const int mid =
create_monster( mons, 3, beh, p.x, p.y, MHITNOT, 250 );
return (mid != -1);
}
return (false);
}
static void apply_corruption_effect(
map_marker *marker, int duration)
{
if (!duration)
return;
map_corruption_marker *cmark = dynamic_cast<map_corruption_marker*>(marker);
const coord_def center = cmark->pos;
const int neffects = std::max(div_rand_round(duration, 5), 1);
for (int i = 0; i < neffects; ++i)
{
if (random2(7000) < cmark->duration)
{
if (!spawn_corrupted_servant_near(cmark->pos))
break;
}
}
cmark->duration -= duration;
if (cmark->duration < 1)
env_remove_marker(cmark);
}
void run_corruption_effects(int duration)
{
std::vector<map_marker*> markers =
env_get_all_markers(MAT_CORRUPTION_NEXUS);
for (int i = 0, size = markers.size(); i < size; ++i)
{
map_marker *mark = markers[i];
if (mark->get_type() != MAT_CORRUPTION_NEXUS)
continue;
apply_corruption_effect(mark, duration);
}
}
static bool is_grid_corruptible(const coord_def &c)
{
if (c == you.pos())
return (false);
const dungeon_feature_type feat = grd(c);
// Stairs and portals cannot be corrupted.
if (grid_stair_direction(feat) != CMD_NO_CMD)
return (false);
switch (feat)
{
case DNGN_PERMAROCK_WALL:
case DNGN_GREEN_CRYSTAL_WALL:
return (false);
case DNGN_METAL_WALL:
return (one_chance_in(5));
case DNGN_STONE_WALL:
return (one_chance_in(3));
case DNGN_ROCK_WALL:
return (!one_chance_in(3));
default:
return (true);
}
}
// Returns true if the square has <= 4 traversable neighbours.
static bool is_crowded_square(const coord_def &c)
{
int neighbours = 0;
for (int xi = -1; xi <= 1; ++xi)
{
for (int yi = -1; yi <= 1; ++yi)
{
if (!xi && !yi)
continue;
const coord_def n(c.x + xi, c.y + yi);
if (!in_bounds(n) || !is_traversable(grd(n)))
continue;
if (++neighbours > 4)
return (false);
}
}
return (true);
}
// Returns true if the square has all opaque neighbours.
static bool is_sealed_square(const coord_def &c)
{
for (int xi = -1; xi <= 1; ++xi)
{
for (int yi = -1; yi <= 1; ++yi)
{
if (!xi && !yi)
continue;
const coord_def n(c.x + xi, c.y + yi);
if (!in_bounds(n))
continue;
if (!grid_is_opaque(grd(n)))
return (false);
}
}
return (true);
}
static void corrupt_square(const crawl_environment &oenv, const coord_def &c)
{
dungeon_feature_type feat = DNGN_UNSEEN;
if (grid_altar_god(grd(c)) != GOD_NO_GOD)
{
if (!one_chance_in(3))
feat = DNGN_ALTAR_LUGONU;
}
else
feat = oenv.grid(c);
if (grid_is_trap(feat) || feat == DNGN_UNDISCOVERED_TRAP
|| feat == DNGN_SECRET_DOOR || feat == DNGN_UNSEEN)
return;
if (is_traversable(grd(c)) && !is_traversable(feat)
&& is_crowded_square(c))
return;
if (!is_traversable(grd(c)) && is_traversable(feat) && is_sealed_square(c))
return;
if (feat == DNGN_EXIT_ABYSS)
feat = DNGN_ENTER_ABYSS;
dungeon_terrain_changed(c, feat, true, true, true);
if (feat == DNGN_ROCK_WALL)
env.grid_colours(c) = oenv.rock_colour;
else if (feat == DNGN_FLOOR)
env.grid_colours(c) = oenv.floor_colour;
}
static void corrupt_level_features(const crawl_environment &oenv)
{
std::vector<coord_def> corrupt_seeds;
std::vector<map_marker*> corrupt_markers =
env_get_all_markers(MAT_CORRUPTION_NEXUS);
for (int i = 0, size = corrupt_markers.size(); i < size; ++i)
corrupt_seeds.push_back(corrupt_markers[i]->pos);
for (int y = MAPGEN_BORDER; y < GYM - MAPGEN_BORDER; ++y)
{
for (int x = MAPGEN_BORDER; x < GXM - MAPGEN_BORDER; ++x)
{
const coord_def c(x, y);
int distance = GXM * GXM + GYM * GYM;
for (int i = 0, size = corrupt_seeds.size(); i < size; ++i)
{
const int dist = (c - corrupt_seeds[i]).rdist();
if (dist < distance)
distance = dist;
}
if ((distance < 6 || one_chance_in(1 + distance - 6))
&& is_grid_corruptible(c))
{
corrupt_square(oenv, c);
}
}
}
}
static bool is_level_corrupted()
{
if (you.level_type == LEVEL_ABYSS
|| you.level_type == LEVEL_PANDEMONIUM
|| player_in_hell()
|| player_in_branch(BRANCH_VESTIBULE_OF_HELL))
return (true);
return (!!env_find_marker(MAT_CORRUPTION_NEXUS));
}
static bool is_level_incorruptible()
{
if (is_level_corrupted())
{
mpr("This place is already infused with evil and corruption.");
return (true);
}
return (false);
}
bool lugonu_corrupt_level(int power)
{
if (is_level_incorruptible())
return (false);
mprf(MSGCH_GOD, "Lugonu's Hand of Corruption reaches out!");
you.flash_colour = EC_MUTAGENIC;
viewwindow(true, false);
initialise_level_corrupt_seeds(power);
std::auto_ptr<crawl_environment> backup(new crawl_environment(env));
generate_abyss();
generate_area(MAPGEN_BORDER, MAPGEN_BORDER,
GXM - MAPGEN_BORDER, GYM - MAPGEN_BORDER);
dgn_set_colours_from_monsters();
std::auto_ptr<crawl_environment> abyssal(new crawl_environment(env));
env = *backup;
backup.reset(NULL);
corrupt_level_features(*abyssal);
run_corruption_effects(100);
you.flash_colour = EC_MUTAGENIC;
viewwindow(true, false);
// Allow extra time for the flash to linger.
delay(1000);
viewwindow(true, false);
return (true);
}
static void lugonu_bends_space();
static int find_ability_slot( ability_type which_ability );
static bool activate_talent(const talent& tal);
static bool do_ability(const ability_def& abil);
static void pay_ability_costs(const ability_def& abil);
static std::string describe_talent(const talent& tal);
static void lugonu_bends_space();
static int find_ability_slot( ability_type which_ability );
static bool activate_talent(const talent& tal);
static bool do_ability(const ability_def& abil);
static void pay_ability_costs(const ability_def& abil);
static std::string describe_talent(const talent& tal);
{ ABIL_LUGONU_ABYSS_EXIT, "Depart the Abyss", 0, 0, 100, 10, ABFLAG_PAIN },
{ ABIL_LUGONU_BEND_SPACE, "Bend Space", 1, 0, 50, 0, ABFLAG_PAIN },
{ ABIL_LUGONU_SUMMON_DEMONS, "Summon Abyssal Servants", 7, 0, 100, 5, ABFLAG_NONE },
{ ABIL_LUGONU_ABYSS_ENTER, "Enter the Abyss", 9, 0, 200, 40, ABFLAG_NONE },
{ ABIL_LUGONU_ABYSS_EXIT, "Depart the Abyss", 0, 0, 100, 10, ABFLAG_PAIN },
{ ABIL_LUGONU_BEND_SPACE, "Bend Space", 1, 0, 50, 0, ABFLAG_PAIN },
{ ABIL_LUGONU_BANISH, "Banish", 4, 0, 200, 5, ABFLAG_NONE },
{ ABIL_LUGONU_CORRUPT, "Corrupt", 7, 5, 500, 20, ABFLAG_NONE },
{ ABIL_LUGONU_ABYSS_ENTER, "Enter the Abyss", 9, 0, 500, 40, ABFLAG_NONE },
case ABIL_LUGONU_SUMMON_DEMONS:
{
int ndemons = 1 + you.skills[SK_INVOCATIONS] / 4;
if (ndemons > 5)
ndemons = 5;
for ( int i = 0; i < ndemons; ++i )
summon_ice_beast_etc( 20 + you.skills[SK_INVOCATIONS] * 3,
summon_any_demon(DEMON_COMMON), true);
exercise(SK_INVOCATIONS, 6 + random2(6));
case ABIL_LUGONU_BANISH:
if ( !spell_direction(spd, beam, DIR_NONE, TARG_ENEMY) )
return (false);
zapping( ZAP_BANISHMENT, 16 + you.skills[SK_INVOCATIONS] * 8, beam );
exercise(SK_INVOCATIONS, 3 + random2(5));
break;
case ABIL_LUGONU_CORRUPT:
if (!lugonu_corrupt_level(300 + you.skills[SK_INVOCATIONS] * 15))
return (false);
exercise(SK_INVOCATIONS, 5 + random2(5));