From: Pasi Kallinen Date: Thu, 12 Mar 2015 19:35:04 +0000 (+0200) Subject: Add Extended Logfile X-Git-Tag: NetHack-3.6.0_RC01~590^2 X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=f8aced5480b42527d2e6bed7586501ae31b6ab0e;p=nethack Add Extended Logfile --- diff --git a/doc/fixes35.0 b/doc/fixes35.0 index 4ad731e36..10b4a8f68 100644 --- a/doc/fixes35.0 +++ b/doc/fixes35.0 @@ -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 diff --git a/include/config.h b/include/config.h index 930bd549c..d8c96af14 100644 --- a/include/config.h +++ b/include/config.h @@ -187,6 +187,7 @@ #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 */ diff --git a/include/decl.h b/include/decl.h index 4591226e4..2071277dc 100644 --- a/include/decl.h +++ b/include/decl.h @@ -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) diff --git a/include/dungeon.h b/include/dungeon.h index f2bf75ef6..3607649b0 100644 --- a/include/dungeon.h +++ b/include/dungeon.h @@ -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 */ diff --git a/include/extern.h b/include/extern.h index f382c4f7a..7e222778f 100644 --- a/include/extern.h +++ b/include/extern.h @@ -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 ### */ diff --git a/include/obj.h b/include/obj.h index fe43d0878..f4fd78007 100644 --- a/include/obj.h +++ b/include/obj.h @@ -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; diff --git a/include/you.h b/include/you.h index 0c343b3c4..81aba0ba4 100644 --- a/include/you.h +++ b/include/you.h @@ -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 */ diff --git a/src/allmain.c b/src/allmain.c index 2bb1c4240..eb1f2b69b 100644 --- a/src/allmain.c +++ b/src/allmain.c @@ -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; diff --git a/src/do.c b/src/do.c index 3069a4047..44b2a23bb 100644 --- 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; diff --git a/src/dungeon.c b/src/dungeon.c index 4c8e6beeb..fd253750f 100644 --- a/src/dungeon.c +++ b/src/dungeon.c @@ -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 }, diff --git a/src/end.c b/src/end.c index 995ef8ec7..111fd1b3a 100644 --- 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 diff --git a/src/invent.c b/src/invent.c index 62295915c..24213c7e3 100644 --- a/src/invent.c +++ b/src/invent.c @@ -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; + } } /* diff --git a/src/mon.c b/src/mon.c index 49f6282dc..b848e7586 100644 --- 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); diff --git a/src/pray.c b/src/pray.c index d2b24c00a..ffdee9b49 100644 --- a/src/pray.c +++ b/src/pray.c @@ -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); diff --git a/src/restore.c b/src/restore.c index af974d147..f7707f5ed 100644 --- a/src/restore.c +++ b/src/restore.c @@ -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 diff --git a/src/save.c b/src/save.c index b220f945d..1c9dea6e6 100644 --- a/src/save.c +++ b/src/save.c @@ -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); diff --git a/src/sp_lev.c b/src/sp_lev.c index 6be2c9713..623504855 100644 --- a/src/sp_lev.c +++ b/src/sp_lev.c @@ -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) */ diff --git a/src/topten.c b/src/topten.c index db2e6fccb..cc4aefbe1 100644 --- a/src/topten.c +++ b/src/topten.c @@ -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 { diff --git a/sys/unix/Makefile.top b/sys/unix/Makefile.top index 6d94d6908..f9e474a5b 100644 --- a/sys/unix/Makefile.top +++ b/sys/unix/Makefile.top @@ -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.