From: nethack.rankin Date: Mon, 23 Jan 2012 10:45:31 +0000 (+0000) Subject: bones tracking (trunk only) X-Git-Tag: MOVE2GIT~70 X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=97214706350cfbf3ba58fb290e03bf04a49a5ba7;p=nethack bones tracking (trunk only) [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. --- diff --git a/include/extern.h b/include/extern.h index 4f894ef78..1e8f1683b 100644 --- a/include/extern.h +++ b/include/extern.h @@ -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 *)); diff --git a/include/patchlevel.h b/include/patchlevel.h index 63cd196ae..4dc0598a3 100644 --- a/include/patchlevel.h +++ b/include/patchlevel.h @@ -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" diff --git a/include/winprocs.h b/include/winprocs.h index eac4e9c42..d7c5c5f89 100644 --- a/include/winprocs.h +++ b/include/winprocs.h @@ -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)); diff --git a/include/wintty.h b/include/wintty.h index 119052c30..baff7c2ff 100644 --- a/include/wintty.h +++ b/include/wintty.h @@ -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)); diff --git a/src/bones.c b/src/bones.c index 843d38402..8358490cf 100644 --- a/src/bones.c +++ b/src/bones.c @@ -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 diff --git a/src/end.c b/src/end.c index 78c96fd16..f6487cb84 100644 --- 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); diff --git a/src/mklev.c b/src/mklev.c index 813e7fc89..2a98163cd 100644 --- a/src/mklev.c +++ b/src/mklev.c @@ -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; diff --git a/src/restore.c b/src/restore.c index ad027e1df..65247370a 100644 --- a/src/restore.c +++ b/src/restore.c @@ -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)); diff --git a/src/rip.c b/src/rip.c index b391e828d..1fe094d84 100644 --- 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; linenext; + 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; diff --git a/src/topten.c b/src/topten.c index 8acb06404..3d0f56668 100644 --- a/src/topten.c +++ b/src/topten.c @@ -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; diff --git a/src/windows.c b/src/windows.c index 47cd4485d..fc13631c0 100644 --- a/src/windows.c +++ b/src/windows.c @@ -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; } diff --git a/win/chain/wc_chainin.c b/win/chain/wc_chainin.c index c1bc50cbc..1508affd7 100644 --- a/win/chain/wc_chainin.c +++ b/win/chain/wc_chainin.c @@ -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 diff --git a/win/chain/wc_chainout.c b/win/chain/wc_chainout.c index be9bb894d..286942009 100644 --- a/win/chain/wc_chainout.c +++ b/win/chain/wc_chainout.c @@ -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 diff --git a/win/chain/wc_trace.c b/win/chain/wc_trace.c index acf96a5b3..b89bcf935 100644 --- a/win/chain/wc_trace.c +++ b/win/chain/wc_trace.c @@ -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; }