pc-hack

PC HACK 3.61 source code (archival)
git clone http://frotz.net/git/pc-hack.git
Log | Files | Refs

save.c (8744B)


      1 /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
      2 /* save.c - version 1.0.3 */
      3 
      4 #include "hack.h"
      5 extern char genocided[60];	/* defined in Decl.c */
      6 extern char fut_geno[60];	/* idem */
      7 #include <signal.h>
      8 
      9 extern char nul[], pl_character[PL_CSIZ], SAVEF[];
     10 extern long lseek();
     11 extern struct obj *restobjchn();
     12 extern struct monst *restmonchn();
     13 
     14 dosave(){
     15 	if(dosave0(0)) {
     16 		clear_screen();
     17 		settty("Be seeing you ...\n");
     18 		exit(0);
     19 	}
     20 }
     21 
     22 /* returns 1 if save successful */
     23 dosave0(hu) int hu; {
     24 	register fd, ofd;
     25 	int tmp;		/* not register ! */
     26 #ifdef DGK
     27 	long		fds, needed;
     28 	int		mode;
     29 	extern long	bytes_counted;
     30 	extern int	saveprompt;
     31 #endif
     32 
     33 	(void) signal(SIGINT, SIG_IGN);
     34 #ifdef DGK
     35 	if (!saveDiskPrompt(0))
     36 		return 0;
     37 	fd = open(SAVEF, O_WRONLY | O_BINARY | O_CREAT, FMASK);
     38 #else
     39 	fd = creat(SAVEF, FMASK);
     40 #endif
     41 	if(fd < 0) {
     42 		if(!hu) pline("Cannot open save file. (Continue or Quit)");
     43 		(void) unlink(SAVEF);		/* ab@unido */
     44 		return(0);
     45 	}
     46 	if(flags.moonphase == FULL_MOON)	/* ut-sally!fletcher */
     47 		u.uluck--;			/* and unido!ab */
     48 #ifdef DGK
     49 	home();
     50 	cl_end();
     51 	msmsg("Saving: ");
     52 #endif
     53 #ifdef DGK
     54 	mode = COUNT;
     55 again:
     56 	savelev(fd, dlevel, mode);
     57 	/* count_only will be set properly by savelev */
     58 #else
     59 	savelev(fd,dlevel);
     60 #endif
     61 	saveobjchn(fd, invent);
     62 	saveobjchn(fd, fcobj);
     63 	savemonchn(fd, fallen_down);
     64 	tmp = getuid();
     65 	bwrite(fd, (char *) &tmp, sizeof tmp);
     66 	bwrite(fd, (char *) &flags, sizeof(struct flag));
     67 	bwrite(fd, (char *) &dlevel, sizeof dlevel);
     68 	bwrite(fd, (char *) &maxdlevel, sizeof maxdlevel);
     69 	bwrite(fd, (char *) &moves, sizeof moves);
     70 	bwrite(fd, (char *) &u, sizeof(struct you));
     71 	if(u.ustuck)
     72 		bwrite(fd, (char *) &(u.ustuck->m_id), sizeof u.ustuck->m_id);
     73 	bwrite(fd, (char *) pl_character, sizeof pl_character);
     74 	bwrite(fd, (char *) genocided, sizeof genocided);
     75 	bwrite(fd, (char *) fut_geno, sizeof fut_geno);
     76 	savenames(fd);
     77 #ifdef DGK
     78 	if (mode == COUNT) {
     79 		/* make sure there is enough disk space */
     80 		needed = bytes_counted;
     81 		for (tmp = 1; tmp <= maxdlevel; tmp++)
     82 			if (tmp != dlevel && fileinfo[tmp].where)
     83 				needed += fileinfo[tmp].size + (sizeof tmp);
     84 		fds = freediskspace(SAVEF);
     85 		if (needed > fds) {
     86 			pline("There is insufficient space on SAVE disk.");
     87 			pline("Require %ld bytes but only have %ld.", needed,
     88 				fds);
     89 			flushout();
     90 			(void) close(fd);
     91 			(void) unlink(SAVEF);
     92 			saveprompt = 0;		/* allow a disk change */
     93 			return 0;
     94 		}
     95 		mode = WRITE;
     96 		goto again;
     97 	}
     98 #endif
     99 	for(tmp = 1; tmp <= maxdlevel; tmp++) {
    100 		extern int hackpid;
    101 #ifdef DGK
    102 		if (tmp == dlevel || !fileinfo[tmp].where) continue;
    103 		if (fileinfo[tmp].where != ACTIVE)
    104 			swapin_file(tmp);
    105 #else
    106 		extern boolean level_exists[];
    107 		if(tmp == dlevel || !level_exists[tmp]) continue;
    108 #endif
    109 		glo(tmp);
    110 #ifdef DGK
    111 		msmsg(".");
    112 #endif
    113 		if((ofd = open(lock, 0)) < 0) {
    114 		    if(!hu) pline("Error while saving: cannot read %s.", lock);
    115 		    (void) close(fd);
    116 		    (void) unlink(SAVEF);
    117 		    if(!hu) done("tricked");
    118 		    return(0);
    119 		}
    120 		getlev(ofd, hackpid, tmp);
    121 		(void) close(ofd);
    122 		bwrite(fd, (char *) &tmp, sizeof tmp);	/* level number */
    123 #ifdef DGK
    124 		savelev(fd,tmp,WRITE);			/* actual level */
    125 #else
    126 		savelev(fd,tmp);			/* actual level */
    127 #endif
    128 		(void) unlink(lock);
    129 	}
    130 	(void) close(fd);
    131 	glo(dlevel);
    132 	(void) unlink(lock);	/* get rid of current level --jgm */
    133 	glo(0);
    134 	(void) unlink(lock);
    135 	return(1);
    136 }
    137 
    138 dorecover(fd)
    139 register fd;
    140 {
    141 	register nfd;
    142 	int tmp;		/* not a register ! */
    143 	unsigned mid;		/* idem */
    144 	struct obj *otmp;
    145 	extern boolean restoring;
    146 #ifdef DGK
    147 	struct flag oldflags;
    148 
    149 	oldflags = flags;	/* Save flags set in the config file */
    150 #endif
    151 	restoring = TRUE;
    152 	getlev(fd, 0, 0);
    153 	invent = restobjchn(fd);
    154 	for(otmp = invent; otmp; otmp = otmp->nobj)
    155 		if(otmp->owornmask)
    156 			setworn(otmp, otmp->owornmask);
    157 	fcobj = restobjchn(fd);
    158 	fallen_down = restmonchn(fd);
    159 	mread(fd, (char *) &tmp, sizeof tmp);
    160 	if(tmp != getuid()) {		/* strange ... */
    161 		(void) close(fd);
    162 		(void) unlink(SAVEF);
    163 		puts("Saved game was not yours.");
    164 		restoring = FALSE;
    165 		return(0);
    166 	}
    167 	mread(fd, (char *) &flags, sizeof(struct flag));
    168 #ifdef DGK
    169 	/* Some config file OPTIONS take precedence over those in save file.
    170 	 */
    171 	flags.rawio = oldflags.rawio;
    172 	flags.DECRainbow = oldflags.DECRainbow;
    173 	flags.IBMBIOS = oldflags.IBMBIOS;
    174 #endif
    175 	mread(fd, (char *) &dlevel, sizeof dlevel);
    176 	mread(fd, (char *) &maxdlevel, sizeof maxdlevel);
    177 	mread(fd, (char *) &moves, sizeof moves);
    178 	mread(fd, (char *) &u, sizeof(struct you));
    179 	if(u.ustuck)
    180 		mread(fd, (char *) &mid, sizeof mid);
    181 	mread(fd, (char *) pl_character, sizeof pl_character);
    182 	mread(fd, (char *) genocided, sizeof genocided);
    183 	mread(fd, (char *) fut_geno, sizeof fut_geno);
    184 	restnames(fd);
    185 #ifdef DGK
    186 	msmsg("\n");
    187 	cl_end();
    188 	msmsg("You got as far as level %d%s.\n", maxdlevel,
    189 		flags.debug ? " in WIZARD mode" : "");
    190 	cl_end();
    191 	msmsg("Restoring: ");
    192 #endif
    193 	while(1) {
    194 		if(read(fd, (char *) &tmp, sizeof tmp) != sizeof tmp)
    195 			break;
    196 		getlev(fd, 0, tmp);
    197 		glo(tmp);
    198 #ifdef DGK
    199 		msmsg(".");
    200 		nfd = open(lock, O_WRONLY | O_BINARY | O_CREAT | O_TRUNC, FMASK);
    201 #else
    202 		nfd = creat(lock, FMASK);
    203 #endif
    204 		if (nfd < 0)
    205 			panic("Cannot open level file %s!\n", lock);
    206 #ifdef DGK
    207 		if (!savelev(nfd, tmp, COUNT | WRITE)) {
    208 
    209 			/* The savelev can't proceed because the size required
    210 			 * is greater than the available disk space.
    211 			 */
    212 			msmsg("\nNot enough space on `%s' to restore your game.\n",
    213 				levels);
    214 
    215 			/* Remove levels and bones that may have been created.
    216 			 */
    217 			(void) close(nfd);
    218 			eraseall(levels, alllevels);
    219 			eraseall(levels, allbones);
    220 
    221 			/* Perhaps the person would like to play without a
    222 			 * RAMdisk.
    223 			 */
    224 			if (ramdisk) {
    225 				/* PlaywoRAMdisk may not return, but if it does
    226 				 * it is certain that ramdisk will be 0.
    227 				 */
    228 				playwoRAMdisk();
    229 				(void) lseek(fd, 0L, 0); /* Rewind save file */
    230 				return dorecover(fd);	 /* and try again */
    231 			} else {
    232 				msmsg("Be seeing you ...\n");
    233 				exit(0);
    234 			}
    235 		}
    236 #else
    237 		savelev(nfd,tmp);
    238 #endif
    239 		(void) close(nfd);
    240 	}
    241 	(void) lseek(fd, 0L, 0);
    242 	getlev(fd, 0, 0);
    243 	(void) close(fd);
    244 	(void) unlink(SAVEF);
    245 	if(Punished) {
    246 		for(otmp = fobj; otmp; otmp = otmp->nobj)
    247 			if(otmp->olet == CHAIN_SYM) goto chainfnd;
    248 		panic("Cannot find the iron chain?");
    249 	chainfnd:
    250 		uchain = otmp;
    251 		if(!uball){
    252 			for(otmp = fobj; otmp; otmp = otmp->nobj)
    253 				if(otmp->olet == BALL_SYM && otmp->spe)
    254 					goto ballfnd;
    255 			panic("Cannot find the iron ball?");
    256 		ballfnd:
    257 			uball = otmp;
    258 		}
    259 	}
    260 	if(u.ustuck) {
    261 		register struct monst *mtmp;
    262 
    263 		for(mtmp = fmon; mtmp; mtmp = mtmp->nmon)
    264 			if(mtmp->m_id == mid) goto monfnd;
    265 		panic("Cannot find the monster ustuck.");
    266 	monfnd:
    267 		u.ustuck = mtmp;
    268 	}
    269 	setsee();  /* only to recompute seelx etc. - these weren't saved */
    270 #ifdef DGK
    271 	gameDiskPrompt();
    272 #endif
    273 	docrt();
    274 	restoring = FALSE;
    275 	return(1);
    276 }
    277 
    278 struct obj *
    279 restobjchn(fd)
    280 register fd;
    281 {
    282 	register struct obj *otmp, *otmp2;
    283 	register struct obj *first = 0;
    284 	int xl;
    285 #ifdef lint
    286 	/* suppress "used before set" warning from lint */
    287 	otmp2 = 0;
    288 #endif /* lint /**/
    289 	while(1) {
    290 		mread(fd, (char *) &xl, sizeof(xl));
    291 		if(xl == -1) break;
    292 		otmp = newobj(xl);
    293 		if(!first) first = otmp;
    294 		else otmp2->nobj = otmp;
    295 		mread(fd, (char *) otmp, (unsigned) xl + sizeof(struct obj));
    296 		if(!otmp->o_id) otmp->o_id = flags.ident++;
    297 		otmp2 = otmp;
    298 	}
    299 	if(first && otmp2->nobj){
    300 		impossible("Restobjchn: error reading objchn.");
    301 		otmp2->nobj = 0;
    302 	}
    303 	return(first);
    304 }
    305 
    306 struct monst *
    307 restmonchn(fd)
    308 register fd;
    309 {
    310 	register struct monst *mtmp, *mtmp2;
    311 	register struct monst *first = 0;
    312 	int xl;
    313 	int monsindex;
    314 	extern struct permonst li_dog, dog, la_dog, hell_hound, pm_guard;
    315 
    316 #ifdef lint
    317 	/* suppress "used before set" warning from lint */
    318 	mtmp2 = 0;
    319 #endif /* lint /**/
    320 	while(1) {
    321 		mread(fd, (char *) &xl, sizeof(xl));
    322 		if(xl == -1) break;
    323 		mtmp = newmonst(xl);
    324 		if(!first) first = mtmp;
    325 		else mtmp2->nmon = mtmp;
    326 		mread(fd, (char *) mtmp, (unsigned) xl + sizeof(struct monst));
    327 		if(!mtmp->m_id)
    328 			mtmp->m_id = flags.ident++;
    329 		monsindex = *((int *)&mtmp->data);
    330 		if (monsindex == INDEX_LITTLEDOG)
    331 			mtmp->data = &li_dog;
    332 		else if (monsindex == INDEX_DOG)
    333 			mtmp->data = &dog;
    334 		else if (monsindex == INDEX_LARGEDOG)
    335 			mtmp->data = &la_dog;
    336 		else if (monsindex == INDEX_HELLHOUND)
    337 			mtmp->data = &hell_hound;
    338 		else if (monsindex == INDEX_GUARD)
    339 			mtmp->data = &pm_guard;
    340 		else if (monsindex < 0) {
    341 			msmsg("Monster index %d in restmonchn\n", monsindex);
    342 			goto next;
    343 		} else
    344 			mtmp->data = &mons[monsindex];
    345 		if(mtmp->minvent)
    346 			mtmp->minvent = restobjchn(fd);
    347 next:
    348 		mtmp2 = mtmp;
    349 	}
    350 	if(first && mtmp2->nmon){
    351 		impossible("Restmonchn: error reading monchn.");
    352 		mtmp2->nmon = 0;
    353 	}
    354 	return(first);
    355 }