]> granicus.if.org Git - nethack/commitdiff
address #H4247 & #4248 - theft of quest artifact
authorPatR <rankin@nethack.org>
Sun, 28 Feb 2016 00:23:24 +0000 (16:23 -0800)
committerPatR <rankin@nethack.org>
Sun, 28 Feb 2016 00:23:24 +0000 (16:23 -0800)
Two different reports complaining that having the Wizard steal the
hero's quest artifact is a bad thing.  This doesn't change that,
but it does make all quest artifacts become equal targets so that
wishing for other roles' artifacts doesn't offer such a safe way to
have whichever special attributes they provide.

Quest artifacts are actually higher priority targets for theft than
the Amulet.  I suspect that probably wasn't originally intended,
but I left things that way.  Taking quest artifacts leaves the hero
more vulnerable to future thefts, and once they're gone the Amulet
has priority over the invocation tools.

doc/fixes36.1
include/obj.h
src/mhitu.c
src/steal.c
src/wizard.c

index 7003206ed9f388b5a61728ec05e88b387e00ae21..dc0c8e9af1bf613a0db32047f61a3e57b61ab2cb 100644 (file)
@@ -169,6 +169,7 @@ if a long worm inherited inventory from a previous shape, and if an egg or
        figurine in that inventory hatched or auto-activated, messages were
        given when hero could see any tail segment even if head was unseen,
        making it seem as if worm's inventory was kept in the visible segment
+Wizard will now steal any quest artifact from hero, not just own role's
 
 
 Platform- and/or Interface-Specific Fixes
index f2acaf80e1bedf1d2afefffc4dacba074f7cc243..d03aec2eca67efe8750b4d1da3629f8af4f046b8 100644 (file)
@@ -1,4 +1,4 @@
-/* NetHack 3.6 obj.h   $NHDT-Date: 1450306176 2015/12/16 22:49:36 $  $NHDT-Branch: NetHack-3.6.0 $:$NHDT-Revision: 1.51 $ */
+/* NetHack 3.6 obj.h   $NHDT-Date: 1456618994 2016/02/28 00:23:14 $  $NHDT-Branch: NetHack-3.6.0 $:$NHDT-Revision: 1.53 $ */
 /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
 /* NetHack may be freely redistributed.  See license for details. */
 
@@ -200,6 +200,8 @@ struct obj {
      && objects[otmp->otyp].oc_skill >= -P_SHURIKEN \
      && objects[otmp->otyp].oc_skill <= -P_BOW)
 #define uslinging() (uwep && objects[uwep->otyp].oc_skill == P_SLING)
+/* 'is_quest_artifact()' only applies to the current role's artifact */
+#define any_quest_artifact(o) ((o)->oartifact >= ART_ORB_OF_DETECTION)
 
 /* Armor */
 #define is_shield(otmp)          \
index d8c85a1330657b22d570deb31a8e2fdaae56245e..872ef8a17f8af5f6a57def9ce21f48d0109e7375 100644 (file)
@@ -1,4 +1,4 @@
-/* NetHack 3.6 mhitu.c $NHDT-Date: 1451084422 2015/12/25 23:00:22 $  $NHDT-Branch: NetHack-3.6.0 $:$NHDT-Revision: 1.132 $ */
+/* NetHack 3.6 mhitu.c $NHDT-Date: 1456618997 2016/02/28 00:23:17 $  $NHDT-Branch: NetHack-3.6.0 $:$NHDT-Revision: 1.135 $ */
 /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
 /* NetHack may be freely redistributed.  See license for details. */
 
@@ -1321,11 +1321,11 @@ register struct attack *mattk;
 
     case AD_SAMU:
         hitmsg(mtmp, mattk);
-        /* when the Wiz hits, 1/20 steals the amulet */
-        if (u.uhave.amulet || u.uhave.bell || u.uhave.book || u.uhave.menorah
-            || u.uhave.questart) /* carrying the Quest Artifact */
-            if (!rn2(20))
-                stealamulet(mtmp);
+        /* when the Wizard or quest nemesis hits, there's a 1/20 chance
+           to steal a quest artifact (any, not just the one for the hero's
+           own role) or the Amulet or one of the invocation tools */
+        if (!rn2(20))
+            stealamulet(mtmp);
         break;
 
     case AD_TLPT:
