]> granicus.if.org Git - nethack/commitdiff
OPTIONS=scores:own
authorPatR <rankin@nethack.org>
Fri, 16 Apr 2021 22:35:25 +0000 (15:35 -0700)
committerPatR <rankin@nethack.org>
Fri, 16 Apr 2021 22:35:25 +0000 (15:35 -0700)
From a beta tester six years ago:  specifying 'scores:own' resulted
in an option setting of 'scores:3 top/2 around/own' when player
wanted 'scores:0 top/0 around/own'.  Change it so that when fewer
than all three fields are given new values, the others are reset
rather than having their old values merge with new settings.

Also, 'scores:none' can be used to get 'scores:0 top/0 around/!own'
to skip the scores at the end without skipping notification of
whether the ending game's score made it into the top N list.
Options parsing accepts '!scores' and then ignores the negation.
Changing the optlist flags for 'scores' to allow negation resulted
in a complaint about missing value; I gave up instead of pursuing
that.  'scores:none' should suffice.

Setting 'scores:!top/own' or 'scores:!around/own' would behave as
'scores:1 top/!own' or 'scores:1 around/!own', respectively.
'scores:!top/!around/own' behaved as 'scores:1 top/1 around/own'
(note affect of two prior negations on final field compared to
single negation in the earlier two variations).  This fixes those.

doc/fixes37.0
src/options.c
src/topten.c

index a9b39b92834b90b172704bb17dc16806f0770ca8..c9809608248ff29adaf80904d05630f759567708 100644 (file)
@@ -455,6 +455,11 @@ if a branch has only one level (Fort Ludios), prevent creation of any level
 opening/unlocking magic zapped at monster holding the hero will release hold
        (zap at engulfer already expels hero); zapping at self has same effect
 when riding, allow scroll of remove curse to affect to affect steed's saddle
+the 'scores' option for final top ten display left default values in place if
+       only some of the three settings were set; 'scores:own' should have
+       produced '0 top/0 around/own' but ended up as '3 top/2 around/own';
+       also, allow 'scores:none' as shorthand for 'scores:0 t/0 a/!o' (player
+       will to told whether new score made the list but no scores get shown)
 
 
 Fixes to 3.7.0-x Problems that Were Exposed Via git Repository
index 4865ed6754b5262c39fac109a750ab025b8c646b..d04ab4ac437326ad37dcf795a3bb654dae3eaeec 100644 (file)
@@ -2721,44 +2721,61 @@ optfn_scores(int optidx, int req, boolean negated, char *opts, char *op)
         if ((op = string_for_opt(opts, FALSE)) == empty_optstr)
             return optn_err;
 
