Improve m_search_item
Previously when monster was interested to pick up an item, the code went through the whole object chain, so going through all the items on the level. This caused problems with some games, for example where the player created thousands of meatballs in separate stacks. Changed the code so it now looks at the map locations inside the search radius, and the stacks in those map locations, skipping locations as early as possible.
This commit is contained in:
+75
-55
@@ -1100,19 +1100,22 @@ maybe_spin_web(struct monst *mtmp)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* max distmin() distance for monster to look for items */
|
||||||
#define SQSRCHRADIUS 5
|
#define SQSRCHRADIUS 5
|
||||||
|
|
||||||
|
/* monster looks for items it wants nearby */
|
||||||
static boolean
|
static boolean
|
||||||
m_search_items(struct monst *mtmp, coordxy *ggx, coordxy *ggy, schar *mmoved, int *appr)
|
m_search_items(struct monst *mtmp, coordxy *ggx, coordxy *ggy, schar *mmoved, int *appr)
|
||||||
{
|
{
|
||||||
register int minr = SQSRCHRADIUS; /* not too far away */
|
register int minr = SQSRCHRADIUS; /* not too far away */
|
||||||
register struct obj *otmp;
|
register struct obj *otmp;
|
||||||
register coordxy xx, yy;
|
register coordxy xx, yy;
|
||||||
coordxy oomx, oomy, lmx, lmy;
|
coordxy hmx, hmy, lmx, lmy;
|
||||||
struct trap *ttmp;
|
struct trap *ttmp;
|
||||||
coordxy omx = mtmp->mx, omy = mtmp->my;
|
coordxy omx = mtmp->mx, omy = mtmp->my;
|
||||||
struct permonst *ptr = mtmp->data;
|
struct permonst *ptr = mtmp->data;
|
||||||
struct monst *mtoo;
|
struct monst *mtoo;
|
||||||
|
boolean costly;
|
||||||
|
|
||||||
/* cut down the search radius if it thinks character is closer. */
|
/* cut down the search radius if it thinks character is closer. */
|
||||||
if (distmin(mtmp->mux, mtmp->muy, omx, omy) < SQSRCHRADIUS
|
if (distmin(mtmp->mux, mtmp->muy, omx, omy) < SQSRCHRADIUS
|
||||||
@@ -1122,76 +1125,93 @@ m_search_items(struct monst *mtmp, coordxy *ggx, coordxy *ggy, schar *mmoved, in
|
|||||||
if (!mtmp->mpeaceful && is_mercenary(ptr))
|
if (!mtmp->mpeaceful && is_mercenary(ptr))
|
||||||
minr = 1;
|
minr = 1;
|
||||||
|
|
||||||
if ((!*in_rooms(omx, omy, SHOPBASE) || (!rn2(25) && !mtmp->isshk))) {
|
/* in shop, usually skip */
|
||||||
oomx = min(COLNO - 1, omx + minr);
|
if (*in_rooms(omx, omy, SHOPBASE) && (rn2(25) || mtmp->isshk))
|
||||||
oomy = min(ROWNO - 1, omy + minr);
|
goto finish_search;
|
||||||
lmx = max(1, omx - minr);
|
|
||||||
lmy = max(0, omy - minr);
|
|
||||||
for (otmp = fobj; otmp; otmp = otmp->nobj) {
|
|
||||||
/* monsters may pick rocks up, but won't go out of their way
|
|
||||||
to grab them; this might hamper sling wielders, but it cuts
|
|
||||||
down on move overhead by filtering out most common item */
|
|
||||||
if (otmp->otyp == ROCK)
|
|
||||||
continue;
|
|
||||||
/* avoid special items; once hero picks them up, they'll
|
|
||||||
cease being special */
|
|
||||||
if (is_mines_prize(otmp) || is_soko_prize(otmp))
|
|
||||||
continue;
|
|
||||||
|
|
||||||
xx = otmp->ox;
|
/* distmin() gives a rectangular area */
|
||||||
yy = otmp->oy;
|
hmx = min(COLNO - 1, omx + minr);
|
||||||
/* Nymphs take everything. Most other creatures should not
|
hmy = min(ROWNO - 1, omy + minr);
|
||||||
* pick up corpses except as a special case like in
|
lmx = max(1, omx - minr);
|
||||||
* searches_for_item(). We need to do this check in
|
lmy = max(0, omy - minr);
|
||||||
* mpickstuff() as well.
|
|
||||||
*/
|
|
||||||
if (xx >= lmx && xx <= oomx && yy >= lmy && yy <= oomy) {
|
|
||||||
/* don't get stuck circling around object that's
|
|
||||||
underneath an immobile or hidden monster;
|
|
||||||
paralysis victims excluded */
|
|
||||||
if ((mtoo = m_at(xx, yy)) != 0
|
|
||||||
&& (helpless(mtoo) || mtoo->mundetected
|
|
||||||
|| (mtoo->mappearance && !mtoo->iswiz)
|
|
||||||
|| !mtoo->data->mmove))
|
|
||||||
continue;
|
|
||||||
/* the mfndpos() test for whether to allow a move to a
|
|
||||||
water location accepts flyers, but they can't reach
|
|
||||||
underwater objects, so being able to move to a spot
|
|
||||||
is insufficient for deciding whether to do so */
|
|
||||||
if (!could_reach_item(mtmp, xx, yy))
|
|
||||||
continue;
|
|
||||||
|
|
||||||
/* ignore obj if there's a trap and monster knows it */
|
for (xx = lmx; xx <= hmx; xx++) {
|
||||||
if ((ttmp = t_at(xx, yy)) != 0
|
for (yy = lmy; yy <= hmy; yy++) {
|
||||||
&& mon_knows_traps(mtmp, ttmp->ttyp)) {
|
/* no object here */
|
||||||
if (*ggx == xx && *ggy == yy) {
|
if (!OBJ_AT(xx, yy))
|
||||||
*ggx = mtmp->mux;
|
continue;
|
||||||
*ggy = mtmp->muy;
|
/* found an object closer already */
|
||||||
}
|
if (minr < distmin(omx, omy, xx, yy))
|
||||||
continue;
|
continue;
|
||||||
|
/* the mfndpos() test for whether to allow a move to a
|
||||||
|
water location accepts flyers, but they can't reach
|
||||||
|
underwater objects, so being able to move to a spot
|
||||||
|
is insufficient for deciding whether to do so */
|
||||||
|
if (!could_reach_item(mtmp, xx, yy))
|
||||||
|
continue;
|
||||||
|
/* hiders avoid hero's line of sight */
|
||||||
|
if (hides_under(ptr) && cansee(xx, yy))
|
||||||
|
continue;
|
||||||
|
/* don't get stuck circling around object that's
|
||||||
|
underneath an immobile or hidden monster;
|
||||||
|
paralysis victims excluded */
|
||||||
|
if ((mtoo = m_at(xx, yy)) != 0
|
||||||
|
&& (helpless(mtoo) || mtoo->mundetected
|
||||||
|
|| (mtoo->mappearance && !mtoo->iswiz)
|
||||||
|
|| !mtoo->data->mmove))
|
||||||
|
continue;
|
||||||
|
/* Don't get stuck circling an Elbereth */
|
||||||
|
if (onscary(xx, yy, mtmp))
|
||||||
|
continue;
|
||||||
|
/* ignore obj if there's a trap and monster knows it */
|
||||||
|
if ((ttmp = t_at(xx, yy)) != 0
|
||||||
|
&& mon_knows_traps(mtmp, ttmp->ttyp)) {
|
||||||
|
if (*ggx == xx && *ggy == yy) {
|
||||||
|
*ggx = mtmp->mux;
|
||||||
|
*ggy = mtmp->muy;
|
||||||
}
|
}
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
/* avoid getting stuck on eg. items in niches */
|
||||||
|
if (!m_cansee(mtmp, xx, yy))
|
||||||
|
continue;
|
||||||
|
|
||||||
if (((mon_would_take_item(mtmp, otmp) && (can_carry(mtmp, otmp) > 0))
|
costly = costly_spot(xx, yy);
|
||||||
|| (hides_under(ptr) && !cansee(otmp->ox, otmp->oy)))
|
|
||||||
&& can_touch_safely(mtmp, otmp)
|
/* look through the items on this location */
|
||||||
/* Don't get stuck circling an Elbereth */
|
for (otmp = gl.level.objects[xx][yy];
|
||||||
&& !onscary(xx, yy, mtmp)) {
|
otmp; otmp = otmp->nexthere) {
|
||||||
|
/* monsters may pick rocks up, but won't go out of their way
|
||||||
|
to grab them; this might hamper sling wielders, but it cuts
|
||||||
|
down on move overhead by filtering out most common item */
|
||||||
|
if (otmp->otyp == ROCK)
|
||||||
|
continue;
|
||||||
|
/* avoid special items; once hero picks them up, they'll
|
||||||
|
cease being special */
|
||||||
|
if (is_mines_prize(otmp) || is_soko_prize(otmp))
|
||||||
|
continue;
|
||||||
|
/* skip shop merchandise */
|
||||||
|
if (costly && !otmp->no_charge)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (mon_would_take_item(mtmp, otmp)
|
||||||
|
&& (can_carry(mtmp, otmp) > 0)
|
||||||
|
&& can_touch_safely(mtmp, otmp)) {
|
||||||
minr = distmin(omx, omy, xx, yy);
|
minr = distmin(omx, omy, xx, yy);
|
||||||
oomx = min(COLNO - 1, omx + minr);
|
|
||||||
oomy = min(ROWNO - 1, omy + minr);
|
|
||||||
lmx = max(1, omx - minr);
|
|
||||||
lmy = max(0, omy - minr);
|
|
||||||
*ggx = otmp->ox;
|
*ggx = otmp->ox;
|
||||||
*ggy = otmp->oy;
|
*ggy = otmp->oy;
|
||||||
if (*ggx == omx && *ggy == omy) {
|
if (*ggx == omx && *ggy == omy) {
|
||||||
*mmoved = MMOVE_DONE; /* actually unnecessary */
|
*mmoved = MMOVE_DONE; /* actually unnecessary */
|
||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
/* found an item of interest; skip the rest of the pile */
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
finish_search:
|
||||||
if (minr < SQSRCHRADIUS && *appr == -1) {
|
if (minr < SQSRCHRADIUS && *appr == -1) {
|
||||||
if (distmin(omx, omy, mtmp->mux, mtmp->muy) <= 3) {
|
if (distmin(omx, omy, mtmp->mux, mtmp->muy) <= 3) {
|
||||||
*ggx = mtmp->mux;
|
*ggx = mtmp->mux;
|
||||||
|
|||||||
Reference in New Issue
Block a user