]> granicus.if.org Git - nethack/commitdiff
bones tracking (trunk only)
authornethack.rankin <nethack.rankin>
Mon, 23 Jan 2012 10:45:31 +0000 (10:45 +0000)
committernethack.rankin <nethack.rankin>
Mon, 23 Jan 2012 10:45:31 +0000 (10:45 +0000)
[See cvs log for include/rm.h or doc/window.doc for more complete description.]

Attach hero info, death reason, and date+time to a level that's being saved
as bones.  Read such data back when loading a bones file, then treat it as
part of that level for the rest of the game.  Dying on a loaded bones file
will chain the new hero+death+date to previous one(s) if new bones get saved.

outrip() now takes an extra argument of type time_t, and interface-specific
implementations of this routine need to be updated to handle that.

15 files changed:
include/extern.h
include/patchlevel.h
include/winprocs.h
include/wintty.h
src/bones.c
src/end.c
src/mklev.c
src/restore.c
src/rip.c
src/save.c
src/topten.c
src/windows.c
win/chain/wc_chainin.c
win/chain/wc_chainout.c
win/chain/wc_trace.c

index 4f894ef780a31bd990494ac6f2323e0f9fc6d2f0..1e8f1683b2eb0c6298f5b99edf50be3a879f8b42 100644 (file)
@@ -132,7 +132,7 @@ E void NDECL(drag_down);
 E void FDECL(sanitize_name, (char *));
 E void FDECL(drop_upon_death, (struct monst *,struct obj *,int,int));
 E boolean NDECL(can_make_bones);
-E void FDECL(savebones, (struct obj *));
+E void FDECL(savebones, (int,time_t,struct obj *));
 E int NDECL(getbones);
 
 /* ### botl.c ### */
@@ -1947,7 +1947,7 @@ E void FDECL(put_gold_back, (struct monst *));
 
 /* ### rip.c ### */
 
-E void FDECL(genl_outrip, (winid,int));
+E void FDECL(genl_outrip, (winid,int,time_t));
 
 /* ### rnd.c ### */
 
@@ -2270,7 +2270,8 @@ E void NDECL(timer_sanity_check);
 
 /* ### topten.c ### */
 
-E void FDECL(topten, (int));
+E void FDECL(formatkiller, (char *,unsigned,int));
+E void FDECL(topten, (int,time_t));
 E void FDECL(prscore, (int,char **));
 E struct obj *FDECL(tt_oname, (struct obj *));
 
index 63cd196aebbb14dcfdf26e74e9bc7726a32340bb..4dc0598a3dc7c923e799c07373a8f3e636cd068d 100644 (file)
@@ -13,7 +13,7 @@
  * Incrementing EDITLEVEL can be used to force invalidation of old bones
  * and save files.
  */
-#define EDITLEVEL      50
+#define EDITLEVEL      51
 
 #define COPYRIGHT_BANNER_A \
 "NetHack, Copyright 1985-2012"
