OSDN Git Service

upgrade to 3.6.2
[jnethack/source.git] / src / topten.c
index 164a3b2..61819e8 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-2019            */
 /* 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, */
@@ -112,10 +118,12 @@ int how;
     };
 #if 0 /*JP*/
     unsigned l;
-#endif
+    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*//*\90æ\82É\91Î\8fÛ\82ð\83R\83s\81[*/
     strncat(buf, kname, siz - 1);
     siz -= strlen(buf);
@@ -145,10 +153,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*//*JP:TODO:\8e\80\88ö\82Ì\91O\82É\8e\9d\82Á\82Ä\8ds\82©\82È\82¯\82ê\82Î\82È\82ç\82È\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
 }
 
@@ -172,7 +213,7 @@ const char *x;
         putstr(toptenwin, ATR_BOLD, x);
 }
 
-STATIC_OVL xchar
+int
 observable_depth(lev)
 d_level *lev;
 {
@@ -301,10 +342,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);
@@ -319,17 +360,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);
@@ -337,15 +369,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);
@@ -360,11 +395,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
@@ -374,13 +411,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);
@@ -474,6 +506,8 @@ encodeachieve()
     return r;
 }
 
+#endif /* XLOGFILE */
+
 STATIC_OVL void
 free_ttlist(tt)
 struct toptenentry *tt;
@@ -561,13 +595,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
@@ -588,7 +619,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);
@@ -599,12 +630,14 @@ time_t when;
         if (how != PANICKED)
             HUP {
                 char pbuf[BUFSZ];
+
                 topten_print("");
-                Sprintf(pbuf,
 #if 0 /*JP*/
+                Sprintf(pbuf,
              "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
@@ -951,7 +984,11 @@ boolean so;
 #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:
@@ -1013,9 +1050,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, ".");
@@ -1039,7 +1078,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';
@@ -1227,8 +1266,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("");
 
@@ -1329,25 +1381,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;
@@ -1365,13 +1411,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;
 }