Source:SLASH'EM 0.0.7E7F2/save.c

Below is the full text to save.c from the source code of SLASH'EM 0.0.7E7F2. To link to a particular line, write [[SLASH'EM 0.0.7E7F2/save.c#line123 ]], for example.

The latest source code for vanilla NetHack is at Source code.

1.   /*	SCCS Id: @(#)save.c	3.4	2003/11/14	*/ 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.    #include "quest.h"  8. 9.   #ifndef NO_SIGNAL 10.  #include   11. #endif 12.  #if !defined(LSC) && !defined(O_WRONLY) && !defined(AZTEC_C) 13.  #include   14. #endif 15.   16.   #ifdef MFLOPPY 17.  long bytes_counted; 18.  static int count_only; 19.  #endif 20.   21.   /*WAC boolean here to keep track of quit status*/ 22.  boolean saverestore; 23.   24.   #ifdef MICRO 25.  int dotcnt, dotrow;	/* also used in restore */ 26.  #endif 27.   28.   #ifdef ZEROCOMP 29.  STATIC_DCL void FDECL(bputc, (int)); 30.  #endif 31.  STATIC_DCL void FDECL(savelevchn, (int,int)); 32.  STATIC_DCL void FDECL(savedamage, (int,int)); 33.  STATIC_DCL void FDECL(saveobjchn, (int,struct obj *,int)); 34.  STATIC_DCL void FDECL(savemonchn, (int,struct monst *,int)); 35.  STATIC_DCL void FDECL(savetrapchn, (int,struct trap *,int)); 36.  STATIC_DCL void FDECL(savegamestate, (int,int)); 37.  #ifdef MFLOPPY 38.  STATIC_DCL void FDECL(savelev0, (int,XCHAR_P,int)); 39.  STATIC_DCL boolean NDECL(swapout_oldest); 40.  STATIC_DCL void FDECL(copyfile, (char *,char *)); 41.  #endif /* MFLOPPY */ 42.  #ifdef GCC_WARN 43.  static long nulls[10]; 44.  #else 45.  #define nulls nul 46.  #endif 47.   48.   #if defined(UNIX) || defined(VMS) || defined(__EMX__) || defined(WIN32) 49.  #define HUP	if (!program_state.done_hup) 50.  #else 51.  #define HUP 52.  #endif 53.   54.   #ifdef MENU_COLOR 55.  extern struct menucoloring *menu_colorings; 56.  #endif 57.   58.   /* need to preserve these during save to avoid accessing freed memory */ 59.  static unsigned ustuck_id = 0, usteed_id = 0; 60.   61.   int 62.  dosave 63.  {  64.   #ifdef KEEP_SAVE 65.  	/*WAC for reloading*/ 66.  	register int fd; 67.  #endif 68.   69.   	clear_nhwindow(WIN_MESSAGE); 70.  	if(yn("Really save?") == 'n') { 71.  		clear_nhwindow(WIN_MESSAGE); 72.  		if(multi > 0) nomul(0); 73.  	} else { 74.  		clear_nhwindow(WIN_MESSAGE); 75.  		pline("Saving..."); 76.  #if defined(UNIX) || defined(VMS) || defined(__EMX__) 77.  		program_state.done_hup = 0; 78.  #endif 79.  #ifdef KEEP_SAVE 80.                  saverestore = FALSE; 81.                  if (flags.keep_savefile) 82.                          if(yn("Really quit?") == 'n') saverestore = TRUE; 83.                  if(dosave0 && !saverestore) { 84.  #else 85.  		if(dosave0) { 86.  #endif 87.  			program_state.something_worth_saving = 0; 88.  			u.uhp = -1;		/* universal game's over indicator */ 89.  			/* make sure they see the Saving message */ 90.  			display_nhwindow(WIN_MESSAGE, TRUE); 91.  			exit_nhwindows("Be seeing you..."); 92.  			terminate(EXIT_SUCCESS); 93.  	}  94.   /*WAC redraw later 95.  		else (void)doredraw;*/ 96.  	}  97.   #ifdef KEEP_SAVE 98.  	if (saverestore) { 99.  /*WAC pulled this from pcmain.c - restore game from the file just saved*/ 100. 		fd = create_levelfile(0); 101. 		if (fd < 0) { 102. 			raw_print("Cannot create lock file"); 103. 		} else { 104. 			hackpid = 1; 105. 			write(fd, (genericptr_t) &hackpid, sizeof(hackpid)); 106. 			close(fd); 107. 		}  108.  #ifdef MFLOPPY 109. 		level_info[0].where = ACTIVE; 110. #endif 111.  112.  		fd = restore_saved_game; 113. 		if (fd >= 0) dorecover(fd); 114. 		check_special_room(FALSE); 115. 		flags.move = 0; 116. /*WAC correct these after restore*/ 117. 		if(flags.moonphase == FULL_MOON) 118. 			change_luck(1); 119. 		if(flags.friday13) 120. 			change_luck(-1); 121. 		if(iflags.window_inited) 122. 			clear_nhwindow(WIN_MESSAGE); 123. 	}  124.  	saverestore = FALSE; 125. #endif 126. 	(void)doredraw; 127. 	return 0; 128. }  129.   130.   131.  #if defined(UNIX) || defined(VMS) || defined (__EMX__) || defined(WIN32) 132. /*ARGSUSED*/ 133. void 134. hangup(sig_unused)  /* called as signal handler, so sent at least one arg */ 135. int sig_unused; 136. {  137.  # ifdef NOSAVEONHANGUP 138. 	(void) signal(SIGINT, SIG_IGN); 139. 	clearlocks; 140. #  ifndef VMS 141. 	terminate(EXIT_FAILURE); 142. #  endif 143. # else	/* SAVEONHANGUP */ 144. 	if (!program_state.done_hup++) { 145. 	    if (program_state.something_worth_saving) 146. 		(void) dosave0; 147. #  ifdef VMS 148. 	    /* don't call exit when already within an exit handler; 149. 	       that would cancel any other pending user-mode handlers */ 150. 	    if (!program_state.exiting) 151. #  endif 152. 	    {  153.  		clearlocks; 154. 		terminate(EXIT_FAILURE); 155. 	    }  156.  	}  157.  # endif 158. 	return; 159. }  160.  #endif 161.  162.  /* returns 1 if save successful */ 163. int 164. dosave0 165. {  166.  	const char *fq_save; 167. 	register int fd, ofd; 168. 	xchar ltmp; 169. 	d_level uz_save; 170. 	char whynot[BUFSZ]; 171.  172.  	if (!SAVEF[0]) 173. 		return 0; 174. 	fq_save = fqname(SAVEF, SAVEPREFIX, 1);	/* level files take 0 */ 175.  176.  #if defined(UNIX) || defined(VMS) 177. 	(void) signal(SIGHUP, SIG_IGN); 178. #endif 179. #ifndef NO_SIGNAL 180. 	(void) signal(SIGINT, SIG_IGN); 181. #endif 182.  183.  #if defined(MICRO) && defined(MFLOPPY) 184. 	if (!saveDiskPrompt(0)) return 0; 185. #endif 186.  187.  	HUP if (iflags.window_inited) { 188. 	    uncompress_area(fq_save, SAVEF); 189. 	    fd = open_savefile; 190. 	    if (fd > 0) { 191. 		(void) close(fd); 192. 		clear_nhwindow(WIN_MESSAGE); 193. 		There("seems to be an old save file."); 194. 		if (yn("Overwrite the old file?") == 'n') { 195. 		    compress_area(fq_save, SAVEF); 196. #ifdef KEEP_SAVE 197. /*WAC don't restore if you didn't save*/ 198. 			saverestore = FALSE; 199. #endif 200. 		    return 0; 201. 		}  202.  	    }  203.  	}  204.   205.  	HUP mark_synch;	/* flush any buffered screen output */ 206.  207.  	fd = create_savefile; 208. 	if(fd < 0) { 209. 		HUP pline("Cannot open save file."); 210. 		(void) delete_savefile;	/* ab@unido */ 211. 		return(0); 212. 	}  213.   214.  	vision_recalc(2);	/* shut down vision to prevent problems 215. 				   in the event of an impossible call */ 216. 	  217.  	/* undo date-dependent luck adjustments made at startup time */ 218. 	if(flags.moonphase == FULL_MOON)	/* ut-sally!fletcher */ 219. 		change_luck(-1);		/* and unido!ab */ 220. 	if(flags.friday13) 221. 		change_luck(1); 222. 	if(iflags.window_inited) 223. 	    HUP clear_nhwindow(WIN_MESSAGE); 224.  225.  #if defined(MICRO) && defined(TTY_GRAPHICS) 226. 	if (!strncmpi("tty", windowprocs.name, 3)) { 227. 	dotcnt = 0; 228. 	dotrow = 2; 229. 	curs(WIN_MAP, 1, 1); 230. 	  putstr(WIN_MAP, 0, "Saving:"); 231. 	}  232.  #endif 233. #ifdef MFLOPPY 234. 	/* make sure there is enough disk space */ 235. 	if (iflags.checkspace) { 236. 	    long fds, needed; 237.  238.  	    savelev(fd, ledger_no(&u.uz), COUNT_SAVE); 239. 	    savegamestate(fd, COUNT_SAVE); 240. 	    needed = bytes_counted; 241.  242.  	    for (ltmp = 1; ltmp <= maxledgerno; ltmp++) 243. 		if (ltmp != ledger_no(&u.uz) && level_info[ltmp].where) 244. 		    needed += level_info[ltmp].size + (sizeof ltmp); 245. 	    fds = freediskspace(fq_save); 246. 	    if (needed > fds) { 247. 		HUP { 248. 		    There("is insufficient space on SAVE disk."); 249. 		    pline("Require %ld bytes but only have %ld.", needed, fds); 250. 		}  251.  		flushout; 252. 		(void) close(fd); 253. 		(void) delete_savefile; 254. 		return 0; 255. 	    }  256.   257.  	    co_false; 258. 	}  259.  #endif /* MFLOPPY */ 260.  261.  	store_version(fd); 262. #ifdef STORE_PLNAME_IN_FILE 263. 	bwrite(fd, (genericptr_t) plname, PL_NSIZ); 264. #endif 265. 	ustuck_id = (u.ustuck ? u.ustuck->m_id : 0); 266. #ifdef STEED 267. 	usteed_id = (u.usteed ? u.usteed->m_id : 0); 268. #endif 269.  270.  	savelev(fd, ledger_no(&u.uz), WRITE_SAVE | FREE_SAVE); 271. /*Keep things from beeing freed if not restoring*/ 272. /*  273.  #ifdef KEEP_SAVE 274. 	if (saverestore) savegamestate(fd, WRITE_SAVE); 275. 	else 276. #endif 277. */  278.  	savegamestate(fd, WRITE_SAVE | FREE_SAVE); 279.  280.  	/* While copying level files around, zero out u.uz to keep 281. 	 * parts of the restore code from completely initializing all 282. 	 * in-core data structures, since all we're doing is copying. 283. 	 * This also avoids at least one nasty core dump. 284. 	 */  285.  	uz_save = u.uz; 286. 	u.uz.dnum = u.uz.dlevel = 0; 287. 	/* these pointers are no longer valid, and at least u.usteed 288. 	 * may mislead place_monster on other levels 289. 	 */  290.  	setustuck((struct monst *)0); 291. #ifdef STEED 292. 	u.usteed = (struct monst *)0; 293. #endif 294.  295.  	for(ltmp = (xchar)1; ltmp <= maxledgerno; ltmp++) { 296. 		if (ltmp == ledger_no(&uz_save)) continue; 297. 		if (!(level_info[ltmp].flags & LFILE_EXISTS)) continue; 298. #if defined(MICRO) && defined(TTY_GRAPHICS) 299. 		curs(WIN_MAP, 1 + dotcnt++, dotrow); 300. 		if (dotcnt >= (COLNO - 1)) { 301. 			dotrow++; 302. 			dotcnt = 0; 303. 		}  304.  		  putstr(WIN_MAP, 0, "."); 305. 		mark_synch; 306. #endif 307. 		ofd = open_levelfile(ltmp, whynot); 308. 		if (ofd < 0) { 309. 		    HUP pline("%s", whynot); 310. 		    (void) close(fd); 311. 		    (void) delete_savefile; 312. 		    HUP killer = whynot; 313. 		    HUP done(TRICKED); 314. 		    return(0); 315. 		}  316.  		minit;	/* ZEROCOMP */ 317. 		getlev(ofd, hackpid, ltmp, FALSE); 318. 		(void) close(ofd); 319. 		bwrite(fd, (genericptr_t) &ltmp, sizeof ltmp); /* level number*/ 320. 		savelev(fd, ltmp, WRITE_SAVE | FREE_SAVE);     /* actual level*/ 321. 		delete_levelfile(ltmp); 322. 	}  323.  	bclose(fd); 324.  325.  	u.uz = uz_save; 326.  327.  	/* get rid of current level --jgm */ 328.  329.  	delete_levelfile(ledger_no(&u.uz)); 330. 	delete_levelfile(0); 331. 	compress_area(FILE_AREA_SAVE, fq_save); 332. 	return(1); 333. }  334.   335.  STATIC_OVL void 336. savegamestate(fd, mode) 337. register int fd, mode; 338. {  339.  	int uid; 340.  341.  #ifdef MFLOPPY 342. 	count_only = (mode & COUNT_SAVE); 343. #endif 344. 	uid = getuid; 345. 	bwrite(fd, (genericptr_t) &uid, sizeof uid); 346. 	bwrite(fd, (genericptr_t) &flags, sizeof(struct flag)); 347. 	bwrite(fd, (genericptr_t) &u, sizeof(struct you)); 348.  349.  	/* must come before migrating_objs and migrating_mons are freed */ 350. 	save_timers(fd, mode, RANGE_GLOBAL); 351. 	save_light_sources(fd, mode, RANGE_GLOBAL); 352.  353.  	saveobjchn(fd, invent, mode); 354. 	saveobjchn(fd, migrating_objs, mode); 355. 	savemonchn(fd, migrating_mons, mode); 356. 	if (release_data(mode)) { 357. 	    invent = 0; 358. 	    migrating_objs = 0; 359. 	    migrating_mons = 0; 360. 	}  361.  	bwrite(fd, (genericptr_t) mvitals, sizeof(mvitals)); 362.  363.  	save_dungeon(fd, (boolean)!!perform_bwrite(mode),  364.  			 (boolean)!!release_data(mode)); 365. 	savelevchn(fd, mode); 366. 	bwrite(fd, (genericptr_t) &moves, sizeof moves); 367. 	bwrite(fd, (genericptr_t) &monstermoves, sizeof monstermoves); 368. 	bwrite(fd, (genericptr_t) &quest_status, sizeof(struct q_score)); 369. 	bwrite(fd, (genericptr_t) spl_book,  370.  				sizeof(struct spell) * (MAXSPELL + 1)); 371. 	bwrite(fd, (genericptr_t) tech_list,  372.  			sizeof(struct tech) * (MAXTECH + 1)); 373. 	save_artifacts(fd); 374. 	save_oracles(fd, mode); 375. 	if(ustuck_id) 376. 	    bwrite(fd, (genericptr_t) &ustuck_id, sizeof ustuck_id); 377. #ifdef STEED 378. 	if(usteed_id) 379. 	    bwrite(fd, (genericptr_t) &usteed_id, sizeof usteed_id); 380. #endif 381. 	bwrite(fd, (genericptr_t) pl_character, sizeof pl_character); 382. 	bwrite(fd, (genericptr_t) pl_fruit, sizeof pl_fruit); 383. 	bwrite(fd, (genericptr_t) &current_fruit, sizeof current_fruit); 384. 	savefruitchn(fd, mode); 385. 	savenames(fd, mode); 386. 	save_waterlevel(fd, mode); 387. 	bflush(fd); 388. }  389.   390.  #ifdef INSURANCE 391. void 392. savestateinlock 393. {  394.  	int fd, hpid; 395. 	static boolean havestate = TRUE; 396. 	char whynot[BUFSZ]; 397.  398.  	/* When checkpointing is on, the full state needs to be written 399. 	 * on each checkpoint. When checkpointing is off, only the pid 400. 	 * needs to be in the level.0 file, so it does not need to be  401. * constantly rewritten. When checkpointing is turned off during 402. 	 * a game, however, the file has to be rewritten once to truncate 403. 	 * it and avoid restoring from outdated information. 404. 	 *  405.  	 * Restricting havestate to this routine means that an additional 406. 	 * noop pid rewriting will take place on the first "checkpoint" after 407. 	 * the game is started or restored, if checkpointing is off. 408. 	 */  409.  	if (flags.ins_chkpt || havestate) { 410. 		/* save the rest of the current game state in the lock file, 411. 		 * following the original int pid, the current level number, 412. 		 * and the current savefile name, which should not be subject 413. 		 * to any internal compression schemes since they must be  414. * readable by an external utility 415. 		 */  416.  		fd = open_levelfile(0, whynot); 417. 		if (fd < 0) { 418. 		    pline("%s", whynot); 419. 		    pline("Probably someone removed it."); 420. 		    killer = whynot; 421. 		    done(TRICKED); 422. 		    return; 423. 		}  424.   425.  		(void) read(fd, (genericptr_t) &hpid, sizeof(hpid)); 426. 		if (hackpid != hpid) { 427. 		    Sprintf(whynot,  428.  			    "Level #0 pid (%d) doesn't match ours (%d)!",  429.  			    hpid, hackpid); 430. 		    pline("%s", whynot); 431. 		    killer = whynot; 432. 		    done(TRICKED); 433. 		}  434.  		(void) close(fd); 435.  436.  		fd = create_levelfile(0, whynot); 437. 		if (fd < 0) { 438. 		    pline("%s", whynot); 439. 		    killer = whynot; 440. 		    done(TRICKED); 441. 		    return; 442. 		}  443.  		(void) write(fd, (genericptr_t) &hackpid, sizeof(hackpid)); 444. 		if (flags.ins_chkpt) { 445. 		    int currlev = ledger_no(&u.uz); 446.  447.  		    (void) write(fd, (genericptr_t) &currlev, sizeof(currlev)); 448. 		    save_savefile_name(fd); 449. 		    store_version(fd); 450. #ifdef STORE_PLNAME_IN_FILE 451. 		    bwrite(fd, (genericptr_t) plname, PL_NSIZ); 452. #endif 453. 		    ustuck_id = (u.ustuck ? u.ustuck->m_id : 0); 454. #ifdef STEED 455. 		    usteed_id = (u.usteed ? u.usteed->m_id : 0); 456. #endif 457. 		    savegamestate(fd, WRITE_SAVE); 458. 		}  459.  		bclose(fd); 460. 	}  461.  	havestate = flags.ins_chkpt; 462. }  463.  #endif 464.  465.  #ifdef MFLOPPY 466. boolean 467. savelev(fd, lev, mode) 468. int fd; 469. xchar lev; 470. int mode; 471. {  472.  	if (mode & COUNT_SAVE) { 473. 		bytes_counted = 0; 474. 		savelev0(fd, lev, COUNT_SAVE); 475. 		/* probably bytes_counted will be filled in again by an  476. * immediately following WRITE_SAVE anyway, but we'll 477. * leave it out of checkspace just in case */ 478. 		if (iflags.checkspace) { 479. 			while (bytes_counted > freediskspace(levels)) 480. 				if (!swapout_oldest) 481. 					return FALSE; 482. 		}  483.  	}  484.  	if (mode & (WRITE_SAVE | FREE_SAVE)) { 485. 		bytes_counted = 0; 486. 		savelev0(fd, lev, mode); 487. 	}  488.  	if (mode != FREE_SAVE) { 489. 		level_info[lev].where = ACTIVE; 490. 		level_info[lev].time = moves; 491. 		level_info[lev].size = bytes_counted; 492. 	}  493.  	return TRUE; 494. }  495.   496.  STATIC_OVL void 497. savelev0(fd,lev,mode) 498. #else 499. void 500. savelev(fd,lev,mode) 501. #endif 502. int fd; 503. xchar lev; 504. int mode; 505. {  506.  #ifdef TOS 507. 	short tlev; 508. #endif 509.  510.  	/* if we're tearing down the current level without saving anything 511. 	   (which happens upon entrance to the endgame or after an aborted  512.  	   restore attempt) then we don't want to do any actual I/O */ 513. 	if (mode == FREE_SAVE) goto skip_lots; 514. 	if (iflags.purge_monsters) { 515. 		/* purge any dead monsters (necessary if we're starting  516.  		 * a panic save rather than a normal one, or sometimes  517.  		 * when changing levels without taking time -- e.g.  518.  		 * create statue trap then immediately level teleport) */ 519. 		dmonsfree; 520. 	}  521.   522.  	if(fd < 0) panic("Save on bad file!");	/* impossible */ 523. #ifdef MFLOPPY 524. 	count_only = (mode & COUNT_SAVE); 525. #endif 526. 	if (lev >= 0 && lev <= maxledgerno) 527. 	    level_info[lev].flags |= VISITED; 528. 	bwrite(fd,(genericptr_t) &hackpid,sizeof(hackpid)); 529. #ifdef TOS 530. 	tlev=lev; tlev &= 0x00ff; 531. 	bwrite(fd,(genericptr_t) &tlev,sizeof(tlev)); 532. #else 533. 	bwrite(fd,(genericptr_t) &lev,sizeof(lev)); 534. #endif 535. #ifdef RLECOMP 536. 	{  537.  	    /* perform run-length encoding of rm structs */ 538. 	    struct rm *prm, *rgrm; 539. 	    int x, y;  540. uchar match; 541.  542.  	    rgrm = &levl[0][0];		/* start matching at first rm */ 543. 	    match = 0; 544.  545.  	    for (y = 0; y < ROWNO; y++) { 546. 		for (x = 0; x < COLNO; x++) { 547. 		    prm = &levl[x][y]; 548. #ifdef DISPLAY_LAYERS 549. 		    if (prm->mem_bg == rgrm->mem_bg  550.  			&& prm->mem_trap == rgrm->mem_trap  551.  			&& prm->mem_obj == rgrm->mem_obj  552.  			&& prm->mem_corpse == rgrm->mem_corpse  553.  			&& prm->mem_invis == rgrm->mem_invis  554.  #else  555.  		    if (prm->glyph == rgrm->glyph 556. #endif 557. 			&& prm->typ == rgrm->typ 558. 			&& prm->seenv == rgrm->seenv 559. 			&& prm->horizontal == rgrm->horizontal 560. 			&& prm->flags == rgrm->flags 561. 			&& prm->lit == rgrm->lit 562. 			&& prm->waslit == rgrm->waslit 563. 			&& prm->roomno == rgrm->roomno 564. 			&& prm->edge == rgrm->edge) {  565.  			match++;  566.  			if (match > 254) {  567.  			    match = 254;	/* undo this match */  568.  			    goto writeout;  569.  			}  570.  		    } else {  571.  			/* the run has been broken,  572.  			 * write out run-length encoding */  573.  		    writeout:  574.  			bwrite(fd, (genericptr_t)&match, sizeof(uchar));  575.  			bwrite(fd, (genericptr_t)rgrm, sizeof(struct rm));  576.  			/* start encoding again. we have at least 1 rm  577.  			 * in the next run, viz. this one. */  578.  			match = 1;  579.  			rgrm = prm;  580.  		    }  581.  		}  582.  	    }  583.  	    if (match > 0) {  584.  		bwrite(fd, (genericptr_t)&match, sizeof(uchar));  585.  		bwrite(fd, (genericptr_t)rgrm, sizeof(struct rm));  586.  	    }  587.  	}  588.  #else  589.  	bwrite(fd,(genericptr_t) levl,sizeof(levl));  590.  #endif /* RLECOMP */  591.   592.  	bwrite(fd,(genericptr_t) &monstermoves,sizeof(monstermoves)); 593. 	bwrite(fd,(genericptr_t) &upstair,sizeof(stairway)); 594. 	bwrite(fd,(genericptr_t) &dnstair,sizeof(stairway)); 595. 	bwrite(fd,(genericptr_t) &upladder,sizeof(stairway)); 596. 	bwrite(fd,(genericptr_t) &dnladder,sizeof(stairway)); 597. 	bwrite(fd,(genericptr_t) &sstairs,sizeof(stairway)); 598. 	bwrite(fd,(genericptr_t) &updest,sizeof(dest_area)); 599. 	bwrite(fd,(genericptr_t) &dndest,sizeof(dest_area)); 600. 	bwrite(fd,(genericptr_t) &level.flags,sizeof(level.flags)); 601. 	bwrite(fd, (genericptr_t) doors, sizeof(doors)); 602. 	save_rooms(fd);	/* no dynamic memory to reclaim */ 603.  604.  	/* from here on out, saving also involves allocated memory cleanup */ 605.  skip_lots: 606. 	/* must be saved before mons, objs, and buried objs */ 607. 	save_timers(fd, mode, RANGE_LEVEL); 608. 	save_light_sources(fd, mode, RANGE_LEVEL); 609.  610.  	savemonchn(fd, fmon, mode); 611. 	save_worm(fd, mode);	/* save worm information */ 612. 	savetrapchn(fd, ftrap, mode); 613. 	saveobjchn(fd, fobj, mode); 614. 	saveobjchn(fd, level.buriedobjlist, mode); 615. 	saveobjchn(fd, billobjs, mode); 616. 	if (release_data(mode)) { 617. 	    fmon = 0; 618. 	    ftrap = 0; 619. 	    fobj = 0; 620. 	    level.buriedobjlist = 0; 621. 	    billobjs = 0; 622. 	}  623.  	save_engravings(fd, mode); 624. 	savedamage(fd, mode); 625. 	save_regions(fd, mode); 626. 	if (mode != FREE_SAVE) bflush(fd); 627. }  628.   629.  #ifdef ZEROCOMP 630. /* The runs of zero-run compression are flushed after the game state or a  631. * level is written out. This adds a couple bytes to a save file, where 632.  * the runs could be mashed together, but it allows gluing together game 633.  * state and level files to form a save file, and it means the flushing 634.  * does not need to be specifically called for every other time a level 635.  * file is written out. 636.  */  637.   638.  #define RLESC '\0'    /* Leading character for run of LRESC's */ 639. #define flushoutrun(ln) (bputc(RLESC), bputc(ln), ln = -1) 640.  641.  #ifndef ZEROCOMP_BUFSIZ 642. # define ZEROCOMP_BUFSIZ BUFSZ 643. #endif 644. static NEARDATA unsigned char outbuf[ZEROCOMP_BUFSIZ]; 645. static NEARDATA unsigned short outbufp = 0; 646. static NEARDATA short outrunlength = -1; 647. static NEARDATA int bwritefd; 648. static NEARDATA boolean compressing = FALSE; 649.  650.  /*dbg 651. {  652.      HUP printf("outbufp %d outrunlength %d\n", outbufp,outrunlength); 653. }*/  654.   655.  STATIC_OVL void 656. bputc(c) 657. int c;  658. { 659.  #ifdef MFLOPPY 660.     bytes_counted++; 661.     if (count_only) 662.       return; 663. #endif 664.     if (outbufp >= sizeof outbuf) { 665. 	(void) write(bwritefd, outbuf, sizeof outbuf); 666. 	outbufp = 0; 667.     }  668.      outbuf[outbufp++] = (unsigned char)c; 669. }  670.   671.  /*ARGSUSED*/ 672. void 673. bufon(fd) 674. int fd; 675. {  676.      compressing = TRUE; 677.     return; 678. }  679.   680.  /*ARGSUSED*/ 681. void 682. bufoff(fd) 683. int fd; 684. {  685.      if (outbufp) { 686. 	outbufp = 0; 687. 	panic("closing file with buffered data still unwritten"); 688.     }  689.      outrunlength = -1; 690.     compressing = FALSE; 691.     return; 692. }  693.   694.  void 695. bflush(fd)  /* flush run and buffer */ 696. register int fd; 697. {  698.      bwritefd = fd; 699.     if (outrunlength >= 0) {	/* flush run */ 700. 	flushoutrun(outrunlength); 701.     }  702.  #ifdef MFLOPPY 703.     if (count_only) outbufp = 0; 704. #endif 705.  706.      if (outbufp) { 707. 	if (write(fd, outbuf, outbufp) != outbufp) { 708. #if defined(UNIX) || defined(VMS) || defined(__EMX__) 709. 	    if (program_state.done_hup) 710. 		terminate(EXIT_FAILURE); 711. 	    else 712. #endif 713. 		bclose(fd);	/* panic (outbufp != 0) */ 714. 	}  715.  	outbufp = 0; 716.     }  717.  }  718.   719.  void 720. bwrite(fd, loc, num) 721. int fd; 722. genericptr_t loc; 723. register unsigned num; 724. {  725.      register unsigned char *bp = (unsigned char *)loc; 726.  727.      if (!compressing) { 728. #ifdef MFLOPPY 729. 	bytes_counted += num; 730. 	if (count_only) return; 731. #endif 732. 	if ((unsigned) write(fd, loc, num) != num) { 733. #if defined(UNIX) || defined(VMS) || defined(__EMX__) 734. 	    if (program_state.done_hup) 735. 		terminate(EXIT_FAILURE); 736. 	    else 737. #endif 738. 		panic("cannot write %u bytes to file #%d", num, fd); 739. 	}  740.      } else { 741. 	bwritefd = fd; 742. 	for (num; num--, bp++) { 743. 	    if (*bp == RLESC) {	/* One more char in run */ 744. 		if (++outrunlength == 0xFF) { 745. 		    flushoutrun(outrunlength); 746. 		}  747.  	    } else {		/* end of run */ 748. 		if (outrunlength >= 0) {	/* flush run */ 749. 		    flushoutrun(outrunlength); 750. 		}  751.  		bputc(*bp); 752. 	    }  753.  	}  754.      }  755.  }  756.   757.  void 758. bclose(fd) 759. int fd; 760. {  761.      bufoff(fd); 762.     (void) close(fd); 763.     return; 764. }  765.   766.  #else /* ZEROCOMP */ 767.  768.  static int bw_fd = -1; 769. static FILE *bw_FILE = 0; 770. static boolean buffering = FALSE; 771.  772.  void 773. bufon(fd) 774.     int fd; 775. {  776.  #ifdef UNIX 777.     if(bw_fd >= 0) 778. 	panic("double buffering unexpected"); 779.     bw_fd = fd; 780.     if((bw_FILE = fdopen(fd, "w")) == 0) 781. 	panic("buffering of file %d failed", fd); 782. #endif 783.     buffering = TRUE; 784. }  785.   786.  void 787. bufoff(fd) 788. int fd; 789. {  790.      bflush(fd); 791.     buffering = FALSE; 792. }  793.   794.  void 795. bflush(fd) 796.     int fd; 797. {  798.  #ifdef UNIX 799.     if(fd == bw_fd) { 800. 	if(fflush(bw_FILE) == EOF) 801. 	    panic("flush of savefile failed!"); 802.     }  803.  #endif 804.     return; 805. }  806.   807.  void 808. bwrite(fd,loc,num) 809. register int fd; 810. register genericptr_t loc; 811. register unsigned num; 812. {  813.  	boolean failed; 814.  815.  #ifdef MFLOPPY 816. 	bytes_counted += num; 817. 	if (count_only) return; 818. #endif 819.  820.  #ifdef UNIX 821. 	if (buffering) { 822. 	    if(fd != bw_fd) 823. 		panic("unbuffered write to fd %d (!= %d)", fd, bw_fd); 824.  825.  	    failed = (fwrite(loc, (int)num, 1, bw_FILE) != 1); 826. 	} else 827. #endif /* UNIX */ 828. 	{  829.  /* lint wants the 3rd arg of write to be an int; lint -p an unsigned */ 830. #if defined(BSD) || defined(ULTRIX) 831. 	    failed = (write(fd, loc, (int)num) != (int)num); 832. #else /* e.g. SYSV, __TURBOC__ */ 833. 	    failed = (write(fd, loc, num) != num); 834. #endif 835. 	}  836.   837.  	if (failed) { 838. #if defined(UNIX) || defined(VMS) || defined(__EMX__) 839. 	    if (program_state.done_hup) 840. 		terminate(EXIT_FAILURE); 841. 	    else 842. #endif 843. 		panic("cannot write %u bytes to file #%d", num, fd); 844. 	}  845.  }  846.   847.  void 848. bclose(fd) 849.     int fd; 850. {  851.      bufoff(fd); 852. #ifdef UNIX 853.     if (fd == bw_fd) { 854. 	(void) fclose(bw_FILE); 855. 	bw_fd = -1; 856. 	bw_FILE = 0; 857.     } else 858. #endif 859. 	(void) close(fd); 860.     return; 861. }  862.  #endif /* ZEROCOMP */ 863.  864.  STATIC_OVL void 865. savelevchn(fd, mode) 866. register int fd, mode; 867. {  868.  	s_level	*tmplev, *tmplev2; 869. 	int cnt = 0; 870.  871.  	for (tmplev = sp_levchn; tmplev; tmplev = tmplev->next) cnt++; 872. 	if (perform_bwrite(mode)) 873. 	    bwrite(fd, (genericptr_t) &cnt, sizeof(int)); 874.  875.  	for (tmplev = sp_levchn; tmplev; tmplev = tmplev2) { 876. 	    tmplev2 = tmplev->next; 877. 	    if (perform_bwrite(mode)) 878. 		bwrite(fd, (genericptr_t) tmplev, sizeof(s_level)); 879. 	    if (release_data(mode)) 880. 		free((genericptr_t) tmplev); 881. 	}  882.  	if (release_data(mode)) 883. 	    sp_levchn = 0; 884. }  885.   886.  STATIC_OVL void 887. savedamage(fd, mode) 888. register int fd, mode; 889. {  890.  	register struct damage *damageptr, *tmp_dam; 891. 	unsigned int xl = 0; 892.  893.  	damageptr = level.damagelist; 894. 	for (tmp_dam = damageptr; tmp_dam; tmp_dam = tmp_dam->next) 895. 	    xl++; 896. 	if (perform_bwrite(mode)) 897. 	    bwrite(fd, (genericptr_t) &xl, sizeof(xl)); 898.  899.  	while (xl--) { 900. 	    if (perform_bwrite(mode)) 901. 		bwrite(fd, (genericptr_t) damageptr, sizeof(*damageptr)); 902. 	    tmp_dam = damageptr; 903. 	    damageptr = damageptr->next; 904. 	    if (release_data(mode)) 905. 		free((genericptr_t)tmp_dam); 906. 	}  907.  	if (release_data(mode)) 908. 	    level.damagelist = 0; 909. }  910.   911.  STATIC_OVL void 912. saveobjchn(fd, otmp, mode) 913. register int fd, mode; 914. register struct obj *otmp; 915. {  916.  	register struct obj *otmp2; 917. 	unsigned int xl; 918. 	int minusone = -1; 919.  920.  	while(otmp) { 921. 	    otmp2 = otmp->nobj; 922. 	    if (perform_bwrite(mode)) { 923. 		xl = otmp->oxlth + otmp->onamelth; 924. 		bwrite(fd, (genericptr_t) &xl, sizeof(int)); 925. 		bwrite(fd, (genericptr_t) otmp, xl + sizeof(struct obj)); 926. 	    }  927.  	    if (Has_contents(otmp)) 928. 		saveobjchn(fd,otmp->cobj,mode); 929. 	    if (release_data(mode)) { 930. 		if (otmp->oclass == FOOD_CLASS) food_disappears(otmp); 931. 		if (otmp->oclass == SPBOOK_CLASS) book_disappears(otmp); 932. 		otmp->where = OBJ_FREE;	/* set to free so dealloc will work */ 933. 		otmp->timed = 0;	/* not timed any more */ 934. 		otmp->lamplit = 0;	/* caller handled lights */ 935. 		dealloc_obj(otmp); 936. 	    }  937.  	    otmp = otmp2; 938. 	}  939.  	if (perform_bwrite(mode)) 940. 	    bwrite(fd, (genericptr_t) &minusone, sizeof(int)); 941. }  942.   943.  STATIC_OVL void 944. savemonchn(fd, mtmp, mode) 945. register int fd, mode; 946. register struct monst *mtmp; 947. {  948.  	register struct monst *mtmp2; 949. 	unsigned int xl; 950. 	int minusone = -1; 951. 	struct permonst *monbegin = &mons[0]; 952.  953.  	if (perform_bwrite(mode)) 954. 	    bwrite(fd, (genericptr_t) &monbegin, sizeof(monbegin)); 955.  956.  	while (mtmp) { 957. 	    mtmp2 = mtmp->nmon; 958.  959.  	    if (perform_bwrite(mode)) { 960. 		xl = mtmp->mxlth + mtmp->mnamelth; 961. 		bwrite(fd, (genericptr_t) &xl, sizeof(int)); 962. 		bwrite(fd, (genericptr_t) mtmp, xl + sizeof(struct monst)); 963. 	    }  964.  	    if (mtmp->minvent) 965. 		saveobjchn(fd,mtmp->minvent,mode); 966. 	    if (release_data(mode)) 967. 		dealloc_monst(mtmp); 968. 	    mtmp = mtmp2; 969. 	}  970.  	if (perform_bwrite(mode)) 971. 	    bwrite(fd, (genericptr_t) &minusone, sizeof(int)); 972. }  973.   974.  STATIC_OVL void 975. savetrapchn(fd, trap, mode) 976. register int fd, mode; 977. register struct trap *trap; 978. {  979.  	register struct trap *trap2; 980.  981.  	while (trap) { 982. 	    trap2 = trap->ntrap; 983. 	    if (perform_bwrite(mode)) 984. 		bwrite(fd, (genericptr_t) trap, sizeof(struct trap)); 985. 	    if (release_data(mode)) 986. 		dealloc_trap(trap); 987. 	    trap = trap2; 988. 	}  989.  	if (perform_bwrite(mode)) 990. 	    bwrite(fd, (genericptr_t)nulls, sizeof(struct trap)); 991. }  992.   993.  /* save all the fruit names and ID's; this is used only in saving whole games 994.  * (not levels) and in saving bones levels. When saving a bones level, 995.  * we only want to save the fruits which exist on the bones level; the bones 996.  * level routine marks nonexistent fruits by making the fid negative. 997.  */  998.  void 999. savefruitchn(fd, mode) 1000. register int fd, mode; 1001. { 1002. 	register struct fruit *f2, *f1; 1003. 1004. 	f1 = ffruit; 1005. 	while (f1) { 1006. 	   f2 = f1->nextf; 1007. 	   if (f1->fid >= 0 && perform_bwrite(mode)) 1008. 		bwrite(fd, (genericptr_t) f1, sizeof(struct fruit)); 1009. 	   if (release_data(mode)) 1010. 		dealloc_fruit(f1); 1011. 	   f1 = f2; 1012. 	} 1013. 	if (perform_bwrite(mode)) 1014. 	   bwrite(fd, (genericptr_t)nulls, sizeof(struct fruit)); 1015. 	if (release_data(mode)) 1016. 	   ffruit = 0; 1017. } 1018.  1019. /* also called by prscore; this probably belongs in dungeon.c... */ 1020. /*  1021.  * [ALI] Also called by init_dungeons for the sake of the GTK interface 1022. * and the display_score callback of the proxy interface. For this purpose, 1023. * the previous dungeon must be discarded. 1024. */  1025. void 1026. free_dungeons 1027. { 1028. #if defined(FREE_ALL_MEMORY) || defined(GTK_GRAPHICS) || defined(PROXY_GRAPHICS) 1029. 	savelevchn(0, FREE_SAVE); 1030. 	save_dungeon(0, FALSE, TRUE); 1031. #endif 1032. 	return; 1033. } 1034.  1035. #ifdef MENU_COLOR 1036. void 1037. free_menu_coloring 1038. { 1039.    struct menucoloring *tmp = menu_colorings; 1040.    1041.    while (tmp) { 1042.      struct menucoloring *tmp2 = tmp->next; 1043. #ifdef USE_REGEX_MATCH 1044.      (void) regfree(&tmp->match); 1045. #else 1046.      free(tmp->match); 1047. #endif 1048.      free(tmp); 1049.      tmp = tmp2; 1050.   }  1051.    return; 1052. } 1053. #endif 1054. 1055. void 1056. freedynamicdata 1057. { 1058. 	unload_qtlist; 1059. 	free_invbuf;	/* let_to_name (invent.c) */ 1060. 	free_youbuf;	/* You_buf,&c (pline.c) */ 1061. #ifdef MENU_COLOR 1062.        free_menu_coloring; 1063. #endif 1064. 	tmp_at(DISP_FREEMEM, 0);	/* temporary display effects */ 1065. #ifdef FREE_ALL_MEMORY 1066. # define freeobjchn(X)	(saveobjchn(0, X, FREE_SAVE), X = 0) 1067. # define freemonchn(X)	(savemonchn(0, X, FREE_SAVE), X = 0) 1068. # define freetrapchn(X)	(savetrapchn(0, X, FREE_SAVE), X = 0) 1069. # define freefruitchn	 savefruitchn(0, FREE_SAVE) 1070. # define freenames	 savenames(0, FREE_SAVE) 1071. # define free_oracles	save_oracles(0, FREE_SAVE) 1072. # define free_waterlevel save_waterlevel(0, FREE_SAVE) 1073. # define free_worm	 save_worm(0, FREE_SAVE) 1074. # define free_timers(R)	 save_timers(0, FREE_SAVE, R) 1075. # define free_light_sources(R) save_light_sources(0, FREE_SAVE, R); 1076. # define free_engravings save_engravings(0, FREE_SAVE) 1077. # define freedamage	 savedamage(0, FREE_SAVE) 1078. # define free_animals	 mon_animal_list(FALSE) 1079. 1080. 	/* move-specific data */ 1081. 	dmonsfree;		/* release dead monsters */ 1082. 1083. 	/* level-specific data */ 1084. 	free_timers(RANGE_LEVEL); 1085. 	free_light_sources(RANGE_LEVEL); 1086. 	freemonchn(fmon); 1087. 	free_worm;		/* release worm segment information */ 1088. 	freetrapchn(ftrap); 1089. 	freeobjchn(fobj); 1090. 	freeobjchn(level.buriedobjlist); 1091. 	freeobjchn(billobjs); 1092. 	free_engravings; 1093. 	freedamage; 1094. 1095. 	/* game-state data */ 1096. 	free_timers(RANGE_GLOBAL); 1097. 	free_light_sources(RANGE_GLOBAL); 1098. 	freeobjchn(invent); 1099. 	freeobjchn(migrating_objs); 1100. 	freemonchn(migrating_mons); 1101. 	freemonchn(mydogs);		/* ascension or dungeon escape */ 1102.     /* freelevchn;	[folded into free_dungeons] */ 1103. 	free_animals; 1104. 	free_oracles; 1105. 	freefruitchn; 1106. 	freenames; 1107. 	free_waterlevel; 1108. 	free_dungeons; 1109. 1110. 	/* some pointers in iflags */ 1111. 	if (iflags.wc_font_map) free(iflags.wc_font_map); 1112. 	if (iflags.wc_font_message) free(iflags.wc_font_message); 1113. 	if (iflags.wc_font_text) free(iflags.wc_font_text); 1114. 	if (iflags.wc_font_menu) free(iflags.wc_font_menu); 1115. 	if (iflags.wc_font_status) free(iflags.wc_font_status); 1116. 	if (iflags.wc_tile_file) free(iflags.wc_tile_file); 1117. #ifdef AUTOPICKUP_EXCEPTIONS 1118. 	free_autopickup_exceptions; 1119. #endif 1120. 1121. #endif	/* FREE_ALL_MEMORY */ 1122. 	return; 1123. } 1124.  1125. #ifdef MFLOPPY 1126. boolean 1127. swapin_file(lev) 1128. int lev; 1129. { 1130. 	char to[PATHLEN], from[PATHLEN]; 1131. 1132. 	Sprintf(from, "%s%s", permbones, alllevels); 1133. 	Sprintf(to, "%s%s", levels, alllevels); 1134. 	set_levelfile_name(from, lev); 1135. 	set_levelfile_name(to, lev); 1136. 	if (iflags.checkspace) { 1137. 		while (level_info[lev].size > freediskspace(to)) 1138. 			if (!swapout_oldest) 1139. 				return FALSE; 1140. 	} 1141. # ifdef WIZARD 1142. 	if (wizard) { 1143. 		pline("Swapping in `%s'.", from); 1144. 		wait_synch; 1145. 	} 1146. # endif 1147. 	copyfile(from, to); 1148. 	(void) unlink(from); 1149. 	level_info[lev].where = ACTIVE; 1150. 	return TRUE; 1151. } 1152.  1153. STATIC_OVL boolean 1154. swapout_oldest { 1155. 	char to[PATHLEN], from[PATHLEN]; 1156. 	int i, oldest; 1157. 	long oldtime; 1158. 1159. 	if (!ramdisk) 1160. 		return FALSE; 1161. 	for (i = 1, oldtime = 0, oldest = 0; i <= maxledgerno; i++) 1162. 		if (level_info[i].where == ACTIVE 1163. 		&& (!oldtime || level_info[i].time < oldtime)) { 1164. 			oldest = i; 1165. oldtime = level_info[i].time; 1166. 		} 1167. 	if (!oldest) 1168. 		return FALSE; 1169. 	Sprintf(from, "%s%s", levels, alllevels); 1170. 	Sprintf(to, "%s%s", permbones, alllevels); 1171. 	set_levelfile_name(from, oldest); 1172. 	set_levelfile_name(to, oldest); 1173. # ifdef WIZARD 1174. 	if (wizard) { 1175. 		pline("Swapping out `%s'.", from); 1176. 		wait_synch; 1177. 	} 1178. # endif 1179. 	copyfile(from, to); 1180. 	(void) unlink(from); 1181. 	level_info[oldest].where = SWAPPED; 1182. 	return TRUE; 1183. } 1184.  1185. STATIC_OVL void 1186. copyfile(from, to) 1187. char *from, *to; 1188. { 1189. # ifdef TOS 1190. 1191. 	if (_copyfile(from, to)) 1192. 		panic("Can't copy %s to %s", from, to); 1193. # else 1194. 	char buf[BUFSIZ];	/* this is system interaction, therefore 1195. 				 * BUFSIZ instead of NetHack's BUFSZ */ 1196. 	int nfrom, nto, fdfrom, fdto; 1197. 1198. 	if ((fdfrom = open(from, O_RDONLY | O_BINARY, FCMASK)) < 0) 1199. 		panic("Can't copy from %s !?", from); 1200. 	if ((fdto = open(to, O_WRONLY | O_BINARY | O_CREAT | O_TRUNC, FCMASK)) < 0) 1201. 		panic("Can't copy to %s", to); 1202. 	do { 1203. 		nfrom = read(fdfrom, buf, BUFSIZ); 1204. 		nto = write(fdto, buf, nfrom); 1205. 		if (nto != nfrom) 1206. 			panic("Copyfile failed!"); 1207. 	} while (nfrom == BUFSIZ); 1208. 	(void) close(fdfrom); 1209. 	(void) close(fdto); 1210. # endif /* TOS */ 1211. } 1212.  1213. void 1214. co_false	   /* see comment in bones.c */ 1215. { 1216.     count_only = FALSE; 1217.    return; 1218. } 1219.  1220. #endif /* MFLOPPY */ 1221. 1222. /*save.c*/