Source:NetHack 3.1.0/save.c

Below is the full text to save.c from the source code of NetHack 3.1.0. To link to a particular line, write [[NetHack 3.1.0/save.c#line123 ]], for example.

Warning! This is the source code from an old release. For the latest release, see Source code

1.   /*	SCCS Id: @(#)save.c	3.1	93/01/07	*/ 2.   /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ 3.    /* NetHack may be freely redistributed. See license for details. */ 4.     5.    #include "hack.h"  6.    #include "lev.h"  7. 8.   #ifndef NO_SIGNAL 9.   #include   10. #endif /* !NO_SIGNAL */ 11.  #if defined(EXPLORE_MODE) && !defined(LSC) && !defined(O_WRONLY) && !defined(AZTEC_C) 12.  #include   13. #endif /* EXPLORE_MODE */ 14.   15.   boolean hu;		/* set during hang-up */ 16.   17.   #ifdef MULDGN 18.  #include "quest.h"  19. #endif 20.   21.   #ifdef MFLOPPY 22.  extern struct finfo fileinfo[]; 23.  long bytes_counted; 24.  static int count_only; 25.  #else 26.  extern boolean level_exists[]; 27.  #endif 28.   29.   #ifdef MICRO 30.  int dotcnt;	/* also used in restore */ 31.  #endif 32.   33.   #ifdef ZEROCOMP 34.  static void FDECL(bputc, (UCHAR_P)); 35.  #endif 36.  static void FDECL(savelevchn, (int, int)); 37.  static void FDECL(savedamage, (int,struct damage *, int)); 38.  static void FDECL(saveobjchn, (int,struct obj *, int)); 39.  static void FDECL(savemonchn, (int,struct monst *, int)); 40.  static void FDECL(savetrapchn, (int,struct trap *, int)); 41.  static void FDECL(savegenoinfo, (int)); 42.  static void FDECL(savegamestate, (int, int)); 43.  #ifdef MFLOPPY 44.  static void FDECL(savelev0, (int,XCHAR_P,int)); 45.  static boolean NDECL(swapout_oldest); 46.  static void FDECL(copyfile, (char *,char *)); 47.  #endif /* MFLOPPY */ 48.  #ifdef GCC_WARN 49.  static long nulls[10]; 50.  #else 51.  #define nulls nul 52.  #endif 53.   54.   int 55.  dosave 56.  {  57.   	clear_nhwindow(WIN_MESSAGE); 58.  	if(yn("Really save?") == 'n') { 59.  		clear_nhwindow(WIN_MESSAGE); 60.  		if(multi > 0) nomul(0); 61.  	} else { 62.  		clear_nhwindow(WIN_MESSAGE); 63.  		pline("Saving..."); 64.  		mark_synch;	/* flush output */ 65.  		hu = FALSE; 66.  		if(dosave0) { 67.  			/* make sure they see the Saving message */ 68.  			display_nhwindow(WIN_MESSAGE, TRUE); 69.  			exit_nhwindows("Be seeing you..."); 70.  			terminate(0); 71.  		} else (void)doredraw; 72.  	}  73.   	return 0; 74.  }  75.    76.   #ifndef NOSAVEONHANGUP 77.  int 78.  hangup { 79.  	if(!hu) { 80.  		hu = TRUE; 81.  		(void) dosave0; 82.  # ifndef VMS 83.  		terminate(1); 84.  # endif 85.  	}  86.   	return 0; 87.  }  88.   #endif 89.   90.   /* returns 1 if save successful */ 91.  int 92.  dosave0 93.  {  94.   	register int fd, ofd; 95.  	xchar ltmp; 96.  #ifdef MFLOPPY 97.  	long fds, needed; 98.  #endif 99.   100.  	if (!SAVEF[0]) 101. 		return 0; 102.  103.  #if defined(UNIX) || defined(VMS) 104. 	(void) signal(SIGHUP, SIG_IGN); 105. #endif 106. #ifndef NO_SIGNAL 107. 	(void) signal(SIGINT, SIG_IGN); 108. #endif 109.  110.  #if defined(MICRO) && defined(MFLOPPY) 111. 	if(!hu && !saveDiskPrompt(0))	return 0; 112. #endif 113.  114.  #ifdef EXPLORE_MODE 115. 	if(!hu && flags.window_inited) { 116. 	    fd = open_savefile; 117. 	    if (fd > 0) { 118. 		(void) close(fd); 119. 		clear_nhwindow(WIN_MESSAGE); 120. 		pline("There seems to be an old save file."); 121. 		if (yn("Overwrite the old file?") == 'n') return 0; 122. 	    }  123.  	}  124.  #endif 125. 	  126.  	fd = create_savefile; 127.  128.  	if(fd < 0) { 129. 		if(!hu) pline("Cannot open save file."); 130. 		(void) delete_savefile;	/* ab@unido */ 131. 		return(0); 132. 	}  133.  	if(flags.moonphase == FULL_MOON)	/* ut-sally!fletcher */ 134. 		change_luck(-1);		/* and unido!ab */ 135. 	if(flags.friday13) 136. 		change_luck(1); 137. 	if(flags.window_inited) 138. 	    clear_nhwindow(WIN_MESSAGE); 139.  140.  #ifdef MFLOPPY 141. 	if(!hu) { 142. 	    dotcnt = 0; 143. 	    curs(WIN_MAP, 1, 1); 144. 	    putstr(WIN_MAP, 0, "Saving:"); 145. 	}  146.  	/* make sure there is enough disk space */ 147. 	savelev(fd, ledger_no(&u.uz), COUNT_SAVE); 148. 	savegamestate(fd, COUNT_SAVE); 149. 	needed = bytes_counted; 150. 	for (ltmp = 1; ltmp <= maxledgerno; ltmp++) 151. 		if (ltmp != ledger_no(&u.uz) && fileinfo[ltmp].where) 152. 			needed += fileinfo[ltmp].size + (sizeof ltmp); 153. # ifdef AMIGA 154. 	needed+=ami_wbench_iconsize(SAVEF); 155. # endif 156. 	fds = freediskspace(SAVEF); 157. 	if(needed > fds) { 158. 	    if(!hu) { 159. 		pline("There is insufficient space on SAVE disk."); 160. 		pline("Require %ld bytes but only have %ld.", needed, fds); 161. 	    }  162.  	    flushout; 163. 	    (void) close(fd); 164. 	    (void) delete_savefile; 165. 	    return 0; 166. 	}  167.  #endif /* MFLOPPY */ 168.  169.  	bufon(fd); 170. 	savelev(fd, ledger_no(&u.uz), WRITE_SAVE | FREE_SAVE); 171. 	savegamestate(fd, WRITE_SAVE | FREE_SAVE); 172.  173.  	for(ltmp = (xchar)1; ltmp <= maxledgerno; ltmp++) { 174. 		if (ltmp == ledger_no(&u.uz)) continue; 175. #ifdef MFLOPPY 176. 		if (!fileinfo[ltmp].where) continue; 177. #else 178. 		if(!level_exists[ltmp]) continue; 179. #endif 180. #ifdef MICRO 181. 		if(!hu) { 182. 		    curs(WIN_MAP, 8 + dotcnt++, 1); 183. 		    putstr(WIN_MAP, 0, "."); 184. 		}  185.  #endif 186. 		ofd = open_levelfile(ltmp); 187. 		if(ofd < 0) { 188. 		    if(!hu) pline("Cannot read level %d.", ltmp); 189. 		    (void) close(fd); 190. 		    (void) delete_savefile; 191. 		    if(!hu) done(TRICKED); 192. 		    return(0); 193. 		}  194.  		minit;	/* ZEROCOMP */ 195. 		getlev(ofd, hackpid, ltmp, FALSE); 196. 		(void) close(ofd); 197. 		bwrite(fd, (genericptr_t) &ltmp, sizeof ltmp); /* level number*/ 198. 		savelev(fd, ltmp, WRITE_SAVE | FREE_SAVE);     /* actual level*/ 199. 		delete_levelfile(ltmp); 200. 	}  201.  	bclose(fd); 202.  203.  	/* get rid of current level --jgm */ 204. 	delete_levelfile(ledger_no(&u.uz)); 205. 	delete_levelfile(0); 206. 	compress(SAVEF); 207. #ifdef AMIGA 208. 	ami_wbench_iconwrite(SAVEF); 209. #endif 210. 	return(1); 211. }  212.   213.  static void 214. savegamestate(fd, mode) 215. register int fd, mode; 216. {  217.  	int tmp;		/* not register ! */ 218.   219.  #ifdef MFLOPPY 220. 	count_only = (mode & COUNT_SAVE); 221. #endif 222. 	saveobjchn(fd, invent, mode); 223. 	saveobjchn(fd, migrating_objs, mode); 224. 	savemonchn(fd, migrating_mons, mode); 225. 	savegenoinfo(fd); 226. 	tmp = getuid; 227. 	bwrite(fd, (genericptr_t) &tmp, sizeof tmp); 228. 	bwrite(fd, (genericptr_t) &flags, sizeof(struct flag)); 229. 	bwrite(fd, (genericptr_t) &u, sizeof(struct you)); 230. 	save_dungeon(fd); 231. 	bwrite(fd, (genericptr_t) &inv_pos, sizeof inv_pos); 232. 	savelevchn(fd, mode); 233. 	bwrite(fd, (genericptr_t) &moves, sizeof moves); 234. 	bwrite(fd, (genericptr_t) &monstermoves, sizeof monstermoves); 235. #ifdef MULDGN 236. 	bwrite(fd, (genericptr_t) &quest_status, sizeof(struct q_score)); 237. #endif 238. 	bwrite(fd, (genericptr_t) spl_book,  239.  				sizeof(struct spell) * (MAXSPELL + 1)); 240. 	save_artifacts(fd); 241. 	save_oracles(fd); 242. 	if(u.ustuck) 243. 	    bwrite(fd, (genericptr_t) &(u.ustuck->m_id), sizeof u.ustuck->m_id); 244. 	bwrite(fd, (genericptr_t) pl_character, sizeof pl_character); 245. #ifdef TUTTI_FRUTTI 246. 	bwrite(fd, (genericptr_t) pl_fruit, sizeof pl_fruit); 247. 	bwrite(fd, (genericptr_t) &current_fruit, sizeof current_fruit); 248. 	savefruitchn(fd, mode); 249. #endif 250. 	savenames(fd); 251. 	save_waterlevel(fd); 252. 	bflush(fd); 253. }  254.   255.  #ifdef INSURANCE 256. void 257. savestateinlock 258. {  259.  	int fd, hpid; 260. 	static boolean havestate = TRUE; 261.  262.  	/* When checkpointing is on, the full state needs to be written 263. 	 * on each checkpoint. When checkpointing is off, only the pid 264. 	 * needs to be in the level.0 file, so it does not need to be  265. * constantly rewritten. When checkpointing is turned off during 266. 	 * a game, however, the file has to be rewritten once to truncate 267. 	 * it and avoid restoring from outdated information. 268. 	 *  269.  	 * Restricting havestate to this routine means that an additional 270. 	 * noop pid rewriting will take place on the first "checkpoint" after 271. 	 * the game is started or restored, if checkpointing is off. 272. 	 */  273.  	if (flags.ins_chkpt || havestate) { 274. 		/* save the rest of the current game state in the lock file, 275. 		 * following the original int pid, the current level number, 276. 		 * and the current savefile name, which should not be subject 277. 		 * to any internal compression schemes since they must be  278. * readable by an external utility 279. 		 */  280.  		fd = open_levelfile(0); 281. 		if (fd < 0) { 282. 		    pline("Cannot open level 0."); 283. 		    pline("Probably someone removed it."); 284. 		    done(TRICKED); 285. 		    return; 286. 		}  287.   288.  		(void) read(fd, (genericptr_t) &hpid, sizeof(hpid)); 289. 		if (hackpid != hpid) { 290. 		    pline("Level 0 pid bad!"); 291. 		    done(TRICKED); 292. 		}  293.  		(void) close(fd); 294.  295.  		fd = create_levelfile(0); 296. 		if (fd < 0) { 297. 		    pline("Cannot rewrite level 0."); 298. 		    done(TRICKED); 299. 		    return; 300. 		}  301.  		(void) write(fd, (genericptr_t) &hackpid, sizeof(hackpid)); 302. 		if (flags.ins_chkpt) { 303. 		    int currlev = ledger_no(&u.uz); 304.  305.  		    (void) write(fd, (genericptr_t) &currlev, sizeof(currlev)); 306. 		    save_savefile_name(fd); 307. 		    bufon(fd); 308. 		    savegamestate(fd, WRITE_SAVE); 309. 		}  310.  		bclose(fd); 311. 	}  312.  	havestate = flags.ins_chkpt; 313. }  314.  #endif 315.  316.  #ifdef MFLOPPY 317. boolean 318. savelev(fd, lev, mode) 319. int fd; 320. xchar lev; 321. int mode; 322. {  323.  	if (mode & COUNT_SAVE) { 324. 		bytes_counted = 0; 325. 		savelev0(fd, lev, COUNT_SAVE); 326. 		while (bytes_counted > freediskspace(levels)) 327. 			if (!swapout_oldest) 328. 				return FALSE; 329. 	}  330.  	if (mode & WRITE_SAVE) { 331. 		bytes_counted = 0; 332. 		/* mode is WRITE_SAVE and possibly FREE_SAVE */ 333. 		savelev0(fd, lev, mode); 334. 	}  335.  	fileinfo[lev].where = ACTIVE; 336. 	fileinfo[lev].time = moves; 337. 	fileinfo[lev].size = bytes_counted; 338. 	return TRUE; 339. }  340.   341.  static void 342. savelev0(fd,lev,mode) 343. #else 344. void 345. savelev(fd,lev,mode) 346. #endif 347. int fd; 348. xchar lev; 349. int mode; 350. {  351.  #ifdef TOS 352. 	short tlev; 353. #endif 354.  355.  	if(fd < 0) panic("Save on bad file!");	/* impossible */ 356. #ifdef MFLOPPY 357. 	count_only = (mode & COUNT_SAVE); 358. #else 359. 	if(lev >= 0 && lev <= maxledgerno) level_exists[lev] = TRUE; 360. #endif 361. 	bwrite(fd,(genericptr_t) &hackpid,sizeof(hackpid)); 362. #ifdef TOS 363. 	tlev=lev; tlev &= 0x00ff; 364. 	bwrite(fd,(genericptr_t) &tlev,sizeof(tlev)); 365. #else 366. 	bwrite(fd,(genericptr_t) &lev,sizeof(lev)); 367. #endif 368. #ifdef RLECOMP 369. 	{  370.  	    /* perform run-length encoding of rm structs */ 371. 	    struct rm *prm, *rgrm; 372. 	    int x, y;  373. uchar match; 374. 	     375.  	    rgrm = &levl[0][0];		/* start matching at first rm */ 376. 	    match = 0; 377.  378.  	    for (y = 0; y < ROWNO; y++) { 379. 		for (x = 0; x < COLNO; x++) { 380. 		    prm = &levl[x][y]; 381. 		    if (prm->glyph == rgrm->glyph  382.  			&& prm->typ == rgrm->typ  383.  			&& prm->seen == rgrm->seen  384.  			&& prm->lit == rgrm->lit  385.  			&& prm->doormask == rgrm->doormask  386.  			&& prm->horizontal == rgrm->horizontal  387.  			&& prm->waslit == rgrm->waslit  388.  			&& prm->roomno == rgrm->roomno  389.  			&& prm->edge == rgrm->edge) { 390. 			match++; 391. 			if (match > 254) { 392. 			    match = 254;	/* undo this match */ 393. 			    goto writeout; 394. 			}  395.  		    } else { 396. 			/* the run has been broken, 397. 			 * write out run-length encoding */ 398. 		    writeout: 399. 			bwrite(fd, (genericptr_t)&match, sizeof(uchar)); 400. 			bwrite(fd, (genericptr_t)rgrm, sizeof(struct rm)); 401. 			/* start encoding again. we have at least 1 rm 402. * in the next run, viz. this one. */ 403.  			match = 1; 404. 			rgrm = prm; 405. 		    }  406.  		}  407.  	    }  408.  	    if (match > 0) { 409. 		bwrite(fd, (genericptr_t)&match, sizeof(uchar)); 410. 		bwrite(fd, (genericptr_t)rgrm, sizeof(struct rm)); 411. 	    }  412.  	}  413.  #else 414. 	bwrite(fd,(genericptr_t) levl,sizeof(levl)); 415. #endif /* RLECOMP */ 416.  417.  	bwrite(fd,(genericptr_t) &monstermoves,sizeof(monstermoves)); 418. 	bwrite(fd,(genericptr_t) &upstair,sizeof(stairway)); 419. 	bwrite(fd,(genericptr_t) &dnstair,sizeof(stairway)); 420. 	bwrite(fd,(genericptr_t) &upladder,sizeof(stairway)); 421. 	bwrite(fd,(genericptr_t) &dnladder,sizeof(stairway)); 422. 	bwrite(fd,(genericptr_t) &sstairs,sizeof(stairway)); 423. 	bwrite(fd,(genericptr_t) &updest,sizeof(dest_area)); 424. 	bwrite(fd,(genericptr_t) &dndest,sizeof(dest_area)); 425. 	bwrite(fd,(genericptr_t) &level.flags,sizeof(level.flags)); 426. 	savemonchn(fd, fmon, mode); 427. 	save_worm(fd, mode);	/* save worm information */ 428. 	savetrapchn(fd, ftrap, mode); 429. 	saveobjchn(fd, fobj, mode); 430. 	saveobjchn(fd, billobjs, mode); 431.  432.  	save_engravings(fd, mode); 433. 	save_rooms(fd); 434. 	bwrite(fd,(genericptr_t) doors,sizeof(doors)); 435. 	savedamage(fd, level.damagelist, mode); 436. 	if (mode & FREE_SAVE) { 437. 		billobjs = 0; 438. 		ftrap = 0; 439. 		fmon = 0; 440. 		fobj = 0; 441. 	}  442.  	bflush(fd); 443. }  444.   445.  #ifdef ZEROCOMP 446. /* The runs of zero-run compression are flushed after the game state or a  447. * level is written out. This adds a couple bytes to a save file, where 448.  * the runs could be mashed together, but it allows gluing together game 449.  * state and level files to form a save file, and it means the flushing 450.  * does not need to be specifically called for every other time a level 451.  * file is written out. 452.  */  453.   454.  #define RLESC '\0'    /* Leading character for run of LRESC's */ 455. #define flushoutrun(ln) (bputc(RLESC), bputc(ln), ln = -1) 456.  457.  #ifndef ZEROCOMP_BUFSIZ 458. #define ZEROCOMP_BUFSIZ BUFSZ 459. #endif 460. static unsigned char NEARDATA outbuf[ZEROCOMP_BUFSIZ]; 461. static unsigned short NEARDATA outbufp = 0; 462. static short NEARDATA outrunlength = -1; 463. static int NEARDATA bwritefd; 464.  465.  /*dbg 466. {  467.     if(!hu) printf("outbufp %d outrunlength %d\n", outbufp,outrunlength); 468. }*/  469.   470.  static void 471. bputc(c) 472. unsigned char c;  473. { 474.  #ifdef MFLOPPY 475.     bytes_counted++; 476.     if (count_only) 477.       return; 478. #endif 479.     if (outbufp >= sizeof outbuf) { 480. 	(void) write(bwritefd, outbuf, sizeof outbuf); 481. 	outbufp = 0; 482.     }  483.      outbuf[outbufp++] = c;  484. } 485.   486.  /*ARGSUSED*/ 487. void 488. bufon(fd) 489.     int fd; 490. {  491.      return; 492. }  493.   494.  void 495. bflush(fd)  /* flush run and buffer */ 496. register int fd; 497. {  498.        bwritefd = fd; 499.       if (outrunlength >= 0) {    /* flush run */ 500. 	  flushoutrun(outrunlength); 501.       }  502.        if (outbufp) { 503. #ifdef MFLOPPY 504. 	  if (!count_only)    /* flush buffer */ 505. #endif 506. 		  (void) write(fd, outbuf, outbufp); 507. 	  outbufp = 0; 508.       }  509.        /*printf("bflush"); getret;*/ 510. }  511.   512.  void 513. bwrite(fd, loc, num) 514. register int fd; 515. genericptr_t loc; 516. register unsigned num; 517. {  518.        bwritefd = fd; 519.       for (num; num--, (*(char **)&loc)++) { 520. 	      if (*((char *)loc) == RLESC) { /* One more char in run */ 521. 		  if (++outrunlength == 0xFF) { 522. 		      flushoutrun(outrunlength); 523. 		  }  524.  	      } else { /* end of run */ 525. 		  if (outrunlength >= 0) {    /* flush run */ 526. 		      flushoutrun(outrunlength); 527. 		  }  528.  		  bputc(*((char *)loc)); 529. 	      }  530.        }  531.  }  532.   533.  void 534. bclose(fd) 535.     int fd; 536. {  537.      if (outbufp) 538. 	panic("closing file with buffered data still unwritten"); 539.     (void) close(fd); 540. }  541.   542.  #else /* ZEROCOMP */ 543.  544.  static int bw_fd = -1; 545. static FILE *bw_FILE = 0; 546.  547.  void 548. bufon(fd) 549.     int fd; 550. {  551.  #ifdef UNIX 552.     if(bw_fd >= 0) 553. 	panic("double buffering unexpected"); 554.     bw_fd = fd; 555.     if((bw_FILE = fdopen(fd, "w")) == 0) 556. 	panic("buffering of file %d failed", fd); 557. #endif 558. }  559.   560.  void 561. bflush(fd) 562.     int fd; 563. {  564.  #ifdef UNIX 565.     if(fd == bw_fd) { 566. 	if(fflush(bw_FILE) == EOF) 567. 	    panic("flush of savefile failed!"); 568.     }  569.  #endif 570.     return; 571. }  572.   573.  void 574. bwrite(fd,loc,num) 575. register int fd; 576. register genericptr_t loc; 577. register unsigned num; 578. {  579.  #ifdef MFLOPPY 580. 	bytes_counted += num; 581. 	if (!count_only) 582. #endif 583. 	{  584.  #ifdef UNIX 585. 	    if(fd != bw_fd) 586. 		panic("unbuffered write to fd %d (!= %d)", fd, bw_fd); 587.  588.  	    if(fwrite(loc, (int)num, 1, bw_FILE) != 1) 589. /* lint wants the 3rd arg of write to be an int; lint -p an unsigned */ 590. #else 591. # if defined(BSD) || defined(ULTRIX) 592. 	    if(write(fd, loc, (int)num) != (int)num) 593. # else /* e.g. SYSV, __TURBOC__ */ 594. 	    if(write(fd, loc, num) != num) 595. # endif 596. #endif 597. 	    {  598.  		if(!hu) panic("cannot write %u bytes to file #%d", num, fd); 599. 		else	terminate(1); 600. 	    }  601.  	}  602.  }  603.   604.  void 605. bclose(fd) 606.     int fd; 607. {  608.      bflush(fd); 609. #ifdef UNIX 610.     if (fd == bw_fd) { 611. 	(void) fclose(bw_FILE); 612. 	bw_fd = -1; 613. 	bw_FILE = 0; 614. 	return; 615.     }  616.  #endif 617.     (void) close(fd); 618. }  619.  #endif /* ZEROCOMP */ 620.  621.  static void 622. savelevchn(fd, mode) 623. register int fd, mode; 624. {  625.  	int cnt = 0; 626. 	s_level	*tmplev, *tmplev2; 627.  628.  	for(tmplev = sp_levchn; tmplev; tmplev = tmplev->next) cnt++; 629. 	bwrite(fd, (genericptr_t) &cnt, sizeof(int)); 630.  631.  	for(tmplev = sp_levchn; tmplev; tmplev = tmplev2) { 632.  633.  	    tmplev2 = tmplev->next; 634. 	    bwrite(fd, (genericptr_t) tmplev, sizeof(s_level)); 635. 	    if (mode & FREE_SAVE) 636. 		free((genericptr_t) tmplev); 637. 	}  638.  }  639.   640.  static void 641. savedamage(fd, damageptr, mode) 642. register int fd, mode; 643. register struct damage *damageptr; 644. {  645.  	register struct damage *tmp_dam; 646. 	unsigned int xl = 0; 647.  648.  	for (tmp_dam = damageptr; tmp_dam; tmp_dam = tmp_dam->next) 649. 	    xl++; 650. 	bwrite(fd, (genericptr_t) &xl, sizeof(xl)); 651. 	while (xl--) { 652. 	    bwrite(fd, (genericptr_t) damageptr, sizeof(*damageptr)); 653. 	    tmp_dam = damageptr; 654. 	    damageptr = damageptr->next; 655. 	    if (mode & FREE_SAVE) 656. 		free((genericptr_t)tmp_dam); 657. 	}  658.  	if (mode & FREE_SAVE) 659. 	    level.damagelist = 0; 660. }  661.   662.  static void 663. saveobjchn(fd,otmp,mode) 664. register int fd, mode; 665. register struct obj *otmp; 666. {  667.  	register struct obj *otmp2; 668. 	unsigned int xl; 669. 	int minusone = -1; 670.  671.  	while(otmp) { 672. 	    otmp2 = otmp->nobj; 673. 	    xl = otmp->onamelth; 674. 	    bwrite(fd, (genericptr_t) &xl, sizeof(int)); 675. 	    bwrite(fd, (genericptr_t) otmp, xl + sizeof(struct obj)); 676.  677.  	    if (Is_container(otmp) || otmp->otyp == STATUE) 678. 		saveobjchn(fd,otmp->cobj,mode); 679. 	    if (mode & FREE_SAVE) 680. 		dealloc_obj(otmp); 681. 	    otmp = otmp2; 682. 	}  683.  	bwrite(fd, (genericptr_t) &minusone, sizeof(int)); 684. }  685.   686.  static void 687. savemonchn(fd,mtmp,mode) 688. register int fd, mode; 689. register struct monst *mtmp; 690. {  691.  	register struct monst *mtmp2; 692. 	unsigned int xl; 693. 	int minusone = -1; 694. 	struct permonst *monbegin = &mons[0]; 695.  696.  	bwrite(fd, (genericptr_t) &monbegin, sizeof(monbegin)); 697.  698.  	while(mtmp) { 699. 		mtmp2 = mtmp->nmon; 700. #ifdef MUSE 701. 		if (mtmp->mw && mtmp->mw != mtmp->minvent) sort_mwep(mtmp); 702. #endif 703. 		xl = mtmp->mxlth + mtmp->mnamelth; 704. 		bwrite(fd, (genericptr_t) &xl, sizeof(int)); 705. 		bwrite(fd, (genericptr_t) mtmp, xl + sizeof(struct monst)); 706. 		if(mtmp->minvent) saveobjchn(fd,mtmp->minvent,mode); 707. 		if (mode & FREE_SAVE) 708. 		    dealloc_monst(mtmp); 709. 		mtmp = mtmp2; 710. 	}  711.  	bwrite(fd, (genericptr_t) &minusone, sizeof(int)); 712. }  713.   714.  static void 715. savetrapchn(fd,trap,mode) 716. register int fd,mode; 717. register struct trap *trap; 718. {  719.  	register struct trap *trap2; 720. 	while(trap) { 721. 		trap2 = trap->ntrap; 722. 		bwrite(fd, (genericptr_t) trap, sizeof(struct trap)); 723. 		if (mode & FREE_SAVE) 724. 			dealloc_trap(trap); 725. 		trap = trap2; 726. 	}  727.  	bwrite(fd, (genericptr_t)nulls, sizeof(struct trap)); 728. }  729.   730.  #ifdef TUTTI_FRUTTI 731. /* save all the fruit names and ID's; this is used only in saving whole games 732.  * (not levels) and in saving bones levels. When saving a bones level, 733.  * we only want to save the fruits which exist on the bones level; the bones 734.  * level routine marks nonexistent fruits by making the fid negative. 735.  */  736.  void 737. savefruitchn(fd, mode) 738. register int fd, mode; 739. {  740.  	register struct fruit *f2, *f1; 741.  742.  	f1 = ffruit; 743. 	while(f1) { 744. 		f2 = f1->nextf; 745. 		if (f1->fid >= 0) { 746. 			bwrite(fd, (genericptr_t) f1, sizeof(struct fruit)); 747. 		}  748.  		if (mode & FREE_SAVE) 749. 			dealloc_fruit(f1); 750. 		f1 = f2; 751. 	}  752.  	bwrite(fd, (genericptr_t)nulls, sizeof(struct fruit)); 753. }  754.  #endif 755.  756.  static void 757. savegenoinfo(fd) 758. register int fd; 759. {  760.  	register int i;  761. unsigned genolist[NUMMONS]; 762.  763.  	for (i = 0; i < NUMMONS; i++) 764. 		genolist[i] = mons[i].geno; 765.  766.  	bwrite(fd, (genericptr_t) genolist, sizeof(genolist)); 767. }  768.   769.  #ifdef MFLOPPY 770. boolean 771. swapin_file(lev) 772. int lev; 773. {  774.  	char to[PATHLEN], from[PATHLEN]; 775.  776.  	Sprintf(from, "%s%s", permbones, alllevels); 777. 	Sprintf(to, "%s%s", levels, alllevels); 778. 	set_levelfile_name(from, lev); 779. 	set_levelfile_name(to, lev); 780. 	while (fileinfo[lev].size > freediskspace(to)) 781. 		if (!swapout_oldest) 782. 			return FALSE; 783. # ifdef WIZARD 784. 	if (wizard) { 785. 		pline("Swapping in `%s'", from); 786. 		wait_synch; 787. 	}  788.  # endif 789. 	copyfile(from, to); 790. 	(void) unlink(from); 791. 	fileinfo[lev].where = ACTIVE; 792. 	return TRUE; 793. }  794.   795.  static boolean 796. swapout_oldest { 797. 	char to[PATHLEN], from[PATHLEN]; 798. 	int i, oldest; 799. 	long oldtime; 800.  801.  	if (!ramdisk) 802. 		return FALSE; 803. 	for (i = 1, oldtime = 0, oldest = 0; i <= maxledgerno; i++) 804. 		if (fileinfo[i].where == ACTIVE  805.  		&& (!oldtime || fileinfo[i].time < oldtime)) { 806. 			oldest = i;  807. oldtime = fileinfo[i].time; 808. 		}  809.  	if (!oldest) 810. 		return FALSE; 811. 	Sprintf(from, "%s%s", levels, alllevels); 812. 	Sprintf(to, "%s%s", permbones, alllevels); 813. 	set_levelfile_name(from, oldest); 814. 	set_levelfile_name(to, oldest); 815. # ifdef WIZARD 816. 	if (wizard) { 817. 		pline("Swapping out `%s'.", from); 818. 		wait_synch; 819. 	}  820.  # endif 821. 	copyfile(from, to); 822. 	(void) unlink(from); 823. 	fileinfo[oldest].where = SWAPPED; 824. 	return TRUE; 825. }  826.   827.  static void 828. copyfile(from, to) 829. char *from, *to; 830. {  831.  # ifdef TOS 832.  833.  	if (_copyfile(from, to)) 834. 		panic("Can't copy %s to %s", from, to); 835. # else 836. 	char buf[BUFSIZ];	/* this is system interaction, therefore 837. 				 * BUFSIZ instead of NetHack's BUFSZ */ 838. 	int nfrom, nto, fdfrom, fdto; 839.  840.  	if ((fdfrom = open(from, O_RDONLY | O_BINARY, FCMASK)) < 0) 841. 		panic("Can't copy from %s !?", from); 842. 	if ((fdto = open(to, O_WRONLY | O_BINARY | O_CREAT | O_TRUNC, FCMASK)) < 0) 843. 		panic("Can't copy to %s", to); 844. 	do { 845. 		nfrom = read(fdfrom, buf, BUFSIZ); 846. 		nto = write(fdto, buf, nfrom); 847. 		if (nto != nfrom) 848. 			panic("Copyfile failed!"); 849. 	} while (nfrom == BUFSIZ); 850. 	(void) close(fdfrom); 851. 	(void) close(fdto); 852. # endif /* TOS */ 853. }  854.   855.  void 856. co_false	    /* see comment in bones.c */ 857. {  858.      count_only = FALSE; 859.     return; 860. }  861.   862.  #endif /* MFLOPPY */ 863.  864.  /*save.c*/