summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--crawl-ref/source/acr.cc4
-rw-r--r--crawl-ref/source/dungeon.cc64
-rw-r--r--crawl-ref/source/effects.cc94
-rw-r--r--crawl-ref/source/externs.h2
-rw-r--r--crawl-ref/source/fight.cc62
-rw-r--r--crawl-ref/source/it_use3.cc10
-rw-r--r--crawl-ref/source/mon-util.cc37
-rw-r--r--crawl-ref/source/monplace.h13
-rw-r--r--crawl-ref/source/monstuff.cc313
-rw-r--r--crawl-ref/source/tags.cc5
-rw-r--r--crawl-ref/source/tags.h3
-rw-r--r--crawl-ref/source/travel.cc4
12 files changed, 376 insertions, 235 deletions
diff --git a/crawl-ref/source/acr.cc b/crawl-ref/source/acr.cc
index 06f82d291d..397abc48dd 100644
--- a/crawl-ref/source/acr.cc
+++ b/crawl-ref/source/acr.cc
@@ -3516,8 +3516,8 @@ static void _open_door(int move_x, int move_y, bool check_confused)
}
- you_attack(mgrd[dx][dy], true);
you.turn_is_over = true;
+ you_attack(mgrd[dx][dy], true);
if (you.berserk_penalty != NO_BERSERK_PENALTY)
you.berserk_penalty = 0;
@@ -4075,8 +4075,8 @@ static void _move_player(int move_x, int move_y)
// an invisible monster attacks the monster, thus allowing
// the player to figure out which adjacent wall an invis
// monster is in "for free".
- you_attack( targ_monst, true );
you.turn_is_over = true;
+ you_attack( targ_monst, true );
// We don't want to create a penalty if there isn't
// supposed to be one.
diff --git a/crawl-ref/source/dungeon.cc b/crawl-ref/source/dungeon.cc
index 9e7cbe1c76..c87f158c14 100644
--- a/crawl-ref/source/dungeon.cc
+++ b/crawl-ref/source/dungeon.cc
@@ -1789,8 +1789,8 @@ static bool _make_box(int room_x1, int room_y1, int room_x2, int room_y2,
return true;
}
-// take care of labyrinth, abyss, pandemonium
-// returns 1 if we should skip further generation,
+// Take care of labyrinth, abyss, pandemonium.
+// Returns 1 if we should skip further generation,
// -1 if we should immediately quit, and 0 otherwise.
static builder_rc_type _builder_by_type(int level_number, char level_type)
{
@@ -2874,9 +2874,9 @@ static int _place_monster_vector(std::vector<monster_type> montypes,
int result = 0;
mgen_data mg;
- mg.power = level_number;
+ mg.power = level_number;
mg.behaviour = BEH_SLEEP;
- mg.flags |= MG_PERMIT_BANDS;
+ mg.flags |= MG_PERMIT_BANDS;
mg.map_mask |= MMT_NO_MONS;
for (int i = 0; i < num_to_place; i++)
@@ -2962,8 +2962,8 @@ static void _builder_monsters(int level_number, char level_type, int mon_wanted)
for (int i = 0; i < mon_wanted; i++)
{
mgen_data mg;
- mg.power = level_number;
- mg.flags |= MG_PERMIT_BANDS;
+ mg.power = level_number;
+ mg.flags |= MG_PERMIT_BANDS;
mg.map_mask |= MMT_NO_MONS;
place_monster(mg);
@@ -3191,9 +3191,9 @@ static void _fill_monster_pit( spec_room &sr, FixedVector<pit_mons_def,
if (lord_type != MONS_PROGRAM_BUG)
{
mgen_data mg;
- mg.cls = lord_type;
+ mg.cls = lord_type;
mg.behaviour = BEH_SLEEP;
- mg.pos = coord_def(lordx, lordy);
+ mg.pos = coord_def(lordx, lordy);
mons_place(
mgen_data::sleeper_at(lord_type, coord_def(lordx, lordy)));
@@ -3218,9 +3218,8 @@ static void _fill_monster_pit( spec_room &sr, FixedVector<pit_mons_def,
if (roll < pit_list[i].rare)
{
mons_place(
- mgen_data::sleeper_at(
- pit_list[i].type,
- coord_def(x, y)));
+ mgen_data::sleeper_at( pit_list[i].type,
+ coord_def(x, y)));
break;
}
}
@@ -3336,9 +3335,8 @@ static void _special_room(int level_number, spec_room &sr)
continue;
mons_place(
- mgen_data::sleeper_at(
- mons_alloc[random2(10)],
- coord_def(x, y)));
+ mgen_data::sleeper_at( mons_alloc[random2(10)],
+ coord_def(x, y) ));
}
break;
@@ -3372,9 +3370,8 @@ static void _special_room(int level_number, spec_room &sr)
continue;
mons_place(
- mgen_data::sleeper_at(
- mons_alloc[random2(10)],
- coord_def(x, y) ));
+ mgen_data::sleeper_at( mons_alloc[random2(10)],
+ coord_def(x, y) ));
}
// put the boss monster down
@@ -3384,7 +3381,7 @@ static void _special_room(int level_number, spec_room &sr)
break;
case SROOM_TREASURY:
- // should only appear in deep levels, with a guardian
+ // Should only appear in deep levels, with a guardian
// Maybe have several types of treasure room?
// place treasure {dlb}:
for (x = sr.x1; x <= sr.x2; x++)
@@ -3417,7 +3414,8 @@ static void _special_room(int level_number, spec_room &sr)
mgen_data::sleeper_at(
MONS_GUARDIAN_NAGA,
coord_def(sr.x1 + random2( sr.x2 - sr.x1 ),
- sr.y1 + random2( sr.y2 - sr.y1 )) ));
+ sr.y1 + random2( sr.y2 - sr.y1 )),
+ MG_PATROLLING ));
break;
case SROOM_BEEHIVE:
@@ -3472,15 +3470,16 @@ static void _beehive(spec_room &sr)
mons_place(
mgen_data::sleeper_at(
- one_chance_in(7) ?
- MONS_KILLER_BEE_LARVA : MONS_KILLER_BEE,
+ one_chance_in(7) ? MONS_KILLER_BEE_LARVA
+ : MONS_KILLER_BEE,
coord_def(x, y)));
}
mons_place(
mgen_data::sleeper_at(
MONS_QUEEN_BEE,
- coord_def(queenx, queeny )));
+ coord_def(queenx, queeny ),
+ MG_PATROLLING));
}
// used for placement of vaults
@@ -4517,7 +4516,7 @@ bool dgn_place_monster(mons_spec &mspec,
if (mspec.mid != -1)
{
const int mid = mspec.mid;
- const bool m_generate_awake = generate_awake || mspec.generate_awake;
+ const bool m_generate_awake = (generate_awake || mspec.generate_awake);
const int mlev = mspec.mlevel;
if (mlev)
@@ -4541,12 +4540,12 @@ bool dgn_place_monster(mons_spec &mspec,
}
mgen_data mg(static_cast<monster_type>(mid));
- mg.power = monster_level;
- mg.behaviour = m_generate_awake ? BEH_WANDER : BEH_SLEEP;
+ mg.power = monster_level;
+ mg.behaviour = (m_generate_awake ? BEH_WANDER : BEH_SLEEP);
mg.base_type = mspec.monbase;
- mg.number = mspec.number;
- mg.colour = mspec.colour;
- mg.pos = coord_def(vx, vy);
+ mg.number = mspec.number;
+ mg.colour = mspec.colour;
+ mg.pos = coord_def(vx, vy);
const int mindex = place_monster(mg);
if (mindex != -1)
@@ -4878,8 +4877,8 @@ static int _vault_grid( vault_placement &place,
if (vgrid == 'S' || vgrid == 'H')
{
- const monster_type mtype =
- (vgrid == 'H') ? MONS_ORANGE_STATUE : MONS_SILVER_STATUE;
+ const monster_type mtype = ((vgrid == 'H') ? MONS_ORANGE_STATUE
+ : MONS_SILVER_STATUE);
grd[vx][vy] = DNGN_FLOOR;
@@ -6231,10 +6230,7 @@ static void _labyrinth_place_items(const coord_def &end)
static void _labyrinth_place_exit(const coord_def &end)
{
_labyrinth_place_items(end);
- mons_place(
- mgen_data::sleeper_at(
- MONS_MINOTAUR,
- end));
+ mons_place( mgen_data::sleeper_at(MONS_MINOTAUR, end, MG_PATROLLING) );
grd(end) = DNGN_ESCAPE_HATCH_UP;
}
diff --git a/crawl-ref/source/effects.cc b/crawl-ref/source/effects.cc
index 9a49d673fa..e8ef2d8705 100644
--- a/crawl-ref/source/effects.cc
+++ b/crawl-ref/source/effects.cc
@@ -1902,14 +1902,33 @@ bool recharge_wand(int item_slot)
} // end recharge_wand()
// Sets foe target of friendly monsters.
-static void set_friendly_foes()
+// If allow_patrol is true, patrolling monsters get MHITNOT instead.
+static void _set_friendly_foes(bool allow_patrol = false)
{
for (int i = 0; i < MAX_MONSTERS; ++i)
{
monsters *mon(&menv[i]);
if (!mon->alive() || !mons_near(mon) || !mons_friendly(mon))
continue;
- mon->foe = you.pet_target;
+
+ mon->foe = (allow_patrol && mon->is_patrolling() ? MHITNOT
+ : you.pet_target);
+ }
+}
+
+static void _set_allies_patrol_point(bool clear = false)
+{
+ for (int i = 0; i < MAX_MONSTERS; ++i)
+ {
+ monsters *mon(&menv[i]);
+ if (!mon->alive() || !mons_near(mon) || !mons_friendly(mon))
+ continue;
+
+ mon->patrol_point = (clear ? coord_def(0, 0)
+ : coord_def(mon->x, mon->y));
+
+ if (!clear)
+ mon->behaviour = BEH_WANDER;
}
}
@@ -1986,7 +2005,9 @@ void yell(bool force)
}
}
- mpr(" h - Order allies to stop attacking");
+ mpr(" s - Order allies to stop attacking");
+ mpr(" w - Order allies to wait here");
+ mpr(" f - Order allies to follow you");
}
mprf(" Anything else - Stay silent%s",
@@ -1996,13 +2017,47 @@ void yell(bool force)
switch (keyn)
{
- case '!': // for players using the old keyset
+ case '!': // for players using the old keyset
case 't':
mprf(MSGCH_SOUND, "You %s for attention!", shout_verb.c_str());
you.turn_is_over = true;
noisy( noise_level, you.x_pos, you.y_pos );
return;
+ case 'f':
+ case 's':
+ mons_targd = MHITYOU;
+ if (keyn == 'f')
+ {
+ // Don't reset patrol points for 'Stop fighting!'
+ _set_allies_patrol_point(true);
+ mpr("Follow me!");
+ }
+ else
+ mpr("Stop fighting!");
+ break;
+
+ case 'w':
+ mpr("Wait here!");
+ mons_targd = MHITNOT;
+ _set_allies_patrol_point();
+ break;
+
+ case 'p':
+ if (you.duration[DUR_BERSERKER])
+ {
+ canned_msg(MSG_TOO_BERSERK);
+ return;
+ }
+
+ if (targ_prev)
+ {
+ mons_targd = you.prev_targ;
+ mpr("Attack!");
+ break;
+ }
+
+ // fall through
case 'a':
if (you.duration[DUR_BERSERKER])
{
@@ -2027,39 +2082,22 @@ void yell(bool force)
}
mons_targd = mgrd[targ.tx][targ.ty];
+ mpr("Attack!");
break;
- case 'p':
- if (you.duration[DUR_BERSERKER])
- {
- canned_msg(MSG_TOO_BERSERK);
- return;
- }
-
- if (targ_prev)
- {
- mons_targd = you.prev_targ;
- break;
- }
-
- case 'h':
- mons_targd = MHITYOU;
- break;
-
- // fall through...
default:
mpr("Okely-dokely.");
return;
}
- if (mons_targd != MHITNOT)
- {
- you.pet_target = mons_targd;
- set_friendly_foes();
- }
+ you.pet_target = mons_targd;
+ // Allow patrolling for "Stop fighting!" and "Wait here!"
+ _set_friendly_foes(keyn == 's' || keyn == 'w');
+
+ if (mons_targd != MHITNOT && mons_targd != MHITYOU)
+ mpr("Attack!");
noisy( 10, you.x_pos, you.y_pos );
- mpr(mons_targd == MHITYOU ? "Come here!" : "Attack!");
} // end yell()
bool forget_inventory(bool quiet)
diff --git a/crawl-ref/source/externs.h b/crawl-ref/source/externs.h
index 5c70f5e1f5..ed86c042b7 100644
--- a/crawl-ref/source/externs.h
+++ b/crawl-ref/source/externs.h
@@ -1028,6 +1028,7 @@ public:
unsigned char y;
unsigned char target_x;
unsigned char target_y;
+ coord_def patrol_point;
FixedVector<short, NUM_MONSTER_SLOTS> inv;
monster_spells spells;
mon_attitude_type attitude;
@@ -1104,6 +1105,7 @@ public:
void timeout_enchantments(int levels);
+ bool is_patrolling() const;
bool needs_transit() const;
void set_transit(const level_id &destination);
bool find_place_to_live(bool near_player = false);
diff --git a/crawl-ref/source/fight.cc b/crawl-ref/source/fight.cc
index 9fea017008..8a26e078f8 100644
--- a/crawl-ref/source/fight.cc
+++ b/crawl-ref/source/fight.cc
@@ -357,13 +357,12 @@ melee_attack::melee_attack(actor *attk, actor *defn,
void melee_attack::check_hand_half_bonus_eligible()
{
- hand_half_bonus =
- unarmed_ok
- && !can_do_unarmed
- && !shield
- && weapon
- && !item_cursed( *weapon )
- && hands == HANDS_HALF;
+ hand_half_bonus = (unarmed_ok
+ && !can_do_unarmed
+ && !shield
+ && weapon
+ && !item_cursed( *weapon )
+ && hands == HANDS_HALF);
}
void melee_attack::init_attack()
@@ -396,11 +395,11 @@ void melee_attack::init_attack()
water_attack = is_water_attack(attacker, defender);
attacker_visible = attacker->visible();
- attacker_invisible = !attacker_visible && see_grid(attacker->pos());
- defender_visible = defender && defender->visible();
- defender_invisible = !defender_visible && defender
- && see_grid(defender->pos());
- needs_message = attacker_visible || defender_visible;
+ attacker_invisible = (!attacker_visible && see_grid(attacker->pos()));
+ defender_visible = (defender && defender->visible());
+ defender_invisible = (!defender_visible && defender
+ && see_grid(defender->pos()));
+ needs_message = (attacker_visible || defender_visible);
if (defender && defender->submerged())
unarmed_ok = false;
@@ -607,10 +606,13 @@ bool melee_attack::attack()
if (attacker->atype() == ACT_PLAYER)
{
- if (!stop_attack_prompt(def, false, false))
- set_attack_conducts(def, conduct);
- else
+ if (stop_attack_prompt(def, false, false))
+ {
cancel_attack = true;
+ return (false);
+ }
+ else
+ set_attack_conducts(def, conduct);
}
// Trying to stay general beyond this point is a recipe for insanity.
@@ -782,8 +784,8 @@ bool melee_attack::player_attack()
if (damage_done > 0)
{
- int blood =
- _modify_blood_amount(damage_done, attacker->damage_type());
+ int blood = _modify_blood_amount(damage_done,
+ attacker->damage_type());
if (blood > defender->stat_hp())
blood = defender->stat_hp();
@@ -3080,8 +3082,8 @@ bool melee_attack::mons_attack_mons()
behaviour_event(def, ME_WHACK, monster_index(atk));
}
- // if an enemy attacked a friend, set the pet target if it isn't
- // set already
+ // If an enemy attacked a friend, set the pet target if it isn't
+ // set already.
if (perceived_attack && atk->alive() && mons_friendly(def)
&& !mons_wont_attack(atk) && you.pet_target == MHITNOT)
{
@@ -3837,8 +3839,8 @@ void melee_attack::mons_perform_attack_rounds()
if (defender->atype() == ACT_MONSTER)
type = defender->id();
- int blood
- = _modify_blood_amount(damage_done, attacker->damage_type());
+ int blood = _modify_blood_amount(damage_done,
+ attacker->damage_type());
if (blood > defender->stat_hp())
blood = defender->stat_hp();
@@ -3983,12 +3985,20 @@ bool you_attack(int monster_attacked, bool unarmed_attacks)
wielded_weapon_check(attk.weapon);
bool attack = attk.attack();
- if (attack && (is_sanctuary(you.x_pos, you.y_pos)
- || is_sanctuary(defender->x, defender->y)))
+ if (!attack)
+ {
+ // Attack was cancelled or unsuccessful...
+ if (attk.cancel_attack)
+ you.turn_is_over = false;
+ return (false);
+ }
+
+ if (is_sanctuary(you.x_pos, you.y_pos)
+ || is_sanctuary(defender->x, defender->y))
{
remove_sanctuary(true);
}
- return attack;
+ return (true);
}
// Lose attack energy for attacking with a weapon. The monster has already lost
@@ -4026,7 +4036,7 @@ bool monster_attack(int monster_attacking)
// Friendly and good neutral monsters won't attack unless confused.
if (mons_wont_attack(attacker) && !mons_is_confused(attacker))
- return false;
+ return (false);
// In case the monster hasn't noticed you, bumping into it will
// change that.
@@ -4034,7 +4044,7 @@ bool monster_attack(int monster_attacking)
melee_attack attk(attacker, &you);
attk.attack();
- return true;
+ return (true);
} // end monster_attack()
bool monsters_fight(int monster_attacking, int monster_attacked)
diff --git a/crawl-ref/source/it_use3.cc b/crawl-ref/source/it_use3.cc
index f478c5ee9d..4c8478290c 100644
--- a/crawl-ref/source/it_use3.cc
+++ b/crawl-ref/source/it_use3.cc
@@ -296,16 +296,16 @@ static bool reaching_weapon_attack(const item_def& wpn)
* slips between the squares.
*/
- // if we're attacking more than a space away
- if ((x_distance > 1) || (y_distance > 1))
+ // If we're attacking more than a space away...
+ if (x_distance > 1 || y_distance > 1)
{
const int x_middle = MAX(beam.tx, you.x_pos) - (x_distance / 2);
const int y_middle = MAX(beam.ty, you.y_pos) - (y_distance / 2);
- // if either the x or the y is the same, we should check for
+ // If either the x or the y is the same, we should check for
// a monster:
- if (((beam.tx == you.x_pos) || (beam.ty == you.y_pos))
- && (mgrd[x_middle][y_middle] != NON_MONSTER))
+ if ((beam.tx == you.x_pos || beam.ty == you.y_pos)
+ && mgrd[x_middle][y_middle] != NON_MONSTER)
{
const int skill = weapon_skill( wpn.base_type, wpn.sub_type );
diff --git a/crawl-ref/source/mon-util.cc b/crawl-ref/source/mon-util.cc
index 5197d2ac2f..edd906743f 100644
--- a/crawl-ref/source/mon-util.cc
+++ b/crawl-ref/source/mon-util.cc
@@ -2214,7 +2214,7 @@ bool ms_waste_of_time( const monsters *mon, spell_type monspell )
// life-protected if he has triple life protection.
const mon_holy_type holiness = foe->holiness();
return (holiness == MH_UNDEAD || holiness == MH_DEMONIC
- || holiness == MH_NONLIVING || holiness == MH_PLANT);
+ || holiness == MH_NONLIVING || holiness == MH_PLANT);
}
case SPELL_DISPEL_UNDEAD:
@@ -2222,7 +2222,7 @@ bool ms_waste_of_time( const monsters *mon, spell_type monspell )
case SPELL_BACKLIGHT:
{
- ret = !foe || foe->backlit();
+ ret = (!foe || foe->backlit());
break;
}
@@ -2591,10 +2591,11 @@ 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), 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(), seen_context("")
+ target_x(0), target_y(0), patrol_point(0, 0), 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(),
+ seen_context("")
{
}
@@ -2641,6 +2642,7 @@ void monsters::reset()
mgrd[x][y] = NON_MONSTER;
x = y = 0;
+ patrol_point = coord_def(0, 0);
ghost.reset(NULL);
}
@@ -2660,6 +2662,7 @@ void monsters::init_with(const monsters &mon)
y = mon.y;
target_x = mon.target_x;
target_y = mon.target_y;
+ patrol_point = mon.patrol_point;
inv = mon.inv;
spells = mon.spells;
attitude = mon.attitude;
@@ -4558,12 +4561,17 @@ void monsters::destroy_inventory()
}
}
+bool monsters::is_patrolling() const
+{
+ return (patrol_point != coord_def(0, 0));
+}
+
bool monsters::needs_transit() const
{
return ((mons_is_unique(type)
- || (flags & MF_BANISHED)
- || type == MONS_ROYAL_JELLY
- || (you.level_type == LEVEL_DUNGEON && hit_dice > 8 + random2(25)))
+ || (flags & MF_BANISHED)
+ || type == MONS_ROYAL_JELLY
+ || you.level_type == LEVEL_DUNGEON && hit_dice > 8 + random2(25))
&& !mons_is_summoned(this));
}
@@ -4613,7 +4621,7 @@ void monsters::load_spells(mon_spellbook_type book)
bool monsters::has_hydra_multi_attack() const
{
return (type == MONS_HYDRA
- || (mons_is_zombified(this) && base_monster == MONS_HYDRA));
+ || mons_is_zombified(this) && base_monster == MONS_HYDRA);
}
bool monsters::has_ench(enchant_type ench) const
@@ -4728,9 +4736,9 @@ void monsters::add_enchantment_effect(const mon_enchant &ench, bool quiet)
case ENCH_CHARM:
behaviour = BEH_SEEK;
- target_x = you.x_pos;
- target_y = you.y_pos;
- foe = MHITYOU;
+ target_x = you.x_pos;
+ target_y = you.y_pos;
+ foe = MHITYOU;
break;
default:
@@ -5572,7 +5580,8 @@ actor *monsters::get_foe() const
int monsters::foe_distance() const
{
const actor *afoe = get_foe();
- return (afoe? pos().distance_from(afoe->pos()) : INFINITE_DISTANCE);
+ return (afoe ? pos().distance_from(afoe->pos())
+ : INFINITE_DISTANCE);
}
bool monsters::can_go_berserk() const
diff --git a/crawl-ref/source/monplace.h b/crawl-ref/source/monplace.h
index 6a72bca628..05be654743 100644
--- a/crawl-ref/source/monplace.h
+++ b/crawl-ref/source/monplace.h
@@ -94,10 +94,11 @@ enum proximity_type // proximity to player to create monster
enum mgen_flag_type
{
- MG_PERMIT_BANDS = 0x1,
- MG_FORCE_PLACE = 0x2,
- MG_FORCE_BEH = 0x4,
- MG_PLAYER_MADE = 0x8
+ MG_PERMIT_BANDS = 0x01,
+ MG_FORCE_PLACE = 0x02,
+ MG_FORCE_BEH = 0x04,
+ MG_PLAYER_MADE = 0x08,
+ MG_PATROLLING = 0x10
};
// A structure with all the data needed to whip up a new monster.
@@ -186,6 +187,7 @@ struct mgen_data
bool permit_bands() const { return (flags & MG_PERMIT_BANDS); }
bool force_place() const { return (flags & MG_FORCE_PLACE); }
+ bool needs_patrol_point() const { return (flags & MG_PATROLLING); }
// Is there a valid position set on this struct that we want to use
// when placing the monster?
@@ -194,7 +196,8 @@ struct mgen_data
bool summoned() const { return (abjuration_duration > 0); }
static mgen_data sleeper_at(monster_type what,
- const coord_def &where)
+ const coord_def &where,
+ unsigned flags = 0)
{
return mgen_data(what, BEH_SLEEP, 0, where);
}
diff --git a/crawl-ref/source/monstuff.cc b/crawl-ref/source/monstuff.cc
index 5d782c3120..ab4a48d441 100644
--- a/crawl-ref/source/monstuff.cc
+++ b/crawl-ref/source/monstuff.cc
@@ -732,7 +732,7 @@ void monster_die(monsters *monster, killer_type killer, int i, bool silent)
if (mons_is_caught(monster))
mons_clear_trapping_net(monster);
- // update list of monsters beholding player
+ // Update list of monsters beholding player.
update_beholders(monster, true);
const int monster_killed = monster_index(monster);
@@ -1029,7 +1029,7 @@ void monster_die(monsters *monster, killer_type killer, int i, bool silent)
MDAM_DEAD);
}
- // no piety loss if god gifts killed by other monsters
+ // No piety loss if god gifts killed by other monsters.
if (mons_friendly(monster) && !testbits(monster->flags,MF_GOD_GIFT))
{
did_god_conduct(DID_FRIEND_DIED, 1 + (monster->hit_dice / 2),
@@ -1319,7 +1319,7 @@ void monster_cleanup(monsters *monster)
if (you.pet_target == monster_killed)
you.pet_target = MHITNOT;
-} // end monster_cleanup()
+}
static bool _jelly_divide(monsters * parent)
{
@@ -1330,10 +1330,10 @@ static bool _jelly_divide(monsters * parent)
if (!mons_class_flag( parent->type, M_SPLITS ) || parent->hit_points == 1)
return (false);
- // first, find a suitable spot for the child {dlb}:
+ // First, find a suitable spot for the child {dlb}:
for (jex = -1; jex < 3; jex++)
{
- // loop moves beyond those tiles contiguous to parent {dlb}:
+ // Loop moves beyond those tiles contiguous to parent {dlb}:
if (jex > 1)
return (false);
@@ -1351,7 +1351,7 @@ static bool _jelly_divide(monsters * parent)
if (foundSpot)
break;
- } // end of for jex
+ } // end of for jex
int k = 0; // must remain outside loop that follows {dlb}
@@ -1366,7 +1366,7 @@ static bool _jelly_divide(monsters * parent)
return (false);
}
- // handle impact of split on parent {dlb}:
+ // Handle impact of split on parent {dlb}:
parent->max_hit_points /= 2;
if (parent->hit_points > parent->max_hit_points)
@@ -1375,11 +1375,11 @@ static bool _jelly_divide(monsters * parent)
parent->init_experience();
parent->experience = parent->experience * 3 / 5 + 1;
- // create child {dlb}:
- // this is terribly partial and really requires
+ // Create child {dlb}:
+ // This is terribly partial and really requires
// more thought as to generation ... {dlb}
*child = *parent;
- child->max_hit_points = child->hit_points;
+ child->max_hit_points = child->hit_points;
child->speed_increment = 70 + random2(5);
child->x = parent->x + jex;
child->y = parent->y + jey;
@@ -1395,7 +1395,7 @@ static bool _jelly_divide(monsters * parent)
return (true);
} // end jelly_divide()
-// if you're invis and throw/zap whatever, alerts menv to your position
+// If you're invis and throw/zap whatever, alerts menv to your position.
void alert_nearby_monsters(void)
{
monsters *monster = 0; // NULL {dlb}
@@ -2028,6 +2028,9 @@ void behaviour_event( monsters *mon, int event, int src,
// interesting for a moment. -- bwr
if (!isSmart || mon->foe == MHITNOT || mon->behaviour == BEH_WANDER)
{
+ if (mon->is_patrolling())
+ break;
+
mon->target_x = src_x;
mon->target_y = src_y;
}
@@ -2035,13 +2038,13 @@ void behaviour_event( monsters *mon, int event, int src,
case ME_WHACK:
case ME_ANNOY:
- // will turn monster against <src>, unless they
+ // Will turn monster against <src>, unless they
// are BOTH friendly or good neutral AND stupid,
// or else fleeing anyway. Hitting someone over
// the head, of course, always triggers this code.
if (event == ME_WHACK
|| ((wontAttack != sourceWontAttack || isSmart)
- && mon->behaviour != BEH_FLEE && mon->behaviour != BEH_PANIC))
+ && mon->behaviour != BEH_FLEE && mon->behaviour != BEH_PANIC))
{
// (plain) plants and fungi cannot flee or fight back
if (mon->type == MONS_FUNGUS || mon->type == MONS_PLANT)
@@ -2059,16 +2062,19 @@ void behaviour_event( monsters *mon, int event, int src,
}
}
- // now set target x,y so that monster can whack
- // back (once) at an invisible foe
+ // Now set target x,y so that monster can whack
+ // back (once) at an invisible foe.
if (event == ME_WHACK)
setTarget = true;
break;
case ME_ALERT:
- // will alert monster to <src> and turn them
+ if (mon->is_patrolling())
+ break;
+
+ // Will alert monster to <src> and turn them
// against them, unless they have a current foe.
- // it won't turn friends hostile either.
+ // It won't turn friends hostile either.
if (mon->behaviour != BEH_CORNERED && mon->behaviour != BEH_PANIC
&& mon->behaviour != BEH_FLEE)
{
@@ -2108,7 +2114,7 @@ void behaviour_event( monsters *mon, int event, int src,
break;
}
- // Just set behaviour.. foe doesn't change.
+ // Just set behaviour... foe doesn't change.
if (mon->behaviour != BEH_CORNERED)
simple_monster_message(mon, " turns to fight!");
@@ -2135,14 +2141,45 @@ void behaviour_event( monsters *mon, int event, int src,
}
}
- // now, break charms if appropriate
+ // Now, break charms if appropriate.
if (breakCharm)
mon->del_ench(ENCH_CHARM);
- // do any resultant foe or state changes
+ // Do any resultant foe or state changes.
_handle_behaviour( mon );
}
+static bool _choose_random_target_grid_in_los(monsters *mon)
+{
+ int pos_x, pos_y;
+ int count_grids = 0;
+ for (int j = -LOS_RADIUS; j < LOS_RADIUS; j++)
+ for (int k = -LOS_RADIUS; k < LOS_RADIUS; k++)
+ {
+ if (j == 0 && k == 0)
+ continue;
+
+ pos_x = mon->x + j;
+ pos_y = mon->y + k;
+
+ if (!in_bounds(pos_x, pos_y))
+ continue;
+ if (!mon->mon_see_grid(pos_x, pos_y))
+ continue;
+ if (!mon->can_pass_through_feat(grd[pos_x][pos_y]))
+ continue;
+
+ if (one_chance_in(++count_grids))
+ {
+ mon->target_x = pos_x;
+ mon->target_y = pos_y;
+ }
+ }
+
+ return (count_grids);
+}
+
+
//---------------------------------------------------------------
//
// handle_behaviour
@@ -2164,11 +2201,12 @@ static void _handle_behaviour(monsters *mon)
bool wontAttack = mons_wont_attack(mon);
bool proxPlayer = mons_near(mon);
bool proxFoe;
- bool isHurt = (mon->hit_points <= mon->max_hit_points / 4 - 1);
- bool isHealthy = (mon->hit_points > mon->max_hit_points / 2);
- bool isSmart = (mons_intel(mon->type) > I_ANIMAL);
- bool isScared = mon->has_ench(ENCH_FEAR);
- bool isMobile = !mons_is_stationary(mon);
+ bool isHurt = (mon->hit_points <= mon->max_hit_points / 4 - 1);
+ bool isHealthy = (mon->hit_points > mon->max_hit_points / 2);
+ bool isSmart = (mons_intel(mon->type) > I_ANIMAL);
+ bool isScared = mon->has_ench(ENCH_FEAR);
+ bool isMobile = !mons_is_stationary(mon);
+ bool patrolling = mon->is_patrolling();
// check for confusion -- early out.
if (mon->has_ench(ENCH_CONFUSION))
@@ -2178,7 +2216,7 @@ static void _handle_behaviour(monsters *mon)
return;
}
- // validate current target exists
+ // Validate current target exists.
if (mon->foe != MHITNOT && mon->foe != MHITYOU
&& menv[mon->foe].type == -1)
{
@@ -2197,15 +2235,15 @@ static void _handle_behaviour(monsters *mon)
proxPlayer = false;
const int intel = mons_intel(mon->type);
- // now, the corollary to that is that sometimes, if a
- // player is right next to a monster, they will 'see'
+ // Now, the corollary to that is that sometimes, if a
+ // player is right next to a monster, they will 'see'.
if (grid_distance( you.x_pos, you.y_pos, mon->x, mon->y ) == 1
&& one_chance_in(3))
{
proxPlayer = true;
}
- // [dshaligram] Very smart monsters have a chance of cluing in to
+ // [dshaligram] Very smart monsters have a chance of clueing in to
// invisible players in various ways.
else if (intel == I_NORMAL && one_chance_in(13)
|| intel == I_HIGH && one_chance_in(6))
@@ -2239,7 +2277,7 @@ static void _handle_behaviour(monsters *mon)
if (isNeutral && mon->foe == MHITNOT)
_set_nearest_monster_foe(mon);
- // monsters do not attack themselves {dlb}
+ // Monsters do not attack themselves. {dlb}
if (mon->foe == monster_index(mon))
mon->foe = MHITNOT;
@@ -2280,7 +2318,7 @@ static void _handle_behaviour(monsters *mon)
int foe_x = you.x_pos;
int foe_y = you.y_pos;
- // evaluate these each time; they may change
+ // Evaluate these each time; they may change.
if (mon->foe == MHITNOT)
proxFoe = false;
else
@@ -2303,12 +2341,12 @@ static void _handle_behaviour(monsters *mon)
}
}
- // track changes to state; attitude never changes here.
- beh_type new_beh = mon->behaviour;
+ // Track changes to state; attitude never changes here.
+ beh_type new_beh = mon->behaviour;
unsigned int new_foe = mon->foe;
// take care of monster state changes
- switch(mon->behaviour)
+ switch (mon->behaviour)
{
case BEH_SLEEP:
// default sleep state
@@ -2321,7 +2359,7 @@ static void _handle_behaviour(monsters *mon)
// no foe? then wander or seek the player
if (mon->foe == MHITNOT)
{
- if (!proxPlayer || isNeutral)
+ if (!proxPlayer || isNeutral || patrolling)
new_beh = BEH_WANDER;
else
{
@@ -2329,13 +2367,19 @@ static void _handle_behaviour(monsters *mon)
mon->target_x = you.x_pos;
mon->target_y = you.y_pos;
}
-
break;
}
// foe gone out of LOS?
if (!proxFoe)
{
+ if (patrolling)
+ {
+ new_foe = MHITNOT;
+ new_beh = BEH_WANDER;
+ break;
+ }
+
if (isFriendly)
{
new_foe = MHITYOU;
@@ -2410,11 +2454,11 @@ static void _handle_behaviour(monsters *mon)
break; // switch/case BEH_SEEK
}
- // monster can see foe: continue 'tracking'
- // by updating target x,y
+ // Monster can see foe: continue 'tracking'
+ // by updating target x,y.
if (mon->foe == MHITYOU)
{
- // sometimes, your friends will wander a bit.
+ // Sometimes, your friends will wander a bit.
if (isFriendly && one_chance_in(8))
{
mon->target_x = 10 + random2(GXM - 10);
@@ -2439,7 +2483,7 @@ static void _handle_behaviour(monsters *mon)
break;
case BEH_WANDER:
- // is our foe in LOS?
+ // Is our foe in LOS?
// Batty monsters don't automatically reseek so that
// they'll flitter away, we'll reset them just before
// they get movement in handle_monsters() instead. -- bwr
@@ -2462,14 +2506,25 @@ static void _handle_behaviour(monsters *mon)
|| one_chance_in(20)
|| testbits( mon->flags, MF_BATTY ))
{
- mon->target_x = 10 + random2(GXM - 10);
- mon->target_y = 10 + random2(GYM - 10);
+ if (patrolling)
+ {
+ if (mon->patrol_point != coord_def(mon->x, mon->y)
+ || !_choose_random_target_grid_in_los(mon))
+ {
+ mon->target_x = mon->patrol_point.x;
+ mon->target_y = mon->patrol_point.y;
+ }
+ }
+ else
+ {
+ mon->target_x = 10 + random2(GXM - 10);
+ mon->target_y = 10 + random2(GYM - 10);
+ }
}
- // during their wanderings, monsters will
- // eventually relax their guard (stupid
- // ones will do so faster, smart monsters
- // have longer memories
+ // During their wanderings, monsters will eventually relax their
+ // guard (stupid ones will do so faster, smart monsters have
+ // longer memories.
if (!proxFoe && mon->foe != MHITNOT
&& one_chance_in( isSmart ? 60 : 20 ))
{
@@ -2482,11 +2537,9 @@ static void _handle_behaviour(monsters *mon)
if (isHealthy && !isScared)
new_beh = BEH_SEEK;
- // Smart monsters flee until they can
- // flee no more... possible to get a
- // 'CORNERED' event, at which point
- // we can jump back to WANDER if the foe
- // isn't present.
+ // Smart monsters flee until they can flee no more...
+ // possible to get a 'CORNERED' event, at which point
+ // we can jump back to WANDER if the foe isn't present.
// XXX: If a monster can move through solid grids, then it
// should preferentially flee towards the nearest solid grid
@@ -2497,13 +2550,13 @@ static void _handle_behaviour(monsters *mon)
if (isFriendly)
{
- // Special-cased below so that it will flee *towards* you
+ // Special-cased below so that it will flee *towards* you.
mon->target_x = you.x_pos;
mon->target_y = you.y_pos;
}
else if (proxFoe)
{
- // try to flee _from_ the correct position
+ // Try to flee _from_ the correct position.
mon->target_x = foe_x;
mon->target_y = foe_y;
}
@@ -2516,7 +2569,7 @@ static void _handle_behaviour(monsters *mon)
// foe gone out of LOS?
if (!proxFoe)
{
- if ((isFriendly || proxPlayer) && !isNeutral)
+ if ((isFriendly || proxPlayer) && !isNeutral && !patrolling)
new_foe = MHITYOU;
else
new_beh = BEH_WANDER;
@@ -2571,8 +2624,7 @@ static bool _mons_check_set_foe(monsters *mon, int x, int y,
return (false);
}
-// choose nearest monster as a foe
-// (used for berserking monsters)
+// Choose nearest monster as a foe. (Used for berserking monsters.)
void _set_nearest_monster_foe(monsters *mon)
{
const bool friendly = mons_friendly(mon);
@@ -3579,7 +3631,7 @@ static bool _handle_reaching(monsters *monster)
{
int foe_x = menv[monster->foe].x;
int foe_y = menv[monster->foe].y;
- // same comments as to invisibility as above.
+ // Same comments as to invisibility as above.
if (monster->target_x == foe_x && monster->target_y == foe_y
&& monster->mon_see_grid(foe_x, foe_y, true))
{
@@ -4526,7 +4578,7 @@ static bool _handle_throw(monsters *monster, bolt & beem)
if (one_chance_in(archer? 9 : 5))
return (false);
- // don't allow offscreen throwing for now.
+ // Don't allow offscreen throwing for now.
if (monster->foe == MHITYOU && !mons_near(monster))
return (false);
@@ -4900,63 +4952,87 @@ static void _handle_monster_move(int i, monsters *monster)
}
else
{
- // calculates mmov_x, mmov_y based on monster target.
+ // Calculates mmov_x, mmov_y based on monster target.
_handle_movement(monster);
brkk = false;
- if (mons_is_confused(monster)
- || monster->type == MONS_AIR_ELEMENTAL
- && monster->has_ench(ENCH_SUBMERGED))
- {
- std::vector<coord_def> moves;
-
- int pfound = 0;
- for (int yi = -1; yi <= 1; ++yi)
- for (int xi = -1; xi <= 1; ++xi)
- {
- coord_def c = monster->pos() + coord_def(xi, yi);
- if (in_bounds(c) && monster->can_pass_through(c)
- && one_chance_in(++pfound))
- {
- mmov_x = xi;
- mmov_y = yi;
- }
- }
-
- if (random2(2 + pfound) < 2)
- mmov_x = mmov_y = 0;
-
- // Bounds check: don't let confused monsters try to run
- // off the map.
- if (monster->x + mmov_x < 0 || monster->x + mmov_x >= GXM)
- mmov_x = 0;
-
- if (monster->y + mmov_y < 0 || monster->y + mmov_y >= GYM)
- mmov_y = 0;
-
- if (!monster->can_pass_through(monster->x + mmov_x,
- monster->y + mmov_y))
- {
- mmov_x = mmov_y = 0;
- }
-
- if (mgrd[monster->x + mmov_x][monster->y + mmov_y] != NON_MONSTER
- && !is_sanctuary(monster->x, monster->y)
- && (mmov_x != 0 || mmov_y != 0))
- {
- monsters_fight(i,
- mgrd[monster->x + mmov_x][monster->y + mmov_y]);
-
- brkk = true;
- mmov_x = 0;
- mmov_y = 0;
- DEBUG_ENERGY_USE("monsters_fight()");
- }
- }
+ if (mons_is_confused(monster)
+ || monster->type == MONS_AIR_ELEMENTAL
+ && monster->has_ench(ENCH_SUBMERGED))
+ {
+ std::vector<coord_def> moves;
- if (brkk)
- continue;
+ int pfound = 0;
+ for (int yi = -1; yi <= 1; ++yi)
+ for (int xi = -1; xi <= 1; ++xi)
+ {
+ coord_def c = monster->pos() + coord_def(xi, yi);
+ if (in_bounds(c) && monster->can_pass_through(c)
+ && one_chance_in(++pfound))
+ {
+ mmov_x = xi;
+ mmov_y = yi;
+ }
+ }
+
+ if (random2(2 + pfound) < 2)
+ mmov_x = mmov_y = 0;
+
+ // Bounds check: don't let confused monsters try to run
+ // off the map.
+ if (monster->x + mmov_x < 0 || monster->x + mmov_x >= GXM)
+ mmov_x = 0;
+
+ if (monster->y + mmov_y < 0 || monster->y + mmov_y >= GYM)
+ mmov_y = 0;
+
+ if (!monster->can_pass_through(monster->x + mmov_x,
+ monster->y + mmov_y))
+ {
+ mmov_x = mmov_y = 0;
+ }
+
+ int enemy = mgrd[monster->x + mmov_x][monster->y + mmov_y];
+ if (enemy != NON_MONSTER
+ && !is_sanctuary(monster->x, monster->y)
+ && (mmov_x != 0 || mmov_y != 0))
+ {
+ if (monsters_fight(i, enemy))
+ {
+ brkk = true;
+ mmov_x = 0;
+ mmov_y = 0;
+ DEBUG_ENERGY_USE("monsters_fight()");
+ }
+ else
+ {
+ // FIXME: None of these work!
+ // Instead run away!
+ if (monster->add_ench(mon_enchant(ENCH_FEAR)))
+ {
+ behaviour_event(monster, ME_SCARE, MHITNOT,
+ monster->x + mmov_x,
+ monster->y + mmov_y);
+ }
+ break;
+/*
+ if (monster->foe == enemy || mons_friendly(monster)
+ && monster->foe == MHITYOU)
+ {
+ monster->foe = MHITNOT;
+ monster->behaviour = BEH_WANDER;
+ }
+
+ monster->target_x = 10 + random2(GXM - 10);
+ monster->target_y = 10 + random2(GYM - 10);
+*/
+ }
+ }
+ }
+
+ if (brkk)
+ continue;
}
_handle_nearby_ability( monster );
@@ -5027,7 +5103,7 @@ static void _handle_monster_move(int i, monsters *monster)
&& targmon != i
&& !mons_aligned(i, targmon))
{
- // figure out if they fight
+ // Figure out if they fight.
if (monsters_fight(i, targmon))
{
if (testbits(monster->flags, MF_BATTY))
@@ -5102,7 +5178,7 @@ static void _handle_monster_move(int i, monsters *monster)
}
update_beholders(monster);
- // reevaluate behaviour, since the monster's
+ // Reevaluate behaviour, since the monster's
// surroundings have changed (it may have moved,
// or died for that matter. Don't bother for
// dead monsters. :)
@@ -5883,13 +5959,13 @@ bool _mon_can_move_to_pos(const monsters *monster, const int count_x,
return false;
}
- // smacking the player is always a good move if we're
- // hostile (even if we're heading somewhere else)
- // also friendlies want to keep close to the player
- // so it's okay as well
+ // Smacking the player is always a good move if we're
+ // hostile (even if we're heading somewhere else).
+ // Also friendlies want to keep close to the player
+ // so it's okay as well.
- // smacking another monster is good, if the monsters
- // are aligned differently
+ // Smacking another monster is good, if the monsters
+ // are aligned differently.
if (mgrd[targ_x][targ_y] != NON_MONSTER)
{
if (just_check)
@@ -5902,6 +5978,7 @@ bool _mon_can_move_to_pos(const monsters *monster, const int count_x,
const int thismonster = monster_index(monster),
targmonster = mgrd[targ_x][targ_y];
+
if (mons_aligned(thismonster, targmonster)
&& targmonster != MHITNOT
&& targmonster != MHITYOU
diff --git a/crawl-ref/source/tags.cc b/crawl-ref/source/tags.cc
index 076405a1ad..8610f3fd9c 100644
--- a/crawl-ref/source/tags.cc
+++ b/crawl-ref/source/tags.cc
@@ -1770,6 +1770,7 @@ static void marshall_monster(writer &th, const monsters &m)
marshallByte(th, m.y);
marshallByte(th, m.target_x);
marshallByte(th, m.target_y);
+ marshallCoord(th, m.patrol_point);
marshallLong(th, m.flags);
marshallLong(th, m.experience);
@@ -2030,6 +2031,10 @@ static void unmarshall_monster(reader &th, monsters &m)
m.y = unmarshallByte(th);
m.target_x = unmarshallByte(th);
m.target_y = unmarshallByte(th);
+
+ if (_tag_minor_version >= TAG_MINOR_MPATROL)
+ unmarshallCoord(th, m.patrol_point);
+
m.flags = unmarshallLong(th);
m.experience = static_cast<unsigned long>(unmarshallLong(th));
diff --git a/crawl-ref/source/tags.h b/crawl-ref/source/tags.h
index 5b30de1779..ae16aef150 100644
--- a/crawl-ref/source/tags.h
+++ b/crawl-ref/source/tags.h
@@ -56,7 +56,8 @@ enum tag_minor_version
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_VERSION = 7 // Current version
+ TAG_MINOR_MPATROL = 8, // Added monster patrol points.
+ TAG_MINOR_VERSION = 8 // Current version
};
diff --git a/crawl-ref/source/travel.cc b/crawl-ref/source/travel.cc
index e3b8ebe2f7..8be9d2ecc7 100644
--- a/crawl-ref/source/travel.cc
+++ b/crawl-ref/source/travel.cc
@@ -523,8 +523,8 @@ void init_travel_terrain_check(bool check_race_equip)
_set_pass_feature(DNGN_DEEP_WATER, water);
// Permanently levitating players can cross most hostile terrain.
- const signed char trav = you.permanent_levitation() ?
- TRAVERSABLE : IMPASSABLE;
+ const signed char trav = (you.permanent_levitation() ? TRAVERSABLE
+ : IMPASSABLE);
if (water != TRAVERSABLE)
_set_pass_feature(DNGN_DEEP_WATER, trav);