index eac4e9c4242d8219a45530a11b88fedaf5f6fe5b..d7c5c5f897155c6435944a5b09a112d2f8ca2bd9 100644 (file)
@@ -69,7 +69,7 @@ struct window_procs {
     void NDECL((*win_start_screen));
     void NDECL((*win_end_screen));
 
-    void FDECL((*win_outrip), (winid,int));
+    void FDECL((*win_outrip), (winid,int,time_t));
     void FDECL((*win_preference_update), (const char *));
     char * FDECL((*win_getmsghistory), (BOOLEAN_P));
     void FDECL((*win_putmsghistory), (const char *,BOOLEAN_P));
@@ -351,7 +351,7 @@ struct chain_procs {
     void FDECL((*win_start_screen), (CARGS));
     void FDECL((*win_end_screen), (CARGS));
 
-    void FDECL((*win_outrip), (CARGS, winid,int));
+    void FDECL((*win_outrip), (CARGS, winid,int,time_t));
     void FDECL((*win_preference_update), (CARGS, const char *));
     char * FDECL((*win_getmsghistory), (CARGS, BOOLEAN_P));
     void FDECL((*win_putmsghistory), (CARGS, const char *,BOOLEAN_P));
index 119052c30b56ad3d867c8e7b2173e8597c218ad5..baff7c2ffb9e6e35fa284fb72e1254e02243244e 100644 (file)
@@ -226,7 +226,7 @@ E char * NDECL(tty_get_color_string);
 E void NDECL(tty_start_screen);
 E void NDECL(tty_end_screen);
 
-E void FDECL(genl_outrip, (winid,int));
+E void FDECL(genl_outrip, (winid,int,time_t));
 
 E char *FDECL(tty_getmsghistory, (BOOLEAN_P));
 E void FDECL(tty_putmsghistory, (const char *,BOOLEAN_P));
index 843d38402bd48f422141dca9cef21850a607a3e6..8358490cfdc2c3a1341b8f79956dfaba913ace84 100644 (file)
@@ -273,7 +273,9 @@ can_make_bones()
 
 /* save bones and possessions of a deceased adventurer */
 void
-savebones(corpse)
+savebones(how, when, corpse)
+int how;
+time_t when;
 struct obj *corpse;
 {
        int fd, x, y;
@@ -281,6 +283,7 @@ struct obj *corpse;
        struct monst *mtmp;
        struct permonst *mptr;
        struct fruit *f;
+       struct cemetery *newbones;
        char c, *bonesid;
        char whynot[BUFSZ];
 
@@ -407,6 +410,29 @@ struct obj *corpse;
 #endif
        }
 
+       /* Attach bones info to the current level before saving. */
+       newbones = (struct cemetery *)alloc(sizeof *newbones);
+       /* entries are '\0' terminated but have fixed length allocations,
+          so pre-fill with spaces to initialize any excess room */
+       (void)memset((genericptr_t)newbones, ' ', sizeof *newbones);
+       /* format name+role,&c, death reason, and date+time;
+          gender and alignment reflect final values rather than what the
+          character started out as, same as topten and logfile entries */
+       Sprintf(newbones->who, "%s-%.3s-%.3s-%.3s-%.3s",
+               plname, urole.filecode, urace.filecode,
+               genders[flags.female].filecode,
+               aligns[1 - u.ualign.type].filecode);
+       formatkiller(newbones->how, sizeof newbones->how, how);
+       Strcpy(newbones->when, yyyymmddhhmmss(when));
+       /* if current character died on a bones level, the cememtery list
+          will have multiple entries, most recent (this dead hero) first */
+       newbones->next = level.bonesinfo;
+       level.bonesinfo = newbones;
+       /* flag these bones if they are being created in wizard mode;
+          they might already be flagged as such, even when we're playing
+          in normal mode, if this level came from a previous bones file */
+       if (wizard) level.flags.wizard_bones = 1;
+
        fd = create_bonesfile(&u.uz, &bonesid, whynot);
        if(fd < 0) {
 #ifdef WIZARD
index 78c96fd160cfa47a05595faee70d043b6c27ab92..f6487cb84e2f80f4935ef64279b1f89c78888226 100644 (file)
--- a/src/end.c
+++ b/src/end.c
@@ -830,6 +830,7 @@ int how;
        winid endwin = WIN_ERR;
        boolean bones_ok, have_windows = iflags.window_inited;
        struct obj *corpse = (struct obj *)0;
+       time_t endtime;
        long umoney;
        long tmp;
 
@@ -909,6 +910,11 @@ die:
        if (thrownobj && thrownobj->where == OBJ_FREE) dealloc_obj(thrownobj);
        if (kickedobj && kickedobj->where == OBJ_FREE) dealloc_obj(kickedobj);
 
+       /* remember time of death here instead of having bones, rip, and
+          topten figure it out separately and possibly getting different
+           time or even day if player is slow responding to --More-- */
+       endtime = getnow();
+
        /* Sometimes you die on the first move.  Life's not fair.
         * On those rare occasions you get hosed immediately, go out
         * smiling... :-)  -3.
@@ -1035,7 +1041,7 @@ die:
 #ifdef WIZARD
            if (!wizard || paranoid_query(ParanoidBones, "Save bones?"))
 #endif
-               savebones(corpse);
+               savebones(how, endtime, corpse);
            /* corpse may be invalid pointer now so
                ensure that it isn't used again */
            corpse = (struct obj *)0;
@@ -1067,7 +1073,7 @@ die:
                endwin = create_nhwindow(NHW_TEXT);
 
            if (how < GENOCIDED && flags.tombstone && endwin != WIN_ERR)
-               outrip(endwin, how);
+             outrip(endwin, how, endtime);
        } else
            done_stopprint = 1; /* just avoid any more output */
 
@@ -1220,15 +1226,11 @@ die:
 
        /* "So when I die, the first thing I will see in Heaven is a
         * score list?" */
-       if (iflags.toptenwin) {
-           topten(how);
-           if (have_windows)
-               exit_nhwindows((char *)0);
-       } else {
-           if (have_windows)
-               exit_nhwindows((char *)0);
-           topten(how);
-       }
+       if (have_windows && !iflags.toptenwin)
+           exit_nhwindows((char *)0), have_windows = FALSE;
+       topten(how, endtime);
+       if (have_windows)
+           exit_nhwindows((char *)0);
 
        if(done_stopprint) { raw_print(""); raw_print(""); }
        terminate(EXIT_SUCCESS);
index 813e7fc89740dd73aaff4de51660b37c8a57b01a..2a98163cdf4401d01531fd2ebba4b4ae98f34421 100644 (file)
@@ -572,6 +572,7 @@ clear_level_structures()
        level.buriedobjlist = (struct obj *)0;
        level.monlist = (struct monst *)0;
        level.damagelist = (struct damage *)0;
+       level.bonesinfo = (struct cemetery *)0;
 
        level.flags.nfountains = 0;
        level.flags.nsinks = 0;
@@ -593,6 +594,7 @@ clear_level_structures()
        level.flags.is_maze_lev = 0;
        level.flags.is_cavernous_lev = 0;
        level.flags.arboreal = 0;
+       level.flags.wizard_bones = 0;
 
        nroom = 0;
        rooms[0].hx = -1;
index ad027e1dfcafbe72288a0bf9596d334eb0f8cc29..65247370a9c12e97c99e8ab0c5130f78b436308d 100644 (file)
@@ -39,6 +39,7 @@ STATIC_DCL void FDECL(restlevelstate, (unsigned int, unsigned int));
 STATIC_DCL int FDECL(restlevelfile, (int,XCHAR_P));
 STATIC_OVL void FDECL(restore_msghistory, (int));
 STATIC_DCL void FDECL(reset_oattached_mids, (BOOLEAN_P));
+STATIC_DCL void FDECL(restcemetery, (int));
 STATIC_DCL void FDECL(rest_levl, (int,BOOLEAN_P));
 
 static struct restore_procs {
@@ -901,6 +902,27 @@ register int fd;
        return(1);
 }
 
+STATIC_OVL void
+restcemetery(fd)
+int fd;
+{
+    struct cemetery *bonesinfo, **bonesaddr;
+    int flag;
+
+    mread(fd, (genericptr_t)&flag, sizeof flag);
+    if (flag == 0) {
+       bonesaddr = &level.bonesinfo;
+       do {
+           bonesinfo = (struct cemetery *)alloc(sizeof *bonesinfo);
+           mread(fd, (genericptr_t)bonesinfo, sizeof *bonesinfo);
+           *bonesaddr = bonesinfo;
+           bonesaddr = &(*bonesaddr)->next;
+       } while (*bonesaddr);
+    } else {
+       level.bonesinfo = 0;
+    }
+}
+
 /*ARGSUSED*/
 STATIC_OVL void
 rest_levl(fd, rlecomp)
@@ -998,6 +1020,7 @@ boolean ghostly;
 #endif
            trickery(trickbuf);
        }
+       restcemetery(fd);
        rest_levl(fd, (boolean)((sfrestinfo.sfi1 & SFI1_RLECOMP) == SFI1_RLECOMP));
 #ifdef DUNGEON_OVERVIEW
        mread(fd, (genericptr_t)lastseentyp, sizeof(lastseentyp));
index b391e828d7f8f5408e6b93cd358eeade28d29a24..1fe094d844384ee971e265dd380fcf23b8966348 100644 (file)
--- a/src/rip.c
+++ b/src/rip.c
@@ -1,5 +1,4 @@
 /* NetHack 3.5 rip.c   $Date$  $Revision$ */
-/*     SCCS Id: @(#)rip.c      3.5     2003/01/08      */
 /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
 /* NetHack may be freely redistributed.  See license for details. */
 
@@ -86,13 +85,15 @@ char *text;
 
 
 void
-genl_outrip(tmpwin, how)
+genl_outrip(tmpwin, how, when)
 winid tmpwin;
 int how;
+time_t when;
 {
        register char **dp;
        register char *dpx;
        char buf[BUFSZ];
+       long year;
        register int x;
        int line;
 
@@ -118,20 +119,7 @@ int how;
        center(GOLD_LINE, buf);
 
        /* Put together death description */
-       switch (killer.format) {
-               default: impossible("bad killer format?");
-               case KILLED_BY_AN:
-                       Strcpy(buf, killed_by_prefix[how]);
-                       Strcat(buf, an(killer.name));
-                       break;
-               case KILLED_BY:
-                       Strcpy(buf, killed_by_prefix[how]);
-                       Strcat(buf, killer.name);
-                       break;
-               case NO_KILLER_PREFIX:
-                       Strcpy(buf, killer.name);
-                       break;
-       }
+       formatkiller(buf, sizeof buf, how);
 
        /* Put death type on stone */
        for (line=DEATH_LINE, dpx = buf; line<YEAR_LINE; line++) {
@@ -154,7 +142,8 @@ int how;
        }
 
        /* Put year on stone */
-       Sprintf(buf, "%4d", getyear());
+       year = yyyymmdd(when) / 10000L;
+       Sprintf(buf, "%4ld", year);
        center(YEAR_LINE, buf);
 
        putstr(tmpwin, 0, "");
index 302b430d038f3aff1e401f73eedfa048a58de76b..c1ad372e23c2c7681e089c45cce60c35996ce2c7 100644 (file)
@@ -22,6 +22,7 @@ int dotcnt, dotrow;   /* also used in restore */
 #endif
 
 STATIC_DCL void FDECL(savelevchn, (int,int));
+STATIC_DCL void FDECL(savecemetery, (int,int));
 STATIC_DCL void FDECL(savedamage, (int,int));
 STATIC_DCL void FDECL(saveobj, (int,struct obj *));
 STATIC_DCL void FDECL(saveobjchn, (int,struct obj *,int));
@@ -520,6 +521,7 @@ int mode;
 #else
        bwrite(fd,(genericptr_t) &lev,sizeof(lev));
 #endif
+       savecemetery(fd, mode);
        savelevl(fd, (boolean)((sfsaveinfo.sfi1 & SFI1_RLECOMP) == SFI1_RLECOMP));
 #ifdef DUNGEON_OVERVIEW
        bwrite(fd,(genericptr_t) lastseentyp,sizeof(lastseentyp));
@@ -554,6 +556,7 @@ int mode;
            fobj = 0;
            level.buriedobjlist = 0;
            billobjs = 0;
+           level.bonesinfo = 0;
        }
        save_engravings(fd, mode);
        savedamage(fd, mode);
@@ -918,6 +921,27 @@ register int fd, mode;
            sp_levchn = 0;
 }
 
