muse looting
Give better feedback than "<Monster> rummages through something" when hero sees a monster looting a container. Have monster take out up to 4 items at a time instead of always 1. (Hero can take out an arbitrary number in one move.) When deciding what to try to take out, 'count' (now 'nitems') was initialized to 1 instead of 0, giving the monster a 1 out of N+1 chance of not trying to take anything out. It wasn't clear whether that was intentional (there's already a chance for not taking things out when deciding whether to use the container). I kept that result in and made it more explicit now. When deciding whether the chosen item could be moved from container to monster's inventory, the can_carry(item) check was counting the weight of the item twice, once explicitly when considering adding it to minvent but also implicitly as part of the carried container's weight already in minvent.
This commit is contained in:
155
src/muse.c
155
src/muse.c
@@ -1,4 +1,4 @@
|
||||
/* NetHack 3.6 muse.c $NHDT-Date: 1574648940 2019/11/25 02:29:00 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.115 $ */
|
||||
/* NetHack 3.6 muse.c $NHDT-Date: 1580685754 2020/02/02 23:22:34 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.119 $ */
|
||||
/* Copyright (C) 1990 by Ken Arromdee */
|
||||
/* NetHack may be freely redistributed. See license for details. */
|
||||
|
||||
@@ -14,7 +14,6 @@
|
||||
* are confused don't know not to read scrolls, etc....
|
||||
*/
|
||||
|
||||
static struct permonst *FDECL(muse_newcham_mon, (struct monst *));
|
||||
static int FDECL(precheck, (struct monst *, struct obj *));
|
||||
static void FDECL(mzapwand, (struct monst *, struct obj *, BOOLEAN_P));
|
||||
static void FDECL(mplayhorn, (struct monst *, struct obj *, BOOLEAN_P));
|
||||
@@ -25,6 +24,9 @@ static int FDECL(mbhitm, (struct monst *, struct obj *));
|
||||
static void FDECL(mbhit, (struct monst *, int,
|
||||
int FDECL((*), (MONST_P, OBJ_P)),
|
||||
int FDECL((*), (OBJ_P, OBJ_P)), struct obj *));
|
||||
static struct permonst *FDECL(muse_newcham_mon, (struct monst *));
|
||||
static int FDECL(mloot_container, (struct monst *mon, struct obj *,
|
||||
BOOLEAN_P));
|
||||
static void FDECL(you_aggravate, (struct monst *));
|
||||
static void FDECL(mon_consume_unstone, (struct monst *, struct obj *,
|
||||
BOOLEAN_P, BOOLEAN_P));
|
||||
@@ -1668,12 +1670,26 @@ struct monst *mtmp;
|
||||
if (nohands(mdat))
|
||||
return 0;
|
||||
|
||||
#define nomore(x) if (g.m.has_misc == x) continue
|
||||
/* normally we would want to bracket a macro expansion containing
|
||||
'if' without matching 'else' with 'do { ... } while (0)' but we
|
||||
can't do that here because it would intercept 'continue' */
|
||||
#define nomore(x) if (g.m.has_misc == (x)) continue
|
||||
/*
|
||||
* [bug?] Choice of item is not prioritized; the last viable one
|
||||
* in the monster's inventory will be chosen.
|
||||
* 'nomore()' is nearly worthless because it only screens checking
|
||||
* of duplicates when there is no alternate type in between them.
|
||||
*
|
||||
* MUSE_BAG issues:
|
||||
* should allow looting floor container instead of needing the
|
||||
* monster to have picked it up and now be carrying it which takes
|
||||
* extra time and renders heavily filled containers immune;
|
||||
* hero should have a chance to see the monster fail to open a
|
||||
* locked container instead of monster always knowing lock state
|
||||
* (may not be feasible to implement--requires too much per-object
|
||||
* info for each monster);
|
||||
* monster with key should be able to unlock a locked floor
|
||||
* container and not know whether it is trapped.
|
||||
*/
|
||||
for (obj = mtmp->minvent; obj; obj = obj->nobj) {
|
||||
/* Monsters shouldn't recognize cursed items; this kludge is
|
||||
@@ -1768,6 +1784,116 @@ struct monst *mon;
|
||||
return rndmonst();
|
||||
}
|
||||
|
||||
static int
|
||||
mloot_container(mon, container, vismon)
|
||||
struct monst *mon;
|
||||
struct obj *container;
|
||||
boolean vismon;
|
||||
{
|
||||
char contnr_nam[BUFSZ], mpronounbuf[20];
|
||||
boolean nearby;
|
||||
int takeout_indx, takeout_count, howfar, res = 0;
|
||||
|
||||
if (!container || !Has_contents(container) || container->olocked)
|
||||
return res; /* 0 */
|
||||
/* FIXME: handle cursed bag of holding */
|
||||
if (Is_mbag(container) && container->cursed)
|
||||
return res; /* 0 */
|
||||
|
||||
switch (rn2(10)) {
|
||||
default: /* case 0, 1, 2, 3: */
|
||||
takeout_count = 1;
|
||||
break;
|
||||
case 4: case 5: case 6:
|
||||
takeout_count = 2;
|
||||
break;
|
||||
case 7: case 8:
|
||||
takeout_count = 3;
|
||||
break;
|
||||
case 9:
|
||||
takeout_count = 4;
|
||||
break;
|
||||
}
|
||||
howfar = distu(mon->mx, mon->my);
|
||||
nearby = (howfar <= 7 * 7);
|
||||
contnr_nam[0] = mpronounbuf[0] = '\0';
|
||||
if (vismon) {
|
||||
/* do this once so that when hallucinating it won't change
|
||||
from one item to the next */
|
||||
Strcpy(mpronounbuf, mhe(mon));
|
||||
}
|
||||
|
||||
for (takeout_indx = 0; takeout_indx < takeout_count; ++takeout_indx) {
|
||||
struct obj *xobj;
|
||||
int nitems;
|
||||
|
||||
if (!Has_contents(container)) /* might have removed all items */
|
||||
break;
|
||||
/* TODO?
|
||||
* Monster ought to prioritize on something it wants to use.
|
||||
*/
|
||||
nitems = 0;
|
||||
for (xobj = container->cobj; xobj != 0; xobj = xobj->nobj)
|
||||
++nitems;
|
||||
/* nitems is always greater than 0 due to Has_contents() check;
|
||||
throttle item removal as the container becomes less filled */
|
||||
if (!rn2(nitems + 1))
|
||||
break;
|
||||
nitems = rn2(nitems);
|
||||
for (xobj = container->cobj; nitems > 0; xobj = xobj->nobj)
|
||||
--nitems;
|
||||
|
||||
container->cknown = 0; /* hero no longer knows container's contents
|
||||
* even if [attempted] removal is observed */
|
||||
if (!*contnr_nam) {
|
||||
/* xname sets dknown, distant_name doesn't */
|
||||
Strcpy(contnr_nam, nearby ? xname(container)
|
||||
: distant_name(container, xname));
|
||||
}
|
||||
/* this was originally just 'can_carry(mon, xobj)' which
|
||||
covers objects a monster shouldn't pick up but also
|
||||
checks carrying capacity; for that, it ended up counting
|
||||
xobj's weight twice when container is carried; so take
|
||||
xobj out, check whether it can be carried, and then put
|
||||
it back (below) if it can't be */
|
||||
obj_extract_self(xobj); /* this reduces container's weight */
|
||||
/* check whether mon can handle xobj and whether weight of xobj plus
|
||||
minvent (including container, now without xobj) can be carried */
|
||||
if (can_carry(mon, xobj)) {
|
||||
if (vismon) {
|
||||
if (howfar > 2) /* not adjacent */
|
||||
Norep("%s rummages through %s.", Monnam(mon), contnr_nam);
|
||||
else if (takeout_indx == 0) /* adjacent, first item */
|
||||
pline("%s removes %s from %s.", Monnam(mon),
|
||||
an(xname(xobj)), contnr_nam);
|
||||
else /* adjacent, additional items */
|
||||
pline("%s removes %s.", upstart(mpronounbuf),
|
||||
an(xname(xobj)));
|
||||
}
|
||||
/* obj_extract_self(xobj); -- already done above */
|
||||
(void) mpickobj(mon, xobj);
|
||||
res = 2;
|
||||
} else { /* couldn't carry xobj separately so put back inside */
|
||||
/* an achievement prize (castle's wand?) might already be
|
||||
marked nomerge (when it hasn't been in invent yet) */
|
||||
boolean already_nomerge = xobj->nomerge != 0,
|
||||
just_xobj = !Has_contents(container);
|
||||
|
||||
/* this doesn't restore the original contents ordering
|
||||
[shouldn't be a problem; even though this item didn't
|
||||
give the rummage message, that's what mon was doing] */
|
||||
xobj->nomerge = 1;
|
||||
xobj = add_to_container(container, xobj);
|
||||
if (!already_nomerge)
|
||||
xobj->nomerge = 0;
|
||||
container->owt = weight(container);
|
||||
if (just_xobj)
|
||||
break; /* out of takeout_count loop */
|
||||
} /* can_carry */
|
||||
} /* takeout_count */
|
||||
return res;
|
||||
}
|
||||
|
||||
int
|
||||
use_misc(mtmp)
|
||||
struct monst *mtmp;
|
||||
@@ -1884,28 +2010,7 @@ struct monst *mtmp;
|
||||
m_useup(mtmp, otmp);
|
||||
return 2;
|
||||
case MUSE_BAG:
|
||||
{
|
||||
struct obj *xobj;
|
||||
long count = 1;
|
||||
|
||||
/* FIXME: handle cursed bag of holding */
|
||||
if (Is_mbag(otmp) && otmp->cursed)
|
||||
return 0;
|
||||
if (!Has_contents(otmp) || otmp->olocked)
|
||||
return 0;
|
||||
|
||||
for (xobj = otmp->cobj; xobj; xobj = xobj->nobj) count++;
|
||||
count = rn2(count);
|
||||
for (xobj = otmp->cobj; xobj && count; xobj = xobj->nobj) count--;
|
||||
if (xobj && can_carry(mtmp, xobj)) {
|
||||
if (vismon)
|
||||
pline("%s rummages through something.", Monnam(mtmp));
|
||||
obj_extract_self(xobj);
|
||||
(void) mpickobj(mtmp, xobj);
|
||||
return 2;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
return mloot_container(mtmp, otmp, vismon);
|
||||
case MUSE_POLY_TRAP:
|
||||
if (vismon) {
|
||||
const char *Mnam = Monnam(mtmp);
|
||||
|
||||
Reference in New Issue
Block a user