home *** CD-ROM | disk | FTP | other *** search
/ Celestin Apprentice 2 / Apprentice-Release2.iso / Source Code / C / Games / NetHack 3.1.3 / source / src / save.c < prev    next >
Encoding:
C/C++ Source or Header  |  1993-08-01  |  20.0 KB  |  891 lines  |  [TEXT/R*ch]

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