saving message history (trunk only)
On September 11, 2003 "<Someone>" wrote: > When we're going to have a different save file format, could > the last messages in the message history be saved as well, so > ^P would work the same before and after saving (possibly > including a few less messages to make room for the startup > messages?). This seemed like a reasonable request. This patch: - adds the core support required. - adds the tty supporting routines.
This commit is contained in:
@@ -59,12 +59,14 @@ burying a punishment ball no longer ends your punishment
|
||||
add clicklook option to allow looking at things on the display by clicking
|
||||
right mouse button when floating mouse pointer over them
|
||||
Izchak's lighting store is now able to stock oil for your lamp
|
||||
provide core support for saving of messsage history in save file
|
||||
|
||||
|
||||
Platform- and/or Interface-Specific New Features
|
||||
------------------------------------------------
|
||||
win32gui: support perm_invent
|
||||
win32gui: menu option to add/remove windows captions
|
||||
tty: add window port routines for saving/restoring message recall history
|
||||
|
||||
|
||||
Code Cleanup and Reorganization
|
||||
|
||||
@@ -378,6 +378,35 @@ preference_update(preference)
|
||||
change if it indicated that it wants to be by setting the
|
||||
corresponding bit in the wincap mask.
|
||||
|
||||
getmsghistory(init)
|
||||
-- This is used to preserve message history between games by
|
||||
obtaining the messages from the window port so that the core
|
||||
can put them into the savefile.
|
||||
The routine is called repeatedly from the core save routine,
|
||||
and the window port routine is expected to successively return
|
||||
each message that it wants the game to store in the savefile,
|
||||
starting with the oldest message first, finishing
|
||||
with the most recent.
|
||||
If init is TRUE, start over again from most recent message.
|
||||
|
||||
putmsghistory(msg)
|
||||
-- The is the counterpart to getmsghistory() for restores
|
||||
used to reload the port's message recall buffer.
|
||||
The routine is called repeatedly from the core restore
|
||||
routine, starting with the oldest message first, and
|
||||
finishing with the most recent one that it read from the savefile.
|
||||
The window port routine is expected to load the message
|
||||
recall buffers in such a way that the ordering remains correct.
|
||||
The window port routine should make no assumptions about how
|
||||
many messages are forthcoming, nor should it assume that
|
||||
another message will follow this one, so it must be careful
|
||||
to keep all pointers/indexes intact at the end of each call.
|
||||
If the window port receives more messages that can fit in
|
||||
its buffers, it is expected to scroll away the oldest from
|
||||
its buffers, much like it would with new messages being
|
||||
produced.
|
||||
|
||||
|
||||
III. Global variables
|
||||
|
||||
The following global variables are defined in decl.c and must be used by
|
||||
|
||||
@@ -2288,6 +2288,8 @@ E void FDECL(setmnotwielded, (struct monst *,struct obj *));
|
||||
E void FDECL(choose_windows, (const char *));
|
||||
E char FDECL(genl_message_menu, (CHAR_P,int,const char *));
|
||||
E void FDECL(genl_preference_update, (const char *));
|
||||
E char *FDECL(genl_getmsghistory, (BOOLEAN_P));
|
||||
E void FDECL(genl_putmsghistory, (const char *));
|
||||
|
||||
/* ### wizard.c ### */
|
||||
|
||||
|
||||
@@ -13,7 +13,7 @@
|
||||
* Incrementing EDITLEVEL can be used to force invalidation of old bones
|
||||
* and save files.
|
||||
*/
|
||||
#define EDITLEVEL 3
|
||||
#define EDITLEVEL 4
|
||||
|
||||
#define COPYRIGHT_BANNER_A \
|
||||
"NetHack, Copyright 1985-2003"
|
||||
|
||||
@@ -65,6 +65,8 @@ struct window_procs {
|
||||
|
||||
void FDECL((*win_outrip), (winid,int));
|
||||
void FDECL((*win_preference_update), (const char *));
|
||||
char * FDECL((*win_getmsghistory), (BOOLEAN_P));
|
||||
void FDECL((*win_putmsghistory), (const char *));
|
||||
};
|
||||
|
||||
extern NEARDATA struct window_procs windowprocs;
|
||||
@@ -134,6 +136,8 @@ extern NEARDATA struct window_procs windowprocs;
|
||||
|
||||
#define outrip (*windowprocs.win_outrip)
|
||||
#define preference_update (*windowprocs.win_preference_update)
|
||||
#define getmsghistory (*windowprocs.win_getmsghistory)
|
||||
#define putmsghistory (*windowprocs.win_putmsghistory)
|
||||
|
||||
/*
|
||||
* WINCAP
|
||||
|
||||
@@ -222,6 +222,10 @@ E void NDECL(tty_end_screen);
|
||||
|
||||
E void FDECL(genl_outrip, (winid,int));
|
||||
|
||||
E char *FDECL(tty_getmsghistory, (BOOLEAN_P));
|
||||
E void FDECL(tty_putmsghistory, (const char *));
|
||||
|
||||
|
||||
#ifdef NO_TERMS
|
||||
# ifdef MAC
|
||||
# ifdef putchar
|
||||
|
||||
@@ -452,6 +452,7 @@ unsigned int *stuckid, *steedid; /* STEED */
|
||||
|
||||
restnames(fd);
|
||||
restore_waterlevel(fd);
|
||||
restore_msghistory(fd);
|
||||
/* must come after all mons & objs are restored */
|
||||
relink_timers(FALSE);
|
||||
relink_light_sources(FALSE);
|
||||
@@ -910,6 +911,26 @@ boolean ghostly;
|
||||
clear_id_mapping();
|
||||
}
|
||||
|
||||
restore_msghistory(fd)
|
||||
register int fd;
|
||||
{
|
||||
int msgsize, k, msgcount = 0;
|
||||
char msg[BUFSZ];
|
||||
|
||||
while(1) {
|
||||
mread(fd, (genericptr_t) &msgsize, sizeof(msgsize));
|
||||
if(msgsize == -1) break;
|
||||
if (msgsize > (BUFSZ - 1))
|
||||
panic("restore_msghistory: msg too big (%d)", msgsize);
|
||||
mread(fd, (genericptr_t)msg, msgsize);
|
||||
msg[msgsize] = '\0';
|
||||
putmsghistory(msg);
|
||||
++msgcount;
|
||||
}
|
||||
#ifdef DEBUG_MSGCOUNT
|
||||
pline("Read %d messages from savefile.", msgcount);
|
||||
#endif
|
||||
}
|
||||
|
||||
/* Clear all structures for object and monster ID mapping. */
|
||||
STATIC_OVL void
|
||||
|
||||
31
src/save.c
31
src/save.c
@@ -339,6 +339,7 @@ register int fd, mode;
|
||||
savefruitchn(fd, mode);
|
||||
savenames(fd, mode);
|
||||
save_waterlevel(fd, mode);
|
||||
save_msghistory(fd, mode);
|
||||
bflush(fd);
|
||||
}
|
||||
|
||||
@@ -984,6 +985,36 @@ register int fd, mode;
|
||||
ffruit = 0;
|
||||
}
|
||||
|
||||
save_msghistory(fd, mode)
|
||||
register int fd, mode;
|
||||
{
|
||||
char *msg, buf[BUFSZ];
|
||||
int msgcount = 0, msglen = 0;
|
||||
int minusone = -1;
|
||||
boolean init = TRUE;
|
||||
|
||||
/* Ask window port for each message in sequence */
|
||||
while ((msg = getmsghistory(init)) != 0) {
|
||||
init = FALSE;
|
||||
msglen = strlen(msg);
|
||||
if (msglen < (BUFSZ-1))
|
||||
Strcpy(buf, msg);
|
||||
else {
|
||||
/* impossible */
|
||||
(void)strncpy(buf, msg, (BUFSZ - 1));
|
||||
buf[BUFSZ-1] = '\0';
|
||||
msglen = strlen(buf);
|
||||
}
|
||||
bwrite(fd, (genericptr_t)&msglen, sizeof(msglen));
|
||||
bwrite(fd, (genericptr_t)msg, msglen);
|
||||
++msgcount;
|
||||
}
|
||||
bwrite(fd, (genericptr_t) &minusone, sizeof(int));
|
||||
#ifdef DEBUG_MSGCOUNT
|
||||
pline("Stored %d messages into savefile.", msgcount);
|
||||
#endif
|
||||
}
|
||||
|
||||
/* also called by prscore(); this probably belongs in dungeon.c... */
|
||||
void
|
||||
free_dungeons()
|
||||
|
||||
@@ -143,4 +143,47 @@ const char *pref;
|
||||
they support.
|
||||
Just return in this genl one. */
|
||||
}
|
||||
|
||||
char *
|
||||
genl_getmsghistory(init)
|
||||
boolean init;
|
||||
{
|
||||
/* window ports can provide
|
||||
their own getmsghistory() routine to
|
||||
preserve message history between games.
|
||||
The routine is called repeatedly from
|
||||
the core save routine, and the window
|
||||
port is expected to successively return
|
||||
each message that it wants saved, starting
|
||||
with the oldest message first, finishing
|
||||
with the most recent.
|
||||
Return null pointer when finished.
|
||||
*/
|
||||
return (char *)0;
|
||||
}
|
||||
|
||||
/*ARGSUSED*/
|
||||
void
|
||||
genl_putmsghistory(msg)
|
||||
const char *msg;
|
||||
{
|
||||
/* window ports can provide
|
||||
their own putmsghistory() routine to
|
||||
load message history from a saved game.
|
||||
The routine is called repeatedly from
|
||||
the core restore routine, starting with
|
||||
the oldest saved message first, and
|
||||
finishing with the latest.
|
||||
The window port routine is expected to
|
||||
load the message recall buffers in such
|
||||
a way that the ordering is preserved.
|
||||
The window port routine should make no
|
||||
assumptions about how many messages are
|
||||
forthcoming, nor should it assume that
|
||||
another message will follow this one,
|
||||
so it should keep all pointers/indexes
|
||||
intact at the end of each call.
|
||||
*/
|
||||
}
|
||||
|
||||
/*windows.c*/
|
||||
|
||||
@@ -79,7 +79,9 @@ struct window_procs amii_procs =
|
||||
amii_delay_output,
|
||||
amii_delay_output,
|
||||
amii_outrip,
|
||||
genl_preference_update
|
||||
genl_preference_update,
|
||||
genl_getmsghistory,
|
||||
genl_putmsghistory
|
||||
};
|
||||
|
||||
/* The view window layout uses the same function names so we can use
|
||||
@@ -138,7 +140,9 @@ struct window_procs amiv_procs =
|
||||
amii_delay_output,
|
||||
amii_delay_output,
|
||||
amii_outrip,
|
||||
genl_preference_update
|
||||
genl_preference_update,
|
||||
genl_getmsghistory,
|
||||
genl_putmsghistory
|
||||
};
|
||||
|
||||
unsigned short amii_initmap[ AMII_MAXCOLORS ];
|
||||
|
||||
@@ -2645,6 +2645,8 @@ struct window_procs mac_procs = {
|
||||
0, // mac_end_screen,
|
||||
genl_outrip,
|
||||
genl_preference_update,
|
||||
genl_getmsghistory,
|
||||
genl_putmsghistory,
|
||||
};
|
||||
|
||||
/*macwin.c*/
|
||||
|
||||
@@ -95,6 +95,8 @@ struct window_procs mswin_procs = {
|
||||
mswin_end_screen,
|
||||
mswin_outrip,
|
||||
mswin_preference_update,
|
||||
genl_getmsghistory,
|
||||
genl_putmsghistory,
|
||||
};
|
||||
|
||||
/*
|
||||
|
||||
@@ -5285,6 +5285,8 @@ struct window_procs Qt_procs = {
|
||||
genl_outrip,
|
||||
#endif
|
||||
genl_preference_update,
|
||||
genl_getmsghistory,
|
||||
genl_putmsghistory,
|
||||
};
|
||||
|
||||
extern "C" void play_usersound(const char* filename, int volume)
|
||||
|
||||
@@ -157,6 +157,8 @@ struct window_procs X11_procs = {
|
||||
genl_outrip,
|
||||
#endif
|
||||
X11_preference_update,
|
||||
genl_getmsghistory,
|
||||
genl_putmsghistory,
|
||||
};
|
||||
|
||||
/*
|
||||
|
||||
@@ -97,7 +97,9 @@ struct window_procs Gem_procs = {
|
||||
Gem_start_screen,
|
||||
Gem_end_screen,
|
||||
Gem_outrip,
|
||||
Gem_preference_update
|
||||
Gem_preference_update,
|
||||
genl_getmsghistory,
|
||||
genl_putmsghistory
|
||||
};
|
||||
|
||||
#ifdef MAC
|
||||
|
||||
@@ -73,6 +73,8 @@ struct window_procs Gnome_procs = {
|
||||
gnome_end_screen,
|
||||
gnome_outrip,
|
||||
genl_preference_update,
|
||||
genl_getmsghistory,
|
||||
genl_putmsghistory,
|
||||
};
|
||||
|
||||
/*
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/* SCCS Id: @(#)topl.c 3.4 1996/10/24 */
|
||||
/* SCCS Id: @(#)topl.c 3.4 2003/10/05 */
|
||||
/* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
|
||||
/* NetHack may be freely redistributed. See license for details. */
|
||||
|
||||
@@ -443,6 +443,73 @@ char def;
|
||||
|
||||
return q;
|
||||
}
|
||||
|
||||
/*
|
||||
* This is called by the core save routines.
|
||||
* Each time we are called, we return one string from the
|
||||
* message history starting with the oldest message first. each time
|
||||
* we are called. Each time after that, we return a more recent message,
|
||||
* until there are no more messages to return. Then we return a final
|
||||
* null string.
|
||||
*/
|
||||
char *
|
||||
tty_getmsghistory(init)
|
||||
boolean init;
|
||||
{
|
||||
static int idx = 0, state = 0;
|
||||
static boolean doneinit = FALSE;
|
||||
register struct WinDesc *cw = wins[WIN_MESSAGE];
|
||||
char *retstr = (char *)0;
|
||||
|
||||
/*
|
||||
* state 0 = normal return with string from msg history.
|
||||
* state 1 = finished with recall data, return toplines.
|
||||
* state 2 = completely finished, return null string.
|
||||
*/
|
||||
if (init) {
|
||||
doneinit = TRUE;
|
||||
state = 0;
|
||||
idx = cw->maxrow;
|
||||
}
|
||||
if (doneinit && state < 2) {
|
||||
if (state == 1) {
|
||||
++state;
|
||||
return toplines;
|
||||
}
|
||||
do {
|
||||
if(cw->data[idx] && strcmp(cw->data[idx], "") )
|
||||
retstr = cw->data[idx];
|
||||
idx = (idx + 1) % cw->rows;
|
||||
} while (idx != cw->maxrow && !retstr);
|
||||
if (idx == cw->maxrow) ++state;
|
||||
}
|
||||
return retstr;
|
||||
}
|
||||
|
||||
/*
|
||||
* This is called by the core savefile restore routines.
|
||||
* Each time we are called, we stuff the string into our message
|
||||
* history recall buffer. The core will send the oldest message
|
||||
* first (actually it sends them in the order they exist in the
|
||||
* save file, but that is supposed to be the oldest first).
|
||||
*/
|
||||
void
|
||||
tty_putmsghistory(msg)
|
||||
const char *msg;
|
||||
{
|
||||
register struct WinDesc *cw = wins[WIN_MESSAGE];
|
||||
int idx = cw->maxrow;
|
||||
unsigned len = strlen(msg) + 1;
|
||||
|
||||
if (len > (unsigned)cw->datlen[idx]) {
|
||||
if (cw->data[idx]) free(cw->data[idx]);
|
||||
len += (8 - (len & 7)); /* pad up to next multiple of 8 */
|
||||
cw->data[idx] = (char *)alloc(len);
|
||||
cw->datlen[idx] = (short)len;
|
||||
}
|
||||
Strcpy(cw->data[idx], msg);
|
||||
cw->maxcol = cw->maxrow = (idx + 1) % cw->rows;
|
||||
}
|
||||
#endif /* TTY_GRAPHICS */
|
||||
|
||||
/*topl.c*/
|
||||
|
||||
@@ -109,6 +109,8 @@ struct window_procs tty_procs = {
|
||||
#else
|
||||
genl_preference_update,
|
||||
#endif
|
||||
tty_getmsghistory,
|
||||
tty_putmsghistory,
|
||||
};
|
||||
|
||||
static int maxwin = 0; /* number of windows in use */
|
||||
|
||||
@@ -121,6 +121,8 @@ struct window_procs mswin_procs = {
|
||||
mswin_end_screen,
|
||||
mswin_outrip,
|
||||
mswin_preference_update,
|
||||
genl_getmsghistory,
|
||||
genl_putmsghistory,
|
||||
};
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user