From 1a6289a5ecdc56d1bdcae7fc1b6c45deb5672a63 Mon Sep 17 00:00:00 2001 From: "nethack.rankin" Date: Sat, 24 Jan 2009 22:59:53 +0000 Subject: [PATCH] fix #H1798 - limbless shopkeepers shouldn't take possessions (trunk only) 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 | 1 + src/mon.c | 42 +++++++++++++++++++++++++++++++++++++++--- 2 files changed, 40 insertions(+), 3 deletions(-) diff --git a/doc/fixes35.0 b/doc/fixes35.0 index 37e552582..3217305a2 100644 --- a/doc/fixes35.0 +++ b/doc/fixes35.0 @@ -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 diff --git a/src/mon.c b/src/mon.c index bac721185..54bf70645 100644 --- 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; }