summaryrefslogtreecommitdiffstats
path: root/crawl-ref
diff options
context:
space:
mode:
authordshaligram <dshaligram@c06c8d41-db1a-0410-9941-cceddc491573>2007-08-11 20:56:55 +0000
committerdshaligram <dshaligram@c06c8d41-db1a-0410-9941-cceddc491573>2007-08-11 20:56:55 +0000
commite9e1be789c12cdbaaaeb048251dae0dc22a320ba (patch)
treef62f547aba1d78f1bcbf4b6d09b5c9a1bbc2913b /crawl-ref
parent4c51cdab684e245dd8f050171294dcbc5c471bfe (diff)
downloadcrawl-ref-e9e1be789c12cdbaaaeb048251dae0dc22a320ba.tar.gz
crawl-ref-e9e1be789c12cdbaaaeb048251dae0dc22a320ba.zip
Give Lugonu Banishment and Corruption. I've left the old Bend Space in, because
there needs to be an invocation that can train Invocations, and Banishment is too costly to use for everyday training. Corruption is still a first-cut, needs more work and playtesting: - Terrain modification is one-time only. Creeping modification requires too much savegame magic. - The monsters gated in during the corruption effect are occasionally hostile, but mostly neutral. Neutrals will attack hostile monsters and also pets, but will leave other neutrals and the player alone (in general). A neutral that wants to go somewhere, but finds the player in the way will still take a swing at the player. - Beams are still not fixed to handle neutrals correctly (so neutrals do not target and shoot right yet), will fix soon. Breaks save compatibility. git-svn-id: https://crawl-ref.svn.sourceforge.net/svnroot/crawl-ref/trunk@1990 c06c8d41-db1a-0410-9941-cceddc491573
Diffstat (limited to 'crawl-ref')
-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);
}
}