OSDN Git Service

finalize changelog
[jnethack/source.git] / src / topten.c
index dbd1266..99f40ed 100644 (file)
@@ -1,10 +1,11 @@
-/* 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"
@@ -35,7 +36,10 @@ static long final_fpos;
 
 #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
 
@@ -63,16 +67,17 @@ struct toptenentry {
 
 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,
@@ -86,10 +91,11 @@ static winid toptenwin = WIN_ERR;
 
 /* "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, */
@@ -101,19 +107,31 @@ int how;
 /*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);
@@ -143,10 +161,43 @@ int how;
         (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
 }
 
@@ -170,7 +221,7 @@ const char *x;
         putstr(toptenwin, ATR_BOLD, x);
 }
 
-STATIC_OVL xchar
+int
 observable_depth(lev)
 d_level *lev;
 {
@@ -299,10 +350,10 @@ struct toptenentry *tt;
     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);
@@ -317,17 +368,8 @@ struct toptenentry *tt;
     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);
@@ -335,15 +377,18 @@ struct toptenentry *tt;
 #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);
@@ -358,11 +403,13 @@ struct toptenentry *tt;
     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
@@ -372,13 +419,8 @@ struct toptenentry *tt;
     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);
@@ -472,6 +514,8 @@ encodeachieve()
     return r;
 }
 
+#endif /* XLOGFILE */
+
 STATIC_OVL void
 free_ttlist(tt)
 struct toptenentry *tt;
@@ -559,13 +603,10 @@ time_t when;
     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
@@ -586,7 +627,7 @@ time_t when;
         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);
@@ -597,12 +638,14 @@ time_t when;
         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
@@ -714,7 +757,7 @@ time_t when;
                 } 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);
@@ -826,7 +869,11 @@ boolean so;
 {
     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];
@@ -872,17 +919,17 @@ boolean so;
         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*/
@@ -903,7 +950,7 @@ boolean so;
 #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*/
@@ -918,16 +965,14 @@ boolean so;
 /*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;
@@ -942,10 +987,16 @@ boolean so;
             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:
@@ -1007,9 +1058,11 @@ boolean so;
                 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, ".");
@@ -1033,7 +1086,7 @@ boolean so;
     /* 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';
@@ -1147,6 +1200,7 @@ int uid;
  * 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)
@@ -1221,8 +1275,21 @@ char **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("");
 
@@ -1323,25 +1390,19 @@ boolean fem;
 
 /*
  * 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;
@@ -1359,13 +1420,34 @@ pickentry:
             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;
 }