+        /* 3.7: earlier versions left old values for unspecified arguments
+           if player's scores:foo option only specified some of the three;
+           in particular, attempting to use 'scores:own' rather than
+           'scores:0 top/0 around/own' didn't work as intended */
+        flags.end_top = flags.end_around = 0, flags.end_own = FALSE;
+
+        if (negated)
+            op = eos(op);
+
         while (*op) {
             int inum = 1;
 
+            negated = (*op == '!');
+            if (negated)
+                op++;
+
             if (digit(*op)) {
                 inum = atoi(op);
                 while (digit(*op))
                     op++;
-            } else if (*op == '!') {
-                negated = !negated;
-                op++;
             }
             while (*op == ' ')
                 op++;
 
-            switch (*op) {
+            switch (lowc(*op)) {
             case 't':
-            case 'T':
-                flags.end_top = inum;
+                flags.end_top = negated ? 0 : inum;
                 break;
             case 'a':
-            case 'A':
-                flags.end_around = inum;
+                flags.end_around = negated ? 0 : inum;
                 break;
             case 'o':
-            case 'O':
-                flags.end_own = !negated;
+                flags.end_own = (negated || !inum) ? FALSE : TRUE;
                 break;
+            case 'n': /* none */
+                flags.end_top = flags.end_around = 0, flags.end_own = FALSE;
+                break;
+            case '-':
+                if (digit(*(op + 1))) {
+                    config_error_add(
+                       "Values for %s:top and %s:around must not be negative",
+                                     allopt[optidx].name,
+                                     allopt[optidx].name);
+                    return optn_silenterr;
+                }
+                /*FALLTHRU*/
             default:
                 config_error_add("Unknown %s parameter '%s'",
                                  allopt[optidx].name, op);
-                return optn_err;
+                return optn_silenterr;
             }
-            /* "3a" is sufficient but accept "3around" (or "3abracadabra")
-             */
+            /* "3a" is sufficient but accept "3around" (or "3abracadabra") */
             while (letter(*op))
                 op++;
-            /* t, a, and o can be separated by space(s) or slash or both
-             */
+            /* t, a, and o can be separated by space(s) or slash or both */
             while (*op == ' ')
                 op++;
             if (*op == '/')
@@ -2769,8 +2786,17 @@ optfn_scores(int optidx, int req, boolean negated, char *opts, char *op)
     if (req == get_val) {
         if (!opts)
             return optn_err;
-        Sprintf(opts, "%d top/%d around%s", flags.end_top, flags.end_around,
-                flags.end_own ? "/own" : "");
+        *opts = '\0';
+        if (flags.end_top > 0)
+            Sprintf(opts, "%d top", flags.end_top);
+        if (flags.end_around > 0)
+            Sprintf(eos(opts), "%s%d around",
+                    (flags.end_top > 0) ? "/" : "", flags.end_around);
+        if (flags.end_own)
+            Sprintf(eos(opts), "%sown",
+                    (flags.end_top > 0 || flags.end_around > 0) ? "/" : "");
+        if (!*opts)
+            Strcpy(opts, "none");
         return optn_ok;
     }
     return optn_ok;
index 430cd39ea720461394bb43a8ead15033e62b82ee..51a782c405456993a7111badea34dc36823b7035 100644 (file)
@@ -49,11 +49,13 @@ struct toptenentry {
     char plalign[ROLESZ + 1];
     char name[NAMSZ + 1];
     char death[DTHSZ + 1];
-} * tt_head;
+} *tt_head;
 /* size big enough to read in all the string fields at once; includes
    room for separating space or trailing newline plus string terminator */
 #define SCANBUFSZ (4 * (ROLESZ + 1) + (NAMSZ + 1) + (DTHSZ + 1) + 1)
 
+static struct toptenentry zerott;
+
 static void topten_print(const char *);
 static void topten_print_bold(const char *);
 static void outheader(void);
@@ -162,7 +164,7 @@ topten_print(const char *x)
 }
 
 static void
