]> granicus.if.org Git - nethack/commitdiff
Add Extended Logfile
authorPasi Kallinen <paxed@alt.org>
Thu, 12 Mar 2015 19:35:04 +0000 (21:35 +0200)
committerPasi Kallinen <paxed@alt.org>
Thu, 12 Mar 2015 19:35:04 +0000 (21:35 +0200)
19 files changed:
doc/fixes35.0
include/config.h
include/decl.h
include/dungeon.h
include/extern.h
include/obj.h
include/you.h
src/allmain.c
src/do.c
src/dungeon.c
src/end.c
src/invent.c
src/mon.c
src/pray.c
src/restore.c
src/save.c
src/sp_lev.c
src/topten.c
sys/unix/Makefile.top

index 4ad731e36609356d95f95a66da70a7e6b9c360e3..10b4a8f68588afe19b71daf30e5c9ec3116e3e39 100644 (file)
@@ -1120,6 +1120,7 @@ adopt/adapt/improve the Paranoid_Quit patch; default is paranoid_confirm:pray
        paranoid_confirm:pray    y to confirm #pray; supersedes prayconfirm
        paranoid_confirm:Remove  always pick from inventory for 'R' and 'T'
 adopt/adapt/improve Dungeon Overview
+Aardvark Joe's Extended Logfile
 
 
 Code Cleanup and Reorganization
index 930bd549c123be356f85cb35861d1b2a50f85718..d8c96af14ef7064836f9898bda49df4b434ea620 100644 (file)
 #endif
 
 #define LOGFILE "logfile"      /* larger file for debugging purposes */
+#define XLOGFILE "xlogfile"    /* even larger logfile */
 #define NEWS "news"            /* the file containing the latest hack news */
 #define PANICLOG "paniclog"    /* log of panic and impossible events */
 
index 4591226e49e96502bc6e54dfeb0925e4bc21d3a8..2071277dc439771944550717325ef751b320eaa1 100644 (file)
@@ -67,6 +67,8 @@ E struct dgn_topology {               /* special dungeon levels for speed */
     xchar      d_mines_dnum, d_quest_dnum;
     d_level    d_qstart_level, d_qlocate_level, d_nemesis_level;
     d_level    d_knox_level;
+    d_level    d_mineend_level;
+    d_level    d_sokoend_level;
 } dungeon_topology;
 /* macros for accesing the dungeon levels by their old names */
 #define oracle_level           (dungeon_topology.d_oracle_level)
