-/* NetHack 3.6 topten.c $NHDT-Date: 1448117546 2015/11/21 14:52:26 $ $NHDT-Branch: master $:$NHDT-Revision: 1.40 $ */
+/* NetHack 3.6 topten.c $NHDT-Date: 1450451497 2015/12/18 15:11:37 $ $NHDT-Branch: NetHack-3.6.0 $:$NHDT-Revision: 1.44 $ */
/* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
+/*-Copyright (c) Robert Patrick Rankin, 2012. */
/* NetHack may be freely redistributed. See license for details. */
/* JNetHack Copyright */
/* (c) Issei Numata, Naoki Hamada, Shigehiro Miyashita, 1994-2000 */
-/* For 3.4-, Copyright (c) SHIRAKATA Kentaro, 2002-2016 */
+/* For 3.4-, Copyright (c) SHIRAKATA Kentaro, 2002-2022 */
/* JNetHack may be freely redistributed. See license for details. */
#include "hack.h"
#define newttentry() (struct toptenentry *) alloc(sizeof (struct toptenentry))
#define dealloc_ttentry(ttent) free((genericptr_t) (ttent))
+#ifndef NAMSZ
+/* Changing NAMSZ can break your existing record/logfile */
#define NAMSZ 10
+#endif
#define DTHSZ 100
#define ROLESZ 3
STATIC_DCL void FDECL(topten_print, (const char *));
STATIC_DCL void FDECL(topten_print_bold, (const char *));
-STATIC_DCL xchar FDECL(observable_depth, (d_level *));
STATIC_DCL void NDECL(outheader);
STATIC_DCL void FDECL(outentry, (int, struct toptenentry *, BOOLEAN_P));
STATIC_DCL void FDECL(discardexcess, (FILE *));
STATIC_DCL void FDECL(readentry, (FILE *, struct toptenentry *));
STATIC_DCL void FDECL(writeentry, (FILE *, struct toptenentry *));
-STATIC_DCL void FDECL(writexlentry, (FILE *, struct toptenentry *));
+#ifdef XLOGFILE
+STATIC_DCL void FDECL(writexlentry, (FILE *, struct toptenentry *, int));
STATIC_DCL long NDECL(encodexlogflags);
STATIC_DCL long NDECL(encodeconduct);
STATIC_DCL long NDECL(encodeachieve);
+#endif
STATIC_DCL void FDECL(free_ttlist, (struct toptenentry *));
STATIC_DCL int FDECL(classmon, (char *, BOOLEAN_P));
STATIC_DCL int FDECL(score_wanted, (BOOLEAN_P, int, struct toptenentry *, int,
/* "killed by",&c ["an"] 'killer.name' */
void
-formatkiller(buf, siz, how)
+formatkiller(buf, siz, how, incl_helpless)
char *buf;
unsigned siz;
int how;
+boolean incl_helpless;
{
static NEARDATA const char *const killed_by_prefix[] = {
/* DIED, CHOKING, POISONING, STARVING, */
/*JP
"drowned in ", "burned by ", "dissolved in ", "crushed to death by ",
*/
- "\93M\8e\80\82µ\82½","\8fÄ\8e\80\82µ\82½", "\97n\8aâ\82É\97n\82¯\82½", "\89\9f\82µ\92×\82³\82ê\82½",
+ "\93M\8e\80\82µ\82½","\8fÄ\8e\80\82µ\82½", "\97n\8aâ\82É\97n\82¯\82½", "\89\9f\82µ\92×\82³\82ê\82½",
/* STONING, TURNED_SLIME, GENOCIDED, */
/*JP
"petrified by ", "turned to slime by ", "killed by ",
*/
- "\90Î\82É\82È\82Á\82½", "\82É\83X\83\89\83C\83\80\82É\82³\82ê\82½", "\8bs\8eE\82³\82ê\82½",
+ "\90Î\82É\82È\82Á\82½", "\82É\83X\83\89\83C\83\80\82É\82³\82ê\82½", "\8bs\8eE\82³\82ê\82½",
/* PANICKED, TRICKED, QUIT, ESCAPED, ASCENDED */
"", "", "", "", ""
};
+#if 0 /*JP*/
unsigned l;
+ char c, *kname = killer.name;
+#else
char *kname = killer.name;
+#endif
- buf[0] = '\0'; /* so strncat() can find the end */
+ buf[0] = '\0'; /* lint suppression */
+#if 1 /*JP*//*\91O\82É\8e\9d\82Á\82Ä\82\82é*/
+ if (incl_helpless && multi) {
+ if (multi_reason)
+ Sprintf(buf, "%s\81C", multi_reason);
+ else
+ Strcpy(buf, "\8f\95\82¯\82ð\8eó\82¯\82ç\82ê\82È\82¢\8aÔ\82É\81C");
+ }
+#endif
#if 1 /*JP*//*\90æ\82É\91Î\8fÛ\82ð\83R\83s\81[*/
strncat(buf, kname, siz - 1);
siz -= strlen(buf);
(void) strncat(buf, "\82É\8eE\82³\82ê\82½", siz - 1);
#endif
}
-#if 0 /*JP*//*\8aù\82É\83R\83s\81[\8dÏ\82Ý*/
- /* we're writing into buf[0] (after possibly advancing buf) rather than
- appending, but strncat() appends a terminator and strncpy() doesn't */
- (void) strncat(buf, kname, siz - 1);
+#if 0 /*JP*//*\8aù\82É\83R\83s\81[\8dÏ\82Ý*//*JP:TODO:\83T\83j\83^\83C\83Y\82ª\95K\97v*/
+ /* Copy kname into buf[].
+ * Object names and named fruit have already been sanitized, but
+ * monsters can have "called 'arbitrary text'" attached to them,
+ * so make sure that that text can't confuse field splitting when
+ * record, logfile, or xlogfile is re-read at some later point.
+ */
+ while (--siz > 0) {
+ c = *kname++;
+ if (!c)
+ break;
+ else if (c == ',')
+ c = ';';
+ /* 'xlogfile' doesn't really need protection for '=', but
+ fixrecord.awk for corrupted 3.6.0 'record' does (only
+ if using xlogfile rather than logfile to repair record) */
+ else if (c == '=')
+ c = '_';
+ /* tab is not possible due to use of mungspaces() when naming;
+ it would disrupt xlogfile parsing if it were present */
+ else if (c == '\t')
+ c = ' ';
+ *buf++ = c;
+ }
+ *buf = '\0';
+#endif
+
+#if 0 /*JP*//*\91O\82É\8e\9d\82Á\82Ä\8ds\82*/
+ if (incl_helpless && multi) {
+ /* X <= siz: 'sizeof "string"' includes 1 for '\0' terminator */
+ if (multi_reason && strlen(multi_reason) + sizeof ", while " <= siz)
+ Sprintf(buf, ", while %s", multi_reason);
+ /* either multi_reason wasn't specified or wouldn't fit */
+ else if (sizeof ", while helpless" <= siz)
+ Strcpy(buf, ", while helpless");
+ /* else extra death info won't fit, so leave it out */
+ }
#endif
}
putstr(toptenwin, ATR_BOLD, x);
}
-STATIC_OVL xchar
+int
observable_depth(lev)
d_level *lev;
{
static const char fmt33[] = "%s %s %s %s "; /* role,race,gndr,algn */
#ifndef NO_SCAN_BRACK
static const char fmt0[] = "%d.%d.%d %ld %d %d %d %d %d %d %ld %ld %d ";
- static const char fmtX[] = "%s,%s%s%s\n";
+ static const char fmtX[] = "%s,%s\n";
#else /* NO_SCAN_BRACK */
static const char fmt0[] = "%d %d %d %ld %d %d %d %d %d %d %ld %ld %d ";
- static const char fmtX[] = "%s %s%s%s\n";
+ static const char fmtX[] = "%s %s\n";
nsb_mung_line(tt->name);
nsb_mung_line(tt->death);
else
(void) fprintf(rfile, fmt33, tt->plrole, tt->plrace, tt->plgend,
tt->plalign);
-#if 0 /*JP*/
(void) fprintf(rfile, fmtX, onlyspace(tt->name) ? "_" : tt->name,
- tt->death,
- (multi ? ", while " : ""),
- (multi ? (multi_reason ? multi_reason : "helpless") : ""));
-#else
- (void) fprintf(rfile, fmtX, onlyspace(tt->name) ? "_" : tt->name,
- (multi ? (multi_reason ? multi_reason : "\96³\97Í\82È\8aÔ\82É") : ""),
- tt->death,
- "");
-#endif
+ tt->death);
#ifdef NO_SCAN_BRACK
nsb_unmung_line(tt->name);
#endif
}
+#ifdef XLOGFILE
+
/* as tab is never used in eg. plname or death, no need to mangle those. */
STATIC_OVL void
-writexlentry(rfile, tt)
+writexlentry(rfile, tt, how)
FILE *rfile;
struct toptenentry *tt;
+int how;
{
#define Fprintf (void) fprintf
#define XLOG_SEP '\t' /* xlogfile field separator. */
- char buf[BUFSZ];
+ char buf[BUFSZ], tmpbuf[DTHSZ + 1];
Sprintf(buf, "version=%d.%d.%d", tt->ver_major, tt->ver_minor,
tt->patchlevel);
Sprintf(buf, "%crole=%s%crace=%s%cgender=%s%calign=%s", XLOG_SEP,
tt->plrole, XLOG_SEP, tt->plrace, XLOG_SEP, tt->plgend, XLOG_SEP,
tt->plalign);
+ /* make a copy of death reason that doesn't include ", while helpless" */
+ formatkiller(tmpbuf, sizeof tmpbuf, how, FALSE);
Fprintf(rfile, "%s%cname=%s%cdeath=%s",
buf, /* (already includes separator) */
- XLOG_SEP, plname, XLOG_SEP, tt->death);
+ XLOG_SEP, plname, XLOG_SEP, tmpbuf);
if (multi)
-#if 0 /*JP*/
+#if 0 /*JP:T*/
Fprintf(rfile, "%cwhile=%s", XLOG_SEP,
multi_reason ? multi_reason : "helpless");
#else
Fprintf(rfile, "%cconduct=0x%lx%cturns=%ld%cachieve=0x%lx", XLOG_SEP,
encodeconduct(), XLOG_SEP, moves, XLOG_SEP, encodeachieve());
Fprintf(rfile, "%crealtime=%ld%cstarttime=%ld%cendtime=%ld", XLOG_SEP,
-#if 0 /*C360-19*/
- (long) urealtime.realtime, XLOG_SEP, (long) ubirthday, XLOG_SEP,
- (long) urealtime.endtime);
-#else
(long) urealtime.realtime, XLOG_SEP,
(long) ubirthday, XLOG_SEP, (long) urealtime.finish_time);
-#endif
Fprintf(rfile, "%cgender0=%s%calign0=%s", XLOG_SEP,
genders[flags.initgend].filecode, XLOG_SEP,
aligns[1 - u.ualignbase[A_ORIGINAL]].filecode);
return r;
}
+#endif /* XLOGFILE */
+
STATIC_OVL void
free_ttlist(tt)
struct toptenentry *tt;
copynchars(t0->plgend, genders[flags.female].filecode, ROLESZ);
copynchars(t0->plalign, aligns[1 - u.ualign.type].filecode, ROLESZ);
copynchars(t0->name, plname, NAMSZ);
- formatkiller(t0->death, sizeof t0->death, how);
+ formatkiller(t0->death, sizeof t0->death, how, TRUE);
t0->birthdate = yyyymmdd(ubirthday);
t0->deathdate = yyyymmdd(when);
t0->tt_next = 0;
-#if 0 /*C360-19*/
- urealtime.endtime = when;
-#endif
#ifdef UPDATE_RECORD_IN_PLACE
t0->fpos = -1L;
#endif
if (!(xlfile = fopen_datafile(XLOGFILE, "a", SCOREPREFIX))) {
HUP raw_print("Cannot open extended log file!");
} else {
- writexlentry(xlfile, t0);
+ writexlentry(xlfile, t0, how);
(void) fclose(xlfile);
}
unlock_file(XLOGFILE);
if (how != PANICKED)
HUP {
char pbuf[BUFSZ];
+
topten_print("");
+#if 0 /*JP:T*/
Sprintf(pbuf,
-#if 0 /*JP*/
"Since you were in %s mode, the score list will not be checked.",
wizard ? "wizard" : "discover");
#else
+ Sprintf(pbuf,
"%s\83\82\81[\83h\82Å\83v\83\8c\83C\82µ\82½\82Ì\82Å\83X\83R\83A\83\8a\83X\83g\82É\82Í\8dÚ\82ç\82È\82¢\81D",
wizard ? "\83E\83B\83U\81[\83h" : "\94\8c©");
#endif
} else {
char pbuf[BUFSZ];
-#if 0 /*JP*/
+#if 0 /*JP:T*/
Sprintf(pbuf,
"You reached the %d%s place on the top %d list.",
rank0, ordin(rank0), sysopt.entrymax);
{
boolean second_line = TRUE;
char linebuf[BUFSZ];
+#if 0 /*JP*/
char *bp, hpbuf[24], linebuf3[BUFSZ];
+#else
+ char *bp, hpbuf[24];
+#endif
int hppos, lngr;
#if 1 /*JP*/
char who[BUFSZ];
Strcat(linebuf, "\82Í");
/*JP: \93ú\96{\8cê\82Å\82Í\81u\81\9b\81\9b\82ð\8eè\82É\81v\82ð\90æ\82É\92Ç\89Á\82µ\82È\82¢\82Æ\95s\8e©\91R */
jdeath = t1->death;
- if (!strncmp(jdeath, "\96\82\8f\9c\82¯\82ð\8eè\82É", 12))
+ if (!STRNCMP2(jdeath, "\96\82\8f\9c\82¯\82ð\8eè\82É"))
jdeath += 12;
- else if (!strncmp(jdeath, "\93V\8fã\82Å\92p\90J\82ð\8eó\82¯", 16))
+ else if (!STRNCMP2(jdeath, "\93V\8fã\82Å\92p\90J\82ð\8eó\82¯"))
jdeath += 16;
- else if (!strncmp(jdeath, "\8bU\95¨\82Ì\96\82\8f\9c\82¯\82ð\92Í\82Ü\82³\82ê", 24))
+ else if (!STRNCMP2(jdeath, "\8bU\95¨\82Ì\96\82\8f\9c\82¯\82ð\92Í\82Ü\82³\82ê"))
jdeath += 24;
#endif
#if 0 /*JP*/
if (!strncmp("escaped", t1->death, 7)) {
#else
- if (!strncmp("\92E\8fo\82µ\82½", jdeath, 8)
+ if (!STRNCMP2("\92E\8fo\82µ\82½", jdeath)
|| !strncmp("escaped", jdeath, 7)) {
#endif
#if 0 /*JP*/
#if 0 /*JP*/
} else if (!strncmp("ascended", t1->death, 8)) {
#else
- } else if (!strncmp("\8f¸\93V\82µ\82½", jdeath, 8)
+ } else if (!STRNCMP2("\8f¸\93V\82µ\82½", jdeath)
|| !strncmp("ascended", jdeath, 8)) {
#endif
#if 0 /*JP:T*/
/*JP
if (!strncmp(t1->death, "quit", 4)) {
*/
- if (!strncmp(jdeath, "\94²\82¯\82½", 4)) {
+ if (!STRNCMP2(jdeath, "\94²\82¯\82½")) {
#if 0 /*JP*/
Strcat(linebuf, "quit");
#else
Strcat(action, t1->death);
#endif
second_line = FALSE;
-#if 1 /*JP*/
- }
-#else
+#if 0 /*JP*/
} else if (!strncmp(t1->death, "died of st", 10)) {
Strcat(linebuf, "starved to death");
second_line = FALSE;
Strcat(linebuf, "turned to stone");
} else
Strcat(linebuf, "died");
+#else
+ }
#endif /*JP*/
if (t1->deathdnum == astral_level.dnum) {
+#if 0 /*JP*/
const char *arg, *fmt = " on the Plane of %s";
+#else
+ const char *arg;
+#endif
switch (t1->deathlev) {
case -5:
Sprintf(eos(where), "[\8dÅ\91å\92n\89º%d\8aK]", t1->maxlvl);
}
+#if 0 /*JP*//* \93ú\96{\8cê\82Å\82Í\8d×\8dH\95s\97v */
/* kludge for "quit while already on Charon's boat" */
if (!strncmp(t1->death, "quit ", 5))
Strcat(linebuf, t1->death + 4);
+#endif
}
#if 0 /*JP*/
Strcat(linebuf, ".");
/* beginning of hp column after padding (not actually padded yet) */
hppos = COLNO - (sizeof(" Hp [max]") - 1); /* sizeof(str) includes \0 */
#if 1 /*JP*/
- while(lngr >= hppos ){
+ while (lngr >= hppos) {
/*JP hppos\82æ\82è\91O\82Ì\93K\93\96\82È\88Ê\92u\82Å\95ª\8a\84\82·\82é\81D*/
car[0] = '\0';
cdr[0] = '\0';
* print selected parts of score list.
* argc >= 2, with argv[0] untrustworthy (directory names, et al.),
* and argv[1] starting with "-s".
+ * caveat: some shells might allow argv elements to be arbitrarily long.
*/
void
prscore(argc, argv)
players = &player0;
}
} else {
+#if 0 /*JP*/
playerct = --argc;
players = (const char **) ++argv;
+#else
+ int j;
+ playerct = --argc;
+ ++argv;
+ players = (const char **)alloc(sizeof(char *) * argc + 1);
+ for (j = 0; j < argc; j++) {
+ char *p = (char *)str2ic(argv[j]);
+ players[j] = (char *)alloc(strlen(p) + 1);
+ strcpy((void *)players[j], p);
+ }
+ players[j] = NULL;
+#endif
}
raw_print("");
/*
* Get a random player name and class from the high score list,
- * and attach them to an object (for statues or morgue corpses).
*/
-struct obj *
-tt_oname(otmp)
-struct obj *otmp;
+struct toptenentry *
+get_rnd_toptenentry()
{
- int rank;
- register int i;
- register struct toptenentry *tt;
+ int rank, i;
FILE *rfile;
- struct toptenentry tt_buf;
-
- if (!otmp)
- return (struct obj *) 0;
+ register struct toptenentry *tt;
+ static struct toptenentry tt_buf;
rfile = fopen_datafile(RECORD, "r", SCOREPREFIX);
if (!rfile) {
impossible("Cannot open record file!");
- return (struct obj *) 0;
+ return NULL;
}
tt = &tt_buf;
rewind(rfile);
goto pickentry;
}
- otmp = (struct obj *) 0;
- } else {
- set_corpsenm(otmp, classmon(tt->plrole, (tt->plgend[0] == 'F')));
- otmp = oname(otmp, tt->name);
+ tt = NULL;
}
(void) fclose(rfile);
+ return tt;
+}
+
+
+/*
+ * Attach random player name and class from high score list
+ * to an object (for statues or morgue corpses).
+ */
+struct obj *
+tt_oname(otmp)
+struct obj *otmp;
+{
+ struct toptenentry *tt;
+ if (!otmp)
+ return (struct obj *) 0;
+
+ tt = get_rnd_toptenentry();
+
+ if (!tt)
+ return (struct obj *) 0;
+
+ set_corpsenm(otmp, classmon(tt->plrole, (tt->plgend[0] == 'F')));
+ otmp = oname(otmp, tt->name);
+
return otmp;
}