summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authordshaligram <dshaligram@c06c8d41-db1a-0410-9941-cceddc491573>2006-09-24 11:14:10 +0000
committerdshaligram <dshaligram@c06c8d41-db1a-0410-9941-cceddc491573>2006-09-24 11:14:10 +0000
commit9b65dce7ed03eaa31d8cbd7d9b055de31ce514f6 (patch)
tree9b03aa7f6adcbdd164cf8a934723d2a3b79f3120
parent6e693b7128114ccf331984c9769becd9f43d7a61 (diff)
downloadcrawl-ref-9b65dce7ed03eaa31d8cbd7d9b055de31ce514f6.tar.gz
crawl-ref-9b65dce7ed03eaa31d8cbd7d9b055de31ce514f6.zip
Fixed water elemental generation/movement bugs.
Cleaned up repeated code that controlled what monsters can move to what kinds of squares. Tweaked monster polymorph so monsters that can survive on the current monster's location are valid targets without having to share the same habitat. git-svn-id: https://crawl-ref.svn.sourceforge.net/svnroot/crawl-ref/branches/stone_soup@101 c06c8d41-db1a-0410-9941-cceddc491573
-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)