@@ -97,6 +99,8 @@ E struct dgn_topology {               /* special dungeon levels for speed */
 #define qlocate_level          (dungeon_topology.d_qlocate_level)
 #define nemesis_level          (dungeon_topology.d_nemesis_level)
 #define knox_level             (dungeon_topology.d_knox_level)
+#define mineend_level          (dungeon_topology.d_mineend_level)
+#define sokoend_level          (dungeon_topology.d_sokoend_level)
 
 E NEARDATA stairway dnstair, upstair;          /* stairs up and down */
 #define xdnstair       (dnstair.sx)
index f2bf75ef610db9eb093e7f6e16ab1898797aa708..3607649b0502231528893750a77019583ba84531 100644 (file)
@@ -122,6 +122,8 @@ typedef struct branch {
 #define Is_qlocate(x)          (on_level(x, &qlocate_level))
 #define Is_nemesis(x)          (on_level(x, &nemesis_level))
 #define Is_knox(x)             (on_level(x, &knox_level))
+#define Is_mineend_level(x)    (on_level(x, &mineend_level))
+#define Is_sokoend_level(x)    (on_level(x, &sokoend_level))
 
 #define In_sokoban(x)          ((x)->dnum == sokoban_dnum)
 #define Inhell                 In_hell(&u.uz)  /* now gehennom */
index f382c4f7a5ac9cbc46f5994116194bf6b2330f1f..7e222778fc06058524bd1656ba1e173c0b7b1c02 100644 (file)
@@ -26,6 +26,7 @@ E void NDECL(stop_occupation);
 E void NDECL(display_gamewindows);
 E void NDECL(newgame);
 E void FDECL(welcome, (BOOLEAN_P));
+E time_t NDECL(get_realtime);
 
 /* ### apply.c ### */
 
index fe43d0878f9c7cf3b5c8318a7fa88e0b975dd81e..f4fd7800701e337d668378edf799e461f4f5d16c 100644 (file)
@@ -109,6 +109,7 @@ struct obj {
 #define leashmon  corpsenm     /* gets m_id of attached pet */
 #define spestudied corpsenm    /* # of times a spellbook has been studied */
 #define fromsink  corpsenm     /* a potion from a sink */
+#define record_achieve_special corpsenm
        unsigned oeaten;        /* nutrition left in food, if partly eaten */
        long age;               /* creation date */
        long owornmask;
index 0c343b3c4974237f6cee9f42a693d76bafaa6df0..81aba0ba4f69efb03a17a904a03879a4ebdb343d 100644 (file)
@@ -53,6 +53,26 @@ struct u_event {
        Bitfield(ascended,1);           /* has offered the Amulet */
 };
 
+struct u_achieve {
+       Bitfield(amulet,1);             /* touched Amulet */
+       Bitfield(bell,1);               /* touched Bell */
+       Bitfield(book,1);               /* touched Book */
+       Bitfield(menorah,1);            /* touched Candelabrum */
+       Bitfield(enter_gehennom,1);     /* entered Gehennom (or Valley) by any means */
+       Bitfield(ascended,1);           /* not quite the same as u.uevent.ascended */
+       Bitfield(mines_luckstone,1);    /* got a luckstone at end of mines */
+       Bitfield(finish_sokoban,1);     /* obtained the sokoban prize */
+
+       Bitfield(killed_medusa,1);
+};
+
+struct u_realtime {
+       time_t realtime;                /* actual playing time up until the last restore */
+       time_t restored;                /* time the game was started or restored */
+       time_t endtime;
+};
+
+
 /* KMH, conduct --
  * These are voluntary challenges.  Each field denotes the number of
  * times a challenge has been violated.
@@ -306,6 +326,8 @@ struct you {
        /* 1 free bit! */
 
        unsigned udg_cnt;               /* how long you have been demigod */
+       struct u_achieve uachieve;      /* achievements */
+       struct u_realtime urealtime;
        struct u_event  uevent;         /* certain events have happened */
        struct u_have   uhave;          /* you're carrying special objects */
        struct u_conduct uconduct;      /* KMH, conduct */
index 2bb1c42401781d8e8222a5b517367a46723621d1..eb1f2b69bef8cb68c52be6cd2d77f130900b8d3b 100644 (file)
@@ -533,6 +533,13 @@ newgame()
 #endif
        program_state.something_worth_saving++; /* useful data now exists */
 
+       u.urealtime.realtime = (time_t)0L;
+#if defined(BSD) && !defined(POSIX_TYPES)
+        (void) time((long *)&u.urealtime.restored);
+#else
+        (void) time(&u.urealtime.restored);
+#endif
+
        /* Success! */
        welcome(TRUE);
        return;
index 3069a40479dfcd84e4a85891926368562259d456..44b2a23bbcd7c09f7824c995ba19e972999654bb 100644 (file)
--- a/src/do.c
+++ b/src/do.c
@@ -1316,6 +1316,7 @@ boolean at_stairs, falling, portal;
 #endif
                You_hear("groans and moans everywhere.");
            } else pline("It is hot here.  You smell smoke...");
+           u.uachieve.enter_gehennom = 1;
        }
        /* in case we've managed to bypass the Valley's stairway down */
        if (Inhell && !Is_valley(&u.uz)) u.uevent.gehennom_entered = 1;
index 4c8e6beebf82f7ab2008a122ad2a6fdec222ad4e..fd253750fcf661cd08af68aba7692750723e0328 100644 (file)
@@ -672,6 +672,8 @@ struct level_map {
        { "wizard1",    &wiz1_level },
        { "wizard2",    &wiz2_level },
        { "wizard3",    &wiz3_level },
+       { "minend",     &mineend_level },
+       { "soko1",      &sokoend_level },
        { X_START,      &qstart_level },
        { X_LOCATE,     &qlocate_level },
        { X_GOAL,       &nemesis_level },
index 995ef8ec75bfc98542c87eaa8211ce75bac5e958..111fd1b3a87c83d3544302f6ee1513833119f917 100644 (file)
--- a/src/end.c
+++ b/src/end.c
@@ -911,6 +911,7 @@ die:
           topten figure it out separately and possibly getting different
            time or even day if player is slow responding to --More-- */
        endtime = getnow();
+       u.urealtime.realtime += (endtime - u.urealtime.restored);
 
        /* Sometimes you die on the first move.  Life's not fair.
         * On those rare occasions you get hosed immediately, go out
index 62295915c003942be833c809642407425c9bfc76..24213c7e37823f18a0fd157a5f0273f88cd34909 100644 (file)
@@ -240,15 +240,19 @@ struct obj *obj;
        } else if (obj->otyp == AMULET_OF_YENDOR) {
                if (u.uhave.amulet) impossible("already have amulet?");
                u.uhave.amulet = 1;
+               u.uachieve.amulet = 1;
        } else if (obj->otyp == CANDELABRUM_OF_INVOCATION) {
                if (u.uhave.menorah) impossible("already have candelabrum?");
                u.uhave.menorah = 1;
+               u.uachieve.menorah = 1;
        } else if (obj->otyp == BELL_OF_OPENING) {
                if (u.uhave.bell) impossible("already have silver bell?");
                u.uhave.bell = 1;
+               u.uachieve.bell = 1;
        } else if (obj->otyp == SPE_BOOK_OF_THE_DEAD) {
                if (u.uhave.book) impossible("already have the book?");
                u.uhave.book = 1;
+               u.uachieve.book = 1;
        } else if (obj->oartifact) {
                if (is_quest_artifact(obj)) {
                    if (u.uhave.questart)
@@ -258,6 +262,15 @@ struct obj *obj;
                }
                set_artifact_intrinsic(obj, 1, W_ART);
        }
+        if(obj->otyp == LUCKSTONE && obj->record_achieve_special) {
+           u.uachieve.mines_luckstone = 1;
+           obj->record_achieve_special = 0;
+        } else if((obj->otyp == AMULET_OF_REFLECTION ||
+                   obj->otyp == BAG_OF_HOLDING) &&
+                  obj->record_achieve_special) {
+           u.uachieve.finish_sokoban = 1;
+           obj->record_achieve_special = 0;
+        }
 }
 
 /*
index 49f6282dceeb5eb9095b17aa48e75f311bc251e5..b848e75865f1558ccd5dd2adb542f114b573bc20 100644 (file)
--- a/src/mon.c
+++ b/src/mon.c
@@ -1604,6 +1604,8 @@ register struct monst *mtmp;
        }
        if(mtmp->iswiz) wizdead();
        if(mtmp->data->msound == MS_NEMESIS) nemdead();
+        if(mtmp->data == &mons[PM_MEDUSA])
+            u.uachieve.killed_medusa = 1;
        if(glyph_is_invisible(levl[mtmp->mx][mtmp->my].glyph))
            unmap_object(mtmp->mx, mtmp->my);
        m_detach(mtmp, mptr);
index d2b24c00a8474c158f4e47b4a73af57b64a674a7..ffdee9b4903b25131a10d6f79ca2b9ca3587c08e 100644 (file)
@@ -1373,6 +1373,7 @@ dosacrifice()
                done(ESCAPED);
            } else { /* super big win */
                adjalign(10);
+               u.uachieve.ascended = 1;
 pline("An invisible choir sings, and you are bathed in radiance...");
                godvoice(altaralign, "Congratulations, mortal!");
                display_nhwindow(WIN_MESSAGE, FALSE);
index af974d147fcec97f93bef92b98f77e5b789bb473..f7707f5edb7ef5dd92280df826eeaaff18ec5601 100644 (file)
@@ -554,6 +554,12 @@ unsigned int *stuckid, *steedid;
        mread(fd, (genericptr_t) timebuf, 14);
        timebuf[14] = '\0';
        ubirthday = time_from_yyyymmddhhmmss(timebuf);
+#if defined(BSD) && !defined(POSIX_TYPES)
+       (void) time((long *)&u.urealtime.restored);
+#else
+       (void) time(&u.urealtime.restored);
+#endif
+
 
        set_uasmon();
 #ifdef CLIPPING
index b220f945d2b2f8d4b90f7620a91719ab7abb3ee4..1c9dea6e6457285f87ae2ec7349444f0098baa16 100644 (file)
@@ -307,6 +307,7 @@ register int fd, mode;
 #ifdef SYSFLAGS
        bwrite(fd, (genericptr_t) &sysflags, sizeof(struct sysflag));
 #endif
+       u.urealtime.realtime += (getnow() - u.urealtime.restored);
        bwrite(fd, (genericptr_t) &u, sizeof(struct you));
        bwrite(fd, yyyymmddhhmmss(ubirthday), 14);
        save_killers(fd, mode);
index 6be2c9713f7fe3fec17be0c5153f5cab051fd7cc..623504855052cb086b008039d453f7b15fdb9a9d 100644 (file)
@@ -1062,6 +1062,18 @@ struct mkroom    *croom;
            mongone(was);
        }
 
+       /* Nasty hack here: try to determine if this is the Mines or Sokoban
+        * "prize" and then set record_achieve_special (maps to corpsenm)
+        * for the object.  That field will later be checked to find out if
+        * the player obtained the prize. */
+       if(otmp->otyp == LUCKSTONE && Is_mineend_level(&u.uz)) {
+           otmp->record_achieve_special = 1;
+       } else if((otmp->otyp == AMULET_OF_REFLECTION ||
+                  otmp->otyp == BAG_OF_HOLDING) &&
+                       Is_sokoend_level(&u.uz)) {
+           otmp->record_achieve_special = 1;
+        }
+
        stackobj(otmp);
 
     }          /* if (rn2(100) < o->chance) */
