]> granicus.if.org Git - nethack/commitdiff
more monster key use
authornethack.rankin <nethack.rankin>
Thu, 20 Oct 2005 03:58:46 +0000 (03:58 +0000)
committernethack.rankin <nethack.rankin>
Thu, 20 Oct 2005 03:58:46 +0000 (03:58 +0000)
     Let monsters use lock picks and credit cards in addition to keys for
opening doors.  And the earlier code to have pets hang on to a key didn't
work as intended.  It worked fine if the key was the only object carried,
but the monsters' item dropping code didn't give any special handling to
keys so they'd be dropped too if the pet carried another droppable item.
This eliminates second set of checks for handling some items specially--
dropping now uses the same routine as is used when pet movement decides
whether there's anything to drop.

     Also, a couple more door message tweaks.  "You see a door open" seems
strange when you watch your pet do the opening.  Previously fixed for the
"unlock and open" case, this does the same for opening already unlocked
doors and for giants smashing down doors--it now gives a more specific
message when you see a monster perform the action.

     Possible change in play balance:  pets capable of picking up the
rogue's Master Key of Thievery or tourist's Platinum Yendorian Express
Card will keep one of them.  So a player might accidentally lose one by
leaving it on the floor in a pet's path, or more significantly, the Card
will yield a means of giving magic resistance to a monster who can't wear
a cloak or dragon scales.  It's neutral and the most interesting high-end
pets are lawful (hence won't pick it up), so that probably won't have much
impact.

include/extern.h
src/dogmove.c
src/monmove.c
src/steal.c

index 0fd51656f06616b6a1247bb162d92afbf72783ac..13616d872c9fa856a70ef8989e1d372d483a2885 100644 (file)
@@ -441,6 +441,7 @@ E void FDECL(wary_dog, (struct monst *, BOOLEAN_P));
 
 /* ### dogmove.c ### */
 
+E struct obj *FDECL(droppables, (struct monst *));
 E int FDECL(dog_nutrition, (struct monst *,struct obj *));
 E int FDECL(dog_eat, (struct monst *,struct obj *,int,int,BOOLEAN_P));
 E int FDECL(dog_move, (struct monst *,int));
@@ -1245,6 +1246,7 @@ E boolean FDECL(olfaction, (struct permonst *));
 
 E boolean FDECL(itsstuck, (struct monst *));
 E boolean FDECL(mb_trapped, (struct monst *));
+E boolean FDECL(monhaskey, (struct monst *,BOOLEAN_P));
 E void FDECL(mon_regen, (struct monst *,BOOLEAN_P));
 E int FDECL(dochugw, (struct monst *));
 E boolean FDECL(onscary, (int,int,struct monst *));
index 8add2faffc049cd8e33784f62e4355e82063e513..b6139f5c2ed98575999debb60163ed227a26169a 100644 (file)
@@ -1,4 +1,4 @@
-/*     SCCS Id: @(#)dogmove.c  3.5     2005/10/10      */
+/*     SCCS Id: @(#)dogmove.c  3.5     2005/10/14      */
 /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
 /* NetHack may be freely redistributed.  See license for details. */
 
@@ -13,43 +13,109 @@ STATIC_DCL boolean FDECL(dog_hunger,(struct monst *,struct edog *));
 STATIC_DCL int FDECL(dog_invent,(struct monst *,struct edog *,int));
 STATIC_DCL int FDECL(dog_goal,(struct monst *,struct edog *,int,int,int));
 
-STATIC_DCL struct obj *FDECL(DROPPABLES, (struct monst *));
 STATIC_DCL boolean FDECL(can_reach_location,(struct monst *,XCHAR_P,XCHAR_P,
     XCHAR_P,XCHAR_P));
 STATIC_DCL boolean FDECL(could_reach_item,(struct monst *, XCHAR_P,XCHAR_P));
 STATIC_DCL void FDECL(quickmimic, (struct monst *));
 
-STATIC_OVL struct obj *
-DROPPABLES(mon)
-register struct monst *mon;
+/* pick a carried item for pet to drop */
+struct obj *
+droppables(mon)
+struct monst *mon;
 {
-       register struct obj *obj;
-       struct obj *wep = MON_WEP(mon);
-       boolean item1 = FALSE, item2 = FALSE, item3 = FALSE;
-
-       if (is_animal(mon->data) || mindless(mon->data))
-               item1 = item2 = item3 = TRUE;
-       if (!tunnels(mon->data) || !needspick(mon->data))
-               item1 = TRUE;
-       if (nohands(mon->data) || verysmall(mon->data))
-               item3 = TRUE;
-       for(obj = mon->minvent; obj; obj = obj->nobj) {
-               if (!item1 && is_pick(obj) && (obj->otyp != DWARVISH_MATTOCK
-                                               || !which_armor(mon, W_ARMS))) {
-                       item1 = TRUE;
-                       continue;
-               }
-               if (!item2 && obj->otyp == UNICORN_HORN && !obj->cursed) {
-                       item2 = TRUE;
-                       continue;
-               }
-               if (!item3 && obj->otyp == SKELETON_KEY) {
-                       item3 = TRUE;
-                       continue;
-               }
-               if (!obj->owornmask && obj != wep) return obj;
+    struct obj *obj, *wep,
+              dummy, *pickaxe, *unihorn, *key;
+
+#ifndef TOURIST
+#define CREDIT_CARD STRANGE_OBJECT     /* avoids messy conditionalization */
+#endif
+
+#ifndef GOLDOBJ
+    if (mon->mgold) return &zeroobj;   /* pet has something to drop */
+#endif
+    dummy = zeroobj;
+    dummy.otyp = GOLD_PIECE;   /* not STRANGE_OBJECT or tools of interest */
+    dummy.oartifact = 1; /* so real artifact won't override "don't keep it" */
+    pickaxe = unihorn = key = (struct obj *)0;
+    wep = MON_WEP(mon);
+
+    if (is_animal(mon->data) || mindless(mon->data)) {
+       /* won't hang on to any objects of these types */
+       pickaxe = unihorn = key = &dummy;   /* act as if already have them */
+    } else {
+       /* don't hang on to pick-axe if can't use one or don't need one */
+       if (!tunnels(mon->data) || !needspick(mon->data)) pickaxe = &dummy;
+       /* don't hang on to key if can't open doors */
+       if (nohands(mon->data) || verysmall(mon->data)) key = &dummy;
+    }
+    if (wep) {
+       if (is_pick(wep)) pickaxe = wep;
+       if (wep->otyp == UNICORN_HORN) unihorn = wep;
+       /* don't need any wielded check for keys... */
+    }
+
+    for (obj = mon->minvent; obj; obj = obj->nobj) {
+       switch (obj->otyp) {
+       case DWARVISH_MATTOCK:
+           /* reject mattock if couldn't wield it */
+           if (which_armor(mon, W_ARMS)) break;
+           /* keep mattock in preference to pick unless pick is already
+              wielded or is an artifact and mattock isn't */
+           if (pickaxe && pickaxe->otyp == PICK_AXE &&
+                   pickaxe != wep && (!pickaxe->oartifact || obj->oartifact))  
+               return pickaxe; /* drop the one we earlier decided to keep */   
+           /*FALLTHRU*/
+       case PICK_AXE:
+           if (!pickaxe || (obj->oartifact && !pickaxe->oartifact)) {
+               if (pickaxe) return pickaxe;
+               pickaxe = obj;          /* keep this digging tool */
+               continue;
+           }
+           break;
+
+       case UNICORN_HORN:
+           /* reject cursed unicorn horns */
+           if (obj->cursed) break;
+           /* keep artifact unihorn in preference to ordinary one */
+           if (!unihorn || (obj->oartifact && !unihorn->oartifact)) {
+               if (unihorn) return unihorn;
+               unihorn = obj;          /* keep this unicorn horn */
+               continue;
+           }
+           break;
+
+       case SKELETON_KEY:
+           /* keep key in preference to lock-pick */
+           if (key && key->otyp == LOCK_PICK &&
+                   (!key->oartifact || obj->oartifact))
+               return key;     /* drop the one we earlier decided to keep */   
+           /*FALLTHRU*/
+       case LOCK_PICK:
+           /* keep lock-pick in preference to credit card */
+           if (key && key->otyp == CREDIT_CARD &&
+                   (!key->oartifact || obj->oartifact))
+               return key;
+           /*FALLTHRU*/
+       case CREDIT_CARD:
+           if (!key || (obj->oartifact && !key->oartifact)) {
+               if (key) return key;
+               key = obj;              /* keep this unlocking tool */
+               continue;
+           }
+           break;
+
+       default:
+           break;
        }
-       return (struct obj *)0;
+
+       if (!obj->owornmask && obj != wep) return obj;
+    }
+
+#ifndef TOURIST
+#undef CREDIT_CARD
+#endif
+
+    return (struct obj *)0;    /* don't drop anything */
 }
 
 static NEARDATA const char nofetch[] = { BALL_CLASS, CHAIN_CLASS, ROCK_CLASS, 0 };
@@ -288,11 +354,7 @@ int udist;
        /* if we are carrying sth then we drop it (perhaps near @) */
        /* Note: if apport == 1 then our behaviour is independent of udist */
        /* Use udist+1 so steed won't cause divide by zero */
-#ifndef GOLDOBJ
-       if(DROPPABLES(mtmp) || mtmp->mgold) {
-#else
-       if(DROPPABLES(mtmp)) {
-#endif
+       if (droppables(mtmp)) {
            if (!rn2(udist+1) || !rn2(edog->apport))
                if(rn2(10) < edog->apport){
                    relobj(mtmp, (int)mtmp->minvis, TRUE);
@@ -363,7 +425,7 @@ int after, udist, whappr;
        omy = mtmp->my;
 
        in_masters_sight = couldsee(omx, omy);
-       dog_has_minvent = (DROPPABLES(mtmp) != 0);
+       dog_has_minvent = (droppables(mtmp) != 0);
 
        if (!edog || mtmp->mleashed) {  /* he's not going anywhere... */
            gtyp = APPORT;
@@ -595,7 +657,7 @@ register int after; /* this is extra fast monster movement */
        }
        if (!nohands(mtmp->data) && !verysmall(mtmp->data)) {
            allowflags |= OPENDOOR;
-           if (m_carrying(mtmp, SKELETON_KEY)) allowflags |= UNLOCKDOOR;
+           if (monhaskey(mtmp, TRUE)) allowflags |= UNLOCKDOOR;
            /* note:  the Wizard and Riders can unlock doors without a key;
               they won't use that ability if someone manages to tame them */
        }
index 85c2b46fa486e31979df2ebbf3f29b4d3d498619..1fb1d49345d00513850fec383a03eaa1e0364fd9 100644 (file)
@@ -1,4 +1,4 @@
-/*     SCCS Id: @(#)monmove.c  3.5     2005/10/05      */
+/*     SCCS Id: @(#)monmove.c  3.5     2005/10/14      */
 /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
 /* NetHack may be freely redistributed.  See license for details. */
 
@@ -39,6 +39,18 @@ register struct monst *mtmp;
        return(FALSE);
 }
 
+/* check whether a monster is carrying a locking/unlocking tool */
+boolean
+monhaskey(mon, for_unlocking)
+struct monst *mon;
+boolean for_unlocking; /* true => credit card ok, false => not ok */
+{
+#ifdef TOURIST
+    if (for_unlocking && m_carrying(mon, CREDIT_CARD)) return TRUE;
+#endif
+    return m_carrying(mon, SKELETON_KEY) || m_carrying(mon, LOCK_PICK);
+}
+
 STATIC_OVL void
 watch_on_duty(mtmp)
 register struct monst *mtmp;
@@ -676,7 +688,7 @@ register int after;
 #endif
            can_tunnel = tunnels(ptr);
        can_open = !(nohands(ptr) || verysmall(ptr));
-       can_unlock = ((can_open && m_carrying(mtmp, SKELETON_KEY)) ||
+       can_unlock = ((can_open && monhaskey(mtmp, TRUE)) ||
                      mtmp->iswiz || is_rider(ptr));
        doorbuster = is_giant(ptr);
        if(mtmp->wormno) goto not_special;
@@ -1120,7 +1132,8 @@ postmov:
                        && !can_tunnel /* taken care of below */
                      ) {
                    struct rm *here = &levl[mtmp->mx][mtmp->my];
-                   boolean btrapped = (here->doormask & D_TRAPPED);
+                   boolean btrapped = (here->doormask & D_TRAPPED),
+                           observeit = canseeit && canspotmon(mtmp);
 
                    if(here->doormask & (D_LOCKED|D_CLOSED) &&
                        (amorphous(ptr) || (!amorphous(ptr) && can_fog(mtmp) &&
@@ -1138,7 +1151,7 @@ postmov:
                            if(mb_trapped(mtmp)) return(2);
                        } else {
                            if (flags.verbose) {
-                               if (canseemon(mtmp))
+                               if (observeit)
                                    pline("%s unlocks and opens a door.",
                                          Monnam(mtmp));
                                else if (canseeit)
@@ -1158,7 +1171,9 @@ postmov:
                            if(mb_trapped(mtmp)) return(2);
                        } else {
                            if (flags.verbose) {
-                               if (canseeit)
+                               if (observeit)
+                                    pline("%s opens a door.", Monnam(mtmp));
+                               else if (canseeit)
                                     You_see("a door open.");
                                else if (!Deaf)
                                     You_hear("a door open.");
@@ -1176,7 +1191,10 @@ postmov:
                            if(mb_trapped(mtmp)) return(2);
                        } else {
                            if (flags.verbose) {
-                               if (canseeit)
+                               if (observeit)
+                                   pline("%s smashes down a door.",
+                                         Monnam(mtmp));
+                               else if (canseeit)
                                    You_see("a door crash open.");
                                else if (!Deaf)
                                    You_hear("a door crash open.");
index d3225a8bd0cb764feff7d351b8bd262d6a471e14..772cb04d26099eb8f5740d57f8fd9cbebf4c7027 100644 (file)
@@ -1,4 +1,4 @@
-/*     SCCS Id: @(#)steal.c    3.5     2005/07/14      */
+/*     SCCS Id: @(#)steal.c    3.5     2005/10/14      */
 /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
 /* NetHack may be freely redistributed.  See license for details. */
 
@@ -573,59 +573,32 @@ struct monst *mon;
 
 /* release the objects the creature is carrying */
 void
-relobj(mtmp,show,is_pet)
-register struct monst *mtmp;
-register int show;
+relobj(mtmp, show, is_pet)
+struct monst *mtmp;
+int show;
 boolean is_pet;                /* If true, pet should keep wielded/worn items */
 {
-       register struct obj *otmp;
-       register int omx = mtmp->mx, omy = mtmp->my;
-       struct obj *keepobj = 0;
-       struct obj *wep = MON_WEP(mtmp);
-       boolean item1 = FALSE, item2 = FALSE;
-
-       if (!is_pet || mindless(mtmp->data) || is_animal(mtmp->data))
-               item1 = item2 = TRUE;
-       if (!tunnels(mtmp->data) || !needspick(mtmp->data))
-               item1 = TRUE;
-
-       while ((otmp = mtmp->minvent) != 0) {
-               obj_extract_self(otmp);
-               /* special case: pick-axe and unicorn horn are non-worn */
-               /* items that we also want pets to keep 1 of */
-               /* (It is a coincidence that these can also be wielded.) */
-               if (otmp->owornmask || otmp == wep ||
-                   ((!item1 && otmp->otyp == PICK_AXE) ||
-                    (!item2 && otmp->otyp == UNICORN_HORN && !otmp->cursed))) {
-                       if (is_pet) { /* dont drop worn/wielded item */
-                               if (otmp->otyp == PICK_AXE)
-                                       item1 = TRUE;
-                               if (otmp->otyp == UNICORN_HORN && !otmp->cursed)
-                                       item2 = TRUE;
-                               otmp->nobj = keepobj;
-                               keepobj = otmp;
-                               continue;
-                       }
-               }
-               mdrop_obj(mtmp, otmp, is_pet && flags.verbose);
-       }
+       struct obj *otmp;
+       int omx = mtmp->mx, omy = mtmp->my;
 
-       /* put kept objects back */
-       while ((otmp = keepobj) != (struct obj *)0) {
-           keepobj = otmp->nobj;
-           (void) add_to_minv(mtmp, otmp);
-       }
 #ifndef GOLDOBJ
+       /* handle gold first since droppables() would get stuck on it */
        if (mtmp->mgold) {
-               register long g = mtmp->mgold;
+               long g = mtmp->mgold;
+
                (void) mkgold(g, omx, omy);
                if (is_pet && cansee(omx, omy) && flags.verbose)
-                       pline("%s drops %ld gold piece%s.", Monnam(mtmp),
-                               g, plur(g));
+                   pline("%s drops %ld gold piece%s.", Monnam(mtmp),
+                         g, plur(g));
                mtmp->mgold = 0L;
        }
 #endif
-       
+
+       while ((otmp = (is_pet ? droppables(mtmp) : mtmp->minvent)) != 0) {
+               obj_extract_self(otmp);
+               mdrop_obj(mtmp, otmp, is_pet && flags.verbose);
+       }
+
        if (show & cansee(omx, omy))
                newsym(omx, omy);
 }