[comp.sources.games.bugs] Checkpointing for NetHack2.3

mwp@munmurra.mu.oz (Michael Paddon) (08/25/88)

I tried installing the anticrash patches recently posted to the net,
but they didn't seem to work properly at our installation. The problems
may have been caused by the fact that the save code is *extremely*
destructive.

The idea was very good, however. Who hasn't been frustrated by losing
a really good mega-game once in a while due to a program or system crash?

So I hacked up my own solution to the problem. The following patch
causes NetHack to save the game every time the player goes to a new
level in any fashion (stairs, traps, teleport etc.). No attempt at
efficency has been made -- but the mechanism should be reliable as
very little code has been changed or added, and the game is always
saved in a reasonable state.

Of course, the saved game is removed whenever the players wins, quits
or dies (unless the death is due to a panic).

The patch must be enabled by #defining CHECKPOINTS in the config.h file.


					Michael Paddon
					==============

------------------------------------------------------------------------
*** end.c.orig	Wed Aug 24 21:53:31 1988
--- end.c	Wed Aug 24 21:40:18 1988
***************
*** 89,94
  				    /* was exit(1) */
  	home(); cls();
  	puts(" Suddenly, the dungeon collapses.");
  #ifdef WIZARD
  	pline("Report error to %s and it may be possible to rebuild.",WIZARD);
  	more();

--- 89,95 -----
  				    /* was exit(1) */
  	home(); cls();
  	puts(" Suddenly, the dungeon collapses.");
+ #ifndef CHECKPOINTS
  #ifdef WIZARD
  	pline("Report error to %s and it may be possible to rebuild.",WIZARD);
  	more();
***************
*** 95,100
  	(void) sprintf (SAVEF, "%s.e", SAVEF);
  	dosave0(0);
  #endif	
  	fputs(" ERROR:  ", stdout);
  	printf(str,a1,a2,a3,a4,a5,a6);
  	more();				/* contains a fflush() */

--- 96,102 -----
  	(void) sprintf (SAVEF, "%s.e", SAVEF);
  	dosave0(0);
  #endif	
+ #endif
  	fputs(" ERROR:  ", stdout);
  	printf(str,a1,a2,a3,a4,a5,a6);
  	more();				/* contains a fflush() */
