summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--crawl-ref/source/fight.cc21
-rw-r--r--crawl-ref/source/mon-util.cc101
-rw-r--r--crawl-ref/source/mon-util.h8
-rw-r--r--crawl-ref/source/monplace.cc183
-rw-r--r--crawl-ref/source/monplace.h7
-rw-r--r--crawl-ref/source/monstuff.cc123
-rw-r--r--crawl-ref/source/mstuff2.cc9
-rw-r--r--crawl-ref/source/spells3.cc2
-rw-r--r--crawl-ref/source/stuff.cc3
9 files changed, 285 insertions, 172 deletions
diff --git a/crawl-ref/source/fight.cc b/crawl-ref/source/fight.cc
index 0eaafa19a5..b694f09412 100644
--- a/crawl-ref/source/fight.cc
+++ b/crawl-ref/source/fight.cc
@@ -280,14 +280,8 @@ bool you_attack(int monster_attacked, bool unarmed_attacks)
// wet merfolk
if (player_is_swimming()
- // monster not a water creature
- && monster_habitat( defender->type ) != DNGN_DEEP_WATER
- && !mons_class_flag( defender->type, M_AMPHIBIOUS )
- // monster in water
- && (grd[defender->x][defender->y] == DNGN_SHALLOW_WATER
- || grd[defender->x][defender->y] == DNGN_DEEP_WATER)
- // monster not flying
- && !mons_flies( defender ))
+ // monster not a water creature, but is in water
+ && monster_floundering(defender))
{
water_attack = true;
}
@@ -2957,19 +2951,14 @@ bool monsters_fight(int monster_attacking, int monster_attacked)
return false;
}
- if (grd[attacker->x][attacker->y] == DNGN_SHALLOW_WATER
- && !mons_flies( attacker )
- && !mons_class_flag( attacker->type, M_AMPHIBIOUS )
- && habitat == DNGN_FLOOR
- && one_chance_in(4))
+ if (monster_floundering(attacker) && one_chance_in(4))
{
mpr("You hear a splashing noise.");
return true;
}
- if (grd[defender->x][defender->y] == DNGN_SHALLOW_WATER
- && !mons_flies(defender)
- && habitat == DNGN_DEEP_WATER)
+ // habitat is the favoured habitat of the attacker
+ if (monster_floundering(defender) && habitat == DNGN_DEEP_WATER)
{
water_attack = true;
}
diff --git a/crawl-ref/source/mon-util.cc b/crawl-ref/source/mon-util.cc
index 641662f184..1d229c02c9 100644
--- a/crawl-ref/source/mon-util.cc
+++ b/crawl-ref/source/mon-util.cc
@@ -31,6 +31,7 @@
#include "debug.h"
#include "itemname.h"
#include "itemprop.h"
+#include "monplace.h"
#include "mstuff2.h"
#include "player.h"
#include "randart.h"
@@ -43,6 +44,20 @@ static FixedVector < int, NUM_MONSTERS > mon_entry;
// really important extern -- screen redraws suck w/o it {dlb}
FixedVector < unsigned short, 1000 > mcolour;
+enum habitat_type
+{
+ // Flying monsters will appear in all categories
+ HT_NORMAL, // Normal critters
+ HT_SHALLOW_WATER, // Union of normal + water
+ HT_DEEP_WATER, // Water critters
+ HT_LAVA, // Lava critters
+
+ NUM_HABITATS
+};
+
+static bool initialized_randmons = false;
+static std::vector<int> monsters_by_habitat[NUM_HABITATS];
+
static struct monsterentry mondata[] = {
#include "mon-data.h"
};
@@ -118,6 +133,72 @@ static monsterentry *seekmonster(int p_monsterid);
#define smc seekmonster(mc)
/* ******************** BEGIN PUBLIC FUNCTIONS ******************** */
+
+habitat_type grid2habitat(int grid)
+{
+ switch (grid)
+ {
+ case DNGN_DEEP_WATER:
+ return (HT_DEEP_WATER);
+ case DNGN_SHALLOW_WATER:
+ return (HT_SHALLOW_WATER);
+ case DNGN_LAVA:
+ return (HT_LAVA);
+ default:
+ return (HT_NORMAL);
+ }
+}
+
+int habitat2grid(habitat_type ht)
+{
+ switch (ht)
+ {
+ case HT_DEEP_WATER:
+ return (DNGN_DEEP_WATER);
+ case HT_SHALLOW_WATER:
+ return (DNGN_SHALLOW_WATER);
+ case HT_LAVA:
+ return (DNGN_LAVA);
+ case HT_NORMAL:
+ default:
+ return (DNGN_FLOOR);
+ }
+}
+
+static void initialize_randmons()
+{
+ for (int i = 0; i < NUM_HABITATS; ++i)
+ {
+ int grid = habitat2grid( habitat_type(i) );
+
+ for (int m = 0; m < NUM_MONSTERS; ++m)
+ {
+ if (invalid_monster_class(m))
+ continue;
+ if (monster_habitable_grid(m, grid))
+ monsters_by_habitat[i].push_back(m);
+ }
+ }
+ initialized_randmons = true;
+}
+
+monster_type random_monster_at_grid(int x, int y)
+{
+ return (random_monster_at_grid(grd[x][y]));
+}
+
+monster_type random_monster_at_grid(int grid)
+{
+ if (!initialized_randmons)
+ initialize_randmons();
+
+ const habitat_type ht = grid2habitat(grid);
+ const std::vector<int> &valid_mons = monsters_by_habitat[ht];
+ ASSERT(!valid_mons.empty());
+ return valid_mons.empty()? MONS_PROGRAM_BUG
+ : monster_type(valid_mons[ random2(valid_mons.size()) ]);
+}
+
void init_monsters(FixedVector < unsigned short, 1000 > &colour)
{
unsigned int x; // must be unsigned to match size_t {dlb}
@@ -159,7 +240,7 @@ bool mons_class_flag(int mc, int bf)
return ((smc->bitfields & bf) != 0);
} // end mons_class_flag()
-static int scan_mon_inv_randarts( struct monsters *mon, int ra_prop )
+static int scan_mon_inv_randarts( const monsters *mon, int ra_prop )
{
int ret = 0;
@@ -216,6 +297,14 @@ bool invalid_monster(const monsters *mons)
return (!mons || mons->type == -1);
}
+bool invalid_monster_class(int mclass)
+{
+ return (mclass < 0
+ || mclass >= NUM_MONSTERS
+ || mon_entry[mclass] == -1
+ || mon_entry[mclass] == MONS_PROGRAM_BUG);
+}
+
bool mons_is_mimic( int mc )
{
return (mons_species( mc ) == MONS_GOLD_MIMIC);
@@ -285,7 +374,8 @@ corpse_effect_type mons_corpse_effect(int mc)
monster_type mons_species( int mc )
{
- return (smc->species);
+ const monsterentry *me = seekmonster(mc);
+ return (me? me->species : MONS_PROGRAM_BUG);
} // end mons_species()
monster_type mons_genus( int mc )
@@ -698,7 +788,7 @@ int mons_skeleton(int mc)
return (1);
} // end mons_skeleton()
-char mons_class_flies(int mc)
+int mons_class_flies(int mc)
{
if (mc == MONS_PANDEMONIUM_DEMON)
return (ghost.values[ GVAL_DEMONLORD_FLY ]);
@@ -714,10 +804,9 @@ char mons_class_flies(int mc)
return (0);
}
-char mons_flies( struct monsters *mon )
+int mons_flies( const monsters *mon )
{
- char ret = mons_class_flies( mon->type );
-
+ int ret = mons_class_flies( mon->type );
return (ret ? ret : (scan_mon_inv_randarts(mon, RAP_LEVITATE) > 0) ? 2 : 0);
} // end mons_flies()
diff --git a/crawl-ref/source/mon-util.h b/crawl-ref/source/mon-util.h
index e6f97da0e6..55695d203b 100644
--- a/crawl-ref/source/mon-util.h
+++ b/crawl-ref/source/mon-util.h
@@ -140,8 +140,8 @@ const char *ptr_monam( struct monsters *mon, char desc );
/* ***********************************************************************
* called from: beam - direct - fight - monstuff - mstuff2 - spells4 - view
* *********************************************************************** */
-char mons_class_flies( int mc );
-char mons_flies( struct monsters *mon );
+int mons_class_flies( int mc );
+int mons_flies( const monsters *mon );
// last updated XXmay2000 {dlb}
@@ -430,6 +430,7 @@ bool check_mons_resist_magic( struct monsters *monster, int pow );
bool mons_is_stationary(const monsters *mons);
bool invalid_monster(const monsters *mons);
+bool invalid_monster_class(int mclass);
bool monster_shover(const monsters *m);
bool mons_is_paralysed(const monsters *m);
@@ -437,4 +438,7 @@ bool mons_is_paralysed(const monsters *m);
bool monster_senior(const monsters *first, const monsters *second);
monster_type draco_subspecies( const monsters *mon );
+monster_type random_monster_at_grid(int x, int y);
+monster_type random_monster_at_grid(int grid);
+
#endif
diff --git a/crawl-ref/source/monplace.cc b/crawl-ref/source/monplace.cc
index beef83df3c..355afb7d8d 100644
--- a/crawl-ref/source/monplace.cc
+++ b/crawl-ref/source/monplace.cc
@@ -41,6 +41,101 @@ static int place_monster_aux(int mon_type, char behaviour, int target,
int px, int py, int power, int extra, bool first_band_member,
int dur = 0);
+// Returns whether actual_grid is compatible with grid_wanted for monster
+// movement (or for monster generation, if generation is true).
+bool grid_compatible(int grid_wanted, int actual_grid, bool generation)
+{
+ // XXX What in Xom's name is DNGN_WATER_STUCK? It looks like an artificial
+ // device to slow down fiery monsters flying over water.
+ if (grid_wanted == DNGN_FLOOR)
+ return actual_grid >= DNGN_FLOOR
+ || (!generation
+ && actual_grid == DNGN_SHALLOW_WATER);
+
+ return (grid_wanted == actual_grid
+ || (grid_wanted == DNGN_DEEP_WATER
+ && (actual_grid == DNGN_SHALLOW_WATER
+ || actual_grid == DNGN_BLUE_FOUNTAIN)));
+}
+
+// Can this monster happily on actual_grid?
+//
+// If you have an actual monster, use this instead of the overloaded function
+// that uses only the monster class to make decisions.
+bool monster_habitable_grid(const monsters *m, int actual_grid)
+{
+ return (monster_habitable_grid(m->type, actual_grid, mons_flies(m)));
+}
+
+// Can monsters of class monster_class live happily on actual_grid? Use flies
+// == true to pretend the monster can fly.
+//
+// [dshaligram] We're trying to harmonise the checks from various places into
+// one check, so we no longer care if a water elemental springs into existence
+// on dry land, because they're supposed to be able to move onto dry land
+// anyway.
+bool monster_habitable_grid(int monster_class, int actual_grid, bool flies)
+{
+ const int preferred_habitat = monster_habitat(monster_class);
+ return (grid_compatible(preferred_habitat, actual_grid)
+ // [dshaligram] Flying creatures are all DNGN_FLOOR, so we
+ // only have to check for the additional valid grids of deep
+ // water and lava.
+ || ((flies || mons_class_flies(monster_class))
+ && (actual_grid == DNGN_LAVA
+ || actual_grid == DNGN_DEEP_WATER))
+
+ // Amphibious critters are happy in the water.
+ || (mons_class_flag(monster_class, M_AMPHIBIOUS)
+ && grid_compatible(DNGN_DEEP_WATER, actual_grid))
+
+ // And water elementals are native to the water but happy on land
+ // as well.
+ || (monster_class == MONS_WATER_ELEMENTAL
+ && grid_compatible(DNGN_FLOOR, actual_grid)));
+}
+
+// Returns true if the monster is floundering in water and susceptible to
+// extra damage from water-natives.
+bool monster_floundering(const monsters *m)
+{
+ const int grid = grd[m->x][m->y];
+ return ((grid == DNGN_DEEP_WATER || grid == DNGN_SHALLOW_WATER)
+ // Can't use monster_habitable_grid because that'll return true
+ // for non-water monsters in shallow water.
+ && monster_habitat(m->type) != DNGN_DEEP_WATER
+ && !mons_class_flag(m->type, M_AMPHIBIOUS)
+ && !mons_flies(m));
+}
+
+// Returns the grid type that a monster can submerge in, or -1 if the monster
+// is incapable of submerging.
+int monster_submersible_grid(int monster_class)
+{
+ switch (monster_class)
+ {
+ case MONS_BIG_FISH:
+ case MONS_GIANT_GOLDFISH:
+ case MONS_ELECTRICAL_EEL:
+ case MONS_JELLYFISH:
+ case MONS_WATER_ELEMENTAL:
+ case MONS_SWAMP_WORM:
+ return (DNGN_DEEP_WATER);
+
+ case MONS_LAVA_WORM:
+ case MONS_LAVA_FISH:
+ case MONS_LAVA_SNAKE:
+ case MONS_SALAMANDER:
+ return (DNGN_LAVA);
+
+ default:
+ // [dshaligram] Not exactly a safe sentinel with all the int -> char
+ // -> unsigned char mayhem going around, but it should be sufficient
+ // for now.
+ return (-1);
+ }
+}
+
bool place_monster(int &id, int mon_type, int power, char behaviour,
int target, bool summoned, int px, int py, bool allow_bands,
int proximity, int extra, int dur)
@@ -224,18 +319,10 @@ bool place_monster(int &id, int mon_type, int power, char behaviour,
continue;
}
- // compatible - floor?
- if (grid_wanted == DNGN_FLOOR && grd[px][py] < DNGN_FLOOR)
+ // Is the monster happy where we want to put it?
+ if (!grid_compatible(grid_wanted, grd[px][py], true))
continue;
- // compatible - others (must match, except for deep water monsters
- // generated in shallow water)
- if ((grid_wanted != DNGN_FLOOR && grd[px][py] != grid_wanted)
- && (grid_wanted != DNGN_DEEP_WATER || grd[px][py] != DNGN_SHALLOW_WATER))
- {
- continue;
- }
-
// don't generate monsters on top of teleport traps
// (how did they get there?)
int trap = trap_at_xy(px, py);
@@ -366,7 +453,7 @@ static int place_monster_aux( int mon_type, char behaviour, int target,
bool first_band_member, int dur )
{
int id, i;
- char grid_wanted;
+ unsigned char grid_wanted;
int fx=0, fy=0; // final x,y
// gotta be able to pick an ID
@@ -407,14 +494,7 @@ static int place_monster_aux( int mon_type, char behaviour, int target,
if (mgrd[fx][fy] != NON_MONSTER)
continue;
- // compatible - floor?
- if (grid_wanted == DNGN_FLOOR && grd[fx][fy] < DNGN_FLOOR)
- continue;
-
- // compatible - others (must match, except for deep water monsters
- // generated in shallow water)
- if ((grid_wanted != DNGN_FLOOR && grd[fx][fy] != grid_wanted)
- && (grid_wanted != DNGN_DEEP_WATER || grd[fx][fy] != DNGN_SHALLOW_WATER))
+ if (!grid_compatible(grid_wanted, grd[fx][fy], true))
continue;
// don't generate monsters on top of teleport traps
@@ -486,28 +566,10 @@ static int place_monster_aux( int mon_type, char behaviour, int target,
menv[id].flags |= MF_BATTY;
}
- if ((mon_type == MONS_BIG_FISH
- || mon_type == MONS_GIANT_GOLDFISH
- || mon_type == MONS_ELECTRICAL_EEL
- || mon_type == MONS_JELLYFISH
- || mon_type == MONS_WATER_ELEMENTAL
- || mon_type == MONS_SWAMP_WORM)
- && grd[fx][fy] == DNGN_DEEP_WATER
- && !one_chance_in(5))
- {
+ if (monster_submersible_grid(mon_type) == grd[fx][fy]
+ && !one_chance_in(5))
mons_add_ench( &menv[id], ENCH_SUBMERGED );
- }
-
- if ((mon_type == MONS_LAVA_WORM
- || mon_type == MONS_LAVA_FISH
- || mon_type == MONS_LAVA_SNAKE
- || mon_type == MONS_SALAMANDER)
- && grd[fx][fy] == DNGN_LAVA
- && !one_chance_in(5))
- {
- mons_add_ench( &menv[id], ENCH_SUBMERGED );
- }
-
+
menv[id].flags |= MF_JUST_SUMMONED;
if (mon_type == MONS_DANCING_WEAPON && extra != 1) // ie not from spell
@@ -1241,25 +1303,41 @@ int mons_place( int mon_type, char behaviour, int target, bool summoned,
return (mid);
} // end mons_place()
-
-int create_monster( int cls, int dur, int beha, int cr_x, int cr_y,
- int hitting, int zsec, bool permit_bands )
+coord_def find_newmons_square(int mons_class, int x, int y)
{
- int summd = -1;
FixedVector < char, 2 > empty;
-
- unsigned char spcw = ((cls == RANDOM_MONSTER) ? DNGN_FLOOR
- : monster_habitat( cls ));
+ coord_def pos = { -1, -1 };
empty[0] = 0;
empty[1] = 0;
+ if (mons_class == WANDERING_MONSTER)
+ mons_class = RANDOM_MONSTER;
+
+ int spcw = ((mons_class == RANDOM_MONSTER)? DNGN_FLOOR
+ : monster_habitat( mons_class ));
+
// Might be better if we chose a space and tried to match the monster
// to it in the case of RANDOM_MONSTER, that way if the target square
// is surrounded by water of lava this function would work. -- bwr
- if (empty_surrounds( cr_x, cr_y, spcw, true, empty ))
+ if (empty_surrounds( x, y, spcw, true, empty ))
+ {
+ pos.x = empty[0];
+ pos.y = empty[1];
+ }
+
+ return (pos);
+}
+
+int create_monster( int cls, int dur, int beha, int cr_x, int cr_y,
+ int hitting, int zsec, bool permit_bands )
+{
+ int summd = -1;
+ coord_def pos = find_newmons_square(cls, cr_x, cr_y);
+
+ if (pos.x != -1 && pos.y != -1)
{
- summd = mons_place( cls, beha, hitting, true, empty[0], empty[1],
+ summd = mons_place( cls, beha, hitting, true, pos.x, pos.y,
you.level_type, 0, zsec, dur, permit_bands );
}
@@ -1350,12 +1428,7 @@ bool empty_surrounds(int emx, int emy, unsigned char spc_wanted,
if (grd[tx][ty] == spc_wanted)
success = true;
- // those seeking ground can stand in shallow water or better
- if (spc_wanted == DNGN_FLOOR && grd[tx][ty] >= DNGN_SHALLOW_WATER)
- success = true;
-
- // water monsters can be created in shallow as well as deep water
- if (spc_wanted == DNGN_DEEP_WATER && grd[tx][ty] == DNGN_SHALLOW_WATER)
+ if (grid_compatible(spc_wanted, grd[tx][ty]))
success = true;
if (success)
diff --git a/crawl-ref/source/monplace.h b/crawl-ref/source/monplace.h
index a3c2aa7a2c..7e3f2c8733 100644
--- a/crawl-ref/source/monplace.h
+++ b/crawl-ref/source/monplace.h
@@ -87,4 +87,11 @@ monster_type rand_dragon( dragon_class_type type );
void mark_interesting_monst(struct monsters* monster,
char behaviour = BEH_SLEEP);
+bool grid_compatible(int grid_wanted, int actual_grid, bool generation = false);
+bool monster_habitable_grid(int monster_class, int actual_grid,
+ bool flies = false);
+bool monster_habitable_grid(const monsters *m, int actual_grid);
+bool monster_floundering(const monsters *m);
+int monster_submersible_grid(int monster_class);
+
#endif // MONPLACE_H
diff --git a/crawl-ref/source/monstuff.cc b/crawl-ref/source/monstuff.cc
index 92bf884a85..d306f3a745 100644
--- a/crawl-ref/source/monstuff.cc
+++ b/crawl-ref/source/monstuff.cc
@@ -909,30 +909,8 @@ static bool valid_morph( struct monsters *monster, int new_mclass )
return (false);
}
- /* Not fair to instakill a monster like this --
- order of evaluation of inner conditional important */
- if (current_tile == DNGN_LAVA || current_tile == DNGN_DEEP_WATER)
- {
- if (!mons_class_flies(new_mclass)
- || monster_habitat(new_mclass) != current_tile)
- {
- return (false);
- }
- }
-
- // not fair to strand a water monster on dry land, either. :)
- if (monster_habitat(new_mclass) == DNGN_DEEP_WATER
- && current_tile != DNGN_DEEP_WATER
- && current_tile != DNGN_SHALLOW_WATER)
- {
- return (false);
- }
-
- // and putting lava monsters on non-lava sqaures is a no-no, too
- if (monster_habitat(new_mclass) == DNGN_LAVA && current_tile != DNGN_LAVA)
- return (false);
-
- return (true);
+ // Determine if the monster is happy on current tile
+ return (monster_habitable_grid(new_mclass, current_tile));
} // end valid_morph()
// note that power is (as of yet) unused within this function -
@@ -958,9 +936,11 @@ bool monster_polymorph( struct monsters *monster, int targetc, int power )
{
do
{
- targetc = random2( NUM_MONSTERS );
+ // Pick a monster that's guaranteed happy at this grid
+ targetc = random_monster_at_grid(monster->x, monster->y);
- // valid targets are always base classes
+ // valid targets are always base classes ([ds] which is unfortunate
+ // in that well-populated monster classes will dominate polymorphs)
targetc = mons_species( targetc );
target_power = mons_power( targetc );
@@ -1119,45 +1099,7 @@ bool random_near_space(int ox, int oy, int &tx, int &ty, bool allow_adjacent,
static bool habitat_okay( struct monsters *monster, int targ )
{
- bool ret = false;
- const int habitat = monster_habitat( monster->type );
-
- if (mons_flies( monster ))
- {
- // flying monsters don't care
- ret = true;
- }
- else if (mons_class_flag( monster->type, M_AMPHIBIOUS )
- && (targ == DNGN_DEEP_WATER || targ == DNGN_SHALLOW_WATER))
- {
- // Amphibious creatures are "land" by default in mon-data,
- // we allow them to swim here. -- bwr
- ret = true;
- }
- else if (monster->type == MONS_WATER_ELEMENTAL && targ >= DNGN_DEEP_WATER)
- {
- // water elementals can crawl out over the land
- ret = true;
- }
- else if (habitat == DNGN_FLOOR
- && (targ >= DNGN_FLOOR || targ == DNGN_SHALLOW_WATER))
- {
- // FLOOR habitat monster going to a non-bad place
- ret = true;
- }
- else if (habitat == DNGN_DEEP_WATER
- && (targ == DNGN_DEEP_WATER || targ == DNGN_SHALLOW_WATER))
- {
- // Water monster to water
- ret = true;
- }
- else if (habitat == DNGN_LAVA && targ == DNGN_LAVA)
- {
- // Lava monster to lava
- ret = true;
- }
-
- return (ret);
+ return (monster_habitable_grid(monster, targ));
}
// This doesn't really swap places, it just sets the monster's
@@ -4387,12 +4329,11 @@ static void monster_move(struct monsters *monster)
for (count_y = 0; count_y < 3; count_y++)
{
good_move[count_x][count_y] = true;
+
const int targ_x = monster->x + count_x - 1;
const int targ_y = monster->y + count_y - 1;
- int target_grid = grd[targ_x][targ_y];
-
- const int targ_cloud = env.cgrid[ targ_x ][ targ_y ];
- const int curr_cloud = env.cgrid[ monster->x ][ monster->y ];
+ // [ds] Bounds check was after grd[targ_x][targ_y] which would
+ // trigger an ASSERT. Moved it up.
// bounds check - don't consider moving out of grid!
if (targ_x < 0 || targ_x >= GXM || targ_y < 0 || targ_y >= GYM)
@@ -4401,6 +4342,18 @@ static void monster_move(struct monsters *monster)
continue;
}
+ int target_grid = grd[targ_x][targ_y];
+
+ const int targ_cloud_num = env.cgrid[ targ_x ][ targ_y ];
+ const int targ_cloud_type =
+ targ_cloud_num == EMPTY_CLOUD? CLOUD_NONE
+ : env.cloud[targ_cloud_num].type;
+
+ const int curr_cloud_num = env.cgrid[ monster->x ][ monster->y ];
+ const int curr_cloud_type =
+ curr_cloud_num == EMPTY_CLOUD? CLOUD_NONE
+ : env.cloud[curr_cloud_num].type;
+
if (target_grid == DNGN_DEEP_WATER)
deep_water_available = true;
@@ -4443,10 +4396,10 @@ static void monster_move(struct monsters *monster)
// Water elementals avoid fire and heat
if (monster->type == MONS_WATER_ELEMENTAL
&& (target_grid == DNGN_LAVA
- || targ_cloud == CLOUD_FIRE
- || targ_cloud == CLOUD_FIRE_MON
- || targ_cloud == CLOUD_STEAM
- || targ_cloud == CLOUD_STEAM_MON))
+ || targ_cloud_type == CLOUD_FIRE
+ || targ_cloud_type == CLOUD_FIRE_MON
+ || targ_cloud_type == CLOUD_STEAM
+ || targ_cloud_type == CLOUD_STEAM_MON))
{
good_move[count_x][count_y] = false;
continue;
@@ -4457,8 +4410,8 @@ static void monster_move(struct monsters *monster)
&& (target_grid == DNGN_DEEP_WATER
|| target_grid == DNGN_SHALLOW_WATER
|| target_grid == DNGN_BLUE_FOUNTAIN
- || targ_cloud == CLOUD_COLD
- || targ_cloud == CLOUD_COLD_MON))
+ || targ_cloud_type == CLOUD_COLD
+ || targ_cloud_type == CLOUD_COLD_MON))
{
good_move[count_x][count_y] = false;
continue;
@@ -4466,12 +4419,14 @@ static void monster_move(struct monsters *monster)
// Submerged water creatures avoid the shallows where
// they would be forced to surface. -- bwr
+ // [dshaligram] Monsters now prefer to head for deep water only if
+ // they're low on hitpoints. No point in hiding if they want a
+ // fight.
if (habitat == DNGN_DEEP_WATER
&& (targ_x != you.x_pos || targ_y != you.y_pos)
&& target_grid != DNGN_DEEP_WATER
&& grd[monster->x][monster->y] == DNGN_DEEP_WATER
- && (mons_has_ench( monster, ENCH_SUBMERGED )
- || monster->hit_points < (monster->max_hit_points * 3) / 4))
+ && monster->hit_points < (monster->max_hit_points * 3) / 4)
{
good_move[count_x][count_y] = false;
continue;
@@ -4509,15 +4464,15 @@ static void monster_move(struct monsters *monster)
}
}
- if (targ_cloud != EMPTY_CLOUD)
+ if (targ_cloud_num != EMPTY_CLOUD)
{
- if (curr_cloud != EMPTY_CLOUD
- && env.cloud[targ_cloud].type == env.cloud[curr_cloud].type)
+ if (curr_cloud_num != EMPTY_CLOUD
+ && targ_cloud_type == curr_cloud_type)
{
continue;
}
- switch (env.cloud[ targ_cloud ].type)
+ switch (targ_cloud_type)
{
case CLOUD_FIRE:
case CLOUD_FIRE_MON:
@@ -4621,14 +4576,16 @@ static void monster_move(struct monsters *monster)
} // done door-eating jellies
- // water creatures have a preferance for water they can hide in -- bwr
+ // water creatures have a preference for water they can hide in -- bwr
+ // [ds] Weakened the powerful attraction to deep water if the monster
+ // is in good health.
if (habitat == DNGN_DEEP_WATER
&& deep_water_available
&& grd[monster->x][monster->y] != DNGN_DEEP_WATER
&& grd[monster->x + mmov_x][monster->y + mmov_y] != DNGN_DEEP_WATER
&& (monster->x + mmov_x != you.x_pos
|| monster->y + mmov_y != you.y_pos)
- && (coinflip()
+ && (one_chance_in(3)
|| monster->hit_points <= (monster->max_hit_points * 3) / 4))
{
count = 0;
diff --git a/crawl-ref/source/mstuff2.cc b/crawl-ref/source/mstuff2.cc
index 87b0269166..e5abcd061a 100644
--- a/crawl-ref/source/mstuff2.cc
+++ b/crawl-ref/source/mstuff2.cc
@@ -736,8 +736,6 @@ void monster_teleport(struct monsters *monster, bool instan)
// pick the monster up
mgrd[monster->x][monster->y] = NON_MONSTER;
- char ogrid = monster_habitat(monster->type);
-
int newx, newy;
while(true)
{
@@ -748,12 +746,7 @@ void monster_teleport(struct monsters *monster, bool instan)
if (mgrd[newx][newy] != NON_MONSTER)
continue;
- // monsters going to the same habitat
- if (ogrid == grd[newx][newy])
- break;
-
- // DEEP_WATER monsters can be teleported to SHALLOW_WATER
- if (ogrid == DNGN_DEEP_WATER && grd[newx][newy] == DNGN_SHALLOW_WATER)
+ if (monster_habitable_grid(monster, grd[newx][newy]))
break;
}
diff --git a/crawl-ref/source/spells3.cc b/crawl-ref/source/spells3.cc
index 30c4957f9a..157547eb5f 100644
--- a/crawl-ref/source/spells3.cc
+++ b/crawl-ref/source/spells3.cc
@@ -927,7 +927,7 @@ bool recall(char type_recalled)
if (!mons_friendly(monster))
continue;
- if (monster_habitat(monster->type) != DNGN_FLOOR)
+ if (!monster_habitable_grid(monster, DNGN_FLOOR))
continue;
if (type_recalled == 1)
diff --git a/crawl-ref/source/stuff.cc b/crawl-ref/source/stuff.cc
index 69ea936eee..7384bbc902 100644
--- a/crawl-ref/source/stuff.cc
+++ b/crawl-ref/source/stuff.cc
@@ -15,6 +15,7 @@
#include "AppHdr.h"
#include "direct.h"
+#include "monplace.h"
#include "stuff.h"
#include "view.h"
@@ -136,7 +137,7 @@ void tag_followers( void )
continue;
}
- if (monster_habitat(fmenv->type) != DNGN_FLOOR)
+ if (!monster_habitable_grid(fmenv, DNGN_FLOOR))
continue;
if (fmenv->speed_increment < 50)