]> granicus.if.org Git - nethack/commitdiff
Writing scrolls by type-name followup
authorMichael Meyer <me@entrez.cc>
Thu, 28 Oct 2021 21:18:20 +0000 (17:18 -0400)
committerMichael Meyer <me@entrez.cc>
Thu, 28 Oct 2021 21:18:20 +0000 (17:18 -0400)
Don't allow type-name of a scroll that has since been formally
identified to override a real scroll name.

For example, if a user typenames a scroll of fire 'earth', then IDs
fire but doesn't change the typename (reasonable, since it doesn't show
up anywhere in inventory at that point), if they try to write 'earth'
with a magic marker, don't produce a scroll of fire just because it's
still type-named 'earth'.  At that point they know it's not a scroll of
earth and it's no longer reasonable to assume they mean to use the
typename.

In other words, if a user-assigned typename matches a real scroll type,
write the scroll with the typename -- unless the player knows for sure
it doesn't match the actual scroll (whether because the actual scroll is
already IDed, or the typenamed scroll has been IDed as something else).
In that case write (or attempt to write) the actual scroll as though the
typename didn't exist.

src/write.c

index 20c4ba3bd243e5f6b969696d8b58b1d304065a91..6ccd45546842cd94aa67dde1061bcab170d6b8ea 100644 (file)
@@ -108,7 +108,7 @@ dowrite(struct obj *pen)
     int basecost, actualcost;
     int curseval;
     char qbuf[QBUFSZ];
-    int first, last, i, deferred, deferralchance;
+    int first, last, i, deferred, deferralchance, real;
     boolean by_descr = FALSE;
     const char *typeword;
 
@@ -170,10 +170,11 @@ dowrite(struct obj *pen)
         (void) mungspaces(bp + 1);        /* remove the extra space */
     }
 
-    deferred = 0;       /* not any scroll or book */
-    deferralchance = 0; /* incremented for each oc_uname match */
+    deferred = real = 0; /* not any scroll or book */
+    deferralchance = 0;  /* incremented for each oc_uname match */
     first = g.bases[(int) paper->oclass];
     last = g.bases[(int) paper->oclass + 1] - 1;
+    /* first loop: look for match with name/description */
     for (i = first; i <= last; i++) {
         /* extra shufflable descr not representing a real object */
         if (!OBJ_NAME(objects[i]))
@@ -184,24 +185,30 @@ dowrite(struct obj *pen)
                 /* spellbooks can only be written by_name, so no need to
                    hold out for a 'better' by_descr match */
                 || paper->oclass == SPBOOK_CLASS) {
-                by_descr = FALSE;
                 goto found;
-            } else if (!deferralchance) {
-                /* save item in case there are no better by_descr matches;
-                   don't increment deferralchance so that the first uname
-                   match will always override this */
-                deferred = i;
+            } else {
+                /* save item in case there are no better by_descr matches */
+                real = deferred = i;
+                break;
             }
         }
+
         if (!strcmpi(OBJ_DESCR(objects[i]), nm)) {
             by_descr = TRUE;
             goto found;
         }
-        /* user-assigned name might match real name of a later
-           entry, so we don't simply use first match with it;
-           also, player might assign same name multiple times
-           and if so, we choose one of those matches randomly */
+    }
+    /* second loop: look for match with user-assigned name */
+    /* we will get here if 'nm' isn't a real scroll name/descr, or is the name
+     * of a real scroll that hasn't been formally IDed. */
+    for (i = first; i <= last; i++) {
+        /* player might assign same name multiple times and if so,
+           we choose one of those matches randomly */
         if (objects[i].oc_uname && !strcmpi(objects[i].oc_uname, nm)
+            /* prefer attempting to write the real scroll type if
+               the typename clobbers a real scroll and is known to
+               be incorrect */
+            && !(real && objects[i].oc_name_known)
             /*
              * First match: chance incremented to 1,
              *   !rn2(1) is 1, we remember i;