]> granicus.if.org Git - nethack/commitdiff
redo magic whistle feedback
authorPatR <rankin@nethack.org>
Tue, 10 May 2022 22:53:24 +0000 (15:53 -0700)
committerPatR <rankin@nethack.org>
Tue, 10 May 2022 22:53:24 +0000 (15:53 -0700)
Give more information when magic whistle is already discovered and
applying it affects multiple pets, without much increase in verbosity.
For each of the three categories
 1) was already in view and moves to another spot still in view,
 2) was out of view and arrives at a spot within view,
 3) was in view but gets sent to a spot out of view,
show the pet by name (which might be "your <monst>" if it hasn't been
named) when there is just one, or "two creatures", "three...", "four...",
"several...", or "many..." when there are more than one.  The first
category with more than 1 says "creatures".  When there are additional
categories with more than 1, their part of the message says "others" if
prior part(s) already mention "creatures", or it says "other creatures"
if the prior part(s) only list pets by name.

For example
|Three creatures appear.
|Fido shifts location and Fang appears.
|Your pony shifts location and two other creatures appear.
|Many creatures shift locations, several others appear, and two others
disappear.
|Two creatures appear and two others disappear.

src/apply.c

index 74efe1fa83c0a4a83fd8ff2ccc963c56b570b24e..24bdb93aaeddeb1266f26574474de1e3525955fd 100644 (file)
@@ -1,4 +1,4 @@
-/* NetHack 3.7 apply.c $NHDT-Date: 1652091707 2022/05/09 10:21:47 $  $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.374 $ */
+/* NetHack 3.7 apply.c $NHDT-Date: 1652223183 2022/05/10 22:53:03 $  $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.375 $ */
 /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
 /*-Copyright (c) Robert Patrick Rankin, 2012. */
 /* NetHack may be freely redistributed.  See license for details. */