-topten_print_bold(const charx)
+topten_print_bold(const char *x)
 {
     if (g.toptenwin == WIN_ERR)
         raw_print_bold(x);
@@ -605,28 +607,20 @@ free_ttlist(struct toptenentry* tt)
 void
 topten(int how, time_t when)
 {
-    int uid = getuid();
-    int rank, rank0 = -1, rank1 = 0;
-    int occ_cnt = sysopt.persmax;
     register struct toptenentry *t0, *tprev;
     struct toptenentry *t1;
     FILE *rfile;
-    register int flg = 0;
-    boolean t0_used;
 #ifdef LOGFILE
     FILE *lfile;
-#endif /* LOGFILE */
+#endif
 #ifdef XLOGFILE
     FILE *xlfile;
-#endif /* XLOGFILE */
-
-#ifdef _DCC
-    /* Under DICE 3.0, this crashes the system consistently, apparently due to
-     * corruption of *rfile somewhere.  Until I figure this out, just cut out
-     * topten support entirely - at least then the game exits cleanly.  --AC
-     */
-    return;
 #endif
+    int uid = getuid();
+    int rank, rank0 = -1, rank1 = 0;
+    int occ_cnt = sysopt.persmax;
+    int flg = 0;
+    boolean t0_used, skip_scores;
 
     /* If we are in the midst of a panic, cut out topten entirely.
      * topten uses alloc() several times, which will lead to
@@ -651,6 +645,7 @@ topten(int how, time_t when)
     /* create a new 'topten' entry */
     t0_used = FALSE;
     t0 = newttentry();
+    *t0 = zerott;
     t0->ver_major = VERSION_MAJOR;
     t0->ver_minor = VERSION_MINOR;
     t0->patchlevel = PATCHLEVEL;
@@ -742,7 +737,7 @@ topten(int how, time_t when)
     t1 = tt_head = newttentry();
     tprev = 0;
     /* rank0: -1 undefined, 0 not_on_list, n n_th on list */
-    for (rank = 1;;) {
+    for (rank = 1; ; ) {
         readentry(rfile, t1);
         if (t1->points < sysopt.pointsmin)
             t1->points = 0;
@@ -774,7 +769,7 @@ topten(int how, time_t when)
                     char pbuf[BUFSZ];
 
                     Sprintf(pbuf,
-                        "You didn't beat your previous score of %ld points.",
+                         "You didn't beat your previous score of %ld points.",
                             t1->points);
                     topten_print(pbuf);
                     topten_print("");
@@ -823,43 +818,45 @@ topten(int how, time_t when)
                 topten_print("");
             }
     }
+    skip_scores = !flags.end_top && !flags.end_around && !flags.end_own;
     if (rank0 == 0)
         rank0 = rank1;
     if (rank0 <= 0)
         rank0 = rank;
-    if (!done_stopprint)
+    if (!skip_scores && !done_stopprint)
         outheader();
-    t1 = tt_head;
-    for (rank = 1; t1->points != 0; rank++, t1 = t1->tt_next) {
+    for (t1 = tt_head, rank = 1; t1->points != 0; t1 = t1->tt_next, ++rank) {
         if (flg
 #ifdef UPDATE_RECORD_IN_PLACE
             && rank >= rank0
 #endif
             )
             writeentry(rfile, t1);
-        if (done_stopprint)
-            continue;
-        if (rank > flags.end_top && (rank < rank0 - flags.end_around
-                                     || rank > rank0 + flags.end_around)
-            && (!flags.end_own
-                || (sysopt.pers_is_uid
-                        ? t1->uid == t0->uid
-                        : strncmp(t1->name, t0->name, NAMSZ) == 0)))
+        if (skip_scores || done_stopprint)
             continue;
-        if (rank == rank0 - flags.end_around
-            && rank0 > flags.end_top + flags.end_around + 1 && !flags.end_own)
-            topten_print("");
-        if (rank != rank0)
-            outentry(rank, t1, FALSE);
-        else if (!rank1)
-            outentry(rank, t1, TRUE);
-        else {
-            outentry(rank, t1, TRUE);
-            outentry(0, t0, TRUE);
+        if (rank <= flags.end_top
+            || (rank >= rank0 - flags.end_around
+                && rank <= rank0 + flags.end_around)
+            || (flags.end_own && (sysopt.pers_is_uid
+                                  ? t1->uid == t0->uid
+                                  : !strncmp(t1->name, t0->name, NAMSZ)))) {
+            if (rank == rank0 - flags.end_around
+                && rank0 > flags.end_top + flags.end_around + 1
+                && !flags.end_own)
+                topten_print("");
+
+            if (rank != rank0) {
+                outentry(rank, t1, FALSE);
+            } else if (!rank1) {
+                outentry(rank, t1, TRUE);
+            } else {
+                outentry(rank, t1, TRUE);
+                outentry(0, t0, TRUE);
+            }
         }
     }
     if (rank0 >= rank)
-        if (!done_stopprint)
+        if (!skip_scores && !done_stopprint)
             outentry(0, t0, TRUE);
 #ifdef UPDATE_RECORD_IN_PLACE
     if (flg) {
@@ -868,16 +865,16 @@ topten(int how, time_t when)
         truncate_file(rfile);
 #else
         /* use sentinel record rather than relying on truncation */
-        t1->points = 0L; /* terminates file when read back in */
-        t1->ver_major = t1->ver_minor = t1->patchlevel = 0;
-        t1->uid = t1->deathdnum = t1->deathlev = 0;
-        t1->maxlvl = t1->hp = t1->maxhp = t1->deaths = 0;
+        *t1 = zerott;
+        t1->points = 0L; /* [redundant] terminates file when read back in */
         t1->plrole[0] = t1->plrace[0] = t1->plgend[0] = t1->plalign[0] = '-';
-        t1->plrole[1] = t1->plrace[1] = t1->plgend[1] = t1->plalign[1] = 0;
         t1->birthdate = t1->deathdate = yyyymmdd((time_t) 0L);
         Strcpy(t1->name, "@");
-        Strcpy(t1->death, "<eod>\n");
+        Strcpy(t1->death, "<eod>\n"); /* end of data */
         writeentry(rfile, t1);
+        /* note: there might be junk (if file has shrunk due to shorter
+           entries supplanting longer ones) after this dummy entry, but
+           reading and/or updating will ignore it */
         (void) fflush(rfile);
 #endif /* TRUNCATE_FILE */
     }
@@ -886,10 +883,10 @@ topten(int how, time_t when)
     unlock_file(RECORD);
     free_ttlist(tt_head);
 
-showwin:
+ showwin:
     if (iflags.toptenwin && !done_stopprint)
         display_nhwindow(g.toptenwin, 1);
-destroywin:
+ destroywin:
     if (!t0_used)
         dealloc_ttentry(t0);
     if (iflags.toptenwin) {
@@ -1310,7 +1307,7 @@ get_rnd_toptenentry(void)
 
     tt = &tt_buf;
     rank = rnd(sysopt.tt_oname_maxrank);
-pickentry:
+ pickentry:
     for (i = rank; i; i--) {
         readentry(rfile, tt);
         if (tt->points == 0)