index db2e6fccb52fa3483e4d0c1386d194825704716c..cc4aefbe12323b720dc78e3515a9ea1e4bbb056a 100644 (file)
@@ -65,6 +65,9 @@ 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 *));
+STATIC_DCL long FDECL(encodeconduct, (void));
+STATIC_DCL long FDECL(encodeachieve, (void));
 STATIC_DCL void FDECL(free_ttlist, (struct toptenentry *));
 STATIC_DCL int FDECL(classmon, (char *,BOOLEAN_P));
 STATIC_DCL int FDECL(score_wanted,
@@ -292,6 +295,95 @@ struct toptenentry *tt;
 #endif
 }
 
+#define XLOG_SEP "\t"  /* xlogfile field separator. */
+/* as tab is never used in eg. plname or death, no need to mangle those. */
+STATIC_OVL void
+writexlentry(rfile,tt)
+FILE *rfile;
+struct toptenentry *tt;
+{
+    char buf[DTHSZ+1];
+    (void)fprintf(rfile,
+                 "version=%d.%d.%d"
+                 XLOG_SEP "points=%ld"
+                 XLOG_SEP "deathdnum=%d"
+                 XLOG_SEP "deathlev=%d"
+                 XLOG_SEP "maxlvl=%d"
+                 XLOG_SEP "hp=%d"
+                 XLOG_SEP "maxhp=%d"
+                 XLOG_SEP "deaths=%d"
+                 XLOG_SEP "deathdate=%d"
+                 XLOG_SEP "birthdate=%d"
+                 XLOG_SEP "uid=%d",
+                 tt->ver_major, tt->ver_minor, tt->patchlevel,
+                 tt->points, tt->deathdnum, tt->deathlev,
+                 tt->maxlvl, tt->hp, tt->maxhp, tt->deaths,
+                 tt->deathdate, tt->birthdate, tt->uid);
+    (void)fprintf(rfile,
+                 XLOG_SEP "role=%s"
+                 XLOG_SEP "race=%s"
+                 XLOG_SEP "gender=%s"
+                 XLOG_SEP "align=%s",
+                 tt->plrole, tt->plrace, tt->plgend, tt->plalign);
+    (void)fprintf(rfile, XLOG_SEP "name=%s", plname);
+    (void)fprintf(rfile, XLOG_SEP "death=%s", tt->death);
+    (void)fprintf(rfile, XLOG_SEP "conduct=0x%lx", encodeconduct());
+    (void)fprintf(rfile, XLOG_SEP "turns=%ld", moves);
+    (void)fprintf(rfile, XLOG_SEP "achieve=0x%lx", encodeachieve());
+    (void)fprintf(rfile, XLOG_SEP "realtime=%ld", (long)u.urealtime.realtime);
+    (void)fprintf(rfile, XLOG_SEP "starttime=%ld", (long)ubirthday);
+    (void)fprintf(rfile, XLOG_SEP "endtime=%ld", (long)u.urealtime.endtime);
+    (void)fprintf(rfile, XLOG_SEP "gender0=%s", genders[flags.initgend].filecode);
+    (void)fprintf(rfile, XLOG_SEP "align0=%s",
+                 aligns[1 - u.ualignbase[A_ORIGINAL]].filecode);
+    fprintf(rfile, "\n");
+}
+#undef XLOG_SEP
+
+long
+encodeconduct(void)
+{
+    long e = 0L;
+
+    if(!u.uconduct.food)         e |= 1L << 0;
+    if(!u.uconduct.unvegan)      e |= 1L << 1;
+    if(!u.uconduct.unvegetarian) e |= 1L << 2;
+    if(!u.uconduct.gnostic)      e |= 1L << 3;
+    if(!u.uconduct.weaphit)      e |= 1L << 4;
+    if(!u.uconduct.killer)       e |= 1L << 5;
+    if(!u.uconduct.literate)     e |= 1L << 6;
+    if(!u.uconduct.polypiles)    e |= 1L << 7;
+    if(!u.uconduct.polyselfs)    e |= 1L << 8;
+    if(!u.uconduct.wishes)       e |= 1L << 9;
+    if(!u.uconduct.wisharti)     e |= 1L << 10;
+    if(!num_genocides())         e |= 1L << 11;
+
+    return e;
+}
+
+long
+encodeachieve(void)
+{
+    long r = 0L;
+
+    if(u.uachieve.bell)            r |= 1L << 0;
+    if(u.uachieve.enter_gehennom)  r |= 1L << 1;
+    if(u.uachieve.menorah)         r |= 1L << 2;
+    if(u.uachieve.book)            r |= 1L << 3;
+    if(u.uevent.invoked)           r |= 1L << 4;
+    if(u.uachieve.amulet)          r |= 1L << 5;
+    if(In_endgame(&u.uz))          r |= 1L << 6;
+    if(Is_astralevel(&u.uz))       r |= 1L << 7;
+    if(u.uachieve.ascended)        r |= 1L << 8;
+    if(u.uachieve.mines_luckstone) r |= 1L << 9;
+    if(u.uachieve.finish_sokoban)  r |= 1L << 10;
+    if(u.uachieve.killed_medusa)   r |= 1L << 11;
+
+    return r;
+}
+
+
+
 STATIC_OVL void
 free_ttlist(tt)
 struct toptenentry *tt;
