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 rareif (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 rareif (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;elsereturn 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_DUNGEONconst int youbranch = you.where_are_you;env.floor_colour = branches[youbranch].floor_colour;env.rock_colour = branches[youbranch].rock_colour;// Zot is multicolouredif ( 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_markermap_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 gridfor(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;elsereturn 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_DUNGEONconst int youbranch = you.where_are_you;env.floor_colour = branches[youbranch].floor_colour;env.rock_colour = branches[youbranch].rock_colour;// Zot is multicolouredif ( 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_DIAGNOSTICSmprf(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;dowhere = 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 placefor (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;}elsefeat = 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));