diff --git a/include/extern.h b/include/extern.h index 910f546b9..ab57154d6 100644 --- a/include/extern.h +++ b/include/extern.h @@ -1553,9 +1553,10 @@ extern int meatcorpse(struct monst *); extern void mon_give_prop(struct monst *, int); extern void mon_givit(struct monst *, struct permonst *); extern void mpickgold(struct monst *); -extern boolean mpickstuff(struct monst *, const char *); +extern boolean mpickstuff(struct monst *); extern int curr_mon_load(struct monst *); extern int max_mon_load(struct monst *); +extern boolean can_touch_safely(struct monst *, struct obj *); extern int can_carry(struct monst *, struct obj *); extern long mon_allowflags(struct monst *); extern int mfndpos(struct monst *, coord *, long *, long); @@ -1682,6 +1683,7 @@ extern int mstrength(struct permonst *); /* ### monmove.c ### */ +extern boolean mon_would_take_item(struct monst *, struct obj *); extern boolean itsstuck(struct monst *); extern boolean mb_trapped(struct monst *, boolean); extern void mon_track_add(struct monst *, coordxy, coordxy); diff --git a/src/mon.c b/src/mon.c index dee643ae4..a181e11f8 100644 --- a/src/mon.c +++ b/src/mon.c @@ -11,7 +11,6 @@ static void sanity_check_single_mon(struct monst *, boolean, const char *); static struct obj *make_corpse(struct monst *, unsigned); static int minliquid_core(struct monst *); static void m_calcdistress(struct monst *); -static boolean can_touch_safely(struct monst *, struct obj *); static boolean monlineu(struct monst *, int, int); static long mm_2way_aggression(struct monst *, struct monst *); static long mm_aggression(struct monst *, struct monst *); @@ -1577,8 +1576,9 @@ mpickgold(register struct monst* mtmp) } } +/* monster picks up one item stack from the map location they are at */ boolean -mpickstuff(struct monst *mtmp, const char *str) +mpickstuff(struct monst *mtmp) { register struct obj *otmp, *otmp2, *otmp3; int carryamt = 0; @@ -1587,6 +1587,14 @@ mpickstuff(struct monst *mtmp, const char *str) if (mtmp->isshk && inhishop(mtmp)) return FALSE; + /* non-tame monsters normally don't go shopping */ + if (!mtmp->mtame && *in_rooms(mtmp->mx, mtmp->my, SHOPBASE) && rn2(25)) + return FALSE; + + /* item in a pool, but monster can't swim */ + if (!could_reach_item(mtmp, mtmp->mx, mtmp->my)) + return FALSE; + for (otmp = gl.level.objects[mtmp->mx][mtmp->my]; otmp; otmp = otmp2) { otmp2 = otmp->nexthere; @@ -1596,21 +1604,19 @@ mpickstuff(struct monst *mtmp, const char *str) continue; /* Nymphs take everything. Most monsters don't pick up corpses. */ - if (!str ? searches_for_item(mtmp, otmp) - : !!(strchr(str, otmp->oclass))) { + if (mon_would_take_item(mtmp, otmp)) { + if (otmp->otyp == CORPSE && mtmp->data->mlet != S_NYMPH /* let a handful of corpse types thru to can_carry() */ && !touch_petrifies(&mons[otmp->corpsenm]) && otmp->corpsenm != PM_LIZARD && !acidic(&mons[otmp->corpsenm])) continue; - if (!touch_artifact(otmp, mtmp)) + if (!can_touch_safely(mtmp, otmp)) continue; carryamt = can_carry(mtmp, otmp); if (carryamt == 0) continue; - if (is_pool(mtmp->mx, mtmp->my)) - continue; /* handle cases where the critter can only get some */ otmp3 = otmp; if (carryamt != otmp->quan) { @@ -1681,7 +1687,7 @@ max_mon_load(struct monst* mtmp) } /* can monster touch object safely? */ -static boolean +boolean can_touch_safely(struct monst *mtmp, struct obj *otmp) { int otyp = otmp->otyp; diff --git a/src/monmove.c b/src/monmove.c index c12407ba7..cdc20c83d 100644 --- a/src/monmove.c +++ b/src/monmove.c @@ -841,9 +841,39 @@ static NEARDATA const char practical[] = { WEAPON_CLASS, ARMOR_CLASS, static NEARDATA const char magical[] = { AMULET_CLASS, POTION_CLASS, SCROLL_CLASS, WAND_CLASS, RING_CLASS, SPBOOK_CLASS, 0 }; -static NEARDATA const char indigestion[] = { BALL_CLASS, ROCK_CLASS, 0 }; -static NEARDATA const char boulder_class[] = { ROCK_CLASS, 0 }; -static NEARDATA const char gem_class[] = { GEM_CLASS, 0 }; + +/* monster mtmp would love to take object otmp? */ +boolean +mon_would_take_item(struct monst *mtmp, struct obj *otmp) +{ + int pctload = (curr_mon_load(mtmp) * 100) / max_mon_load(mtmp); + + if (is_unicorn(mtmp->data) && objects[otmp->otyp].oc_material != GEMSTONE) + return FALSE; + if (!mindless(mtmp->data) && !is_animal(mtmp->data) && pctload < 75 + && searches_for_item(mtmp, otmp)) + return TRUE; + if (likes_gold(mtmp->data) && otmp->otyp == GOLD_PIECE && pctload < 95) + return TRUE; + if (likes_gems(mtmp->data) && otmp->oclass == GEM_CLASS + && objects[otmp->otyp].oc_material != MINERAL && pctload < 85) + return TRUE; + if (likes_objs(mtmp->data) && index(practical, otmp->oclass) + && pctload < 75) + return TRUE; + if (likes_magic(mtmp->data) && index(magical, otmp->oclass) + && pctload < 85) + return TRUE; + if (throws_rocks(mtmp->data) && otmp->otyp == BOULDER + && pctload < 50 && !Sokoban) + return TRUE; + if (mtmp->data == &mons[PM_GELATINOUS_CUBE] + && otmp->oclass != ROCK_CLASS && otmp->oclass != BALL_CLASS + && !(otmp->otyp == CORPSE && touch_petrifies(&mons[otmp->corpsenm]))) + return TRUE; + + return FALSE; +} boolean itsstuck(register struct monst* mtmp) @@ -1079,11 +1109,9 @@ m_move(register struct monst* mtmp, register int after) coordxy ggx, ggy, nix, niy; xint16 chcnt; int chi; /* could be schar except for stupid Sun-2 compiler */ - boolean likegold = 0, likegems = 0, likeobjs = 0, likemagic = 0, - conceals = 0; - boolean likerock = 0, can_tunnel = 0; + boolean can_tunnel = 0; boolean can_open = 0, can_unlock = 0 /*, doorbuster = 0 */; - boolean uses_items = 0, setlikes = 0; + boolean getitems = FALSE; boolean avoid = FALSE; boolean better_with_displacing = FALSE; boolean sawmon = canspotmon(mtmp); /* before it moved */ @@ -1248,24 +1276,13 @@ m_move(register struct monst* mtmp, register int after) * situation where you toss arrows at it and it has nothing * better to do than pick the arrows up. */ - register int pctload = - (curr_mon_load(mtmp) * 100) / max_mon_load(mtmp); - - /* look for gold or jewels nearby */ - likegold = (likes_gold(ptr) && pctload < 95); - likegems = (likes_gems(ptr) && pctload < 85); - uses_items = (!mindless(ptr) && !is_animal(ptr) && pctload < 75); - likeobjs = (likes_objs(ptr) && pctload < 75); - likemagic = (likes_magic(ptr) && pctload < 85); - likerock = (throws_rocks(ptr) && pctload < 50 && !Sokoban); - conceals = hides_under(ptr); - setlikes = TRUE; + getitems = TRUE; } } #define SQSRCHRADIUS 5 - { + if (getitems) { register int minr = SQSRCHRADIUS; /* not too far away */ register struct obj *otmp; register coordxy xx, yy; @@ -1280,10 +1297,7 @@ m_move(register struct monst* mtmp, register int after) if (!mtmp->mpeaceful && is_mercenary(ptr)) minr = 1; - if ((likegold || likegems || likeobjs || likemagic || likerock - || conceals) && (!*in_rooms(omx, omy, SHOPBASE) - || (!rn2(25) && !mtmp->isshk))) { - look_for_obj: + if ((!*in_rooms(omx, omy, SHOPBASE) || (!rn2(25) && !mtmp->isshk))) { oomx = min(COLNO - 1, omx + minr); oomy = min(ROWNO - 1, omy + minr); lmx = max(1, omx - minr); @@ -1332,48 +1346,25 @@ m_move(register struct monst* mtmp, register int after) continue; } - if (((likegold && otmp->oclass == COIN_CLASS) - || (likeobjs && strchr(practical, otmp->oclass) - && (otmp->otyp != CORPSE - || (ptr->mlet == S_NYMPH - && !is_rider(&mons[otmp->corpsenm])))) - || (likemagic && strchr(magical, otmp->oclass)) - || (uses_items && searches_for_item(mtmp, otmp)) - || (likerock && otmp->otyp == BOULDER) - || (likegems && otmp->oclass == GEM_CLASS - && objects[otmp->otyp].oc_material != MINERAL) - || (conceals && !cansee(otmp->ox, otmp->oy)) - || (ptr == &mons[PM_GELATINOUS_CUBE] - && !strchr(indigestion, otmp->oclass) - && !(otmp->otyp == CORPSE - && touch_petrifies(&mons[otmp->corpsenm])))) - && touch_artifact(otmp, mtmp)) { - if (can_carry(mtmp, otmp) > 0 - && (throws_rocks(ptr) || !sobj_at(BOULDER, xx, yy)) - && (!is_unicorn(ptr) - || objects[otmp->otyp].oc_material == GEMSTONE) - /* Don't get stuck circling an Elbereth */ - && !onscary(xx, yy, mtmp)) { - 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; - ggy = otmp->oy; - if (ggx == omx && ggy == omy) { - mmoved = MMOVE_DONE; /* actually unnecessary */ - goto postmov; - } + if (((mon_would_take_item(mtmp, otmp) && (can_carry(mtmp, otmp) > 0)) + || (hides_under(ptr) && !cansee(otmp->ox, otmp->oy))) + && can_touch_safely(mtmp, otmp) + /* Don't get stuck circling an Elbereth */ + && !onscary(xx, yy, mtmp)) { + 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; + ggy = otmp->oy; + if (ggx == omx && ggy == omy) { + mmoved = MMOVE_DONE; /* actually unnecessary */ + goto postmov; } } } } - } else if (likegold) { - /* don't try to pick up anything else, but use the same loop */ - uses_items = 0; - likegems = likeobjs = likemagic = likerock = conceals = 0; - goto look_for_obj; } if (minr < SQSRCHRADIUS && appr == -1) { @@ -1718,21 +1709,6 @@ m_move(register struct monst* mtmp, register int after) newsym(mtmp->mx, mtmp->my); } if (OBJ_AT(mtmp->mx, mtmp->my) && mtmp->mcanmove) { - /* recompute the likes tests, in case we polymorphed - * or if the "likegold" case got taken above */ - if (setlikes) { - int pctload = (curr_mon_load(mtmp) * 100) / max_mon_load(mtmp); - - /* look for gold or jewels nearby */ - likegold = (likes_gold(ptr) && pctload < 95); - likegems = (likes_gems(ptr) && pctload < 85); - uses_items = - (!mindless(ptr) && !is_animal(ptr) && pctload < 75); - likeobjs = (likes_objs(ptr) && pctload < 75); - likemagic = (likes_magic(ptr) && pctload < 85); - likerock = (throws_rocks(ptr) && pctload < 50 && !Sokoban); - conceals = hides_under(ptr); - } /* Maybe a rock mole just ate some metal object */ if (metallivorous(ptr)) { @@ -1740,9 +1716,6 @@ m_move(register struct monst* mtmp, register int after) return MMOVE_DIED; /* it died */ } - if (g_at(mtmp->mx, mtmp->my) && likegold) - mpickgold(mtmp); - /* Maybe a cube ate just about anything */ if (ptr == &mons[PM_GELATINOUS_CUBE]) { if ((etmp = meatobj(mtmp)) >= 2) @@ -1756,22 +1729,8 @@ m_move(register struct monst* mtmp, register int after) return etmp; /* it died or got forced off the level */ } - if (!*in_rooms(mtmp->mx, mtmp->my, SHOPBASE) || !rn2(25)) { - boolean picked = FALSE; - - if (likeobjs) - picked |= mpickstuff(mtmp, practical); - if (likemagic) - picked |= mpickstuff(mtmp, magical); - if (likerock) - picked |= mpickstuff(mtmp, boulder_class); - if (likegems) - picked |= mpickstuff(mtmp, gem_class); - if (uses_items) - picked |= mpickstuff(mtmp, (char *) 0); - if (picked) - mmoved = MMOVE_DONE; - } + if (mpickstuff(mtmp)) + mmoved = MMOVE_DONE; if (mtmp->minvis) { newsym(mtmp->mx, mtmp->my);