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 ### */
/* ### rip.c ### */
-E void FDECL(genl_outrip, (winid,int));
+E void FDECL(genl_outrip, (winid,int,time_t));
/* ### rnd.c ### */
/* ### 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 *));
* 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"
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));
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));
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));
/* 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;
struct monst *mtmp;
struct permonst *mptr;
struct fruit *f;
+ struct cemetery *newbones;
char c, *bonesid;
char whynot[BUFSZ];
#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
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;
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.
#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;
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 */
/* "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);
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;
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;
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 {
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)
#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));
/* 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. */
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;
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++) {
}
/* Put year on stone */
- Sprintf(buf, "%4d", getyear());
+ year = yyyymmdd(when) / 10000L;
+ Sprintf(buf, "%4ld", year);
center(YEAR_LINE, buf);
putstr(tmpwin, 0, "");
#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));
#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));
fobj = 0;
level.buriedobjlist = 0;
billobjs = 0;
+ level.bonesinfo = 0;
}
save_engravings(fd, mode);
savedamage(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;
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;
}
void
-topten(how)
+topten(how, when)
int how;
+time_t when;
{
int uid = getuid();
int rank, rank0 = -1, rank1 = 0;
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;
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));
/*ARGSUSED*/
static void
-hup_outrip(tmpwin, how)
+hup_outrip(tmpwin, how, when)
winid tmpwin UNUSED;
int how UNUSED;
+time_t when UNUSED;
{
return;
}
}
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
}
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
}
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;
}