summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorj-p-e-g <j-p-e-g@c06c8d41-db1a-0410-9941-cceddc491573>2008-05-29 21:53:19 +0000
committerj-p-e-g <j-p-e-g@c06c8d41-db1a-0410-9941-cceddc491573>2008-05-29 21:53:19 +0000
commitc7d7127e04437181a909dc4c7bbbc5e408e7f798 (patch)
treea2c99f92832734172185bd78d359ebad2875a036
parentbfed89c67c7d64c104481af653aa8082470a5151 (diff)
downloadcrawl-ref-c7d7127e04437181a909dc4c7bbbc5e408e7f798.tar.gz
crawl-ref-c7d7127e04437181a909dc4c7bbbc5e408e7f798.zip
Diversify patrol behaviour for monsters of different intelligence.
* I_NORMAL, I_HIGH: as before * I_ANIMAL: try to only move within LOS of the patrol point * I_INSECT: as animal, but patrol radius is 5 * I_PLANT : patrol radius is also 5, but there are some other differences: If the patrol point gets out of sight, zombies don't even attempt to get back. Instead they become confused (not literally, though) and reset their patrol point to 0 (if hostile, thus stop patrolling) or to their current position (to continue "waiting" if friendly). Also, while patrolling, if they reach their target there's a 50% chance of not moving this turn, and 50% the next turn, etc. Especially the latter needs testing. If it looks *too* stupid even for zombies I'll take it out again. These changes should also help to make patrolling a bit more efficient because for stupid monsters we have: - one los calculation instead of two (patrol point, monster) - smaller radius - no calculation at all if success is unlikely (distance check) git-svn-id: https://crawl-ref.svn.sourceforge.net/svnroot/crawl-ref/trunk@5335 c06c8d41-db1a-0410-9941-cceddc491573
-rw-r--r--crawl-ref/source/dat/database/monspeak.txt4
-rw-r--r--crawl-ref/source/monstuff.cc110
-rw-r--r--crawl-ref/source/view.cc97
-rw-r--r--crawl-ref/source/view.h4
4 files changed, 151 insertions, 64 deletions
diff --git a/crawl-ref/source/dat/database/monspeak.txt b/crawl-ref/source/dat/database/monspeak.txt
index f0aa07a662..1229f1ca45 100644
--- a/crawl-ref/source/dat/database/monspeak.txt
+++ b/crawl-ref/source/dat/database/monspeak.txt
@@ -2183,7 +2183,7 @@ VISUAL:@The_monster@ stares at you quizzically.
friendly related beogh orc
# As they'll be constantly around you, don't let them talk too much.
-w:45
+w:80
__NONE
# general friendly speech
@@ -2193,7 +2193,7 @@ w:1
w:2
@_generic_orc_speech_@
-w:7
+w:12
@_friendly_beogh_speech_@
%%%%
diff --git a/crawl-ref/source/monstuff.cc b/crawl-ref/source/monstuff.cc
index 07c83a8bcc..7973e56655 100644
--- a/crawl-ref/source/monstuff.cc
+++ b/crawl-ref/source/monstuff.cc
@@ -2155,24 +2155,59 @@ void behaviour_event( monsters *mon, int event, int src,
static bool _choose_random_patrol_target_grid(monsters *mon)
{
- int patrol_x = mon->patrol_point.x;
- int patrol_y = mon->patrol_point.y;
+ const int intel = mons_intel(mon->type);
+
+ // Zombies will occasionally just stand around.
+ // This does not mean that they don't move every second turn. Rather,
+ // once they reach their chosen target, there's a 50% chance they'll
+ // just remain there until next turn when this function is called
+ // again.
+ if (intel == I_PLANT && coinflip())
+ return (true);
- monster_los lm;
- lm.set_monster(mon);
- lm.fill_los_field();
- bool patrol_seen = lm.in_sight(patrol_x, patrol_y);
+ const int patrol_x = mon->patrol_point.x;
+ const int patrol_y = mon->patrol_point.y;
+
+ // If there's no chance we'll find the patrol point, quit right away.
+ if (grid_distance(mon->x, mon->y, patrol_x, patrol_y) > 2*LOS_RADIUS)
+ return (false);
+
+ const bool patrol_seen = mon->mon_see_grid(patrol_x, patrol_y,
+ habitat2grid(mons_habitat(mon)));
+
+ if (intel == I_PLANT && !patrol_seen)
+ {
+ // Really stupid monsters won't even try to get back into the
+ // patrol zone.
+ return (false);
+ }
+
+ // While the patrol point is in easy reach, monsters of insect/plant
+ // intelligence will only use a range of 5 (distance from the patrol point).
+ // Otherwise, try to get back using the full LOS.
+ const int rad = (intel >= I_ANIMAL || !patrol_seen)? LOS_RADIUS : 5;
+ const bool is_smart = (intel >= I_NORMAL);
monster_los patrol;
// Set monster to make monster_los respect habitat restrictions.
patrol.set_monster(mon);
patrol.set_los_centre(patrol_x, patrol_y);
+ patrol.set_los_range(rad);
patrol.fill_los_field();
+ monster_los lm;
+ if (is_smart || !patrol_seen)
+ {
+ // For stupid monsters, don't bother if the patrol point is in sight.
+ lm.set_monster(mon);
+ lm.fill_los_field();
+ }
+
int pos_x, pos_y;
int count_grids = 0;
+ bool set_target = false;
for (int j = -LOS_RADIUS; j < LOS_RADIUS; j++)
- for (int k = -LOS_RADIUS; k < LOS_RADIUS; k++)
+ for (int k = -LOS_RADIUS; k < LOS_RADIUS; k++, set_target = false)
{
pos_x = patrol_x + j;
pos_y = patrol_y + k;
@@ -2202,13 +2237,15 @@ static bool _choose_random_patrol_target_grid(monsters *mon)
// from the current position, it suffices if the target is
// within reach of the patrol point OR the current position:
// we can easily get there.
- // Note: This can take us into a position where the target
- // cannot be easily reached (e.g. blocked by a wall) and the
- // patrol point is out of sight, too. Such a case will be
- // handled below, though it might take a while until a monster
- // gets out of a deadlock.
+ // Only smart monsters will even attempt to move out of the
+ // patrol area.
+ // NOTE: Either of these can take us into a position where the
+ // target cannot be easily reached (e.g. blocked by a wall)
+ // and the patrol point is out of sight, too. Such a case
+ // will be handled below, though it might take a while until
+ // a monster gets out of a deadlock. (5% chance per turn.)
if (!patrol.in_sight(pos_x, pos_y)
- && !lm.in_sight(pos_x, pos_y))
+ && (!is_smart || !lm.in_sight(pos_x, pos_y)))
{
continue;
}
@@ -2229,7 +2266,17 @@ static bool _choose_random_patrol_target_grid(monsters *mon)
// the patrol point.
}
- if (one_chance_in(++count_grids))
+ if (intel == I_PLANT && pos_x == patrol_x && pos_y == patrol_y)
+ {
+ // Slightly greater chance to simply head for the centre.
+ count_grids += 3;
+ if (random2(count_grids) < 3)
+ set_target = true;
+ }
+ else if (one_chance_in(++count_grids))
+ set_target = true;
+
+ if (set_target)
{
mon->target_x = pos_x;
mon->target_y = pos_y;
@@ -2577,9 +2624,38 @@ static void _handle_behaviour(monsters *mon)
{
// If we couldn't find a target that is within easy
// reach of the monster and close to the patrol point,
- // it's time to head back.
- mon->target_x = mon->patrol_point.x;
- mon->target_y = mon->patrol_point.y;
+ // do one of the following:
+ // * set current position as new patrol point
+ // * forget about patrolling
+ // * head back to patrol point
+
+ if (mons_intel(mon->type) == I_PLANT)
+ {
+ // Really stupid monsters forget where they're
+ // supposed to be.
+ if (mons_friendly(mon))
+ {
+ // Your ally was told to wait, and wait it will!
+ // (Though possibly not where you told it to.)
+ mon->patrol_point = coord_def(mon->x, mon->y);
+ }
+ else
+ {
+ // Stop patrolling.
+ mon->patrol_point = coord_def(0, 0);
+ }
+ }
+ else
+ {
+ // It's time to head back!
+ // Ideally, smart monsters should be able to use
+ // pathfinding to find the way back, and animals
+ // could decide to stop patrolling if the path
+ // was too long.
+
+ mon->target_x = mon->patrol_point.x;
+ mon->target_y = mon->patrol_point.y;
+ }
}
}
else
diff --git a/crawl-ref/source/view.cc b/crawl-ref/source/view.cc
index 1ad9934809..801be16f2a 100644
--- a/crawl-ref/source/view.cc
+++ b/crawl-ref/source/view.cc
@@ -5300,7 +5300,7 @@ void handle_terminal_resize(bool redraw)
// monster_los
monster_los::monster_los()
- : gridx(0), gridy(0), mons(), los_field()
+ : gridx(0), gridy(0), mons(), range(LOS_RADIUS), los_field()
{
}
@@ -5308,6 +5308,30 @@ monster_los::~monster_los()
{
}
+void monster_los::set_monster(monsters *mon)
+{
+ mons = mon;
+ if (gridx != mons->x)
+ gridx = mons->x;
+ if (gridy != mons->y)
+ gridy = mons->y;
+}
+
+void monster_los::set_los_centre(int x, int y)
+{
+ if (!in_bounds(x, y))
+ return;
+
+ gridx = x;
+ gridy = y;
+}
+
+void monster_los::set_los_range(int r)
+{
+ ASSERT (r >= 1 && r <= LOS_RADIUS);
+ range = r;
+}
+
coord_def monster_los::pos_to_index(coord_def &p)
{
int ix = LOS_RADIUS + p.x - gridx;
@@ -5384,28 +5408,10 @@ static bool _blocks_movement_sight(monsters *mon, dungeon_feature_type feat)
return (false);
}
-void monster_los::set_monster(monsters *mon)
-{
- mons = mon;
- if (gridx != mons->x)
- gridx = mons->x;
- if (gridy != mons->y)
- gridy = mons->y;
-}
-
-void monster_los::set_los_centre(int x, int y)
-{
- if (!in_bounds(x, y))
- return;
-
- gridx = x;
- gridy = y;
-}
-
void monster_los::fill_los_field()
{
int pos_x, pos_y;
- for (int k = 1; k <= LOS_RADIUS; k++)
+ for (int k = 1; k <= range; k++)
for (int i = -1; i <= 1; i++)
for (int j = -1; j <= 1; j++)
{
@@ -5434,7 +5440,8 @@ void monster_los::fill_los_field()
// target1 and target2 are targets we'll be aiming *at* to fire through (dx,dy)
static bool _set_beam_target(int cx, int cy, int dx, int dy,
int &target1_x, int &target1_y,
- int &target2_x, int &target2_y)
+ int &target2_x, int &target2_y,
+ int range)
{
const int xdist = dx - cx;
const int ydist = dy - cy;
@@ -5442,8 +5449,8 @@ static bool _set_beam_target(int cx, int cy, int dx, int dy,
if (xdist == 0 && ydist == 0)
return (false); // Nothing to be done.
- if (xdist <= -LOS_RADIUS || xdist >= LOS_RADIUS
- || ydist <= -LOS_RADIUS || ydist >= LOS_RADIUS)
+ if (xdist <= -range || xdist >= range
+ || ydist <= -range || ydist >= range)
{
// Grids on the edge of a monster's LOS don't block sight any further.
return (false);
@@ -5475,16 +5482,16 @@ static bool _set_beam_target(int cx, int cy, int dx, int dy,
if (xdist == 0)
{
target1_x = cx;
- target1_y = (ydist > 0 ? cy + LOS_RADIUS
- : cy - LOS_RADIUS);
+ target1_y = (ydist > 0 ? cy + range
+ : cy - range);
target2_x = target1_x;
target2_y = target1_y;
}
else if (ydist == 0)
{
- target1_x = (xdist > 0 ? cx + LOS_RADIUS
- : cx - LOS_RADIUS);
+ target1_x = (xdist > 0 ? cx + range
+ : cx - range);
target1_y = cy;
target2_x = target1_x;
@@ -5494,13 +5501,13 @@ static bool _set_beam_target(int cx, int cy, int dx, int dy,
{
if (xdist < 0)
{
- target1_x = cx - LOS_RADIUS;
- target1_y = cy - LOS_RADIUS;
+ target1_x = cx - range;
+ target1_y = cy - range;
}
else
{
- target1_x = cx + LOS_RADIUS;
- target1_y = cy + LOS_RADIUS;
+ target1_x = cx + range;
+ target1_y = cy + range;
}
if (xdist == ydist)
@@ -5515,11 +5522,11 @@ static bool _set_beam_target(int cx, int cy, int dx, int dy,
if (dx > dy)
{
target2_x = dx;
- target2_y = cy - LOS_RADIUS;
+ target2_y = cy - range;
}
else
{
- target2_x = cx - LOS_RADIUS;
+ target2_x = cx - range;
target2_y = dy;
}
}
@@ -5527,13 +5534,13 @@ static bool _set_beam_target(int cx, int cy, int dx, int dy,
{
if (dx > dy)
{
- target2_x = cx + LOS_RADIUS;
+ target2_x = cx + range;
target2_y = dy;
}
else
{
target2_x = dx;
- target2_y = cy + LOS_RADIUS;
+ target2_y = cy + range;
}
}
}
@@ -5542,13 +5549,13 @@ static bool _set_beam_target(int cx, int cy, int dx, int dy,
{
if (xdist < 0) // lower left corner
{
- target1_x = cx - LOS_RADIUS;
- target1_y = cy + LOS_RADIUS;
+ target1_x = cx - range;
+ target1_y = cy + range;
}
else // upper right corner
{
- target1_x = cx + LOS_RADIUS;
- target1_y = cy - LOS_RADIUS;
+ target1_x = cx + range;
+ target1_y = cy - range;
}
if (xdist == -ydist)
@@ -5562,13 +5569,13 @@ static bool _set_beam_target(int cx, int cy, int dx, int dy,
{
if (-xdist > ydist)
{
- target2_x = cx - LOS_RADIUS;
+ target2_x = cx - range;
target2_y = dy;
}
else
{
target2_x = dx;
- target2_y = cy + LOS_RADIUS;
+ target2_y = cy + range;
}
}
else // xdist > 0, ydist < 0
@@ -5576,11 +5583,11 @@ static bool _set_beam_target(int cx, int cy, int dx, int dy,
if (-xdist > ydist)
{
target2_x = dx;
- target2_y = cy - LOS_RADIUS;
+ target2_y = cy - range;
}
else
{
- target2_x = cx + LOS_RADIUS;
+ target2_x = cx + range;
target2_y = dy;
}
}
@@ -5601,7 +5608,7 @@ void monster_los::check_los_beam(int dx, int dy)
int target1_x = 0, target1_y = 0, target2_x = 0, target2_y = 0;
if (!_set_beam_target(gridx, gridy, dx, dy, target1_x, target1_y,
- target2_x, target2_y))
+ target2_x, target2_y, range))
{
// Nothing to be done.
return;
@@ -5619,7 +5626,7 @@ void monster_los::check_los_beam(int dx, int dy)
target2_y = help;
}
- const int max_dist = LOS_RADIUS;
+ const int max_dist = range;
int dist;
bool blocked = false;
for (int tx = target1_x; tx <= target2_x; tx++)
diff --git a/crawl-ref/source/view.h b/crawl-ref/source/view.h
index 9994707b12..b2251d13cf 100644
--- a/crawl-ref/source/view.h
+++ b/crawl-ref/source/view.h
@@ -256,6 +256,7 @@ public:
// public methods
void set_monster(monsters *mon);
void set_los_centre(int x, int y);
+ void set_los_range(int r);
void fill_los_field(void);
bool in_sight(int x, int y);
@@ -287,6 +288,9 @@ protected:
// Else, any monster trying to move around within this los field.
monsters *mons;
+ // Range may never be greater than LOS_RADIUS!
+ int range;
+
// The array to store the LOS values.
int los_field[LSIZE][LSIZE];
};