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:
@@ -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
|
||||
|
||||
@@ -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;
|
||||
|
||||
95
src/topten.c
95
src/topten.c
@@ -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)
|
||||
|
||||
Reference in New Issue
Block a user