-/* 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. */
* 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));
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));
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
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;
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);