git-svn-id: https://crawl-ref.svn.sourceforge.net/svnroot/crawl-ref/trunk@2583 c06c8d41-db1a-0410-9941-cceddc491573
HAI4YDKI72OBDT5KMMVCO3DOU765OPWCU7GTRKTALFNSDOI4R2LAC
HUHII5CFWHLFNOYQOKPQ6LUJSQ46OJHJMNISRWDJIBN4BMD4NAOAC
PES2QAPAJTLHZORDXNJWKK4VWRDCGXMOVVFI2TQALCPB5JUPHCVQC
I67HCZISOEMUYFEUA6VOJOO2L4TYK73IB4FSTY4CHDR7GZD6CS6QC
K2CS6TCX2NDVL2ASEHGP4J4K4IJ6FP3ANNKTSIWVG43HPYSBX6ZQC
XXBZEIEB6JTDFJC6V2VSDAV2KHDXZYQ245EMQBKOX3I7HTU2DMIAC
RPOZZWKG5GLPHVZZ7ZKMKS64ZMV2LDCQSARBJFJ6FZOTOKCQO7FAC
YCL3W2PFE6ILTGBFODCSXNPDIA46KVSZP2TI7HDMYAOEJT65RIEAC
RSIUBEQUGNU4LO6KH4PKVROWQS33DAKSY4XFVGN7T3CEKSXABCSAC
GQL5SIGBHLU3FMCE54XVGLRY5AZHRM6DUEB722REA2DPLGJSN6EQC
YLWMDMNLJOERFAGH5RIFTRWLGCEOWAD4GIWUIXKYA7EE3EWHCVAQC
SW3RLYFNRT3IJBK6LYKHKP2J2YDU7SXQWAJZX7U6S7ICYW43OMNQC
Y4WR4EIOFFXHRQI2PJAZWD4MVL6A7MNBHLN4KOV6BIKGGA7FXQTQC
E5DMZFW6WCFAKTKKOQPYTQXZ2CGLWMVH64LRXDUI2UIG4VYUHIVQC
if (fmenv->type == MONS_PANDEMONIUM_DEMON
|| fmenv->type == MONS_PLAYER_GHOST // cdl
|| !fmenv->alive()
|| mons_is_stationary(fmenv)
|| fmenv->incapacitated())
{
continue;
}
if (!monster_habitable_grid(fmenv, DNGN_FLOOR))
return (false);
if (fmenv->speed_increment < 50)
continue;
// only friendly monsters, or those actively seeking the
// player, will follow up/down stairs.
if (!(mons_friendly(fmenv) ||
(fmenv->behaviour == BEH_SEEK && fmenv->foe == MHITYOU)))
{
return (false);
}
// only friendly monsters, or those actively seeking the
// player, will follow up/down stairs.
if (!(mons_friendly(fmenv) ||
(fmenv->behaviour == BEH_SEEK && fmenv->foe == MHITYOU)))
{
continue;
}
// Monsters that are not directly adjacent are subject to more
// stringent checks.
if ((pos - you.pos()).abs() > 2)
{
if (!mons_friendly(fmenv))
return (false);
return (true);
}
static int follower_tag_radius2()
{
// If only friendlies are adjacent, we set a max radius of 6, otherwise
// only adjacent friendlies may follow.
coord_def p;
for (p.x = you.x_pos - 1; p.x <= you.x_pos + 1; ++p.x)
for (p.y = you.y_pos - 1; p.y <= you.y_pos + 1; ++p.y)
{
if (p == you.pos())
continue;
if (const monsters *mon = monster_at(p))
{
if (!mons_friendly(mon))
return (2);
}
return (6 * 6);
}
void tag_followers()
{
const int radius2 = follower_tag_radius2();
int n_followers = 18;
std::vector<coord_def> places[2];
int place_set = 0;
places[place_set].push_back(you.pos());
memset(travel_point_distance, 0, sizeof(travel_distance_grid_t));
while (!places[place_set].empty())
{
for (int i = 0, size = places[place_set].size(); i < size; ++i)
{
const coord_def &p = places[place_set][i];
coord_def fp;
for (fp.x = p.x - 1; fp.x <= p.x + 1; ++fp.x)
for (fp.y = p.y - 1; fp.y <= p.y + 1; ++fp.y)
{
if (fp == p || (fp - you.pos()).abs() > radius2
|| !in_bounds(fp) || travel_point_distance[fp.x][fp.y])
{
continue;
}
travel_point_distance[fp.x][fp.y] = 1;
if (tag_follower_at(fp))
{
// If we've run out of our follower allowance, bail.
if (--n_followers <= 0)
return;
places[!place_set].push_back(fp);
}
}
}
places[place_set].clear();
place_set = !place_set;
static bool grab_follower_at(const coord_def &pos)
{
if (pos == you.pos())
return (false);
monsters *fmenv = monster_at(pos);
if (!fmenv || !fmenv->alive())
return (false);
// monster has to be already tagged in order to follow:
if (!testbits( fmenv->flags, MF_TAKING_STAIRS ))
return (false);
#if DEBUG_DIAGNOSTICS
mprf(MSGCH_DIAGNOSTICS, "%s is following to %s.",
fmenv->name(DESC_CAP_THE, true).c_str(),
level_id::current().describe().c_str());
#endif
fmenv->set_transit(level_id::current());
fmenv->destroy_inventory();
monster_cleanup(fmenv);
return (true);
}
if (!can_follow)
if (can_follow)
{
memset(travel_point_distance, 0, sizeof(travel_distance_grid_t));
std::vector<coord_def> places[2];
int place_set = 0;
places[place_set].push_back(you.pos());
while (!places[place_set].empty())
{
for (int i = 0, size = places[place_set].size(); i < size; ++i)
// Monster can't follow us, so clear the follower flag.
fmenv->flags &= ~MF_TAKING_STAIRS;
continue;
const coord_def &p = places[place_set][i];
coord_def fp;
for (fp.x = p.x - 1; fp.x <= p.x + 1; ++fp.x)
for (fp.y = p.y - 1; fp.y <= p.y + 1; ++fp.y)
{
if (!in_bounds(fp) || travel_point_distance[fp.x][fp.y])
continue;
travel_point_distance[fp.x][fp.y] = 1;
if (grab_follower_at(fp))
places[!place_set].push_back(fp);
}
#if DEBUG_DIAGNOSTICS
mprf(MSGCH_DIAGNOSTICS, "%s is following to %s.",
fmenv->name(DESC_CAP_THE, true).c_str(),
level_id::current().describe().c_str());
#endif
fmenv->set_transit(level_id::current());
fmenv->destroy_inventory();
monster_cleanup(fmenv);
places[place_set].clear();
place_set = !place_set;