***************
*** 117,122
  #endif
  #ifdef WIZARD
  	extern char	*nomovemsg;
  
  	if(wizard && index("bcds", *st1)){
  		char buf[BUFSZ];

--- 119,129 -----
  #endif
  #ifdef WIZARD
  	extern char	*nomovemsg;
+ 
+ #ifdef CHECKPOINTS
+ 	if (strcmp (st1,"panicked") != 0)
+ 		(void) unlink (SAVEF);
+ #endif
  
  	if(wizard && index("bcds", *st1)){
  		char buf[BUFSZ];
*** save.c.orig	Wed Aug 24 21:52:46 1988
--- save.c	Wed Aug 24 22:38:31 1988
***************
*** 18,23
  dosave(){
  	clear_screen();
  	fflush(stdout);
  	if(dosave0(0)) {
  		settty("Be seeing you ...\n");
  		exit(0);

--- 18,26 -----
  dosave(){
  	clear_screen();
  	fflush(stdout);
+ #ifdef CHECKPOINTS
+ 	if(dosave0(0,0)) {
+ #else
  	if(dosave0(0)) {
  #endif
  		settty("Be seeing you ...\n");
***************
*** 19,24
  	clear_screen();
  	fflush(stdout);
  	if(dosave0(0)) {
  		settty("Be seeing you ...\n");
  		exit(0);
  	}

--- 22,28 -----
  	if(dosave0(0,0)) {
  #else
  	if(dosave0(0)) {
+ #endif
  		settty("Be seeing you ...\n");
  		exit(0);
  	}
***************
*** 29,34
  
  #ifndef NOSAVEONHANGUP
  hangup(){
  	(void) dosave0(1);
  	exit(1);
  }

--- 33,41 -----
  
  #ifndef NOSAVEONHANGUP
  hangup(){
+ #ifdef CHECKPOINTS
+ 	(void) dosave0(1,0);
+ #else
  	(void) dosave0(1);
  #endif
  	exit(1);
***************
*** 30,35
  #ifndef NOSAVEONHANGUP
  hangup(){
  	(void) dosave0(1);
  	exit(1);
  }
  #endif

--- 37,43 -----
  	(void) dosave0(1,0);
  #else
  	(void) dosave0(1);
+ #endif
  	exit(1);
  }
  #endif
***************
*** 35,40
  #endif
  
  /* returns 1 if save successful */
  dosave0(hu) int hu; {
  	register fd, ofd;
  	int tmp;		/* not register ! */

--- 43,51 -----
  #endif
  
  /* returns 1 if save successful */
+ #ifdef CHECKPOINTS
+ dosave0(hu,checkpoint) int hu,checkpoint; {
+ #else
  dosave0(hu) int hu; {
  #endif
  	register fd, ofd;
***************
*** 36,41
  
  /* returns 1 if save successful */
  dosave0(hu) int hu; {
  	register fd, ofd;
  	int tmp;		/* not register ! */
  #ifdef DGK

--- 47,53 -----
  dosave0(hu,checkpoint) int hu,checkpoint; {
  #else
  dosave0(hu) int hu; {
+ #endif
  	register fd, ofd;
  	int tmp;		/* not register ! */
  #ifdef DGK
***************
*** 149,154
  #else
  		savelev(fd,tmp);			/* actual level */
  #endif
  		(void) unlink(lock);
  	}
  	(void) close(fd);

--- 161,169 -----
  #else
  		savelev(fd,tmp);			/* actual level */
  #endif
+ #ifdef CHECKPOINTS
+ 		if (!checkpoint)
+ #endif
  		(void) unlink(lock);
  	}
  	(void) close(fd);
***************
*** 153,158
  	}
  	(void) close(fd);
  	glo(dlevel);
  	(void) unlink(lock);	/* get rid of current level --jgm */
  	glo(0);
  	(void) unlink(lock);

--- 168,176 -----
  	}
  	(void) close(fd);
  	glo(dlevel);
+ #ifdef CHECKPOINTS
+ 	if (!checkpoint)
+ #endif
  	(void) unlink(lock);	/* get rid of current level --jgm */
  	glo(0);
  #ifdef CHECKPOINTS
***************
*** 155,160
  	glo(dlevel);
  	(void) unlink(lock);	/* get rid of current level --jgm */
  	glo(0);
  	(void) unlink(lock);
  	return(1);
  }

--- 173,181 -----
  #endif
  	(void) unlink(lock);	/* get rid of current level --jgm */
  	glo(0);
+ #ifdef CHECKPOINTS
+ 	if (!checkpoint)
+ #endif
  	(void) unlink(lock);
  	return(1);
  }
***************
*** 278,283
  	(void) lseek(fd, 0L, 0);
  	getlev(fd, 0, 0);
  	(void) close(fd);
  	if(Punished) {
  		for(otmp = fobj; otmp; otmp = otmp->nobj)
  			if(otmp->olet == CHAIN_SYM) goto chainfnd;

--- 299,307 -----
  	(void) lseek(fd, 0L, 0);
  	getlev(fd, 0, 0);
  	(void) close(fd);
+ #ifndef CHECKPOINTS
+ 	(void) unlink(SAVEF);
+ #endif
  	if(Punished) {
  		for(otmp = fobj; otmp; otmp = otmp->nobj)
  			if(otmp->olet == CHAIN_SYM) goto chainfnd;
*** unixmain.c.orig	Wed Aug 24 21:48:40 1988
--- unixmain.c	Wed Aug 24 23:01:47 1988
***************
*** 10,15

  #include <stdio.h>
  #include <signal.h>
  #include "hack.h"
  
  #ifdef QUEST

--- 10,18 -----

  #include <stdio.h>
  #include <signal.h>
  #include "hack.h"
+ #ifdef CHECKPOINTS
+ #include <sys/wait.h>
+ #endif
  
  #ifdef QUEST
***************
*** 47,52
  #ifdef CHDIR
  	register char *dir;
  #endif
  
  	hname = argv[0];
  	hackpid = getpid();

--- 48,56 -----
  #ifdef CHDIR
  	register char *dir;
  #endif
+ #ifdef CHECKPOINTS
+ 	xchar oldlevel;
+ #endif
  
  	hname = argv[0];
  	hackpid = getpid();
***************
*** 309,314
  
  	initrack();
  
  	for(;;) {
  		if(flags.move) {	/* actual time passed */
  

--- 313,321 -----
  
  	initrack();
  
+ #ifdef CHECKPOINTS
+ 	oldlevel = dlevel;
+ #endif
  	for(;;) {
  		if(flags.move) {	/* actual time passed */
  
***************
*** 472,477
  		}
  		if(multi && multi%7 == 0)
  			(void) fflush(stdout);
  	}
  }
  

--- 479,509 -----
  		}
  		if(multi && multi%7 == 0)
  			(void) fflush(stdout);
+ 
+ #ifdef CHECKPOINTS
+ 		if (oldlevel != dlevel){
+ 			union wait status;
+ 			/* have to fork as save code is very destructive! */
+ 			switch (fork ()){
+ 			case -1:
+ 				pline ("Warning: game backup failed.");
+ 				more ();
+ 				break;
+ 			case 0:
+ 				if (dosave0(1,1))
+ 					_exit (0);
+ 				_exit (1);
+ 			default:
+ 				if (wait (&status) != -1)
+ 					if (status.w_termsig != 0 || status.w_retcode != 0){
+ 					pline ("Warning: game backup failed.");
+ 					more ();
+ 					}
+ 				break;
+ 			}
+ 			oldlevel = dlevel;
+ 		}
+ #endif
  	}
  }
  
------------------------------------------------------------------------