@@ -322,6 +414,9 @@ time_t when;
 #ifdef LOGFILE
        FILE *lfile;
 #endif /* LOGFILE */
+#ifdef XLOGFILE
+       FILE *xlfile;
+#endif /* XLOGFILE */
 
 /* Under DICE 3.0, this crashes the system consistently, apparently due to
  * corruption of *rfile somewhere.  Until I figure this out, just cut out
@@ -380,6 +475,7 @@ time_t when;
        t0->birthdate = yyyymmdd(ubirthday);
        t0->deathdate = yyyymmdd(when);
        t0->tt_next = 0;
+       u.urealtime.endtime = when;
 #ifdef UPDATE_RECORD_IN_PLACE
        t0->fpos = -1L;
 #endif
@@ -395,6 +491,17 @@ time_t when;
            unlock_file(LOGFILE);
        }
 #endif /* LOGFILE */
+#ifdef XLOGFILE
+       if (lock_file(XLOGFILE, SCOREPREFIX, 10)) {
+           if(!(xlfile = fopen_datafile(XLOGFILE, "a", SCOREPREFIX))) {
+               HUP raw_print("Cannot open extended log file!");
+           } else {
+               writexlentry(xlfile, t0);
+               (void) fclose(xlfile);
+           }
+           unlock_file(XLOGFILE);
+       }
+#endif /* XLOGFILE */
 
        if (wizard || discover) {
            if (how != PANICKED) HUP {
index 6d94d6908475c8295c518f13900d65cb483ecb8b..f9e474a5b78a209bd79cbab0a9668f771e7dc10d 100644 (file)
@@ -264,10 +264,10 @@ install: rootcheck $(GAME) recover $(VARDAT) dungeon spec_levs
 # set up the game files
        ( $(MAKE) dofiles )
 # set up some additional files
-       touch $(VARDIR)/perm $(VARDIR)/record $(VARDIR)/logfile
-       -( cd $(VARDIR) ; $(CHOWN) $(GAMEUID) perm record logfile ; \
-                       $(CHGRP) $(GAMEGRP) perm record logfile ; \
-                       chmod $(VARFILEPERM) perm record logfile )
+       touch $(VARDIR)/perm $(VARDIR)/record $(VARDIR)/logfile $(VARDIR)/xlogfile
+       -( cd $(VARDIR) ; $(CHOWN) $(GAMEUID) perm record logfile xlogfile ; \
+                       $(CHGRP) $(GAMEGRP) perm record logfile xlogfile ; \
+                       chmod $(VARFILEPERM) perm record logfile xlogfile )
        true; $(POSTINSTALL)
 # and a reminder
        @echo You may also want to reinstall the man pages via the doc Makefile.