summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--crawl-ref/settings/init.txt6
-rw-r--r--crawl-ref/source/externs.h1
-rw-r--r--crawl-ref/source/items.cc3
-rw-r--r--crawl-ref/source/mon-util.cc6
-rw-r--r--crawl-ref/source/monplace.cc13
-rw-r--r--crawl-ref/source/monplace.h4
-rw-r--r--crawl-ref/source/monstuff.cc272
-rw-r--r--crawl-ref/source/tags.cc8
-rw-r--r--crawl-ref/source/tags.h19
9 files changed, 281 insertions, 51 deletions
diff --git a/crawl-ref/settings/init.txt b/crawl-ref/settings/init.txt
index 7499e48ec6..23938b11d2 100644
--- a/crawl-ref/settings/init.txt
+++ b/crawl-ref/settings/init.txt
@@ -89,11 +89,7 @@ lua_file = lua/pickup.lua
#
##### 4-a Picking up and Dropping ###############
#
-autopickup = $?!+"/%)
-
-# Note that ")" have to be in the above list for pickup.lua
-# (autopickup a butchering tool if you don't already have one)
-# to work.
+autopickup = $?!+"/%
# There is a long list of autopickup exceptions in
include = autopickup_exceptions.txt
diff --git a/crawl-ref/source/externs.h b/crawl-ref/source/externs.h
index 0400009eb0..d3b8a8b7d5 100644
--- a/crawl-ref/source/externs.h
+++ b/crawl-ref/source/externs.h
@@ -1024,6 +1024,7 @@ public:
unsigned char target_x;
unsigned char target_y;
coord_def patrol_point;
+ montravel_target_type travel_target;
std::vector<coord_def> travel_path;
FixedVector<short, NUM_MONSTER_SLOTS> inv;
monster_spells spells;
diff --git a/crawl-ref/source/items.cc b/crawl-ref/source/items.cc
index 354257023a..d4ff6e63fa 100644
--- a/crawl-ref/source/items.cc
+++ b/crawl-ref/source/items.cc
@@ -2247,9 +2247,6 @@ bool item_needs_autopickup(const item_def &item)
std::string itemname;
return ((Options.autopickups & (1L << item.base_type)
-#ifdef CLUA_BINDINGS
- && clua.callbooleanfn(true, "ch_autopickup", "u", &item)
-#endif
&& !is_useless_item(item) && !is_inedible(item)
|| _is_forced_autopickup(item, itemname))
&& (Options.pickup_dropped || !(item.flags & ISFLAG_DROPPED))
diff --git a/crawl-ref/source/mon-util.cc b/crawl-ref/source/mon-util.cc
index 3f5f63340b..68ccf0d090 100644
--- a/crawl-ref/source/mon-util.cc
+++ b/crawl-ref/source/mon-util.cc
@@ -2693,7 +2693,7 @@ bool monster_senior(const monsters *m1, const monsters *m2)
monsters::monsters()
: type(-1), hit_points(0), max_hit_points(0), hit_dice(0),
ac(0), ev(0), speed(0), speed_increment(0), x(0), y(0),
- target_x(0), target_y(0), patrol_point(0, 0),
+ target_x(0), target_y(0), patrol_point(0, 0), travel_target(MTRAV_NONE),
inv(NON_ITEM), spells(), attitude(ATT_HOSTILE), behaviour(BEH_WANDER),
foe(MHITYOU), enchantments(), flags(0L), experience(0), number(0),
colour(BLACK), foe_memory(0), shield_blocks(0), god(GOD_NO_GOD), ghost(),
@@ -2745,7 +2745,8 @@ void monsters::reset()
mgrd[x][y] = NON_MONSTER;
x = y = 0;
- patrol_point = coord_def(0, 0);
+ patrol_point = coord_def(0, 0);
+ travel_target = MTRAV_NONE;
travel_path.clear();
ghost.reset(NULL);
}
@@ -2767,6 +2768,7 @@ void monsters::init_with(const monsters &mon)
target_x = mon.target_x;
target_y = mon.target_y;
patrol_point = mon.patrol_point;
+ travel_target = mon.travel_target;
travel_path = mon.travel_path;
inv = mon.inv;
spells = mon.spells;
diff --git a/crawl-ref/source/monplace.cc b/crawl-ref/source/monplace.cc
index 4a00052e01..438e03b9d2 100644
--- a/crawl-ref/source/monplace.cc
+++ b/crawl-ref/source/monplace.cc
@@ -2297,8 +2297,9 @@ monster_type summon_any_dragon(dragon_class_type dct)
/////////////////////////////////////////////////////////////////////////////
// monster_pathfind
+//#define DEBUG_PATHFIND
monster_pathfind::monster_pathfind()
- : mons(), target(), min_length(0), dist(), prev()
+ : mons(), target(), range(0), min_length(0), max_length(0), dist(), prev()
{
}
@@ -2306,6 +2307,12 @@ monster_pathfind::~monster_pathfind()
{
}
+void monster_pathfind::set_range(int r)
+{
+ if (r >= 0)
+ range = r;
+}
+
// Returns true if a path was found, else false.
bool monster_pathfind::start_pathfind(monsters *mon, coord_def dest, bool msg)
{
@@ -2386,6 +2393,10 @@ bool monster_pathfind::calc_path_to_neighbours()
if (!traversable(npos))
continue;
+ // Ignore this grid if it takes us above the allowed distance.
+ if (range && estimated_cost(npos) > range)
+ continue;
+
distance = dist[pos.x][pos.y] + travel_cost(npos);
old_dist = dist[npos.x][npos.y];
#ifdef DEBUG_PATHFIND
diff --git a/crawl-ref/source/monplace.h b/crawl-ref/source/monplace.h
index 7ff492d728..ddc2d01458 100644
--- a/crawl-ref/source/monplace.h
+++ b/crawl-ref/source/monplace.h
@@ -318,6 +318,7 @@ public:
virtual ~monster_pathfind();
// public methods
+ void set_range(int r);
bool start_pathfind(monsters *mon, coord_def dest, bool msg = false);
std::vector<coord_def> backtrack(void);
std::vector<coord_def> calc_waypoints(void);
@@ -339,6 +340,9 @@ protected:
// Our destination, and the current position we're looking at.
coord_def start, target, pos;
+ // Maximum range to search between start and target. None, if zero.
+ int range;
+
// Currently shortest and longest possible total length of the path.
int min_length;
int max_length;
diff --git a/crawl-ref/source/monstuff.cc b/crawl-ref/source/monstuff.cc
index 09f156a371..fbc9538e1d 100644
--- a/crawl-ref/source/monstuff.cc
+++ b/crawl-ref/source/monstuff.cc
@@ -2321,7 +2321,7 @@ static bool _choose_random_patrol_target_grid(monsters *mon)
return (count_grids);
}
-
+//#define DEBUG_PATHFIND
//---------------------------------------------------------------
//
// handle_behaviour
@@ -2342,6 +2342,8 @@ static void _handle_behaviour(monsters *mon)
bool isNeutral = mons_neutral(mon);
bool wontAttack = mons_wont_attack(mon);
bool proxPlayer = mons_near(mon);
+ bool trans_wall_block = trans_wall_blocking(mon->x, mon->y);
+
#ifdef WIZARD
// If stealth is greater than actually possible (wizmode level)
// pretend the player isn't there, but only for hostile monsters.
@@ -2365,6 +2367,15 @@ static void _handle_behaviour(monsters *mon)
return;
}
+ dungeon_feature_type can_move;
+ if (mons_amphibious(mons_is_zombified(mon) ?
+ mon->base_monster : mon->type))
+ {
+ can_move = DNGN_DEEP_WATER;
+ }
+ else
+ can_move = DNGN_SHALLOW_WATER;
+
// Validate current target exists.
if (mon->foe != MHITNOT && mon->foe != MHITYOU
&& menv[mon->foe].type == -1)
@@ -2454,7 +2465,7 @@ static void _handle_behaviour(monsters *mon)
mon->foe = MHITYOU;
}
- // validate target again
+ // Validate target again.
if (mon->foe != MHITNOT && mon->foe != MHITYOU
&& menv[mon->foe].type == -1)
{
@@ -2473,8 +2484,8 @@ static void _handle_behaviour(monsters *mon)
{
if (mon->foe == MHITYOU)
{
- foe_x = you.x_pos;
- foe_y = you.y_pos;
+ foe_x = you.x_pos;
+ foe_y = you.y_pos;
proxFoe = proxPlayer; // take invis into account
}
else
@@ -2493,7 +2504,7 @@ static void _handle_behaviour(monsters *mon)
beh_type new_beh = mon->behaviour;
unsigned short new_foe = mon->foe;
- // take care of monster state changes
+ // Take care of monster state changes.
switch (mon->behaviour)
{
case BEH_SLEEP:
@@ -2522,6 +2533,17 @@ static void _handle_behaviour(monsters *mon)
// Foe gone out of LOS?
if (!proxFoe)
{
+ if (mon->foe == MHITYOU && travelling
+ && mon->travel_target == MTRAV_PLAYER)
+ {
+#ifdef DEBUG_PATHFIND
+ mpr("Player out of LoS... start wandering.");
+#endif
+ new_beh = BEH_WANDER;
+ // We've got a target, so we'll continue on our way.
+ break;
+ }
+
if (patrolling)
{
new_foe = MHITNOT;
@@ -2550,7 +2572,7 @@ static void _handle_behaviour(monsters *mon)
{
if (mon->foe == MHITYOU)
{
- if (check_awaken(mon))
+ if (random2(you.skills[SK_STEALTH]/3))
{
mon->target_x = you.x_pos;
mon->target_y = you.y_pos;
@@ -2606,6 +2628,147 @@ static void _handle_behaviour(monsters *mon)
// by updating target x,y.
if (mon->foe == MHITYOU)
{
+ if (proxPlayer && !trans_wall_block)
+ {
+ if (travelling && mon->travel_target != MTRAV_PATROL)
+ {
+ mon->travel_path.clear();
+ mon->travel_target = MTRAV_NONE;
+ }
+ }
+ else if (proxPlayer && trans_wall_block
+ && (mon->travel_target != MTRAV_UNREACHABLE
+ || one_chance_in(8)))
+ {
+#ifdef DEBUG_PATHFIND
+ mprf("%s: Player out of reach! What now?",
+ mon->name(DESC_PLAIN).c_str());
+#endif
+ // If we're already on our way, do nothing.
+ if (travelling && mon->travel_target == MTRAV_PLAYER)
+ {
+#ifdef DEBUG_PATHFIND
+ mpr("Already travelling...");
+#endif
+ int len = mon->travel_path.size();
+ coord_def targ = mon->travel_path[len - 1];
+ if (grid_see_grid(targ.x, targ.y, you.x_pos, you.y_pos)
+ && !trans_wall_blocking(targ.x, targ.y))
+ {
+#ifdef DEBUG_PATHFIND
+ mpr("Target still valid...");
+#endif
+ // Current target still valid?
+ if (mon->x == mon->travel_path[0].x
+ && mon->y == mon->travel_path[0].y)
+ {
+ // Get next waypoint.
+ mon->travel_path.erase(
+ mon->travel_path.begin() );
+
+ if (!mon->travel_path.empty())
+ {
+ mon->target_x = mon->travel_path[0].x;
+ mon->target_y = mon->travel_path[0].y;
+ break;
+ }
+ }
+ else if (grid_see_grid(mon->x, mon->y,
+ mon->travel_path[0].x,
+ mon->travel_path[0].y,
+ can_move))
+ {
+ mon->target_x = mon->travel_path[0].x;
+ mon->target_y = mon->travel_path[0].y;
+ break;
+ }
+ }
+ }
+
+ // Use pathfinding to find a (new) path to the player.
+ const int dist = grid_distance(mon->x, mon->y,
+ you.x_pos, you.y_pos);
+
+#ifdef DEBUG_PATHFIND
+ mprf("Need to calculate a path... (dist = %d)", dist);
+#endif
+ const bool native =
+ mons_is_native_in_branch(mon, you.where_are_you);
+
+ int range = 0;
+ switch (mons_intel(mon->type))
+ {
+ case I_PLANT:
+ range = 2;
+ break;
+ case I_INSECT:
+ range = 3;
+ break;
+ case I_ANIMAL:
+ range = 5;
+ break;
+ case I_NORMAL:
+ range = 10;
+ break;
+ default:
+ // Highly intelligent monsters can find their way
+ // anywhere.
+ range = 0;
+ break;
+ }
+
+ if (range && native)
+ range += 3;
+
+ if (range > 0 && dist > range)
+ {
+ mon->travel_target = MTRAV_UNREACHABLE;
+#ifdef DEBUG_PATHFIND
+ mprf("Distance too great, don't attempt pathfinding! (%s)",
+ mon->name(DESC_PLAIN).c_str());
+#endif
+ }
+ else
+ {
+#ifdef DEBUG_PATHFIND
+ mprf("Need a path for %s from (%d, %d) to (%d, %d), "
+ "max. dist = %d",
+ mon->name(DESC_PLAIN).c_str(), mon->x, mon->y,
+ you.x_pos, you.y_pos, range);
+#endif
+ monster_pathfind mp;
+ if (range > 0)
+ mp.set_range(range);
+ if (mp.start_pathfind(mon, coord_def(you.x_pos,
+ you.y_pos)))
+ {
+ mon->travel_path = mp.calc_waypoints();
+ if (!mon->travel_path.empty())
+ {
+ // Okay then, we found a path. Let's use it!
+ mon->target_x = mon->travel_path[0].x;
+ mon->target_y = mon->travel_path[0].y;
+ mon->travel_target = MTRAV_PLAYER;
+ break;
+ }
+ else
+ {
+#ifdef DEBUG_PATHFIND
+ mpr("No path found!");
+#endif
+ mon->travel_target = MTRAV_UNREACHABLE;
+ }
+ }
+ else
+ {
+#ifdef DEBUG_PATHFIND
+ mpr("No path found!");
+#endif
+ mon->travel_target = MTRAV_UNREACHABLE;
+ }
+ }
+ }
+
// Sometimes, your friends will wander a bit.
if (isFriendly && one_chance_in(8))
{
@@ -2651,8 +2814,8 @@ static void _handle_behaviour(monsters *mon)
// wandering monsters at least appear to have some sort of
// attention span. -- bwr
if (mon->x == mon->target_x && mon->y == mon->target_y
- || !travelling && (one_chance_in(20)
- || testbits( mon->flags, MF_BATTY )))
+ || one_chance_in(20)
+ || testbits( mon->flags, MF_BATTY ))
{
bool need_target = true;
if (travelling)
@@ -2666,20 +2829,37 @@ static void _handle_behaviour(monsters *mon)
if (mon->x == mon->travel_path[0].x
&& mon->y == mon->travel_path[0].y)
{
+#ifdef DEBUG_PATHFIND
+ mpr("Arrived at first waypoint.");
+#endif
// Hey, we reached our first waypoint!
mon->travel_path.erase( mon->travel_path.begin() );
if (mon->travel_path.empty())
+ {
+#ifdef DEBUG_PATHFIND
+ mpr("We reached the end of our path: stop "
+ "travelling.");
+#endif
+ mon->travel_target = MTRAV_NONE;
need_target = true;
-
- mon->target_x = mon->travel_path[0].x;
- mon->target_y = mon->travel_path[0].y;
+ }
+ else
+ {
+ mon->target_x = mon->travel_path[0].x;
+ mon->target_y = mon->travel_path[0].y;
#ifdef DEBUG_PATHFIND
- mprf("Next waypoint: (%d, %d)",
- mon->target_x, mon->target_y);
+ mprf("Next waypoint: (%d, %d)",
+ mon->target_x, mon->target_y);
#endif
+ }
}
- else
+ else if (!grid_see_grid(mon->x, mon->y,
+ mon->travel_path[0].x,
+ mon->travel_path[0].y, can_move))
{
+#ifdef DEBUG_PATHFIND
+ mpr("Can't see waypoint grid.");
+#endif
// Apparently we got sidetracked a bit.
// Check the waypoints vector backwards and pick the
// first waypoint we can see.
@@ -2688,16 +2868,6 @@ static void _handle_behaviour(monsters *mon)
// thing to do since another path might be even
// *closer* to our actual target now.
- dungeon_feature_type can_move;
- if (mons_amphibious(mons_is_zombified(mon) ?
- mon->base_monster : mon->type))
- {
- can_move = DNGN_DEEP_WATER;
- }
- else
- can_move = DNGN_SHALLOW_WATER;
-
-
int erase = -1; // Erase how many waypoints?
for (unsigned int i = mon->travel_path.size() - 1;
i >= 0; i--)
@@ -2713,8 +2883,12 @@ static void _handle_behaviour(monsters *mon)
}
}
- if (erase != -1)
+ if (erase > 0)
{
+#ifdef DEBUG_PATHFIND
+ mprf("Need to erase %d of %d waypoints.",
+ erase, mon->travel_path.size());
+#endif
// Erase all waypoints that came earlier:
// we don't need them anymore.
while (0 < erase--)
@@ -2727,8 +2901,10 @@ static void _handle_behaviour(monsters *mon)
{
// We can't reach our old path from our current
// position, so calculate a new path instead.
+/*
monster_pathfind mp;
- if (mp.start_pathfind(mon, mon->patrol_point, true))
+ int len = mon->travel_path.size();
+ if (mp.start_pathfind(mon, mon->travel_path[len-1]))
{
mon->travel_path = mp.calc_waypoints();
if (!mon->travel_path.empty())
@@ -2736,18 +2912,33 @@ static void _handle_behaviour(monsters *mon)
mon->target_x = mon->travel_path[0].x;
mon->target_y = mon->travel_path[0].y;
}
+ else
+ {
+ mon->travel_target = MTRAV_NONE;
+ need_target = true;
+ }
}
else
{
+*/
+ // Or just forget about the whole thing.
mon->travel_path.clear();
+ mon->travel_target = MTRAV_NONE;
need_target = true;
- }
+// }
}
}
+ else
+ {
+#ifdef DEBUG_PATHFIND
+ mpr("All clear. Continue travelling.");
+#endif
+ }
}
if (need_target && patrolling)
{
+ need_target = false;
if (!_choose_random_patrol_target_grid(mon))
{
// If we couldn't find a target that is within easy
@@ -2771,6 +2962,8 @@ static void _handle_behaviour(monsters *mon)
{
// Stop patrolling.
mon->patrol_point = coord_def(0, 0);
+ mon->travel_target = MTRAV_NONE;
+ need_target = true;
}
}
else
@@ -2781,19 +2974,27 @@ static void _handle_behaviour(monsters *mon)
// could decide to stop patrolling if the path
// was too long.
monster_pathfind mp;
- if (mp.start_pathfind(mon, mon->patrol_point, true))
+ if (mp.start_pathfind(mon, mon->patrol_point))
{
mon->travel_path = mp.calc_waypoints();
if (!mon->travel_path.empty())
{
mon->target_x = mon->travel_path[0].x;
mon->target_y = mon->travel_path[0].y;
+ mon->travel_target = MTRAV_PATROL;
+ }
+ else
+ {
+ mon->target_x = mon->patrol_point.x;
+ mon->target_y = mon->patrol_point.y;
}
}
else
{
// Stop patrolling.
- mon->patrol_point = coord_def(0, 0);
+ mon->patrol_point = coord_def(0, 0);
+ mon->travel_target = MTRAV_NONE;
+ need_target = true;
}
}
}
@@ -2807,7 +3008,8 @@ static void _handle_behaviour(monsters *mon)
#endif
}
}
- else if (need_target)
+
+ if (need_target)
{
#ifdef DEBUG_PATHFIND
if (!testbits( mon->flags, MF_BATTY ))
@@ -2825,11 +3027,19 @@ static void _handle_behaviour(monsters *mon)
&& one_chance_in( isSmart ? 60 : 20 ))
{
new_foe = MHITNOT;
+ if (travelling && mon->travel_target != MTRAV_PATROL)
+ {
+#ifdef DEBUG_PATHFIND
+ mpr("It's been too long! Stop travelling.");
+#endif
+ mon->travel_path.clear();
+ mon->travel_target = MTRAV_NONE;
+ }
}
break;
case BEH_FLEE:
- // check for healed
+ // Check for healed.
if (isHealthy && !isScared)
new_beh = BEH_SEEK;
diff --git a/crawl-ref/source/tags.cc b/crawl-ref/source/tags.cc
index 77f024c952..caa83181df 100644
--- a/crawl-ref/source/tags.cc
+++ b/crawl-ref/source/tags.cc
@@ -1769,6 +1769,8 @@ static void marshall_monster(writer &th, const monsters &m)
marshallByte(th, m.target_x);
marshallByte(th, m.target_y);
marshallCoord(th, m.patrol_point);
+ int help = m.travel_target;
+ marshallByte(th, help);
// monster pathfinding (TAG_MINOR_PATHFIND)
marshallShort(th, m.travel_path.size());
@@ -2040,6 +2042,12 @@ static void unmarshall_monster(reader &th, monsters &m)
if (_tag_minor_version >= TAG_MINOR_MPATROL)
unmarshallCoord(th, m.patrol_point);
+ if (_tag_minor_version >= TAG_MINOR_TRTARGET)
+ {
+ int help = unmarshallByte(th);
+ m.travel_target = static_cast<montravel_target_type>(help);
+ }
+
if (_tag_minor_version >= TAG_MINOR_PATHFIND)
{
const int len = unmarshallShort(th);
diff --git a/crawl-ref/source/tags.h b/crawl-ref/source/tags.h
index 9aea5c2ce1..dfe48b17e6 100644
--- a/crawl-ref/source/tags.h
+++ b/crawl-ref/source/tags.h
@@ -50,15 +50,16 @@ enum tag_major_version
// Minor version will be reset to zero when major version changes.
enum tag_minor_version
{
- TAG_MINOR_PIETY = 2, // Added piety_hysteresis
- TAG_MINOR_QUIVER = 3, // Added quiver
- TAG_MINOR_MAPMARK = 4, // Added sizes to map markers
- TAG_MINOR_MONNAM = 5, // Monsters get individual names
- TAG_MINOR_MONBASE = 6, // Zombie base monster gets its own field.
- TAG_MINOR_FPICKUP = 7, // Added pickup option for allied monsters.
- TAG_MINOR_MPATROL = 8, // Added monster patrol points.
- TAG_MINOR_PATHFIND = 9, // Added monster pathfinding.
- TAG_MINOR_VERSION = 9 // Current version
+ TAG_MINOR_PIETY = 2, // Added piety_hysteresis
+ TAG_MINOR_QUIVER = 3, // Added quiver
+ TAG_MINOR_MAPMARK = 4, // Added sizes to map markers
+ TAG_MINOR_MONNAM = 5, // Monsters get individual names
+ TAG_MINOR_MONBASE = 6, // Zombie base monster gets its own field.
+ TAG_MINOR_FPICKUP = 7, // Added pickup option for allied monsters.
+ TAG_MINOR_MPATROL = 8, // Added monster patrol points.
+ TAG_MINOR_PATHFIND = 9, // Added monster pathfinding.
+ TAG_MINOR_TRTARGET = 10, // Added travel target.
+ TAG_MINOR_VERSION = 10 // Current version
};