summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authordolorous <dolorous@c06c8d41-db1a-0410-9941-cceddc491573>2008-06-17 18:30:45 +0000
committerdolorous <dolorous@c06c8d41-db1a-0410-9941-cceddc491573>2008-06-17 18:30:45 +0000
commit94410e34844eacecadec9c0f3b8e96b2833d16e6 (patch)
tree801d9dfbafb11f404ac732d304923b74a9ed1141
parent73466105efd4afd0b5317668be0109395e931659 (diff)
downloadcrawl-ref-94410e34844eacecadec9c0f3b8e96b2833d16e6.tar.gz
crawl-ref-94410e34844eacecadec9c0f3b8e96b2833d16e6.zip
Add an unfinished attempt at making pacified monsters leave the level.
BEH_LEAVE replaces BEH_INVESTIGATE, which wasn't being used. Notes: Since leaving the level is similar to fleeing in some ways, monsters leaving the level share some behaviors with fleeing monsters: they are less likely to shoot; they are more likely to use scrolls of blinking or teleportation; and leaving eyeballs won't paralyze you or drain your MP. Leaving the level is also similar to lurking in some ways, so it won't be interrupted by noticing something, just as with lurking. Getting far enough away from a monster will make it leave the level (i.e., die with KILL_DISMISSED and MF_HARD_RESET, so it takes its stuff with it), as will getting it into a grid it can submerge in, at which time it will submerge and leave the level. Neither of these apply to monsters that can't move, of course, except for mimics, since they can teleport. Incomplete things (sorry for the mess): I still haven't figured out how to make a monster target a dungeon feature (in this case, the nearest level exit, the nearest teleportation or shaft trap, or the nearest submersible grid), so, currently, a pacified monster will just go to where its last target was and stand there until/unless one of the aforementioned level exit scenarios occurs. Pacified monsters can still cast summoning spells. Whatever they summon is neutral, just as they are, but such summons can still get in the way. (Try pacifying an orc high priest, for example.) Maybe summoning should be disabled or have its chance lowered for neutral monsters in general, unless something's in their way? Speaking of targeting, the leaving-by-submerging scenario should occur only if there's no other way to reach the target: all ways off the level are blocked, the monster's habitat is water and it's not amphibious, the monster's habitat is lava, or (possibly) the monster's habitat is rock. There should be a message if the monster leaves the level, but what about the ones that do so out of the player's LOS? git-svn-id: https://crawl-ref.svn.sourceforge.net/svnroot/crawl-ref/trunk@5924 c06c8d41-db1a-0410-9941-cceddc491573
-rw-r--r--crawl-ref/source/debug.cc2
-rw-r--r--crawl-ref/source/enum.h2
-rw-r--r--crawl-ref/source/mon-util.cc20
-rw-r--r--crawl-ref/source/mon-util.h3
-rw-r--r--crawl-ref/source/monstuff.cc103
5 files changed, 101 insertions, 29 deletions
diff --git a/crawl-ref/source/debug.cc b/crawl-ref/source/debug.cc
index 8296d9e22b..6b51f2ae84 100644
--- a/crawl-ref/source/debug.cc
+++ b/crawl-ref/source/debug.cc
@@ -1768,7 +1768,7 @@ void debug_stethoscope(int mon)
(menv[i].behaviour == BEH_FLEE) ? "flee" :
(menv[i].behaviour == BEH_CORNERED) ? "cornered" :
(menv[i].behaviour == BEH_PANIC) ? "panic" :
- (menv[i].behaviour == BEH_INVESTIGATE) ? "investigate" :
+ (menv[i].behaviour == BEH_LEAVE) ? "leave" :
(menv[i].behaviour == BEH_LURK) ? "lurk"
: "unknown"),
menv[i].behaviour,
diff --git a/crawl-ref/source/enum.h b/crawl-ref/source/enum.h
index abd9e474ee..14581e94a0 100644
--- a/crawl-ref/source/enum.h
+++ b/crawl-ref/source/enum.h
@@ -1872,7 +1872,7 @@ enum beh_type
BEH_FLEE,
BEH_CORNERED,
BEH_PANIC, // like flee but without running away
- BEH_INVESTIGATE, // investigating an ME_DISTURB
+ BEH_LEAVE, // leave the level
BEH_LURK, // stay still until discovered or
// enemy close by
NUM_BEHAVIOURS, // max # of legal states
diff --git a/crawl-ref/source/mon-util.cc b/crawl-ref/source/mon-util.cc
index bc4877f425..ae7ac4af5c 100644
--- a/crawl-ref/source/mon-util.cc
+++ b/crawl-ref/source/mon-util.cc
@@ -425,6 +425,13 @@ bool mons_is_stationary(const monsters *mon)
return mons_class_is_stationary(mon->type);
}
+// Mimics can teleport, so they're not truly stationary.
+// XXX: There should be a more generic way to check for this!
+bool mons_is_truly_stationary(const monsters *mon)
+{
+ return (mons_is_stationary(mon) && !mons_is_mimic(mon->type));
+}
+
bool mons_is_insubstantial(int mc)
{
return mons_class_flag(mc, M_INSUBSTANTIAL);
@@ -2105,6 +2112,11 @@ bool mons_good_neutral(const monsters *m)
return (m->attitude == ATT_GOOD_NEUTRAL);
}
+bool mons_is_pacified(const monsters *m)
+{
+ return (m->attitude == ATT_NEUTRAL && testbits(m->flags, MF_GOT_HALF_XP));
+}
+
bool mons_wont_attack(const monsters *m)
{
return (mons_friendly(m) || mons_good_neutral(m));
@@ -2200,6 +2212,11 @@ bool mons_is_cornered(const monsters *m)
return (m->behaviour == BEH_CORNERED);
}
+bool mons_is_leaving(const monsters *m)
+{
+ return (m->behaviour == BEH_LEAVE);
+}
+
bool mons_is_lurking(const monsters *m)
{
return (m->behaviour == BEH_LURK);
@@ -2252,6 +2269,9 @@ void mons_pacify(monsters *mon)
gain_exp(exper_value(mon) / 2 + 1, &exp_gain, &avail_gain);
mon->flags |= MF_GOT_HALF_XP;
}
+
+ // Make the monster leave the level.
+ behaviour_event(mon, ME_EVAL);
}
bool mons_should_fire(struct bolt &beam)
diff --git a/crawl-ref/source/mon-util.h b/crawl-ref/source/mon-util.h
index 7914e5f360..7b00dee43e 100644
--- a/crawl-ref/source/mon-util.h
+++ b/crawl-ref/source/mon-util.h
@@ -639,6 +639,7 @@ size_type mons_size(const monsters *m);
bool mons_friendly(const monsters *m);
bool mons_neutral(const monsters *m);
bool mons_good_neutral(const monsters *m);
+bool mons_is_pacified(const monsters *m);
bool mons_wont_attack(const monsters *m);
bool mons_att_wont_attack(mon_attitude_type fr);
mon_attitude_type mons_attitude(const monsters *m);
@@ -657,6 +658,7 @@ bool mons_is_seeking(const monsters *m);
bool mons_is_fleeing(const monsters *m);
bool mons_is_panicking(const monsters *m);
bool mons_is_cornered(const monsters *m);
+bool mons_is_leaving(const monsters *m);
bool mons_is_lurking(const monsters *m);
bool mons_is_batty(const monsters *m);
bool mons_was_seen(const monsters *m);
@@ -681,6 +683,7 @@ bool mons_class_is_confusable(int mc);
bool mons_class_is_slowable(int mc);
bool mons_class_is_stationary(int mc);
bool mons_is_stationary(const monsters *mon);
+bool mons_is_truly_stationary(const monsters *mon);
bool mons_is_wall_shielded(int mc);
bool mons_is_insubstantial(int mc);
bool mons_has_blood(int mc);
diff --git a/crawl-ref/source/monstuff.cc b/crawl-ref/source/monstuff.cc
index f18aa3dc23..ae1f19aa65 100644
--- a/crawl-ref/source/monstuff.cc
+++ b/crawl-ref/source/monstuff.cc
@@ -2147,27 +2147,24 @@ void behaviour_event(monsters *mon, int event, int src,
// Do any resultant foe or state changes.
_handle_behaviour(mon);
- if (old_behaviour == BEH_LURK && !mons_is_lurking(mon))
- {
- switch(event)
- {
- case ME_EVAL:
- case ME_DISTURB:
- case ME_ALERT:
- // Lurking monsters won't stop lurking just because they
- // noticed something.
- mon->behaviour = BEH_LURK;
- break;
+ const bool wasLurking =
+ (old_behaviour == BEH_LURK && !mons_is_lurking(mon));
+ const bool wasLeaving =
+ (old_behaviour == BEH_LEAVE && !mons_is_leaving(mon));
- default:
- if (mon->has_ench(ENCH_SUBMERGED)
- && !mon->del_ench(ENCH_SUBMERGED))
- {
- // Lurking monsters that can't unsubmerge keep lurking.
- mon->behaviour = BEH_LURK;
- }
- break;
- }
+ if ((wasLurking || wasLeaving)
+ && (event == ME_DISTURB || event == ME_ALERT || event == ME_EVAL))
+ {
+ // Lurking monsters or monsters leaving the level won't stop
+ // doing so just because they noticed something.
+ mon->behaviour = old_behaviour;
+ }
+ else if (wasLurking && mon->has_ench(ENCH_SUBMERGED)
+ && !mon->del_ench(ENCH_SUBMERGED))
+ {
+ // The same goes for lurking submerged monsters, if they can't
+ // unsubmerge.
+ mon->behaviour = BEH_LURK;
}
}
@@ -2408,6 +2405,16 @@ static void _mark_neighbours_player_unreachable(monsters *mon)
}
}
+static void _make_mons_leave_level(monsters *mon)
+{
+ if (mons_is_leaving(mon))
+ {
+ // Monsters leaving the level take their stuff with them.
+ mon->flags |= MF_HARD_RESET;
+ monster_die(mon, KILL_DISMISSED, 0);
+ }
+}
+
//---------------------------------------------------------------
//
// handle_behaviour
@@ -2941,6 +2948,14 @@ static void _handle_behaviour(monsters *mon)
break;
case BEH_WANDER:
+ // Monsters that have been pacified leave the level.
+ if (mons_is_pacified(mon))
+ {
+ new_foe = MHITNOT;
+ new_beh = BEH_LEAVE;
+ break;
+ }
+
// Is our foe in LOS?
// Batty monsters don't automatically reseek so that
// they'll flitter away, we'll reset them just before
@@ -3200,6 +3215,31 @@ static void _handle_behaviour(monsters *mon)
}
break;
+ case BEH_LEAVE:
+ // If the monster can't move at all (or even teleport, as a
+ // mimic would), it obviously can't leave, so get out.
+ if (mons_is_truly_stationary(mon))
+ break;
+
+ // If the monster can submerge where it is, make it do so
+ // and leave the level.
+ if (monster_can_submerge(mon, grd(mon->pos())))
+ {
+ mon->add_ench(ENCH_SUBMERGED);
+ _make_mons_leave_level(mon);
+ return;
+ }
+
+ // If the monster is far enough away from the player, make
+ // it leave the level.
+ if (distance(mon->x, mon->y, you.x_pos, you.y_pos)
+ >= LOS_RADIUS * LOS_RADIUS * 4)
+ {
+ _make_mons_leave_level(mon);
+ return;
+ }
+ break;
+
case BEH_FLEE:
// Check for healed.
if (isHealthy && !isScared)
@@ -3673,7 +3713,8 @@ static void _handle_nearby_ability(monsters *monster)
case MONS_GIANT_EYEBALL:
if (coinflip() && !mons_friendly(monster)
&& !mons_is_wandering(monster)
- && !mons_is_fleeing(monster))
+ && !mons_is_fleeing(monster)
+ && !mons_is_leaving(monster))
{
simple_monster_message(monster, " stares at you.");
@@ -3686,7 +3727,8 @@ static void _handle_nearby_ability(monsters *monster)
case MONS_EYE_OF_DRAINING:
if (coinflip() && !mons_friendly(monster)
&& !mons_is_wandering(monster)
- && !mons_is_fleeing(monster))
+ && !mons_is_fleeing(monster)
+ && !mons_is_leaving(monster))
{
simple_monster_message(monster, " stares at you.");
@@ -4135,9 +4177,10 @@ static bool _handle_special_ability(monsters *monster, bolt & beem)
}
// Won't sing if either of you silenced, or it's friendly,
- // confused or fleeing.
+ // confused, fleeing, or leaving the level.
if (monster->has_ench(ENCH_CONFUSION)
|| mons_is_fleeing(monster)
+ || mons_is_leaving(monster)
|| mons_friendly(monster)
|| silenced(monster->x, monster->y)
|| silenced(you.x_pos, you.y_pos))
@@ -4441,7 +4484,8 @@ static bool _handle_scroll(monsters *monster)
case SCR_TELEPORTATION:
if (!monster->has_ench(ENCH_TP))
{
- if (mons_is_fleeing(monster) || mons_is_caught(monster))
+ if (mons_is_fleeing(monster) || mons_is_leaving(monster)
+ || mons_is_caught(monster))
{
simple_monster_message(monster, " reads a scroll.");
monster_teleport(monster, false);
@@ -4452,7 +4496,8 @@ static bool _handle_scroll(monsters *monster)
break;
case SCR_BLINKING:
- if (mons_is_fleeing(monster) || mons_is_caught(monster))
+ if (mons_is_fleeing(monster) || mons_is_leaving(monster)
+ || mons_is_caught(monster))
{
if (mons_near(monster))
{
@@ -5353,9 +5398,13 @@ static bool _handle_throw(monsters *monster, bolt & beem)
return (false);
}
- // Greatly lowered chances if the monster is fleeing.
- if (mons_is_fleeing(monster) && !one_chance_in(8))
+ // Greatly lowered chances if the monster is fleeing or leaving the
+ // level.
+ if ((mons_is_fleeing(monster) || mons_is_leaving(monster))
+ && !one_chance_in(8))
+ {
return (false);
+ }
item_def *launcher = NULL;
const item_def *weapon = NULL;