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:
nethack.allison
2003-10-05 13:43:16 +00:00
parent a5c8b517d2
commit f6f6c1f0d5
19 changed files with 228 additions and 5 deletions

View File

@@ -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

View File

@@ -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

View File

@@ -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 ### */

View File

@@ -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"

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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()

View File

@@ -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*/

View File

@@ -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 ];

View File

@@ -2645,6 +2645,8 @@ struct window_procs mac_procs = {
0, // mac_end_screen,
genl_outrip,
genl_preference_update,
genl_getmsghistory,
genl_putmsghistory,
};
/*macwin.c*/

View File

@@ -95,6 +95,8 @@ struct window_procs mswin_procs = {
mswin_end_screen,
mswin_outrip,
mswin_preference_update,
genl_getmsghistory,
genl_putmsghistory,
};
/*

View File

@@ -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)

View File

@@ -157,6 +157,8 @@ struct window_procs X11_procs = {
genl_outrip,
#endif
X11_preference_update,
genl_getmsghistory,
genl_putmsghistory,
};
/*

View File

@@ -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

View File

@@ -73,6 +73,8 @@ struct window_procs Gnome_procs = {
gnome_end_screen,
gnome_outrip,
genl_preference_update,
genl_getmsghistory,
genl_putmsghistory,
};
/*

View File

@@ -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*/

View File

@@ -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 */

View File

@@ -121,6 +121,8 @@ struct window_procs mswin_procs = {
mswin_end_screen,
mswin_outrip,
mswin_preference_update,
genl_getmsghistory,
genl_putmsghistory,
};