index 4b5378d960c662c8d8f25cbb81bbfbdf04d36f36..b3e5cb1f58c0b4e4f57201181c99cbf3167179fc 100644 (file)
@@ -1,4 +1,4 @@
-/* NetHack 3.6 steal.c $NHDT-Date: 1446713643 2015/11/05 08:54:03 $  $NHDT-Branch: master $:$NHDT-Revision: 1.65 $ */
+/* NetHack 3.6 steal.c $NHDT-Date: 1456618998 2016/02/28 00:23:18 $  $NHDT-Branch: NetHack-3.6.0 $:$NHDT-Revision: 1.67 $ */
 /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
 /* NetHack may be freely redistributed.  See license for details. */
 
@@ -506,50 +506,82 @@ register struct obj *otmp;
     return freed_otmp;
 }
 
+/* called for AD_SAMU (the Wizard and quest nemeses) */
 void
 stealamulet(mtmp)
 struct monst *mtmp;
 {
-    struct obj *otmp = (struct obj *) 0;
-    int real = 0, fake = 0;
-
-    /* select the artifact to steal */
-    if (u.uhave.amulet) {
-        real = AMULET_OF_YENDOR;
-        fake = FAKE_AMULET_OF_YENDOR;
-    } else if (u.uhave.questart) {
+    char buf[BUFSZ];
+    struct obj *otmp = 0, *obj = 0;
+    int real = 0, fake = 0, n;
+
+    /* target every quest artifact, not just current role's;
+       if hero has more than one, choose randomly so that player
+       can't use inventory ordering to influence the theft */
+    for (n = 0, obj = invent; obj; obj = obj->nobj)
+        if (any_quest_artifact(obj))
+            ++n, otmp = obj;
+    if (n > 1) {
+        n = rnd(n);
         for (otmp = invent; otmp; otmp = otmp->nobj)
-            if (is_quest_artifact(otmp))
+            if (any_quest_artifact(otmp) && !--n)
                 break;
-        if (!otmp)
-            return; /* should we panic instead? */
-    } else if (u.uhave.bell) {
-        real = BELL_OF_OPENING;
-        fake = BELL;
-    } else if (u.uhave.book) {
-        real = SPE_BOOK_OF_THE_DEAD;
-    } else if (u.uhave.menorah) {
-        real = CANDELABRUM_OF_INVOCATION;
-    } else
-        return; /* you have nothing of special interest */
+    }
 
     if (!otmp) {
+        /* if we didn't find any quest arifact, find another valuable item */
+        if (u.uhave.amulet) {
+            real = AMULET_OF_YENDOR;
+            fake = FAKE_AMULET_OF_YENDOR;
+        } else if (u.uhave.bell) {
+            real = BELL_OF_OPENING;
+            fake = BELL;
+        } else if (u.uhave.book) {
+            real = SPE_BOOK_OF_THE_DEAD;
+        } else if (u.uhave.menorah) {
+            real = CANDELABRUM_OF_INVOCATION;
+        } else
+            return; /* you have nothing of special interest */
+
         /* If we get here, real and fake have been set up. */
-        for (otmp = invent; otmp; otmp = otmp->nobj)
-            if (otmp->otyp == real || (otmp->otyp == fake && !mtmp->iswiz))
-                break;
+        for (n = 0, obj = invent; obj; obj = obj->nobj)
+            if (obj->otyp == real || (obj->otyp == fake && !mtmp->iswiz))
+                ++n, otmp = obj;
+        if (n > 1) {
+            n = rnd(n);
+            for (otmp = invent; otmp; otmp = otmp->nobj)
+                if ((otmp->otyp == real
+                     || (otmp->otyp == fake && !mtmp->iswiz)) && !--n)
+                    break;
+        }
     }
 
     if (otmp) { /* we have something to snatch */
+        /* take off outer gear if we're targetting [hypothetical]
+           quest artifact suit, shirt, gloves, or rings */
+        if ((otmp == uarm || otmp == uarmu) && uarmc)
+            (void) Cloak_off();
+        if (otmp == uarmu && uarm)
+            (void) Armor_off();
+        if ((otmp == uarmg || ((otmp == uright || otmp == uleft) && uarmg))
+            && uwep) {
+            /* gloves are about to be unworn; unwield weapon(s) first */
+            if (u.twoweap)
+                uswapwepgone(); /* will clear u.twoweap */
+            uwepgone();
+        }
+        if ((otmp == uright || otmp == uleft) && uarmg)
+            (void) Gloves_off(); /* handles wielded cockatrice corpse */
+
+        /* finally, steal the target item */
         if (otmp->owornmask)
             remove_worn_item(otmp, TRUE);
         if (otmp->unpaid)
             subfrombill(otmp, shop_keeper(*u.ushops));
         freeinv(otmp);
-        /* mpickobj wont merge otmp because none of the above things
-           to steal are mergable */
-        (void) mpickobj(mtmp, otmp); /* may merge and free otmp */
-        pline("%s stole %s!", Monnam(mtmp), doname(otmp));
+        Strcpy(buf, doname(otmp));
+        (void) mpickobj(mtmp, otmp); /* could merge and free otmp but won't */
+        pline("%s steals %s!", Monnam(mtmp), buf);
         if (can_teleport(mtmp->data) && !tele_restrict(mtmp))
             (void) rloc(mtmp, TRUE);
     }
@@ -643,7 +675,7 @@ boolean verbosely;
 
 /* some monsters bypass the normal rules for moving between levels or
    even leaving the game entirely; when that happens, prevent them from
-   taking the Amulet or invocation tools with them */
+   taking the Amulet, invocation items, or quest artifact with them */
 void
 mdrop_special_objs(mon)
 struct monst *mon;
@@ -653,8 +685,10 @@ struct monst *mon;
     for (obj = mon->minvent; obj; obj = otmp) {
         otmp = obj->nobj;
         /* the Amulet, invocation tools, and Rider corpses resist even when
-           artifacts and ordinary objects are given 0% resistance chance */
-        if (obj_resists(obj, 0, 0)) {
+           artifacts and ordinary objects are given 0% resistance chance;
+           current role's quest artifact is rescued too--quest artifacts
+           for the other roles are not */
+        if (obj_resists(obj, 0, 0) || is_quest_artifact(obj)) {
             obj_extract_self(obj);
             mdrop_obj(mon, obj, FALSE);
         }
index 2f7d2e7e479e51ca1c0da4c062eaed2260d54a81..f8d72c1c03f1ce678eb3ca1250be0ceae9a01e68 100644 (file)
@@ -1,4 +1,4 @@
-/* NetHack 3.6 wizard.c        $NHDT-Date: 1456185030 2016/02/22 23:50:30 $  $NHDT-Branch: NetHack-3.6.0 $:$NHDT-Revision: 1.47 $ */
+/* NetHack 3.6 wizard.c        $NHDT-Date: 1456618999 2016/02/28 00:23:19 $  $NHDT-Branch: NetHack-3.6.0 $:$NHDT-Revision: 1.48 $ */
 /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
 /* NetHack may be freely redistributed.  See license for details. */
 
@@ -119,7 +119,8 @@ register struct monst *mtmp;
     register struct obj *otmp;
 
     for (otmp = mtmp->minvent; otmp; otmp = otmp->nobj)
-        if (otmp->otyp == AMULET_OF_YENDOR || is_quest_artifact(otmp)
+        if (otmp->otyp == AMULET_OF_YENDOR
+            || any_quest_artifact(otmp)
             || otmp->otyp == BELL_OF_OPENING
             || otmp->otyp == CANDELABRUM_OF_INVOCATION
             || otmp->otyp == SPE_BOOK_OF_THE_DEAD)
@@ -175,7 +176,7 @@ register short otyp;
         if (otyp) {
             if (otmp->otyp == otyp)
                 return 1;
-        } else if (is_quest_artifact(otmp))
+        } else if (any_quest_artifact(otmp))
             return 1;
     }
     return 0;
@@ -207,7 +208,7 @@ register short otyp;
         if (otyp) {
             if (otmp->otyp == otyp)
                 return otmp;
-        } else if (is_quest_artifact(otmp))
+        } else if (any_quest_artifact(otmp))
             return otmp;
     return (struct obj *) 0;
 }