diff options
Diffstat (limited to 'crawl-ref')
29 files changed, 758 insertions, 247 deletions
diff --git a/crawl-ref/source/abl-show.cc b/crawl-ref/source/abl-show.cc index b49295aa11..ed75ea325c 100644 --- a/crawl-ref/source/abl-show.cc +++ b/crawl-ref/source/abl-show.cc @@ -36,6 +36,7 @@ #include "externs.h" +#include "abyss.h" #include "beam.h" #include "decks.h" #include "effects.h" @@ -70,6 +71,13 @@ #include "libunix.h" #endif +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); + // this all needs to be split into data/util/show files // and the struct mechanism here needs to be rewritten (again) // along with the display routine to piece the strings @@ -79,13 +87,6 @@ // of structs than two arrays that share common index // values -- well, doesn't it? {dlb} -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); - // declaring this const messes up externs later, so don't do it ability_type god_abilities[MAX_NUM_GODS][MAX_GOD_ABILITIES] = { @@ -137,7 +138,7 @@ ability_type god_abilities[MAX_NUM_GODS][MAX_GOD_ABILITIES] = ABIL_ELYVILON_GREATER_HEALING }, // Lugonu { ABIL_LUGONU_ABYSS_EXIT, ABIL_LUGONU_BEND_SPACE, - ABIL_LUGONU_SUMMON_DEMONS, ABIL_NON_ABILITY, + ABIL_LUGONU_BANISH, ABIL_LUGONU_CORRUPT, ABIL_LUGONU_ABYSS_ENTER }, // Beogh { ABIL_NON_ABILITY, ABIL_BEOGH_SMITING, @@ -272,10 +273,11 @@ static const ability_def Ability_List[] = ABFLAG_CONF_OK }, // Lugonu - { 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 }, // Nemelex { ABIL_NEMELEX_PEEK_DECK, "Deck Peek", 3, 0, 0, 1, ABFLAG_INSTANT }, @@ -1547,6 +1549,7 @@ static bool do_ability(const ability_def& abil) break; case ABIL_LUGONU_ABYSS_EXIT: + { if ( you.level_type != LEVEL_ABYSS ) { mpr("You aren't in the Abyss!"); @@ -1555,8 +1558,14 @@ static bool do_ability(const ability_def& abil) banished(DNGN_EXIT_ABYSS); exercise(SK_INVOCATIONS, 8 + random2(10)); - // Lose 1d2 permanent HP - you.hp_max -= (coinflip() ? 2 : 1); + const int maxloss = std::max(2, div_rand_round(you.hp_max, 30)); + // Lose permanent HP + you.hp_max -= random_range(1, maxloss); + + // Paranoia. + if (you.hp_max < 1) + you.hp_max = 1; + // Deflate HP set_hp( 1 + random2(you.hp), false ); @@ -1566,25 +1575,25 @@ static bool do_ability(const ability_def& abil) if (you.magic_points) set_mp(random2(you.magic_points), false); break; + } case ABIL_LUGONU_BEND_SPACE: lugonu_bends_space(); exercise(SK_INVOCATIONS, 2 + random2(3)); break; - 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)); break; - } case ABIL_LUGONU_ABYSS_ENTER: if (you.level_type == LEVEL_ABYSS) diff --git a/crawl-ref/source/abyss.cc b/crawl-ref/source/abyss.cc index e047abb094..45ff746ddd 100644 --- a/crawl-ref/source/abyss.cc +++ b/crawl-ref/source/abyss.cc @@ -20,14 +20,17 @@ #include "cloud.h" #include "makeitem.h" +#include "mapmark.h" #include "misc.h" #include "monplace.h" #include "mtransit.h" +#include "player.h" #include "dungeon.h" #include "items.h" #include "lev-pand.h" #include "randart.h" #include "stuff.h" +#include "view.h" // public for abyss generation void generate_abyss(void) @@ -314,7 +317,7 @@ void abyss_teleport( bool new_area ) // teleport to a new area of the abyss: init_pandemonium(); // get new monsters - set_colours_from_monsters(); // and new colours + dgn_set_colours_from_monsters(); // and new colours for (i = 0; i < MAX_MONSTERS; i++) { @@ -368,3 +371,295 @@ void abyss_teleport( bool new_area ) place_transiting_monsters(); } + +////////////////////////////////////////////////////////////////////////////// +// 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); +} diff --git a/crawl-ref/source/abyss.h b/crawl-ref/source/abyss.h index d25770473f..3552dd847b 100644 --- a/crawl-ref/source/abyss.h +++ b/crawl-ref/source/abyss.h @@ -35,4 +35,8 @@ void abyss_teleport( bool new_area ); void save_abyss_uniques(); +bool lugonu_corrupt_level(int power); + +void run_corruption_effects(int duration); + #endif diff --git a/crawl-ref/source/direct.cc b/crawl-ref/source/direct.cc index 47b310f1f1..11acd1c91f 100644 --- a/crawl-ref/source/direct.cc +++ b/crawl-ref/source/direct.cc @@ -578,8 +578,9 @@ void direction(dist& moves, targeting_type restricts, { monsters &m = menv[mid]; - m.attitude = m.attitude == ATT_FRIENDLY? - ATT_HOSTILE : ATT_FRIENDLY; + m.attitude = m.attitude == ATT_FRIENDLY? ATT_NEUTRAL : + m.attitude == ATT_HOSTILE? ATT_FRIENDLY : + ATT_HOSTILE; } break; #endif @@ -1690,6 +1691,9 @@ static void describe_cell(int mx, int my) if (menv[i].attitude == ATT_FRIENDLY) mprf("%s is friendly.", mons_pronoun(menv[i].type, PRONOUN_CAP)); + else if (menv[i].attitude == ATT_NEUTRAL) + mprf("%s is indifferent to you.", + mons_pronoun(menv[i].type, PRONOUN_CAP)); const bool paralysed = mons_is_paralysed(&menv[i]); if (paralysed) diff --git a/crawl-ref/source/dungeon.cc b/crawl-ref/source/dungeon.cc index 9d56537d1d..471d802e6e 100644 --- a/crawl-ref/source/dungeon.cc +++ b/crawl-ref/source/dungeon.cc @@ -512,9 +512,10 @@ static void reset_level() use_random_maps = true; dgn_check_connectivity = false; dgn_zones = 0; - + // blank level with DNGN_ROCK_WALL - make_box(0, 0, GXM - 1, GYM - 1, DNGN_ROCK_WALL, DNGN_ROCK_WALL); + grd.init(DNGN_ROCK_WALL); + env.grid_colours.init(BLACK); // delete all traps for (int i = 0; i < MAX_TRAPS; i++) @@ -528,15 +529,8 @@ static void reset_level() for (int i = 0; i < MAX_MONSTERS; i++) menv[i].type = -1; - // 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); // reset all shops for (int shcount = 0; shcount < MAX_SHOPS; shcount++) @@ -809,8 +803,64 @@ static void build_dungeon_level(int level_number, int level_type) // Translate stairs for pandemonium levels: if (level_type == LEVEL_PANDEMONIUM) fixup_pandemonium_stairs(); + + dgn_set_floor_colours(); } // end builder() + +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]; + } + } + } +} + static void check_doors() { for (int x = 1; x < GXM-1; x++) diff --git a/crawl-ref/source/dungeon.h b/crawl-ref/source/dungeon.h index 09308c7914..576e891965 100644 --- a/crawl-ref/source/dungeon.h +++ b/crawl-ref/source/dungeon.h @@ -272,6 +272,12 @@ bool flood_find<fgrd, bound_check>::path_flood( bool builder(int level_number, int level_type); + +// Set floor/wall colour based on the mons_alloc array. Used for +// Abyss and Pan. +void dgn_set_colours_from_monsters(); +void dgn_set_floor_colours(); + bool dgn_place_map(int map, bool generating_level, bool clobber); void level_clear_vault_memory(); void level_welcome_messages(); diff --git a/crawl-ref/source/enum.h b/crawl-ref/source/enum.h index 3de87c997b..062abef63b 100644 --- a/crawl-ref/source/enum.h +++ b/crawl-ref/source/enum.h @@ -113,7 +113,8 @@ enum ability_type ABIL_ELYVILON_GREATER_HEALING, // 224 ABIL_LUGONU_ABYSS_EXIT, ABIL_LUGONU_BEND_SPACE, - ABIL_LUGONU_SUMMON_DEMONS, + ABIL_LUGONU_BANISH, + ABIL_LUGONU_CORRUPT, ABIL_LUGONU_ABYSS_ENTER, ABIL_NEMELEX_PEEK_DECK, ABIL_NEMELEX_DRAW_CARD, @@ -2393,6 +2394,7 @@ enum beh_type NUM_BEHAVIOURS, // max # of legal states BEH_CHARMED, // hostile-but-charmed; create only BEH_FRIENDLY, // used during creation only + BEH_NEUTRAL, // creation only BEH_HOSTILE, // creation only BEH_GOD_GIFT, // creation only BEH_GUARD // creation only - monster is guard diff --git a/crawl-ref/source/externs.h b/crawl-ref/source/externs.h index 9cc462cdcf..5998a02a42 100644 --- a/crawl-ref/source/externs.h +++ b/crawl-ref/source/externs.h @@ -337,7 +337,7 @@ struct coord_def int rdist() const { - return (MAXIMUM(::abs(x), ::abs(y))); + return (std::max(std::abs(x), std::abs(y))); } }; typedef bool (*coord_predicate)(const coord_def &c); @@ -1260,6 +1260,7 @@ public: FixedArray< unsigned char, GXM, GYM > mgrid; // monster grid FixedArray< int, GXM, GYM > igrid; // item grid FixedArray< unsigned char, GXM, GYM > cgrid; // cloud grid + FixedArray< unsigned short, GXM, GYM > grid_colours; // colour overrides FixedArray< map_cell, GXM, GYM > map; // discovered terrain diff --git a/crawl-ref/source/mapmark.cc b/crawl-ref/source/mapmark.cc index 366d4aa37d..52fcfab17a 100644 --- a/crawl-ref/source/mapmark.cc +++ b/crawl-ref/source/mapmark.cc @@ -24,12 +24,14 @@ map_marker::marker_reader map_marker::readers[NUM_MAP_MARKER_TYPES] = { &map_feature_marker::read, &map_lua_marker::read, + &map_corruption_marker::read, }; map_marker::marker_parser map_marker::parsers[NUM_MAP_MARKER_TYPES] = { &map_feature_marker::parse, &map_lua_marker::parse, + NULL, }; map_marker::map_marker(map_marker_type t, const coord_def &p) @@ -364,6 +366,41 @@ map_marker *map_lua_marker::parse( } ////////////////////////////////////////////////////////////////////////// +// 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); +} + +////////////////////////////////////////////////////////////////////////// // Map markers in env. void env_activate_markers() @@ -421,6 +458,17 @@ map_marker *env_find_marker(const coord_def &c, map_marker_type type) return (NULL); } +map_marker *env_find_marker(map_marker_type type) +{ + for (dgn_marker_map::const_iterator i = env.markers.begin(); + i != env.markers.end(); ++i) + { + if (type == MAT_ANY || i->second->get_type() == type) + return (i->second); + } + return (NULL); +} + void env_move_markers(const coord_def &from, const coord_def &to) { std::pair<dgn_marker_map::iterator, dgn_marker_map::iterator> @@ -442,13 +490,14 @@ void env_move_markers(const coord_def &from, const coord_def &to) } } -std::vector<map_marker*> env_get_all_markers() +std::vector<map_marker*> env_get_all_markers(map_marker_type mat) { std::vector<map_marker*> rmarkers; for (dgn_marker_map::const_iterator i = env.markers.begin(); i != env.markers.end(); ++i) { - rmarkers.push_back(i->second); + if (mat == MAT_ANY || i->second->get_type() == mat) + rmarkers.push_back(i->second); } return (rmarkers); } diff --git a/crawl-ref/source/mapmark.h b/crawl-ref/source/mapmark.h index f8137d4308..cc7e2ee5ee 100644 --- a/crawl-ref/source/mapmark.h +++ b/crawl-ref/source/mapmark.h @@ -14,7 +14,7 @@ enum map_marker_type { MAT_FEATURE, // Stock marker. MAT_LUA_MARKER, - MAT_FEATURE_NAME, + MAT_CORRUPTION_NEXUS, NUM_MAP_MARKER_TYPES, MAT_ANY }; @@ -69,6 +69,23 @@ public: dungeon_feature_type feat; }; +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; +}; + // A marker powered by Lua. class map_lua_marker : public map_marker, public dgn_event_listener { @@ -104,8 +121,9 @@ void env_activate_markers(); void env_add_marker(map_marker *); void env_remove_marker(map_marker *); void env_remove_markers_at(const coord_def &c, map_marker_type); -std::vector<map_marker*> env_get_all_markers(); +std::vector<map_marker*> env_get_all_markers(map_marker_type = MAT_ANY); map_marker *env_find_marker(const coord_def &c, map_marker_type); +map_marker *env_find_marker(map_marker_type type); std::vector<map_marker*> env_get_markers(const coord_def &c); void env_clear_markers(); std::string env_property_at(const coord_def &c, map_marker_type, diff --git a/crawl-ref/source/misc.cc b/crawl-ref/source/misc.cc index d6d42ac7b4..75136c4e76 100644 --- a/crawl-ref/source/misc.cc +++ b/crawl-ref/source/misc.cc @@ -556,7 +556,7 @@ static bool dgn_shift_feature(const coord_def &pos) return (true); } -static void dgn_check_terrain_items(const coord_def &pos) +static void dgn_check_terrain_items(const coord_def &pos, bool preserve_items) { const dungeon_feature_type grid = grd(pos); if (grid_is_solid(grid) || grid_destroys_items(grid)) @@ -569,7 +569,7 @@ static void dgn_check_terrain_items(const coord_def &pos) item = mitm[item].link; // Game-critical item. - if (item_is_critical(mitm[curr])) + if (preserve_items || item_is_critical(mitm[curr])) dgn_shift_item(pos, mitm[curr]); else { @@ -598,7 +598,8 @@ static void dgn_check_terrain_monsters(const coord_def &pos) void dungeon_terrain_changed(const coord_def &pos, dungeon_feature_type nfeat, bool affect_player, - bool preserve_features) + bool preserve_features, + bool preserve_items) { if (nfeat != DNGN_UNSEEN) { @@ -606,11 +607,12 @@ void dungeon_terrain_changed(const coord_def &pos, dgn_shift_feature(pos); unnotice_feature(level_pos(level_id::current(), pos)); grd(pos) = nfeat; + env.grid_colours(pos) = BLACK; if (is_notable_terrain(nfeat) && see_grid(pos)) seen_notable_thing(nfeat, pos.x, pos.y); } - dgn_check_terrain_items(pos); + dgn_check_terrain_items(pos, preserve_items); if (affect_player && pos == you.pos()) { if (!grid_is_solid(grd(pos))) @@ -1420,20 +1422,6 @@ void trackers_init_new_level(bool transit) stash_init_new_level(); } -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]]); -} - std::string level_description_string() { if (you.level_type == LEVEL_PANDEMONIUM) @@ -1476,41 +1464,8 @@ void new_level(void) take_note(Note(NOTE_DUNGEON_LEVEL_CHANGE)); cprintf("%s", level_description_string().c_str()); - 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(); + clear_to_end_of_line(); #ifdef DGL_WHEREIS whereis_record(); @@ -2582,6 +2537,8 @@ void run_environment_effects() apply_environment_effect( sfx_seeds[i] ); } } + + run_corruption_effects(you.time_taken); } coord_def pick_adjacent_free_square(int x, int y) diff --git a/crawl-ref/source/misc.h b/crawl-ref/source/misc.h index bceb4692bb..8bc73de6fe 100644 --- a/crawl-ref/source/misc.h +++ b/crawl-ref/source/misc.h @@ -174,7 +174,8 @@ void run_environment_effects(); void dungeon_terrain_changed(const coord_def &pos, dungeon_feature_type feat = DNGN_UNSEEN, bool affect_player = true, - bool preserve_features = false); + bool preserve_features = false, + bool preserve_items = false); ////////////////////////////////////////////////////////////////////// // Places and names @@ -209,10 +210,6 @@ int player_branch_depth(); bool single_level_branch(branch_type branch); ////////////////////////////////////////////////////////////////////// -// Set floor/wall colour based on the mons_alloc array. Used for -// Abyss and Pan. -void set_colours_from_monsters(); - int str_to_shoptype(const std::string &s); bool do_autopray(); diff --git a/crawl-ref/source/mon-pick.cc b/crawl-ref/source/mon-pick.cc index db5eb88d53..50ad85f64b 100644 --- a/crawl-ref/source/mon-pick.cc +++ b/crawl-ref/source/mon-pick.cc @@ -20,29 +20,29 @@ // NB - When adding new branches or levels above 50, you must // change pre-game deletion routine in new_game in newgame.cc -int mons_level(int mcls) +int mons_level(int mcls, const level_id &place) { int monster_level = 0; - if (you.level_type == LEVEL_ABYSS) + if (place.level_type == LEVEL_ABYSS) monster_level = ((mons_abyss(mcls)) ? 51 : 0); - else if (you.level_type == LEVEL_PANDEMONIUM) + else if (place.level_type == LEVEL_PANDEMONIUM) monster_level = ((mons_pan(mcls)) ? 52 : 0); - else - monster_level = your_branch().mons_level_function(mcls); + else if (place.level_type == LEVEL_DUNGEON) + monster_level = branches[place.branch].mons_level_function(mcls); return monster_level; } // higher values returned means the monster is "more common" // a return value of zero means the monster will never appear {dlb} -int mons_rarity(int mcls) +int mons_rarity(int mcls, const level_id &place) { // now, what about pandemonium ??? {dlb} - if (you.level_type == LEVEL_ABYSS) + if (place.level_type == LEVEL_ABYSS) return mons_rare_abyss(mcls); else - return your_branch().mons_rarity_function(mcls); + return branches[place.branch].mons_rarity_function(mcls); } bool mons_abyss(int mcls) diff --git a/crawl-ref/source/mon-pick.h b/crawl-ref/source/mon-pick.h index 0bbdf1d536..1f8bac453c 100644 --- a/crawl-ref/source/mon-pick.h +++ b/crawl-ref/source/mon-pick.h @@ -12,19 +12,20 @@ #ifndef MONPICK_H #define MONPICK_H +#include "travel.h" // last updated 12may2000 {dlb} /* *********************************************************************** * called from: dungeon - fight * *********************************************************************** */ -int mons_rarity(int mcls); +int mons_rarity(int mcls, const level_id &place = level_id::current()); // last updated 12may2000 {dlb} /* *********************************************************************** * called from: dungeon * *********************************************************************** */ -int mons_level(int mcls); +int mons_level(int mcls, const level_id &place = level_id::current()); // last updated 12may2000 {dlb} diff --git a/crawl-ref/source/mon-util.cc b/crawl-ref/source/mon-util.cc index 416845cd3c..08df90314e 100644 --- a/crawl-ref/source/mon-util.cc +++ b/crawl-ref/source/mon-util.cc @@ -1591,26 +1591,26 @@ int mons_power(int mc) bool mons_aligned(int m1, int m2) { - bool fr1, fr2; + mon_attitude_type fr1, fr2; struct monsters *mon1, *mon2; if (m1 == MHITNOT || m2 == MHITNOT) return (true); if (m1 == MHITYOU) - fr1 = true; + fr1 = ATT_FRIENDLY; else { mon1 = &menv[m1]; - fr1 = (mon1->attitude == ATT_FRIENDLY) || mon1->has_ench(ENCH_CHARM); + fr1 = mons_attitude(mon1); } if (m2 == MHITYOU) - fr2 = true; + fr2 = ATT_FRIENDLY; else { mon2 = &menv[m2]; - fr2 = (mon2->attitude == ATT_FRIENDLY) || mon2->has_ench(ENCH_CHARM); + fr2 = mons_attitude(mon2); } return (fr1 == fr2); @@ -1662,6 +1662,16 @@ bool mons_friendly(const monsters *m) return (m->attitude == ATT_FRIENDLY || m->has_ench(ENCH_CHARM)); } +bool mons_neutral(const monsters *m) +{ + return (m->attitude == ATT_NEUTRAL); +} + +mon_attitude_type mons_attitude(const monsters *m) +{ + return (m->has_ench(ENCH_CHARM)? ATT_FRIENDLY : m->attitude); +} + bool mons_is_submerged( const monsters *mon ) { // FIXME, switch to 4.1's MF_SUBMERGED system which is much cleaner. @@ -2762,7 +2772,7 @@ bool monsters::pickup_misc(item_def &item, int near) bool monsters::pickup_item(item_def &item, int near, bool force) { // Never pick up stuff when we're in battle. - if (!force && behaviour != BEH_WANDER) + if (!force && (behaviour != BEH_WANDER || attitude == ATT_NEUTRAL)) return (false); // Jellies are not handled here. diff --git a/crawl-ref/source/mon-util.h b/crawl-ref/source/mon-util.h index 2b69ebd91d..9b8de81d0b 100644 --- a/crawl-ref/source/mon-util.h +++ b/crawl-ref/source/mon-util.h @@ -326,6 +326,8 @@ bool mons_aligned(int m1, int m2); * called from: monstuff acr * *********************************************************************** */ bool mons_friendly(const monsters *m); +bool mons_neutral(const monsters *m); +mon_attitude_type mons_attitude(const monsters *m); bool mons_behaviour_perceptible(const monsters *mons); bool mons_is_confused(const monsters *m); diff --git a/crawl-ref/source/monplace.cc b/crawl-ref/source/monplace.cc index b26aac753a..2922a1949d 100644 --- a/crawl-ref/source/monplace.cc +++ b/crawl-ref/source/monplace.cc @@ -151,6 +151,101 @@ static int fuzz_mons_level(int level) return (level); } +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); +} + bool place_monster(int &id, int mon_type, int power, beh_type behaviour, int target, bool summoned, int px, int py, bool allow_bands, proximity_type proximity, int extra, int dur, @@ -159,7 +254,6 @@ bool place_monster(int &id, int mon_type, int power, beh_type behaviour, int band_size = 0; int band_monsters[BIG_BAND]; // band monster types int lev_mons = power; // final 'power' - int count; int i; // set initial id to -1 (unsuccessful create) @@ -178,89 +272,10 @@ bool place_monster(int &id, int mon_type, int power, beh_type behaviour, if (mon_type == RANDOM_MONSTER) { - 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); } // (3) decide on banding (good lord!) @@ -619,6 +634,9 @@ static int place_monster_aux( int mon_type, beh_type behaviour, int target, if (behaviour == BEH_FRIENDLY || behaviour == BEH_GOD_GIFT) menv[id].attitude = ATT_FRIENDLY; + if (behaviour == BEH_NEUTRAL) + menv[id].attitude = ATT_NEUTRAL; + menv[id].behaviour = BEH_WANDER; } diff --git a/crawl-ref/source/monplace.h b/crawl-ref/source/monplace.h index 5a125c03e9..1de7d3ba80 100644 --- a/crawl-ref/source/monplace.h +++ b/crawl-ref/source/monplace.h @@ -52,6 +52,11 @@ int create_monster( int cls, int dur, beh_type beha, int cr_x, int cr_y, int hitting, int zsec, bool permit_bands = false, bool force_place = false, bool force_behaviour = false ); +class level_id; +monster_type pick_random_monster(const level_id &place, + int power, + int &lev_mons); + bool player_angers_monster(monsters *mon); // last updated 12may2000 {dlb} diff --git a/crawl-ref/source/monstuff.cc b/crawl-ref/source/monstuff.cc index f7a8bd11e0..87b238f9e5 100644 --- a/crawl-ref/source/monstuff.cc +++ b/crawl-ref/source/monstuff.cc @@ -1537,6 +1537,7 @@ static void handle_behaviour(monsters *mon) { bool changed = true; bool isFriendly = mons_friendly(mon); + bool isNeutral = mons_neutral(mon); bool proxPlayer = mons_near(mon); bool proxFoe; bool isHurt = (mon->hit_points <= mon->max_hit_points / 4 - 1); @@ -1611,6 +1612,9 @@ static void handle_behaviour(monsters *mon) } } + if (mon->attitude == ATT_NEUTRAL && mon->foe == MHITNOT) + set_nearest_monster_foe(mon); + // monsters do not attack themselves {dlb} if (mon->foe == monster_index(mon)) mon->foe = MHITNOT; @@ -1622,9 +1626,17 @@ static void handle_behaviour(monsters *mon) mon->foe = MHITNOT; } + // neutral monsters prefer not to attack players, or other neutrals. + if (mon->foe != MHITNOT && isNeutral + && (mon->foe == MHITYOU || mons_neutral(&menv[mon->foe]))) + { + mon->foe = MHITNOT; + } + // unfriendly monsters fighting other monsters will usually // target the player, if they're healthy - if (!isFriendly && mon->foe != MHITYOU && mon->foe != MHITNOT + if (!isFriendly && !isNeutral + && mon->foe != MHITYOU && mon->foe != MHITNOT && proxPlayer && !(mon->has_ench(ENCH_BERSERK)) && isHealthy && !one_chance_in(3)) { @@ -1688,7 +1700,7 @@ static void handle_behaviour(monsters *mon) // no foe? then wander or seek the player if (mon->foe == MHITNOT) { - if (!proxPlayer) + if (!proxPlayer || isNeutral) new_beh = BEH_WANDER; else { @@ -1871,7 +1883,7 @@ static void handle_behaviour(monsters *mon) // foe gone out of LOS? if (!proxFoe) { - if (isFriendly || proxPlayer) + if ((isFriendly || proxPlayer) && !isNeutral) new_foe = MHITYOU; else new_beh = BEH_WANDER; @@ -1898,12 +1910,12 @@ static void handle_behaviour(monsters *mon) } // end handle_behaviour() static bool mons_check_set_foe(monsters *mon, int x, int y, - bool friendly) + bool friendly, bool neutral) { if (!in_bounds(x, y)) return (false); - if (!friendly && x == you.x_pos && y == you.y_pos + if (!friendly && !neutral && x == you.x_pos && y == you.y_pos && mons_player_visible(mon)) { mon->foe = MHITYOU; @@ -1916,7 +1928,8 @@ static bool mons_check_set_foe(monsters *mon, int x, int y, if (foe != mon && mons_monster_visible(mon, foe) - && mons_friendly(foe) != friendly) + && (mons_friendly(foe) != friendly + || (neutral && !mons_neutral(foe)))) { mon->foe = mgrd[x][y]; return (true); @@ -1930,6 +1943,7 @@ static bool mons_check_set_foe(monsters *mon, int x, int y, void set_nearest_monster_foe(monsters *mon) { const bool friendly = mons_friendly(mon); + const bool neutral = mons_neutral(mon); const int mx = mon->x; const int my = mon->y; @@ -1937,13 +1951,13 @@ void set_nearest_monster_foe(monsters *mon) for (int k = 1; k <= LOS_RADIUS; k++) { for (int x = mx - k; x <= mx + k; ++x) - if (mons_check_set_foe(mon, x, my - k, friendly) - || mons_check_set_foe(mon, x, my + k, friendly)) + if (mons_check_set_foe(mon, x, my - k, friendly, neutral) + || mons_check_set_foe(mon, x, my + k, friendly, neutral)) return; for (int y = my - k + 1; y < my + k; ++y) - if (mons_check_set_foe(mon, mx - k, y, friendly) - || mons_check_set_foe(mon, mx + k, y, friendly)) + if (mons_check_set_foe(mon, mx - k, y, friendly, neutral) + || mons_check_set_foe(mon, mx + k, y, friendly, neutral)) return; } } diff --git a/crawl-ref/source/monstuff.h b/crawl-ref/source/monstuff.h index ef17edc96a..2aa3bb1527 100644 --- a/crawl-ref/source/monstuff.h +++ b/crawl-ref/source/monstuff.h @@ -17,7 +17,8 @@ #include "mon-util.h" // useful macro -#define SAME_ATTITUDE(x) (mons_friendly(x)?BEH_FRIENDLY:BEH_HOSTILE) +#define SAME_ATTITUDE(x) (mons_friendly(x)? BEH_FRIENDLY: \ + mons_neutral(x)? BEH_NEUTRAL : BEH_HOSTILE) #define MONST_INTERESTING(x) (x->flags & MF_INTERESTING) diff --git a/crawl-ref/source/player.cc b/crawl-ref/source/player.cc index 5788486b63..ebaa18142c 100644 --- a/crawl-ref/source/player.cc +++ b/crawl-ref/source/player.cc @@ -4119,9 +4119,9 @@ void set_hp(int new_amount, bool max_too) if (you.hp > you.hp_max) you.hp = you.hp_max; - // take_note(Note(NOTE_HP_CHANGE, you.hp, you.hp_max)); if ( max_too ) - take_note(Note(NOTE_MAXHP_CHANGE, you.hp_max)); + take_note(Note(NOTE_MAXHP_CHANGE, you.hp_max)); + // must remain outside conditional, given code usage {dlb} you.redraw_hit_points = 1; diff --git a/crawl-ref/source/randart.cc b/crawl-ref/source/randart.cc index c549e91e0a..7d13ce9390 100644 --- a/crawl-ref/source/randart.cc +++ b/crawl-ref/source/randart.cc @@ -494,6 +494,7 @@ static const char *rand_wpn_names[] = { " of Egomania", " of Pyrrhic Victory", " of Irrepressible Laughter", + " of Impeachment", }; static const char *rand_armour_names[] = { diff --git a/crawl-ref/source/religion.cc b/crawl-ref/source/religion.cc index 5d11f80aa5..e5be055ebc 100644 --- a/crawl-ref/source/religion.cc +++ b/crawl-ref/source/religion.cc @@ -180,8 +180,8 @@ const char* god_gain_power_messages[MAX_NUM_GODS][MAX_GOD_ABILITIES] = // Lugonu { "depart the Abyss - at a permanent cost", "bend space around yourself", - "summon the demons of the Abyss to your aid", - "", + "banish your foes", + "corrupt the fabric of space", "gate yourself to the Abyss" }, // Beogh { "Beogh supports the use of orcish gear.", diff --git a/crawl-ref/source/spl-cast.cc b/crawl-ref/source/spl-cast.cc index 25526ceb58..f05b6712b1 100644 --- a/crawl-ref/source/spl-cast.cc +++ b/crawl-ref/source/spl-cast.cc @@ -229,7 +229,7 @@ int list_spells() } } -static int apply_vehumet_wizardry_boost(spell_type spell, int chance) +static int apply_spellcasting_success_boosts(spell_type spell, int chance) { int wizardry = player_mag_abil(false); int fail_reduce = 100; @@ -254,6 +254,10 @@ static int apply_vehumet_wizardry_boost(spell_type spell, int chance) wiz_factor += (100 - wiz_factor) / 3; } + // Draconians get a boost to dragon-form. + if (spell == SPELL_DRAGON_FORM && player_genus(GENPC_DRACONIAN)) + fail_reduce = fail_reduce * 70 / 100; + // Hard cap on fail rate reduction. if (fail_reduce < 50) fail_reduce = 50; @@ -444,7 +448,7 @@ int spell_fail(spell_type spell) } // Apply the effects of Vehumet prayer and items of wizardry. - chance2 = apply_vehumet_wizardry_boost(spell, chance2); + chance2 = apply_spellcasting_success_boosts(spell, chance2); if (chance2 > 100) chance2 = 100; diff --git a/crawl-ref/source/stuff.cc b/crawl-ref/source/stuff.cc index 19ab9ebfd1..b1c972b826 100644 --- a/crawl-ref/source/stuff.cc +++ b/crawl-ref/source/stuff.cc @@ -786,7 +786,8 @@ bool map_bounds( int x, int y ) // Returns a random location in (x_pos, y_pos)... the grid will be // DNGN_FLOOR if clear, and NON_MONSTER if empty. Exclusive tells // if we're using in_bounds() or map_bounds() restriction. -void random_in_bounds( int &x_pos, int &y_pos, int terr, bool empty, bool excl ) +void random_in_bounds( int &x_pos, int &y_pos, int terr, + bool empty, bool excl ) { bool done = false; @@ -799,7 +800,8 @@ void random_in_bounds( int &x_pos, int &y_pos, int terr, bool empty, bool excl ) done = true; else if (terr == grd[x_pos][y_pos]) done = true; - else if (terr == DNGN_DEEP_WATER && grd[x_pos][y_pos] == DNGN_SHALLOW_WATER) + else if (terr == DNGN_DEEP_WATER + && grd[x_pos][y_pos] == DNGN_SHALLOW_WATER) done = true; else if (empty && mgrd[x_pos][y_pos] != NON_MONSTER diff --git a/crawl-ref/source/tags.cc b/crawl-ref/source/tags.cc index 8972af6cc0..f90f9a6fee 100644 --- a/crawl-ref/source/tags.cc +++ b/crawl-ref/source/tags.cc @@ -334,6 +334,56 @@ void unmarshallCoord(tagHeader &th, coord_def &c) c.y = unmarshallShort(th); } +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; + } + } +} + union float_marshall_kludge { // [ds] Does ANSI C guarantee that sizeof(float) == sizeof(long)? @@ -1350,6 +1400,8 @@ static void tag_construct_level(struct tagHeader &th) } } + run_length_encode(th, marshallByte, env.grid_colours, GXM, GYM); + marshallShort(th, env.cloud_no); // how many clouds? @@ -1577,6 +1629,9 @@ static void tag_read_level( struct tagHeader &th, char minorVersion ) } } + env.grid_colours.init(BLACK); + run_length_decode(th, unmarshallByte, env.grid_colours, GXM, GYM); + env.cloud_no = unmarshallShort(th); // how many clouds? diff --git a/crawl-ref/source/travel.cc b/crawl-ref/source/travel.cc index 71c674355f..3ef549ec0e 100644 --- a/crawl-ref/source/travel.cc +++ b/crawl-ref/source/travel.cc @@ -37,6 +37,7 @@ #include <cstdarg> #include <cctype> #include <cstdio> +#include <memory> #include <sstream> #ifdef DOS @@ -2487,11 +2488,11 @@ static int find_transtravel_stair( const level_id &cur, static bool loadlev_populate_stair_distances(const level_pos &target) { - crawl_environment tmp = env; + std::auto_ptr<crawl_environment> tmp(new crawl_environment(env)); if (!travel_load_map(target.id.branch, absdungeon_depth(target.id.branch, target.id.depth))) { - env = tmp; + env = *tmp; return false; } @@ -2503,7 +2504,7 @@ static bool loadlev_populate_stair_distances(const level_pos &target) populate_stair_distances(target); - env = tmp; + env = *tmp; curr_excludes = old_excludes; return !curr_stairs.empty(); } diff --git a/crawl-ref/source/version.h b/crawl-ref/source/version.h index 397c811609..fc8bb21412 100644 --- a/crawl-ref/source/version.h +++ b/crawl-ref/source/version.h @@ -58,6 +58,6 @@ #define VERSION_DETAIL BUILD_DATE #endif -#define SAVE_MAJOR_VERSION 2 +#define SAVE_MAJOR_VERSION 3 #endif diff --git a/crawl-ref/source/view.cc b/crawl-ref/source/view.cc index c5901abea8..7e60bc3a63 100644 --- a/crawl-ref/source/view.cc +++ b/crawl-ref/source/view.cc @@ -47,6 +47,7 @@ #include "initfile.h" #include "insult.h" #include "itemprop.h" +#include "luadgn.h" #include "macro.h" #include "misc.h" #include "monstuff.h" @@ -337,16 +338,24 @@ static void get_symbol( int x, int y, if (colour) { const int colmask = *colour & COLFLAG_MASK; - // 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 (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); + } } // Note anything we see that's notable @@ -4053,20 +4062,16 @@ void viewwindow(bool draw_it, bool do_updates) const int object = env.show(ep); if (object) { - if ((grd(gc) == DNGN_ROCK_STAIRS_DOWN || grd(gc) == DNGN_ROCK_STAIRS_UP) - && see_grid( gc.x, gc.y )) - { - learned_something_new(TUT_SEEN_ESCAPE_HATCH, gc.x, gc.y); - } + if (grid_is_rock_stair(grd(gc))) + learned_something_new( + TUT_SEEN_ESCAPE_HATCH, gc.x, gc.y); else if (is_feature('>', gc.x, gc.y)) - learned_something_new(TUT_SEEN_STAIRS, gc.x, gc.y); + learned_something_new(TUT_SEEN_STAIRS, gc.x, gc.y); else if (is_feature('_', gc.x, gc.y)) learned_something_new(TUT_SEEN_ALTAR, gc.x, gc.y); - else if (grd(gc) == DNGN_CLOSED_DOOR - && see_grid( gc.x, gc.y )) + else if (grd(gc) == DNGN_CLOSED_DOOR) learned_something_new(TUT_SEEN_DOOR, gc.x, gc.y); - else if (grd(gc) == DNGN_ENTER_SHOP - && see_grid( gc.x, gc.y )) + else if (grd(gc) == DNGN_ENTER_SHOP) learned_something_new(TUT_SEEN_SHOP, gc.x, gc.y); } } |