diff options
author | j-p-e-g <j-p-e-g@c06c8d41-db1a-0410-9941-cceddc491573> | 2008-05-29 21:53:19 +0000 |
---|---|---|
committer | j-p-e-g <j-p-e-g@c06c8d41-db1a-0410-9941-cceddc491573> | 2008-05-29 21:53:19 +0000 |
commit | c7d7127e04437181a909dc4c7bbbc5e408e7f798 (patch) | |
tree | a2c99f92832734172185bd78d359ebad2875a036 | |
parent | bfed89c67c7d64c104481af653aa8082470a5151 (diff) | |
download | crawl-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.txt | 4 | ||||
-rw-r--r-- | crawl-ref/source/monstuff.cc | 110 | ||||
-rw-r--r-- | crawl-ref/source/view.cc | 97 | ||||
-rw-r--r-- | crawl-ref/source/view.h | 4 |
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]; }; |