]> granicus.if.org Git - nethack/commitdiff
fix #H1798 - limbless shopkeepers shouldn't take possessions (trunk only)
authornethack.rankin <nethack.rankin>
Sat, 24 Jan 2009 22:59:53 +0000 (22:59 +0000)
committernethack.rankin <nethack.rankin>
Sat, 24 Jan 2009 22:59:53 +0000 (22:59 +0000)
     From a bug report, a shopkeeper who's been
polymorphed into a limbless creature shouldn't be able to come take your
possessions when you die since you can't pick up items when in that shape.
Rather than add new special case handling for shopkeepers, prevent them
from taking on shapes that render them unable to behave like shopkeepers
so that they can continue to catch thrown pick-axes and assorted other
things that would otherwise need a lot of extra checking introduced.
Ditto for temple priests, vault guards, and quest leaders.  Restriction
also applies to wizard mode use of #monpolycontrol, the only place where
players can actually notice this.

     It could--perhaps should--restrict them even further, forcing forms
that retain speech capability, but I didn't go that far.

doc/fixes35.0
src/mon.c

index 37e552582a78489ef4b19d6d5ab41ddd5d815527..3217305a2efd1e5cdea461b88156290fb745406b 100644 (file)
@@ -301,6 +301,7 @@ message sequencing for fatal explosions was confusing if feedback was given
 when dipping something in holy/unholy water, only learn its new bless/curse
        state if hero sees it glow
 describe lit Sunsword as shining rather than glowing
+prevent poly'd shopkeepers from taking on forms that can't handle objects
 
 
 Platform- and/or Interface-Specific Fixes
index bac72118501c5405350edc8ff5fe00c9e78e2061..54bf70645337eb515c4be94dea474aa9a960c7f3 100644 (file)
--- a/src/mon.c
+++ b/src/mon.c
@@ -1,4 +1,4 @@
-/*     SCCS Id: @(#)mon.c      3.5     2008/10/20      */
+/*     SCCS Id: @(#)mon.c      3.5     2009/01/24      */
 /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
 /* NetHack may be freely redistributed.  See license for details. */
 
@@ -22,6 +22,8 @@ STATIC_DCL int NDECL(pick_animal);
 STATIC_DCL void FDECL(kill_eggs, (struct obj *));
 STATIC_DCL void FDECL(dealloc_mextra, (struct mextra *));
 STATIC_DCL int FDECL(pickvampshape, (struct monst *));
+STATIC_DCL boolean FDECL(isspecmon, (struct monst *));
+STATIC_DCL boolean FDECL(validspecmon, (struct monst *,int));
 #ifdef WIZARD
 STATIC_DCL boolean FDECL(validvamp, (struct monst *,int *,int));
 #endif
@@ -2583,6 +2585,32 @@ struct monst *mon;
        return mndx;
 }
 
+/* nonshapechangers who warrant special polymorph handling */
+STATIC_OVL boolean
+isspecmon(mon)
+struct monst *mon;
+{
+       return (mon->isshk || mon->ispriest || mon->isgd ||
+               mon->m_id == quest_status.leader_m_id);
+}
+
+/* restrict certain special monsters (shopkeepers, aligned priests,
+   vault guards) to forms that allow them to behave sensibly (catching
+   gold, speaking?) so that they don't need too much extra code */
+STATIC_OVL boolean
+validspecmon(mon, mndx)
+struct monst *mon;
+int mndx;
+{
+       if (isspecmon(mon) && mndx >= LOW_PM) {
+           struct permonst *ptr = &mons[mndx];
+
+           if (notake(ptr) || nohands(ptr) || !has_head(ptr)) return FALSE;
+           /* [should we check ptr->msound here too?] */
+       }
+       return TRUE;    /* potential new form is ok (or still NON_PM) */
+}
+
 #ifdef WIZARD
 /* prevent wizard mode user from specifying invalid vampshifter shape */
 static boolean
@@ -2590,7 +2618,8 @@ validvamp(mon, mndx_p, monclass)
 struct monst *mon;
 int *mndx_p, monclass;
 {
-       if (!is_vampshifter(mon)) return TRUE;  /* simplify caller's usage */
+       /* simplify caller's usage */
+       if (!is_vampshifter(mon)) return validspecmon(mon, *mndx_p);
 
        if (*mndx_p == PM_VAMPIRE || *mndx_p == PM_VAMPIRE_LORD ||
                *mndx_p == PM_VLAD_THE_IMPALER) {
@@ -2696,13 +2725,20 @@ struct monst *mon;
                if (mndx >= LOW_PM && validvamp(mon, &mndx, monclass)) break;
 
                pline("It can't become that.");
+               mndx = NON_PM;
            } while (--tryct > 0);
            if (!tryct) pline(thats_enough_tries);
            if (is_vampshifter(mon) && !validvamp(mon, &mndx, monclass))
                mndx = pickvampshape(mon);      /* don't resort to arbitrary */
        }
 #endif /*WIZARD*/
-       if (mndx == NON_PM) mndx = rn1(SPECIAL_PM - LOW_PM, LOW_PM);
+
+       if (mndx == NON_PM) {
+           tryct = 50;
+           do {
+               mndx = rn1(SPECIAL_PM - LOW_PM, LOW_PM);
+           } while (--tryct > 0 && !validspecmon(mon, mndx));
+       }
        return mndx;
 }