+STATIC_OVL void
+savecemetery(fd, mode)
+int fd;
+int mode;
+{
+    struct cemetery *thisbones, *nextbones;
+    int flag;
+
+    flag = level.bonesinfo ? 0 : -1;
+    if (perform_bwrite(mode))
+       bwrite(fd, (genericptr_t)&flag, sizeof flag);
+    nextbones = level.bonesinfo;
+    while ((thisbones = nextbones) != 0) {
+       nextbones = thisbones->next;
+       if (perform_bwrite(mode))
+           bwrite(fd, (genericptr_t)thisbones, sizeof *thisbones);
+       if (release_data(mode))
+           free((genericptr_t)thisbones);
+    }
+}
+
 STATIC_OVL void
 savedamage(fd, mode)
 register int fd, mode;
index 8acb064048d30b6a853d901597ac7b06134a020d..3d0f566681ed25923b3afbff0186527b21e9a3fe 100644 (file)
@@ -82,6 +82,37 @@ NEARDATA const char * const killed_by_prefix[] = {
 
 static winid toptenwin = WIN_ERR;
 
+/* "killed by",&c ["an"] 'killer.name' */
+void
+formatkiller(buf, siz, how)
+char *buf;
+unsigned siz;
+int how;
+{
+    unsigned l;
+    char *kname = killer.name;
+
+    buf[0] = '\0'; /* so strncat() can find the end */
+    switch (killer.format) {
+    default:
+           impossible("bad killer format? (%d)", killer.format);
+           /*FALLTHRU*/
+    case NO_KILLER_PREFIX:
+           break;
+    case KILLED_BY_AN:
+           kname = an(kname);
+           /*FALLTHRU*/
+    case KILLED_BY:
+           (void) strncat(buf, killed_by_prefix[how], siz - 1);
+           l = strlen(buf);
+           buf += l, siz -= l;
+           break;
+    }
+    /* 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);
+}
+
 STATIC_OVL void
 topten_print(x)
 const char *x;
@@ -271,8 +302,9 @@ struct toptenentry *tt;
 }
 
 void
-topten(how)
+topten(how, when)
 int how;
+time_t when;
 {
        int uid = getuid();
        int rank, rank0 = -1, rank1 = 0;
@@ -339,25 +371,9 @@ int how;
        copynchars(t0->plgend, genders[flags.female].filecode, ROLESZ);
        copynchars(t0->plalign, aligns[1 - u.ualign.type].filecode, ROLESZ);
        copynchars(t0->name, plname, NAMSZ);
-       t0->death[0] = '\0';
-       switch (killer.format) {
-               default: impossible("bad killer format?");
-               case KILLED_BY_AN:
-                       Strcat(t0->death, killed_by_prefix[how]);
-                       (void) strncat(t0->death, an(killer.name),
-                                               DTHSZ-strlen(t0->death));
-                       break;
-               case KILLED_BY:
-                       Strcat(t0->death, killed_by_prefix[how]);
-                       (void) strncat(t0->death, killer.name,
-                                               DTHSZ-strlen(t0->death));
-                       break;
-               case NO_KILLER_PREFIX:
-                       (void) strncat(t0->death, killer.name, DTHSZ);
-                       break;
-       }
+       formatkiller(t0->death, sizeof t0->death, how);
        t0->birthdate = yyyymmdd(ubirthday);
-       t0->deathdate = yyyymmdd((time_t)0L);
+       t0->deathdate = yyyymmdd(when);
        t0->tt_next = 0;
 #ifdef UPDATE_RECORD_IN_PLACE
        t0->fpos = -1L;
index 47cd4485d6c5239e01e61c03090cc6f77cbe83a6..fc13631c02b213a3d0e7b6a53dfbbeb38f5e931e 100644 (file)
@@ -425,7 +425,7 @@ static void FDECL(hup_add_menu, (winid,int,const anything *,CHAR_P,CHAR_P,
 static void FDECL(hup_end_menu, (winid,const char *));
 static void FDECL(hup_putstr, (winid,int,const char *));
 static void FDECL(hup_print_glyph, (winid,XCHAR_P,XCHAR_P,int));
-static void FDECL(hup_outrip, (winid,int));
+static void FDECL(hup_outrip, (winid,int,time_t));
 static void FDECL(hup_curs, (winid,int,int));
 static void FDECL(hup_display_nhwindow, (winid,BOOLEAN_P));
 static void FDECL(hup_display_file, (const char *,BOOLEAN_P));
@@ -670,9 +670,10 @@ int glyph UNUSED;
 
 /*ARGSUSED*/
 static void
-hup_outrip(tmpwin, how)
+hup_outrip(tmpwin, how, when)
 winid tmpwin UNUSED;
 int how UNUSED;
+time_t when UNUSED;
 {
     return;
 }
index c1bc50cbc454f0bbe32971f25e59902d499d753e..1508affd739b748c3cece3209ec5d6d45ab9ed74 100644 (file)
@@ -429,11 +429,12 @@ chainin_end_screen()
 }
 
 void
-chainin_outrip(tmpwin, how)
+chainin_outrip(tmpwin, how, when)
     winid tmpwin;
     int how;
+    time_t when;
 {
-       (*cibase->nprocs->win_outrip)(cibase->ndata, tmpwin, how);
+  (*cibase->nprocs->win_outrip)(cibase->ndata, tmpwin, how, when);
 }
 
 void
index be9bb894d1441fd65f9e33010794f46a41c9e153..286942009cb1dad38680d4aee0e73416f9b48125 100644 (file)
@@ -541,14 +541,15 @@ chainout_end_screen(vp)
 }
 
 void
