summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--crawl-ref/source/abl-show.cc61
-rw-r--r--crawl-ref/source/abyss.cc297
-rw-r--r--crawl-ref/source/abyss.h4
-rw-r--r--crawl-ref/source/direct.cc8
-rw-r--r--crawl-ref/source/dungeon.cc72
-rw-r--r--crawl-ref/source/dungeon.h6
-rw-r--r--crawl-ref/source/enum.h4
-rw-r--r--crawl-ref/source/externs.h3
-rw-r--r--crawl-ref/source/mapmark.cc53
-rw-r--r--crawl-ref/source/mapmark.h22
-rw-r--r--crawl-ref/source/misc.cc63
-rw-r--r--crawl-ref/source/misc.h7
-rw-r--r--crawl-ref/source/mon-pick.cc16
-rw-r--r--crawl-ref/source/mon-pick.h5
-rw-r--r--crawl-ref/source/mon-util.cc22
-rw-r--r--crawl-ref/source/mon-util.h2
-rw-r--r--crawl-ref/source/monplace.cc186
-rw-r--r--crawl-ref/source/monplace.h5
-rw-r--r--crawl-ref/source/monstuff.cc34
-rw-r--r--crawl-ref/source/monstuff.h3
-rw-r--r--crawl-ref/source/player.cc4
-rw-r--r--crawl-ref/source/randart.cc1
-rw-r--r--crawl-ref/source/religion.cc4
-rw-r--r--crawl-ref/source/spl-cast.cc8
-rw-r--r--crawl-ref/source/stuff.cc6
-rw-r--r--crawl-ref/source/tags.cc55
-rw-r--r--crawl-ref/source/travel.cc7
-rw-r--r--crawl-ref/source/version.h2
-rw-r--r--crawl-ref/source/view.cc45
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);
}
}