1 /* NetHack 3.6 save.c $NHDT-Date: 1448241784 2015/11/23 01:23:04 $ $NHDT-Branch: master $:$NHDT-Revision: 1.95 $ */
2 /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
3 /* NetHack may be freely redistributed. See license for details. */
5 /* JNetHack Copyright */
6 /* (c) Issei Numata, Naoki Hamada, Shigehiro Miyashita, 1994-2000 */
7 /* For 3.4-, Copyright (c) SHIRAKATA Kentaro, 2002-2016 */
8 /* JNetHack may be freely redistributed. See license for details. */
16 #if !defined(LSC) && !defined(O_WRONLY) && !defined(AZTEC_C)
22 static int count_only;
26 int dotcnt, dotrow; /* also used in restore */
29 STATIC_DCL void FDECL(savelevchn, (int, int));
30 STATIC_DCL void FDECL(savedamage, (int, int));
31 STATIC_DCL void FDECL(saveobj, (int, struct obj *));
32 STATIC_DCL void FDECL(saveobjchn, (int, struct obj *, int));
33 STATIC_DCL void FDECL(savemon, (int, struct monst *));
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 STATIC_OVL void FDECL(save_msghistory, (int, int));
39 STATIC_DCL void FDECL(savelev0, (int, XCHAR_P, int));
40 STATIC_DCL boolean NDECL(swapout_oldest);
41 STATIC_DCL void FDECL(copyfile, (char *, char *));
43 STATIC_DCL void FDECL(savelevl, (int fd, BOOLEAN_P));
44 STATIC_DCL void FDECL(def_bufon, (int));
45 STATIC_DCL void FDECL(def_bufoff, (int));
46 STATIC_DCL void FDECL(def_bflush, (int));
47 STATIC_DCL void FDECL(def_bwrite, (int, genericptr_t, unsigned int));
49 STATIC_DCL void FDECL(zerocomp_bufon, (int));
50 STATIC_DCL void FDECL(zerocomp_bufoff, (int));
51 STATIC_DCL void FDECL(zerocomp_bflush, (int));
52 STATIC_DCL void FDECL(zerocomp_bwrite, (int, genericptr_t, unsigned int));
53 STATIC_DCL void FDECL(zerocomp_bputc, (int));
56 static struct save_procs {
58 void FDECL((*save_bufon), (int));
59 void FDECL((*save_bufoff), (int));
60 void FDECL((*save_bflush), (int));
61 void FDECL((*save_bwrite), (int, genericptr_t, unsigned int));
62 void FDECL((*save_bclose), (int));
64 #if !defined(ZEROCOMP) || (defined(COMPRESS) || defined(ZLIB_COMP))
65 "externalcomp", def_bufon, def_bufoff, def_bflush, def_bwrite, def_bclose,
67 "zerocomp", zerocomp_bufon, zerocomp_bufoff,
68 zerocomp_bflush, zerocomp_bwrite, zerocomp_bclose,
72 static long nulls[sizeof(struct trap) + sizeof(struct fruit)];
74 #if defined(UNIX) || defined(VMS) || defined(__EMX__) || defined(WIN32)
75 #define HUP if (!program_state.done_hup)
80 /* need to preserve these during save to avoid accessing freed memory */
81 static unsigned ustuck_id = 0, usteed_id = 0;
86 clear_nhwindow(WIN_MESSAGE);
88 if (yn("Really save?") == 'n') {
90 if(yn("
\96{
\93\96\82É
\95Û
\91¶
\82·
\82é
\81H") == 'n') {
91 clear_nhwindow(WIN_MESSAGE);
95 clear_nhwindow(WIN_MESSAGE);
99 pline("
\95Û
\91¶
\92\86\81D
\81D
\81D");
100 #if defined(UNIX) || defined(VMS) || defined(__EMX__)
101 program_state.done_hup = 0;
104 u.uhp = -1; /* universal game's over indicator */
105 /* make sure they see the Saving message */
106 display_nhwindow(WIN_MESSAGE, TRUE);
108 exit_nhwindows("Be seeing you...");
110 exit_nhwindows("
\82Ü
\82½
\89ï
\82¢
\82Ü
\82µ
\82å
\82¤
\81D
\81D
\81D");
111 terminate(EXIT_SUCCESS);
118 /* returns 1 if save successful */
123 register int fd, ofd;
128 /* we may get here via hangup signal, in which case we want to fix up
129 a few of things before saving so that they won't be restored in
130 an improper state; these will be no-ops for normal save sequence */
132 if (iflags.save_uinwater)
133 u.uinwater = 1, iflags.save_uinwater = 0;
134 if (iflags.save_uburied)
135 u.uburied = 1, iflags.save_uburied = 0;
137 if (!program_state.something_worth_saving || !SAVEF[0])
139 fq_save = fqname(SAVEF, SAVEPREFIX, 1); /* level files take 0 */
141 #if defined(UNIX) || defined(VMS)
142 sethanguphandler((void FDECL((*), (int) )) SIG_IGN);
145 (void) signal(SIGINT, SIG_IGN);
148 #if defined(MICRO) && defined(MFLOPPY)
149 if (!saveDiskPrompt(0))
153 HUP if (iflags.window_inited)
155 nh_uncompress(fq_save);
156 fd = open_savefile();
159 clear_nhwindow(WIN_MESSAGE);
161 There("seems to be an old save file.");
163 pline("
\91O
\82É
\83Z
\81[
\83u
\82µ
\82½
\83t
\83@
\83C
\83\8b\82ª
\82 \82è
\82Ü
\82·
\81D");
165 if (yn("Overwrite the old file?") == 'n') {
167 if (yn("
\8cÃ
\82¢
\83t
\83@
\83C
\83\8b\82É
\8fã
\8f\91\82«
\82µ
\82Ü
\82·
\82©
\81H") == 'n') {
168 nh_compress(fq_save);
174 HUP mark_synch(); /* flush any buffered screen output */
176 fd = create_savefile();
178 HUP pline("Cannot open save file.");
179 (void) delete_savefile(); /* ab@unido */
183 vision_recalc(2); /* shut down vision to prevent problems
184 in the event of an impossible() call */
186 /* undo date-dependent luck adjustments made at startup time */
187 if (flags.moonphase == FULL_MOON) /* ut-sally!fletcher */
188 change_luck(-1); /* and unido!ab */
191 if (iflags.window_inited)
192 HUP clear_nhwindow(WIN_MESSAGE);
198 if (strncmpi("X11", windowprocs.name, 3))
199 putstr(WIN_MAP, 0, "Saving:");
202 /* make sure there is enough disk space */
203 if (iflags.checkspace) {
206 savelev(fd, ledger_no(&u.uz), COUNT_SAVE);
207 savegamestate(fd, COUNT_SAVE);
208 needed = bytes_counted;
210 for (ltmp = 1; ltmp <= maxledgerno(); ltmp++)
211 if (ltmp != ledger_no(&u.uz) && level_info[ltmp].where)
212 needed += level_info[ltmp].size + (sizeof ltmp);
213 fds = freediskspace(fq_save);
217 There("is insufficient space on SAVE disk.");
218 pline("Require %ld bytes but only have %ld.", needed, fds);
222 (void) delete_savefile();
231 store_savefileinfo(fd);
232 store_plname_in_file(fd);
233 ustuck_id = (u.ustuck ? u.ustuck->m_id : 0);
234 usteed_id = (u.usteed ? u.usteed->m_id : 0);
235 savelev(fd, ledger_no(&u.uz), WRITE_SAVE | FREE_SAVE);
236 savegamestate(fd, WRITE_SAVE | FREE_SAVE);
238 /* While copying level files around, zero out u.uz to keep
239 * parts of the restore code from completely initializing all
240 * in-core data structures, since all we're doing is copying.
241 * This also avoids at least one nasty core dump.
244 u.uz.dnum = u.uz.dlevel = 0;
245 /* these pointers are no longer valid, and at least u.usteed
246 * may mislead place_monster() on other levels
248 u.ustuck = (struct monst *) 0;
249 u.usteed = (struct monst *) 0;
251 for (ltmp = (xchar) 1; ltmp <= maxledgerno(); ltmp++) {
252 if (ltmp == ledger_no(&uz_save))
254 if (!(level_info[ltmp].flags & LFILE_EXISTS))
257 curs(WIN_MAP, 1 + dotcnt++, dotrow);
258 if (dotcnt >= (COLNO - 1)) {
262 if (strncmpi("X11", windowprocs.name, 3)) {
263 putstr(WIN_MAP, 0, ".");
267 ofd = open_levelfile(ltmp, whynot);
271 (void) delete_savefile();
272 HUP Strcpy(killer.name, whynot);
276 minit(); /* ZEROCOMP */
277 getlev(ofd, hackpid, ltmp, FALSE);
279 bwrite(fd, (genericptr_t) <mp, sizeof ltmp); /* level number*/
280 savelev(fd, ltmp, WRITE_SAVE | FREE_SAVE); /* actual level*/
281 delete_levelfile(ltmp);
287 /* get rid of current level --jgm */
288 delete_levelfile(ledger_no(&u.uz));
290 nh_compress(fq_save);
291 /* this should probably come sooner... */
292 program_state.something_worth_saving = 0;
297 savegamestate(fd, mode)
298 register int fd, mode;
303 count_only = (mode & COUNT_SAVE);
305 uid = (unsigned long) getuid();
306 bwrite(fd, (genericptr_t) &uid, sizeof uid);
307 bwrite(fd, (genericptr_t) &context, sizeof(struct context_info));
308 bwrite(fd, (genericptr_t) &flags, sizeof(struct flag));
310 bwrite(fd, (genericptr_t) &sysflags, sizeof(struct sysflag));
312 urealtime.finish_time = getnow();
313 urealtime.realtime += (long) (urealtime.finish_time
314 - urealtime.start_timing);
315 bwrite(fd, (genericptr_t) &u, sizeof(struct you));
316 bwrite(fd, yyyymmddhhmmss(ubirthday), 14);
317 bwrite(fd, (genericptr_t) &urealtime.realtime, sizeof urealtime.realtime);
318 bwrite(fd, yyyymmddhhmmss(urealtime.start_timing), 14); /** Why? **/
319 /* this is the value to use for the next update of urealtime.realtime */
320 urealtime.start_timing = urealtime.finish_time;
321 save_killers(fd, mode);
323 /* must come before migrating_objs and migrating_mons are freed */
324 save_timers(fd, mode, RANGE_GLOBAL);
325 save_light_sources(fd, mode, RANGE_GLOBAL);
327 saveobjchn(fd, invent, mode);
329 /* prevent loss of ball & chain when swallowed */
330 uball->nobj = uchain;
331 uchain->nobj = (struct obj *) 0;
332 saveobjchn(fd, uball, mode);
334 saveobjchn(fd, (struct obj *) 0, mode);
337 saveobjchn(fd, migrating_objs, mode);
338 savemonchn(fd, migrating_mons, mode);
339 if (release_data(mode)) {
344 bwrite(fd, (genericptr_t) mvitals, sizeof(mvitals));
346 save_dungeon(fd, (boolean) !!perform_bwrite(mode),
347 (boolean) !!release_data(mode));
348 savelevchn(fd, mode);
349 bwrite(fd, (genericptr_t) &moves, sizeof moves);
350 bwrite(fd, (genericptr_t) &monstermoves, sizeof monstermoves);
351 bwrite(fd, (genericptr_t) &quest_status, sizeof(struct q_score));
352 bwrite(fd, (genericptr_t) spl_book,
353 sizeof(struct spell) * (MAXSPELL + 1));
355 save_oracles(fd, mode);
357 bwrite(fd, (genericptr_t) &ustuck_id, sizeof ustuck_id);
359 bwrite(fd, (genericptr_t) &usteed_id, sizeof usteed_id);
360 bwrite(fd, (genericptr_t) pl_character, sizeof pl_character);
361 bwrite(fd, (genericptr_t) pl_fruit, sizeof pl_fruit);
362 savefruitchn(fd, mode);
364 save_waterlevel(fd, mode);
365 save_msghistory(fd, mode);
370 tricked_fileremoved(fd, whynot)
376 pline("Probably someone removed it.");
377 Strcpy(killer.name, whynot);
389 static boolean havestate = TRUE;
392 /* When checkpointing is on, the full state needs to be written
393 * on each checkpoint. When checkpointing is off, only the pid
394 * needs to be in the level.0 file, so it does not need to be
395 * constantly rewritten. When checkpointing is turned off during
396 * a game, however, the file has to be rewritten once to truncate
397 * it and avoid restoring from outdated information.
399 * Restricting havestate to this routine means that an additional
400 * noop pid rewriting will take place on the first "checkpoint" after
401 * the game is started or restored, if checkpointing is off.
403 if (flags.ins_chkpt || havestate) {
404 /* save the rest of the current game state in the lock file,
405 * following the original int pid, the current level number,
406 * and the current savefile name, which should not be subject
407 * to any internal compression schemes since they must be
408 * readable by an external utility
410 fd = open_levelfile(0, whynot);
411 if (tricked_fileremoved(fd, whynot))
414 (void) read(fd, (genericptr_t) &hpid, sizeof(hpid));
415 if (hackpid != hpid) {
416 Sprintf(whynot, "Level #0 pid (%d) doesn't match ours (%d)!",
419 Strcpy(killer.name, whynot);
424 fd = create_levelfile(0, whynot);
427 Strcpy(killer.name, whynot);
431 (void) write(fd, (genericptr_t) &hackpid, sizeof(hackpid));
432 if (flags.ins_chkpt) {
433 int currlev = ledger_no(&u.uz);
435 (void) write(fd, (genericptr_t) &currlev, sizeof(currlev));
436 save_savefile_name(fd);
438 store_savefileinfo(fd);
439 store_plname_in_file(fd);
441 ustuck_id = (u.ustuck ? u.ustuck->m_id : 0);
442 usteed_id = (u.usteed ? u.usteed->m_id : 0);
443 savegamestate(fd, WRITE_SAVE);
447 havestate = flags.ins_chkpt;
453 savelev(fd, lev, mode)
458 if (mode & COUNT_SAVE) {
460 savelev0(fd, lev, COUNT_SAVE);
461 /* probably bytes_counted will be filled in again by an
462 * immediately following WRITE_SAVE anyway, but we'll
463 * leave it out of checkspace just in case */
464 if (iflags.checkspace) {
465 while (bytes_counted > freediskspace(levels))
466 if (!swapout_oldest())
470 if (mode & (WRITE_SAVE | FREE_SAVE)) {
472 savelev0(fd, lev, mode);
474 if (mode != FREE_SAVE) {
475 level_info[lev].where = ACTIVE;
476 level_info[lev].time = moves;
477 level_info[lev].size = bytes_counted;
483 savelev0(fd, lev, mode)
486 savelev(fd, lev, mode)
496 /* if we're tearing down the current level without saving anything
497 (which happens upon entrance to the endgame or after an aborted
498 restore attempt) then we don't want to do any actual I/O */
499 if (mode == FREE_SAVE)
502 /* purge any dead monsters (necessary if we're starting
503 a panic save rather than a normal one, or sometimes
504 when changing levels without taking time -- e.g.
505 create statue trap then immediately level teleport) */
506 if (iflags.purge_monsters)
510 panic("Save on bad file!"); /* impossible */
512 count_only = (mode & COUNT_SAVE);
514 if (lev >= 0 && lev <= maxledgerno())
515 level_info[lev].flags |= VISITED;
516 bwrite(fd, (genericptr_t) &hackpid, sizeof(hackpid));
520 bwrite(fd, (genericptr_t) &tlev, sizeof(tlev));
522 bwrite(fd, (genericptr_t) &lev, sizeof(lev));
524 savecemetery(fd, mode, &level.bonesinfo);
526 (boolean) ((sfsaveinfo.sfi1 & SFI1_RLECOMP) == SFI1_RLECOMP));
527 bwrite(fd, (genericptr_t) lastseentyp, sizeof(lastseentyp));
528 bwrite(fd, (genericptr_t) &monstermoves, sizeof(monstermoves));
529 bwrite(fd, (genericptr_t) &upstair, sizeof(stairway));
530 bwrite(fd, (genericptr_t) &dnstair, sizeof(stairway));
531 bwrite(fd, (genericptr_t) &upladder, sizeof(stairway));
532 bwrite(fd, (genericptr_t) &dnladder, sizeof(stairway));
533 bwrite(fd, (genericptr_t) &sstairs, sizeof(stairway));
534 bwrite(fd, (genericptr_t) &updest, sizeof(dest_area));
535 bwrite(fd, (genericptr_t) &dndest, sizeof(dest_area));
536 bwrite(fd, (genericptr_t) &level.flags, sizeof(level.flags));
537 bwrite(fd, (genericptr_t) doors, sizeof(doors));
538 save_rooms(fd); /* no dynamic memory to reclaim */
540 /* from here on out, saving also involves allocated memory cleanup */
542 /* this comes before the map, so need cleanup here if we skipped */
543 if (mode == FREE_SAVE)
544 savecemetery(fd, mode, &level.bonesinfo);
545 /* must be saved before mons, objs, and buried objs */
546 save_timers(fd, mode, RANGE_LEVEL);
547 save_light_sources(fd, mode, RANGE_LEVEL);
549 savemonchn(fd, fmon, mode);
550 save_worm(fd, mode); /* save worm information */
551 savetrapchn(fd, ftrap, mode);
552 saveobjchn(fd, fobj, mode);
553 saveobjchn(fd, level.buriedobjlist, mode);
554 saveobjchn(fd, billobjs, mode);
555 if (release_data(mode)) {
559 level.buriedobjlist = 0;
561 /* level.bonesinfo = 0; -- handled by savecemetery() */
563 save_engravings(fd, mode);
564 savedamage(fd, mode);
565 save_regions(fd, mode);
566 if (mode != FREE_SAVE)
571 savelevl(fd, rlecomp)
576 struct rm *prm, *rgrm;
581 /* perform run-length encoding of rm structs */
583 rgrm = &levl[0][0]; /* start matching at first rm */
586 for (y = 0; y < ROWNO; y++) {
587 for (x = 0; x < COLNO; x++) {
589 if (prm->glyph == rgrm->glyph && prm->typ == rgrm->typ
590 && prm->seenv == rgrm->seenv
591 && prm->horizontal == rgrm->horizontal
592 && prm->flags == rgrm->flags && prm->lit == rgrm->lit
593 && prm->waslit == rgrm->waslit
594 && prm->roomno == rgrm->roomno && prm->edge == rgrm->edge
595 && prm->candig == rgrm->candig) {
598 match = 254; /* undo this match */
602 /* the run has been broken,
603 * write out run-length encoding */
605 bwrite(fd, (genericptr_t) &match, sizeof(uchar));
606 bwrite(fd, (genericptr_t) rgrm, sizeof(struct rm));
607 /* start encoding again. we have at least 1 rm
608 * in the next run, viz. this one. */
615 bwrite(fd, (genericptr_t) &match, sizeof(uchar));
616 bwrite(fd, (genericptr_t) rgrm, sizeof(struct rm));
622 #endif /* ?RLECOMP */
623 bwrite(fd, (genericptr_t) levl, sizeof levl);
631 (*saveprocs.save_bufon)(fd);
640 (*saveprocs.save_bufoff)(fd);
644 /* flush run and buffer */
649 (*saveprocs.save_bflush)(fd);
657 register unsigned num;
659 (*saveprocs.save_bwrite)(fd, loc, num);
667 (*saveprocs.save_bclose)(fd);
671 static int bw_fd = -1;
672 static FILE *bw_FILE = 0;
673 static boolean buffering = FALSE;
682 panic("double buffering unexpected");
684 if ((bw_FILE = fdopen(fd, "w")) == 0)
685 panic("buffering of file %d failed", fd);
705 if (fflush(bw_FILE) == EOF)
706 panic("flush of savefile failed!");
713 def_bwrite(fd, loc, num)
715 register genericptr_t loc;
716 register unsigned num;
721 bytes_counted += num;
729 panic("unbuffered write to fd %d (!= %d)", fd, bw_fd);
731 failed = (fwrite(loc, (int) num, 1, bw_FILE) != 1);
735 /* lint wants 3rd arg of write to be an int; lint -p an unsigned */
736 #if defined(BSD) || defined(ULTRIX) || defined(WIN32) || defined(_MSC_VER)
737 failed = ((long) write(fd, loc, (int) num) != (long) num);
738 #else /* e.g. SYSV, __TURBOC__ */
739 failed = ((long) write(fd, loc, num) != (long) num);
744 #if defined(UNIX) || defined(VMS) || defined(__EMX__)
745 if (program_state.done_hup)
746 terminate(EXIT_FAILURE);
749 panic("cannot write %u bytes to file #%d", num, fd);
760 (void) fclose(bw_FILE);
770 /* The runs of zero-run compression are flushed after the game state or a
771 * level is written out. This adds a couple bytes to a save file, where
772 * the runs could be mashed together, but it allows gluing together game
773 * state and level files to form a save file, and it means the flushing
774 * does not need to be specifically called for every other time a level
775 * file is written out.
778 #define RLESC '\0' /* Leading character for run of LRESC's */
779 #define flushoutrun(ln) (zerocomp_bputc(RLESC), zerocomp_bputc(ln), ln = -1)
781 #ifndef ZEROCOMP_BUFSIZ
782 #define ZEROCOMP_BUFSIZ BUFSZ
784 static NEARDATA unsigned char outbuf[ZEROCOMP_BUFSIZ];
785 static NEARDATA unsigned short outbufp = 0;
786 static NEARDATA short outrunlength = -1;
787 static NEARDATA int bwritefd;
788 static NEARDATA boolean compressing = FALSE;
792 HUP printf("outbufp %d outrunlength %d\n", outbufp,outrunlength);
804 if (outbufp >= sizeof outbuf) {
805 (void) write(bwritefd, outbuf, sizeof outbuf);
808 outbuf[outbufp++] = (unsigned char) c;
827 panic("closing file with buffered data still unwritten");
834 /* flush run and buffer */
840 if (outrunlength >= 0) { /* flush run */
841 flushoutrun(outrunlength);
849 if (write(fd, outbuf, outbufp) != outbufp) {
850 #if defined(UNIX) || defined(VMS) || defined(__EMX__)
851 if (program_state.done_hup)
852 terminate(EXIT_FAILURE);
855 zerocomp_bclose(fd); /* panic (outbufp != 0) */
862 zerocomp_bwrite(fd, loc, num)
865 register unsigned num;
867 register unsigned char *bp = (unsigned char *) loc;
871 bytes_counted += num;
875 if ((unsigned) write(fd, loc, num) != num) {
876 #if defined(UNIX) || defined(VMS) || defined(__EMX__)
877 if (program_state.done_hup)
878 terminate(EXIT_FAILURE);
881 panic("cannot write %u bytes to file #%d", num, fd);
885 for (; num; num--, bp++) {
886 if (*bp == RLESC) { /* One more char in run */
887 if (++outrunlength == 0xFF) {
888 flushoutrun(outrunlength);
890 } else { /* end of run */
891 if (outrunlength >= 0) { /* flush run */
892 flushoutrun(outrunlength);
908 #endif /* ZEROCOMP */
912 register int fd, mode;
914 s_level *tmplev, *tmplev2;
917 for (tmplev = sp_levchn; tmplev; tmplev = tmplev->next)
919 if (perform_bwrite(mode))
920 bwrite(fd, (genericptr_t) &cnt, sizeof(int));
922 for (tmplev = sp_levchn; tmplev; tmplev = tmplev2) {
923 tmplev2 = tmplev->next;
924 if (perform_bwrite(mode))
925 bwrite(fd, (genericptr_t) tmplev, sizeof(s_level));
926 if (release_data(mode))
927 free((genericptr_t) tmplev);
929 if (release_data(mode))
933 /* used when saving a level and also when saving dungeon overview data */
935 savecemetery(fd, mode, cemeteryaddr)
938 struct cemetery **cemeteryaddr;
940 struct cemetery *thisbones, *nextbones;
943 flag = *cemeteryaddr ? 0 : -1;
944 if (perform_bwrite(mode))
945 bwrite(fd, (genericptr_t) &flag, sizeof flag);
946 nextbones = *cemeteryaddr;
947 while ((thisbones = nextbones) != 0) {
948 nextbones = thisbones->next;
949 if (perform_bwrite(mode))
950 bwrite(fd, (genericptr_t) thisbones, sizeof *thisbones);
951 if (release_data(mode))
952 free((genericptr_t) thisbones);
954 if (release_data(mode))
960 register int fd, mode;
962 register struct damage *damageptr, *tmp_dam;
965 damageptr = level.damagelist;
966 for (tmp_dam = damageptr; tmp_dam; tmp_dam = tmp_dam->next)
968 if (perform_bwrite(mode))
969 bwrite(fd, (genericptr_t) &xl, sizeof(xl));
972 if (perform_bwrite(mode))
973 bwrite(fd, (genericptr_t) damageptr, sizeof(*damageptr));
975 damageptr = damageptr->next;
976 if (release_data(mode))
977 free((genericptr_t) tmp_dam);
979 if (release_data(mode))
980 level.damagelist = 0;
988 int buflen, zerobuf = 0;
990 buflen = sizeof(struct obj);
991 bwrite(fd, (genericptr_t) &buflen, sizeof(int));
992 bwrite(fd, (genericptr_t) otmp, buflen);
995 buflen = strlen(ONAME(otmp)) + 1;
998 bwrite(fd, (genericptr_t) &buflen, sizeof buflen);
1000 bwrite(fd, (genericptr_t) ONAME(otmp), buflen);
1002 /* defer to savemon() for this one */
1004 savemon(fd, OMONST(otmp));
1006 bwrite(fd, (genericptr_t) &zerobuf, sizeof zerobuf);
1009 buflen = sizeof(unsigned);
1012 bwrite(fd, (genericptr_t) &buflen, sizeof buflen);
1014 bwrite(fd, (genericptr_t) OMID(otmp), buflen);
1017 buflen = sizeof(long);
1020 bwrite(fd, (genericptr_t) &buflen, sizeof buflen);
1022 bwrite(fd, (genericptr_t) OLONG(otmp), buflen);
1025 buflen = strlen(OMAILCMD(otmp)) + 1;
1028 bwrite(fd, (genericptr_t) &buflen, sizeof buflen);
1030 bwrite(fd, (genericptr_t) OMAILCMD(otmp), buflen);
1035 saveobjchn(fd, otmp, mode)
1036 register int fd, mode;
1037 register struct obj *otmp;
1039 register struct obj *otmp2;
1044 if (perform_bwrite(mode)) {
1047 if (Has_contents(otmp))
1048 saveobjchn(fd, otmp->cobj, mode);
1049 if (release_data(mode)) {
1050 /* if (otmp->oclass == FOOD_CLASS)
1051 * food_disappears(otmp);
1054 * If these are on the floor, the discarding could
1055 * be because of a game save, or we could just be changing levels.
1056 * Always invalidate the pointer, but ensure that we have
1057 * the o_id in order to restore the pointer on reload.
1059 if (otmp == context.victual.piece) {
1060 /* Store the o_id of the victual if mismatched */
1061 if (context.victual.o_id != otmp->o_id)
1062 context.victual.o_id = otmp->o_id;
1063 /* invalidate the pointer; on reload it will get restored */
1064 context.victual.piece = (struct obj *) 0;
1066 if (otmp == context.tin.tin) {
1067 /* Store the o_id of your tin */
1068 if (context.tin.o_id != otmp->o_id)
1069 context.tin.o_id = otmp->o_id;
1070 /* invalidate the pointer; on reload it will get restored */
1071 context.tin.tin = (struct obj *) 0;
1073 /* if (otmp->oclass == SPBOOK_CLASS)
1074 * book_disappears(otmp);
1076 if (otmp == context.spbook.book) {
1077 /* Store the o_id of your spellbook */
1078 if (context.spbook.o_id != otmp->o_id)
1079 context.spbook.o_id = otmp->o_id;
1080 /* invalidate the pointer; on reload it will get restored */
1081 context.spbook.book = (struct obj *) 0;
1083 otmp->where = OBJ_FREE; /* set to free so dealloc will work */
1084 otmp->nobj = NULL; /* nobj saved into otmp2 */
1085 otmp->cobj = NULL; /* contents handled above */
1086 otmp->timed = 0; /* not timed any more */
1087 otmp->lamplit = 0; /* caller handled lights */
1092 if (perform_bwrite(mode))
1093 bwrite(fd, (genericptr_t) &minusone, sizeof(int));
1103 buflen = sizeof(struct monst);
1104 bwrite(fd, (genericptr_t) &buflen, sizeof(int));
1105 bwrite(fd, (genericptr_t) mtmp, buflen);
1108 buflen = strlen(MNAME(mtmp)) + 1;
1111 bwrite(fd, (genericptr_t) &buflen, sizeof buflen);
1113 bwrite(fd, (genericptr_t) MNAME(mtmp), buflen);
1116 buflen = sizeof(struct egd);
1119 bwrite(fd, (genericptr_t) &buflen, sizeof(int));
1121 bwrite(fd, (genericptr_t) EGD(mtmp), buflen);
1124 buflen = sizeof(struct epri);
1127 bwrite(fd, (genericptr_t) &buflen, sizeof(int));
1129 bwrite(fd, (genericptr_t) EPRI(mtmp), buflen);
1132 buflen = sizeof(struct eshk);
1135 bwrite(fd, (genericptr_t) &buflen, sizeof(int));
1137 bwrite(fd, (genericptr_t) ESHK(mtmp), buflen);
1140 buflen = sizeof(struct emin);
1143 bwrite(fd, (genericptr_t) &buflen, sizeof(int));
1145 bwrite(fd, (genericptr_t) EMIN(mtmp), buflen);
1148 buflen = sizeof(struct edog);
1151 bwrite(fd, (genericptr_t) &buflen, sizeof(int));
1153 bwrite(fd, (genericptr_t) EDOG(mtmp), buflen);
1155 /* mcorpsenm is inline int rather than pointer to something,
1156 so doesn't need to be preceded by a length field */
1157 bwrite(fd, (genericptr_t) &MCORPSENM(mtmp), sizeof MCORPSENM(mtmp));
1162 savemonchn(fd, mtmp, mode)
1163 register int fd, mode;
1164 register struct monst *mtmp;
1166 register struct monst *mtmp2;
1171 if (perform_bwrite(mode)) {
1172 mtmp->mnum = monsndx(mtmp->data);
1174 forget_temple_entry(mtmp); /* EPRI() */
1178 saveobjchn(fd, mtmp->minvent, mode);
1179 if (release_data(mode)) {
1180 if (mtmp == context.polearm.hitmon) {
1181 context.polearm.m_id = mtmp->m_id;
1182 context.polearm.hitmon = NULL;
1184 mtmp->nmon = NULL; /* nmon saved into mtmp2 */
1185 dealloc_monst(mtmp);
1189 if (perform_bwrite(mode))
1190 bwrite(fd, (genericptr_t) &minusone, sizeof(int));
1194 savetrapchn(fd, trap, mode)
1195 register int fd, mode;
1196 register struct trap *trap;
1198 register struct trap *trap2;
1201 trap2 = trap->ntrap;
1202 if (perform_bwrite(mode))
1203 bwrite(fd, (genericptr_t) trap, sizeof(struct trap));
1204 if (release_data(mode))
1208 if (perform_bwrite(mode))
1209 bwrite(fd, (genericptr_t) nulls, sizeof(struct trap));
1212 /* save all the fruit names and ID's; this is used only in saving whole games
1213 * (not levels) and in saving bones levels. When saving a bones level,
1214 * we only want to save the fruits which exist on the bones level; the bones
1215 * level routine marks nonexistent fruits by making the fid negative.
1218 savefruitchn(fd, mode)
1219 register int fd, mode;
1221 register struct fruit *f2, *f1;
1226 if (f1->fid >= 0 && perform_bwrite(mode))
1227 bwrite(fd, (genericptr_t) f1, sizeof(struct fruit));
1228 if (release_data(mode))
1232 if (perform_bwrite(mode))
1233 bwrite(fd, (genericptr_t) nulls, sizeof(struct fruit));
1234 if (release_data(mode))
1239 store_plname_in_file(fd)
1242 int plsiztmp = PL_NSIZ;
1244 /* bwrite() before bufon() uses plain write() */
1245 bwrite(fd, (genericptr_t) &plsiztmp, sizeof(plsiztmp));
1246 bwrite(fd, (genericptr_t) plname, plsiztmp);
1252 save_msghistory(fd, mode)
1256 int msgcount = 0, msglen;
1258 boolean init = TRUE;
1260 if (perform_bwrite(mode)) {
1261 /* ask window port for each message in sequence */
1262 while ((msg = getmsghistory(init)) != 0) {
1264 msglen = strlen(msg);
1265 /* sanity: truncate if necessary (shouldn't happen);
1266 no need to modify msg[] since terminator isn't written */
1267 if (msglen > BUFSZ - 1)
1269 bwrite(fd, (genericptr_t) &msglen, sizeof(msglen));
1270 bwrite(fd, (genericptr_t) msg, msglen);
1273 bwrite(fd, (genericptr_t) &minusone, sizeof(int));
1275 debugpline1("Stored %d messages into savefile.", msgcount);
1276 /* note: we don't attempt to handle release_data() here */
1280 store_savefileinfo(fd)
1283 /* sfcap (decl.c) describes the savefile feature capabilities
1284 * that are supported by this port/platform build.
1286 * sfsaveinfo (decl.c) describes the savefile info that actually
1287 * gets written into the savefile, and is used to determine the
1288 * save file being written.
1290 * sfrestinfo (decl.c) describes the savefile info that is
1291 * being used to read the information from an existing savefile.
1296 /* bwrite() before bufon() uses plain write() */
1297 bwrite(fd, (genericptr_t) &sfsaveinfo, (unsigned) (sizeof sfsaveinfo));
1303 set_savepref(suitename)
1304 const char *suitename;
1306 if (!strcmpi(suitename, "externalcomp")) {
1307 saveprocs.name = "externalcomp";
1308 saveprocs.save_bufon = def_bufon;
1309 saveprocs.save_bufoff = def_bufoff;
1310 saveprocs.save_bflush = def_bflush;
1311 saveprocs.save_bwrite = def_bwrite;
1312 saveprocs.save_bclose = def_bclose;
1313 sfsaveinfo.sfi1 |= SFI1_EXTERNALCOMP;
1314 sfsaveinfo.sfi1 &= ~SFI1_ZEROCOMP;
1316 if (!strcmpi(suitename, "!rlecomp")) {
1317 sfsaveinfo.sfi1 &= ~SFI1_RLECOMP;
1320 if (!strcmpi(suitename, "zerocomp")) {
1321 saveprocs.name = "zerocomp";
1322 saveprocs.save_bufon = zerocomp_bufon;
1323 saveprocs.save_bufoff = zerocomp_bufoff;
1324 saveprocs.save_bflush = zerocomp_bflush;
1325 saveprocs.save_bwrite = zerocomp_bwrite;
1326 saveprocs.save_bclose = zerocomp_bclose;
1327 sfsaveinfo.sfi1 |= SFI1_ZEROCOMP;
1328 sfsaveinfo.sfi1 &= ~SFI1_EXTERNALCOMP;
1332 if (!strcmpi(suitename, "rlecomp")) {
1333 sfsaveinfo.sfi1 |= SFI1_RLECOMP;
1338 /* also called by prscore(); this probably belongs in dungeon.c... */
1342 #ifdef FREE_ALL_MEMORY
1343 savelevchn(0, FREE_SAVE);
1344 save_dungeon(0, FALSE, TRUE);
1353 free_menu_coloring();
1354 free_invbuf(); /* let_to_name (invent.c) */
1355 free_youbuf(); /* You_buf,&c (pline.c) */
1357 tmp_at(DISP_FREEMEM, 0); /* temporary display effects */
1358 #ifdef FREE_ALL_MEMORY
1359 #define freeobjchn(X) (saveobjchn(0, X, FREE_SAVE), X = 0)
1360 #define freemonchn(X) (savemonchn(0, X, FREE_SAVE), X = 0)
1361 #define freetrapchn(X) (savetrapchn(0, X, FREE_SAVE), X = 0)
1362 #define freefruitchn() savefruitchn(0, FREE_SAVE)
1363 #define freenames() savenames(0, FREE_SAVE)
1364 #define free_killers() save_killers(0, FREE_SAVE)
1365 #define free_oracles() save_oracles(0, FREE_SAVE)
1366 #define free_waterlevel() save_waterlevel(0, FREE_SAVE)
1367 #define free_worm() save_worm(0, FREE_SAVE)
1368 #define free_timers(R) save_timers(0, FREE_SAVE, R)
1369 #define free_light_sources(R) save_light_sources(0, FREE_SAVE, R);
1370 #define free_engravings() save_engravings(0, FREE_SAVE)
1371 #define freedamage() savedamage(0, FREE_SAVE)
1372 #define free_animals() mon_animal_list(FALSE)
1374 /* move-specific data */
1375 dmonsfree(); /* release dead monsters */
1377 /* level-specific data */
1378 free_timers(RANGE_LEVEL);
1379 free_light_sources(RANGE_LEVEL);
1382 free_worm(); /* release worm segment information */
1385 freeobjchn(level.buriedobjlist);
1386 freeobjchn(billobjs);
1390 /* game-state data */
1392 free_timers(RANGE_GLOBAL);
1393 free_light_sources(RANGE_GLOBAL);
1395 freeobjchn(migrating_objs);
1396 freemonchn(migrating_mons);
1397 freemonchn(mydogs); /* ascension or dungeon escape */
1398 /* freelevchn(); -- [folded into free_dungeons()] */
1406 /* some pointers in iflags */
1407 if (iflags.wc_font_map)
1408 free(iflags.wc_font_map);
1409 if (iflags.wc_font_message)
1410 free(iflags.wc_font_message);
1411 if (iflags.wc_font_text)
1412 free(iflags.wc_font_text);
1413 if (iflags.wc_font_menu)
1414 free(iflags.wc_font_menu);
1415 if (iflags.wc_font_status)
1416 free(iflags.wc_font_status);
1417 if (iflags.wc_tile_file)
1418 free(iflags.wc_tile_file);
1419 free_autopickup_exceptions();
1422 /* free_pickinv_cache(); -- now done from really_done()... */
1424 #endif /* FREE_ALL_MEMORY */
1425 #ifdef STATUS_VIA_WINDOWPORT
1429 /* last, because it frees data that might be used by panic() to provide
1430 feedback to the user; conceivably other freeing might trigger panic */
1431 sysopt_release(); /* SYSCF strings */
1440 char to[PATHLEN], from[PATHLEN];
1442 Sprintf(from, "%s%s", permbones, alllevels);
1443 Sprintf(to, "%s%s", levels, alllevels);
1444 set_levelfile_name(from, lev);
1445 set_levelfile_name(to, lev);
1446 if (iflags.checkspace) {
1447 while (level_info[lev].size > freediskspace(to))
1448 if (!swapout_oldest())
1452 pline("Swapping in `%s'.", from);
1456 (void) unlink(from);
1457 level_info[lev].where = ACTIVE;
1464 char to[PATHLEN], from[PATHLEN];
1470 for (i = 1, oldtime = 0, oldest = 0; i <= maxledgerno(); i++)
1471 if (level_info[i].where == ACTIVE
1472 && (!oldtime || level_info[i].time < oldtime)) {
1474 oldtime = level_info[i].time;
1478 Sprintf(from, "%s%s", levels, alllevels);
1479 Sprintf(to, "%s%s", permbones, alllevels);
1480 set_levelfile_name(from, oldest);
1481 set_levelfile_name(to, oldest);
1483 pline("Swapping out `%s'.", from);
1487 (void) unlink(from);
1488 level_info[oldest].where = SWAPPED;
1497 if (_copyfile(from, to))
1498 panic("Can't copy %s to %s", from, to);
1500 char buf[BUFSIZ]; /* this is system interaction, therefore
1501 * BUFSIZ instead of NetHack's BUFSZ */
1502 int nfrom, nto, fdfrom, fdto;
1504 if ((fdfrom = open(from, O_RDONLY | O_BINARY, FCMASK)) < 0)
1505 panic("Can't copy from %s !?", from);
1506 if ((fdto = open(to, O_WRONLY | O_BINARY | O_CREAT | O_TRUNC, FCMASK)) < 0)
1507 panic("Can't copy to %s", to);
1509 nfrom = read(fdfrom, buf, BUFSIZ);
1510 nto = write(fdto, buf, nfrom);
1512 panic("Copyfile failed!");
1513 } while (nfrom == BUFSIZ);
1514 (void) nhclose(fdfrom);
1515 (void) nhclose(fdto);
1519 /* see comment in bones.c */
1527 #endif /* MFLOPPY */