Source:NetHack 3.1.0/save.c

From NetHackWiki
Revision as of 07:29, 4 March 2008 by Kernigh bot (talk | contribs) (NetHack 3.1.0/save.c moved to Source:NetHack 3.1.0/save.c: Robot: moved page)
(diff) ← Older revision | Latest revision (diff) | Newer revision → (diff)
Jump to navigation Jump to search

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

The NetHack General Public License applies to screenshots, source code and other content from NetHack.

This content was modified from the original NetHack source code distribution (by splitting up NetHack content between wiki pages, and possibly further editing). See the page history for a list of who changed it, and on what dates.

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 <signal.h>
10.   #endif /* !NO_SIGNAL */
11.   #if defined(EXPLORE_MODE) && !defined(LSC) && !defined(O_WRONLY) && !defined(AZTEC_C)
12.   #include <fcntl.h>
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*/