@@ -492,10 +492,17 @@ static void
 magic_whistled(struct obj *obj)
 {
     struct monst *mtmp, *nextmon;
-    char buf[BUFSZ];
+    char buf[BUFSZ], *mnam,
+         shiftbuf[BUFSZ + sizeof "shifts location"],
+         appearbuf[BUFSZ + sizeof "appears"],
+         disappearbuf[BUFSZ + sizeof "disappears"];
     boolean oseen, already_discovered = objects[obj->otyp].oc_name_known != 0;
     int omx, omy, shift = 0, appear = 0, disappear = 0;
-    const char *one = 0;
+
+    /* need to copy (up to 3) names as they're collected rather than just
+       save pointers to them, otherwise churning through every mbuf[] might
+       clobber the ones we care about */
+    shiftbuf[0] = appearbuf[0] = disappearbuf[0] = '\0';
 
     for (mtmp = fmon; mtmp; mtmp = nextmon) {
         nextmon = mtmp->nmon; /* trap might kill mon */
@@ -513,8 +520,8 @@ magic_whistled(struct obj *obj)
         }
 
         oseen = canspotmon(mtmp);
-        if (oseen && !one)
-            one = upstart(y_monnam(mtmp));
+        if (oseen) /* get name in case it's one we'll remember */
+            mnam = y_monnam(mtmp); /* before mnexto(); it might disappear */
         /* mimic must be revealed before we know whether it
            actually moves because line-of-sight may change */
         if (M_AP_TYPE(mtmp))
@@ -525,15 +532,17 @@ magic_whistled(struct obj *obj)
             mtmp->mundetected = 0; /* reveal non-mimic hider iff it moved */
 
             if (canspotmon(mtmp)) {
-                if (!one)
-                    one = upstart(y_monnam(mtmp));
-
-                if (oseen)
-                    ++shift;
-                else
-                    ++appear;
+                mnam = y_monnam(mtmp);
+                if (oseen) {
+                    if (++shift == 1)
+                        Sprintf(shiftbuf, "%s shifts location", mnam);
+                } else {
+                    if (++appear == 1)
+                        Sprintf(appearbuf, "%s appears", mnam);
+                }
             } else if (oseen) {
-                ++disappear;
+                if (++disappear == 1)
+                    Sprintf(disappearbuf, "%s disappears", mnam);
             }
             /*
              * FIXME:
@@ -568,47 +577,59 @@ magic_whistled(struct obj *obj)
      */
     buf[0] = '\0';
     if (!already_discovered) {
-        /* message(s) handled by rloc(); if the only noticeable change was
+        /* message(s) were handled by rloc(); if only noticeable change was
            pet(s) disappearing, the magic whistle won't become discovered */
         if (shift + appear > 0)
             makeknown(obj->otyp);
-    } else if (shift + appear > 0) {
-        /* rloc() message(s) were suppressed above so issue one now;
-           'one' should always be non-Null at this point */
-        if (shift + appear + disappear == 1 && one) {
-            Sprintf(buf, "%.99s %s", one,
-                    appear ? "appears" : "shifts location");
-        } else {
-            Strcpy(buf, (shift == 1) ? "One creature shifts location"
-                        : (shift > 1) ? "Some creatures shift locations"
-                          : "");
+    } else {
+        /* could use array of cardinal number names like wishcmdassist() but
+           extra precision above 3 or 4 seems pedantic; not used for 0 or 1 */
+#define HowMany(n) (((n) < 2) ? "sqrt(-1)"          \
+                    : ((n) == 2) ? "two"            \
+                      : ((n) == 3) ? "three"        \
+                        : ((n) == 4) ? "four"       \
+                          : ((n) <= 7) ? "several"  \
+                            : "many")
+        /* magic whistle is already discovered so rloc() message(s)
+           were suppressed above; if any discernible relocation occured,
+           construct a message now and issue it below */
+        if (shift > 0) {
+            if (shift > 1)
+                Sprintf(shiftbuf, "%s creatures shift locations",
+                        HowMany(shift));
+            copynchars(buf, upstart(shiftbuf), (int) sizeof buf - 1);
+        }
+        if (appear > 0) {
+            if (appear > 1)
+                /* shift==0: N creatures appear;
+                   shift==1: Foo shifts location and N other creatures appear;
+                   shift >1: M creatures shift locations and N others appear */
+                Sprintf(appearbuf, "%s %s appear", HowMany(appear),
+                        (shift == 0) ? "creatures"
+                        : (shift == 1) ? "other creatures"
+                          : "others");
             if (shift == 0)
-                Strcpy(buf, (appear == 1) ? "One creature appears"
-                            : (appear > 1) ? "Some creatures appear"
-                              : "");
-            else if (appear > 0)
-                Sprintf(eos(buf), "%s%s",
-                        disappear ? ", " : " and ",
-                        (appear == 1) ? "another appears" : "others appear");
-#if 0       /* this case can't happen; only get here when shift+appear > 0 */
-            if (shift == 0 && appear == 0)
-                Strcpy(buf, (disappear == 1) ? "One creature disappears"
-                            : (disappear > 1) ? "Some creatures disappear"
-                              : "");
+                copynchars(buf, upstart(appearbuf), (int) sizeof buf - 1);
             else
-#endif
-            if (disappear > 0)
-                Sprintf(eos(buf), "%s%s",
-                        (shift && appear) ? ", and " : " and ",
-                        (disappear == 1) ? "another disappears"
-                                         : "others disappear");
+                Snprintf(eos(buf), sizeof buf - strlen(buf), "%s %s",
+                         /* to get here:  appear > 0 and shift != 0,
+                            so "shifters, appearers" if disappear != 0
+                            with ", and disappearers" yet to be appended,
+                            or "shifters and appearers" otherwise */
+                         disappear ? "," : " and", appearbuf);
+        }
+        if (disappear > 0) {
+            if (disappear > 1)
+                Sprintf(disappearbuf, "%s %s disappear", HowMany(disappear),
+                        (shift == 0 && appear == 0) ? "creatures"
+                        : (shift < 2 && appear < 2) ? "other creatures"
+                          : "others");
+            if (shift + appear == 0)
+                copynchars(buf, upstart(disappearbuf), (int) sizeof buf - 1);
+            else
+                Snprintf(eos(buf), sizeof buf - strlen(buf), "%s and %s",
+                         (shift && appear) ? "," : "", disappearbuf);
         }
-    } else if (disappear > 0) {
-        /* none appeared or just shifted; 'one' should be non-Null  */
-        if (shift + appear + disappear == 1 && one)
-            Sprintf(buf, "%.99s disappears", one);
-        else
-            Strcpy(buf, "Some creatures disappear");
     }
     if (*buf)
         pline("%s.", buf);