OPTIONS=scores:own

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.
This commit is contained in:
PatR
2021-04-16 15:35:25 -07:00
parent cf62687630
commit 563ed2f7db
3 changed files with 94 additions and 66 deletions

View 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

View 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;

View 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 char* x)
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)
if (skip_scores || 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)))
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)