-chainout_outrip(vp, tmpwin, how)
+chainout_outrip(vp, tmpwin, how, when)
     void *vp;
     winid tmpwin;
     int how;
+    time_t when;
 {
        struct chainout_data *tdp = vp;
 
-       (*tdp->nprocs->win_outrip)(tmpwin, how);
+       (*tdp->nprocs->win_outrip)(tmpwin, how, when);
 }
 
 void
index acf96a5b34c7280735ef15288e6aaa3e1d32bf96..b89bcf935ccfe5acd514f391490afe309a471247 100644 (file)
@@ -928,17 +928,19 @@ trace_end_screen(vp)
 }
 
 void
-trace_outrip(vp, tmpwin, how)
+trace_outrip(vp, tmpwin, how, when)
     void *vp;
     winid tmpwin;
     int how;
+    time_t when;
 {
        struct trace_data *tdp = vp;
 
-       fprintf(wc_tracelogf, "%soutrip(%d, %d)\n", INDENT, tmpwin, how);
+       fprintf(wc_tracelogf, "%soutrip(%d, %d, %ld)\n",
+               INDENT, (int)tmpwin, how, (long)when);
 
        PRE;
-       (*tdp->nprocs->win_outrip)(tdp->ndata, tmpwin, how);
+       (*tdp->nprocs->win_outrip)(tdp->ndata, tmpwin, how, when);
        POST;
 }