1 /* NetHack 3.6 save.c $NHDT-Date: 1559994625 2019/06/08 11:50:25 $ $NHDT-Branch: NetHack-3.6 $:$NHDT-Revision: 1.121 $ */
2 /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
3 /*-Copyright (c) Michael Allison, 2009. */
4 /* NetHack may be freely redistributed. See license for details. */
6 /* JNetHack Copyright */
7 /* (c) Issei Numata, Naoki Hamada, Shigehiro Miyashita, 1994-2000 */
8 /* For 3.4-, Copyright (c) SHIRAKATA Kentaro, 2002-2020 */
9 /* JNetHack may be freely redistributed. See license for details. */
17 #if !defined(LSC) && !defined(O_WRONLY) && !defined(AZTEC_C)
23 static int count_only;
27 int dotcnt, dotrow; /* also used in restore */
30 STATIC_DCL void FDECL(savelevchn, (int, int));
31 STATIC_DCL void FDECL(savedamage, (int, int));
32 STATIC_DCL void FDECL(saveobj, (int, struct obj *));
33 STATIC_DCL void FDECL(saveobjchn, (int, struct obj *, int));
34 STATIC_DCL void FDECL(savemon, (int, struct monst *));
35 STATIC_DCL void FDECL(savemonchn, (int, struct monst *, int));
36 STATIC_DCL void FDECL(savetrapchn, (int, struct trap *, int));
37 STATIC_DCL void FDECL(savegamestate, (int, int));
38 STATIC_OVL void FDECL(save_msghistory, (int, int));
40 STATIC_DCL void FDECL(savelev0, (int, XCHAR_P, int));
41 STATIC_DCL boolean NDECL(swapout_oldest);
42 STATIC_DCL void FDECL(copyfile, (char *, char *));
44 STATIC_DCL void FDECL(savelevl, (int fd, BOOLEAN_P));
45 STATIC_DCL void FDECL(def_bufon, (int));
46 STATIC_DCL void FDECL(def_bufoff, (int));
47 STATIC_DCL void FDECL(def_bflush, (int));
48 STATIC_DCL void FDECL(def_bwrite, (int, genericptr_t, unsigned int));
50 STATIC_DCL void FDECL(zerocomp_bufon, (int));
51 STATIC_DCL void FDECL(zerocomp_bufoff, (int));
52 STATIC_DCL void FDECL(zerocomp_bflush, (int));
53 STATIC_DCL void FDECL(zerocomp_bwrite, (int, genericptr_t, unsigned int));
54 STATIC_DCL void FDECL(zerocomp_bputc, (int));
57 static struct save_procs {
59 void FDECL((*save_bufon), (int));
60 void FDECL((*save_bufoff), (int));
61 void FDECL((*save_bflush), (int));
62 void FDECL((*save_bwrite), (int, genericptr_t, unsigned int));
63 void FDECL((*save_bclose), (int));
65 #if !defined(ZEROCOMP) || (defined(COMPRESS) || defined(ZLIB_COMP))
66 "externalcomp", def_bufon, def_bufoff, def_bflush, def_bwrite, def_bclose,
68 "zerocomp", zerocomp_bufon, zerocomp_bufoff,
69 zerocomp_bflush, zerocomp_bwrite, zerocomp_bclose,
73 #if defined(UNIX) || defined(VMS) || defined(__EMX__) || defined(WIN32)
74 #define HUP if (!program_state.done_hup)
79 /* need to preserve these during save to avoid accessing freed memory */
80 static unsigned ustuck_id = 0, usteed_id = 0;
85 if (iflags.debug_fuzzer)
87 clear_nhwindow(WIN_MESSAGE);
89 if (yn("Really save?") == 'n') {
91 if(yn("
\96{
\93\96\82É
\95Û
\91¶
\82·
\82é
\81H") == 'n') {
92 clear_nhwindow(WIN_MESSAGE);
96 clear_nhwindow(WIN_MESSAGE);
100 pline("
\95Û
\91¶
\92\86\81D
\81D
\81D");
101 #if defined(UNIX) || defined(VMS) || defined(__EMX__)
102 program_state.done_hup = 0;
105 u.uhp = -1; /* universal game's over indicator */
106 /* make sure they see the Saving message */
107 display_nhwindow(WIN_MESSAGE, TRUE);
109 exit_nhwindows("Be seeing you...");
111 exit_nhwindows("
\82Ü
\82½
\89ï
\82¢
\82Ü
\82µ
\82å
\82¤
\81D
\81D
\81D");
112 nh_terminate(EXIT_SUCCESS);
119 /* returns 1 if save successful */
124 register int fd, ofd;
129 /* we may get here via hangup signal, in which case we want to fix up
130 a few of things before saving so that they won't be restored in
131 an improper state; these will be no-ops for normal save sequence */
133 if (iflags.save_uswallow)
134 u.uswallow = 1, iflags.save_uswallow = 0;
135 if (iflags.save_uinwater)
136 u.uinwater = 1, iflags.save_uinwater = 0;
137 if (iflags.save_uburied)
138 u.uburied = 1, iflags.save_uburied = 0;
140 if (!program_state.something_worth_saving || !SAVEF[0])
142 fq_save = fqname(SAVEF, SAVEPREFIX, 1); /* level files take 0 */
144 #if defined(UNIX) || defined(VMS)
145 sethanguphandler((void FDECL((*), (int) )) SIG_IGN);
148 (void) signal(SIGINT, SIG_IGN);
151 #if defined(MICRO) && defined(MFLOPPY)
152 if (!saveDiskPrompt(0))
156 HUP if (iflags.window_inited) {
157 nh_uncompress(fq_save);
158 fd = open_savefile();
161 clear_nhwindow(WIN_MESSAGE);
163 There("seems to be an old save file.");
165 pline("
\91O
\82É
\83Z
\81[
\83u
\82µ
\82½
\83t
\83@
\83C
\83\8b\82ª
\82 \82è
\82Ü
\82·
\81D");
167 if (yn("Overwrite the old file?") == 'n') {
169 if (yn("
\8cÃ
\82¢
\83t
\83@
\83C
\83\8b\82É
\8fã
\8f\91\82«
\82µ
\82Ü
\82·
\82©
\81H") == 'n') {
170 nh_compress(fq_save);
176 HUP mark_synch(); /* flush any buffered screen output */
178 fd = create_savefile();
180 HUP pline("Cannot open save file.");
181 (void) delete_savefile(); /* ab@unido */
185 vision_recalc(2); /* shut down vision to prevent problems
186 in the event of an impossible() call */
188 /* undo date-dependent luck adjustments made at startup time */
189 if (flags.moonphase == FULL_MOON) /* ut-sally!fletcher */
190 change_luck(-1); /* and unido!ab */
193 if (iflags.window_inited)
194 HUP clear_nhwindow(WIN_MESSAGE);
200 if (!WINDOWPORT("X11"))
201 putstr(WIN_MAP, 0, "Saving:");
204 /* make sure there is enough disk space */
205 if (iflags.checkspace) {
208 savelev(fd, ledger_no(&u.uz), COUNT_SAVE);
209 savegamestate(fd, COUNT_SAVE);
210 needed = bytes_counted;
212 for (ltmp = 1; ltmp <= maxledgerno(); ltmp++)
213 if (ltmp != ledger_no(&u.uz) && level_info[ltmp].where)
214 needed += level_info[ltmp].size + (sizeof ltmp);
215 fds = freediskspace(fq_save);
219 There("is insufficient space on SAVE disk.");
220 pline("Require %ld bytes but only have %ld.", needed, fds);
224 (void) delete_savefile();
233 store_savefileinfo(fd);
234 store_plname_in_file(fd);
235 ustuck_id = (u.ustuck ? u.ustuck->m_id : 0);
236 usteed_id = (u.usteed ? u.usteed->m_id : 0);
237 savelev(fd, ledger_no(&u.uz), WRITE_SAVE | FREE_SAVE);
238 savegamestate(fd, WRITE_SAVE | FREE_SAVE);
240 /* While copying level files around, zero out u.uz to keep
241 * parts of the restore code from completely initializing all
242 * in-core data structures, since all we're doing is copying.
243 * This also avoids at least one nasty core dump.
246 u.uz.dnum = u.uz.dlevel = 0;
247 /* these pointers are no longer valid, and at least u.usteed
248 * may mislead place_monster() on other levels
250 u.ustuck = (struct monst *) 0;
251 u.usteed = (struct monst *) 0;
253 for (ltmp = (xchar) 1; ltmp <= maxledgerno(); ltmp++) {
254 if (ltmp == ledger_no(&uz_save))
256 if (!(level_info[ltmp].flags & LFILE_EXISTS))
259 curs(WIN_MAP, 1 + dotcnt++, dotrow);
260 if (dotcnt >= (COLNO - 1)) {
264 if (!WINDOWPORT("X11")) {
265 putstr(WIN_MAP, 0, ".");
269 ofd = open_levelfile(ltmp, whynot);
273 (void) delete_savefile();
274 HUP Strcpy(killer.name, whynot);
278 minit(); /* ZEROCOMP */
279 getlev(ofd, hackpid, ltmp, FALSE);
281 bwrite(fd, (genericptr_t) <mp, sizeof ltmp); /* level number*/
282 savelev(fd, ltmp, WRITE_SAVE | FREE_SAVE); /* actual level*/
283 delete_levelfile(ltmp);
289 /* get rid of current level --jgm */
290 delete_levelfile(ledger_no(&u.uz));
292 nh_compress(fq_save);
293 /* this should probably come sooner... */
294 program_state.something_worth_saving = 0;
299 savegamestate(fd, mode)
300 register int fd, mode;
303 struct obj * bc_objs = (struct obj *)0;
306 count_only = (mode & COUNT_SAVE);
308 uid = (unsigned long) getuid();
309 bwrite(fd, (genericptr_t) &uid, sizeof uid);
310 bwrite(fd, (genericptr_t) &context, sizeof context);
311 bwrite(fd, (genericptr_t) &flags, sizeof flags);
313 bwrite(fd, (genericptr_t) &sysflags, sysflags);
315 urealtime.finish_time = getnow();
316 urealtime.realtime += (long) (urealtime.finish_time
317 - urealtime.start_timing);
318 bwrite(fd, (genericptr_t) &u, sizeof u);
319 bwrite(fd, yyyymmddhhmmss(ubirthday), 14);
320 bwrite(fd, (genericptr_t) &urealtime.realtime, sizeof urealtime.realtime);
321 bwrite(fd, yyyymmddhhmmss(urealtime.start_timing), 14); /** Why? **/
322 /* this is the value to use for the next update of urealtime.realtime */
323 urealtime.start_timing = urealtime.finish_time;
324 save_killers(fd, mode);
326 /* must come before migrating_objs and migrating_mons are freed */
327 save_timers(fd, mode, RANGE_GLOBAL);
328 save_light_sources(fd, mode, RANGE_GLOBAL);
330 saveobjchn(fd, invent, mode);
332 /* save ball and chain if they are currently dangling free (i.e. not on
333 floor or in inventory) */
335 uchain->nobj = bc_objs;
339 uball->nobj = bc_objs;
342 saveobjchn(fd, bc_objs, mode);
344 saveobjchn(fd, migrating_objs, mode);
345 savemonchn(fd, migrating_mons, mode);
346 if (release_data(mode)) {
351 bwrite(fd, (genericptr_t) mvitals, sizeof mvitals);
353 save_dungeon(fd, (boolean) !!perform_bwrite(mode),
354 (boolean) !!release_data(mode));
355 savelevchn(fd, mode);
356 bwrite(fd, (genericptr_t) &moves, sizeof moves);
357 bwrite(fd, (genericptr_t) &monstermoves, sizeof monstermoves);
358 bwrite(fd, (genericptr_t) &quest_status, sizeof quest_status);
359 bwrite(fd, (genericptr_t) spl_book,
360 sizeof(struct spell) * (MAXSPELL + 1));
362 save_oracles(fd, mode);
364 bwrite(fd, (genericptr_t) &ustuck_id, sizeof ustuck_id);
366 bwrite(fd, (genericptr_t) &usteed_id, sizeof usteed_id);
367 bwrite(fd, (genericptr_t) pl_character, sizeof pl_character);
368 bwrite(fd, (genericptr_t) pl_fruit, sizeof pl_fruit);
369 savefruitchn(fd, mode);
371 save_waterlevel(fd, mode);
372 save_msghistory(fd, mode);
377 tricked_fileremoved(fd, whynot)
383 pline("Probably someone removed it.");
384 Strcpy(killer.name, whynot);
396 static boolean havestate = TRUE;
399 /* When checkpointing is on, the full state needs to be written
400 * on each checkpoint. When checkpointing is off, only the pid
401 * needs to be in the level.0 file, so it does not need to be
402 * constantly rewritten. When checkpointing is turned off during
403 * a game, however, the file has to be rewritten once to truncate
404 * it and avoid restoring from outdated information.
406 * Restricting havestate to this routine means that an additional
407 * noop pid rewriting will take place on the first "checkpoint" after
408 * the game is started or restored, if checkpointing is off.
410 if (flags.ins_chkpt || havestate) {
411 /* save the rest of the current game state in the lock file,
412 * following the original int pid, the current level number,
413 * and the current savefile name, which should not be subject
414 * to any internal compression schemes since they must be
415 * readable by an external utility
417 fd = open_levelfile(0, whynot);
418 if (tricked_fileremoved(fd, whynot))
421 _pragma_ignore(-Wunused-result)
422 (void) read(fd, (genericptr_t) &hpid, sizeof hpid);
424 if (hackpid != hpid) {
425 Sprintf(whynot, "Level #0 pid (%d) doesn't match ours (%d)!",
428 Strcpy(killer.name, whynot);
433 fd = create_levelfile(0, whynot);
436 Strcpy(killer.name, whynot);
440 _pragma_ignore(-Wunused-result)
441 (void) write(fd, (genericptr_t) &hackpid, sizeof hackpid);
443 if (flags.ins_chkpt) {
444 int currlev = ledger_no(&u.uz);
446 _pragma_ignore(-Wunused-result)
447 (void) write(fd, (genericptr_t) &currlev, sizeof currlev);
449 save_savefile_name(fd);
451 store_savefileinfo(fd);
452 store_plname_in_file(fd);
454 ustuck_id = (u.ustuck ? u.ustuck->m_id : 0);
455 usteed_id = (u.usteed ? u.usteed->m_id : 0);
456 savegamestate(fd, WRITE_SAVE);
460 havestate = flags.ins_chkpt;
466 savelev(fd, lev, mode)
471 if (mode & COUNT_SAVE) {
473 savelev0(fd, lev, COUNT_SAVE);
474 /* probably bytes_counted will be filled in again by an
475 * immediately following WRITE_SAVE anyway, but we'll
476 * leave it out of checkspace just in case */
477 if (iflags.checkspace) {
478 while (bytes_counted > freediskspace(levels))
479 if (!swapout_oldest())
483 if (mode & (WRITE_SAVE | FREE_SAVE)) {
485 savelev0(fd, lev, mode);
487 if (mode != FREE_SAVE) {
488 level_info[lev].where = ACTIVE;
489 level_info[lev].time = moves;
490 level_info[lev].size = bytes_counted;
496 savelev0(fd, lev, mode)
499 savelev(fd, lev, mode)
510 * Level file contents:
511 * version info (handled by caller);
512 * save file info (compression type; also by caller);
514 * internal level number (ledger number);
518 * If we're tearing down the current level without saving anything
519 * (which happens at end of game or upon entrance to endgame or
520 * after an aborted restore attempt) then we don't want to do any
521 * actual I/O. So when only freeing, we skip to the bones info
522 * portion (which has some freeing to do), then jump quite a bit
523 * further ahead to the middle of the 'actual level data' portion.
525 if (mode != FREE_SAVE) {
526 /* WRITE_SAVE (probably ORed with FREE_SAVE), or COUNT_SAVE */
528 /* purge any dead monsters (necessary if we're starting
529 a panic save rather than a normal one, or sometimes
530 when changing levels without taking time -- e.g.
531 create statue trap then immediately level teleport) */
532 if (iflags.purge_monsters)
536 panic("Save on bad file!"); /* impossible */
538 count_only = (mode & COUNT_SAVE);
540 if (lev >= 0 && lev <= maxledgerno())
541 level_info[lev].flags |= VISITED;
542 bwrite(fd, (genericptr_t) &hackpid, sizeof hackpid);
546 bwrite(fd, (genericptr_t) &tlev, sizeof tlev);
548 bwrite(fd, (genericptr_t) &lev, sizeof lev);
552 /* bones info comes before level data; the intent is for an external
553 program ('hearse') to be able to match a bones file with the
554 corresponding log file entry--or perhaps just skip that?--without
555 the guessing that was needed in 3.4.3 and without having to
556 interpret level data to find where to start; unfortunately it
557 still needs to handle all the data compression schemes */
558 savecemetery(fd, mode, &level.bonesinfo);
559 if (mode == FREE_SAVE) /* see above */
562 savelevl(fd, (boolean) ((sfsaveinfo.sfi1 & SFI1_RLECOMP) == SFI1_RLECOMP));
563 bwrite(fd, (genericptr_t) lastseentyp, sizeof lastseentyp);
564 bwrite(fd, (genericptr_t) &monstermoves, sizeof monstermoves);
565 bwrite(fd, (genericptr_t) &upstair, sizeof (stairway));
566 bwrite(fd, (genericptr_t) &dnstair, sizeof (stairway));
567 bwrite(fd, (genericptr_t) &upladder, sizeof (stairway));
568 bwrite(fd, (genericptr_t) &dnladder, sizeof (stairway));
569 bwrite(fd, (genericptr_t) &sstairs, sizeof (stairway));
570 bwrite(fd, (genericptr_t) &updest, sizeof (dest_area));
571 bwrite(fd, (genericptr_t) &dndest, sizeof (dest_area));
572 bwrite(fd, (genericptr_t) &level.flags, sizeof level.flags);
573 bwrite(fd, (genericptr_t) doors, sizeof doors);
574 save_rooms(fd); /* no dynamic memory to reclaim */
576 /* from here on out, saving also involves allocated memory cleanup */
578 /* timers and lights must be saved before monsters and objects */
579 save_timers(fd, mode, RANGE_LEVEL);
580 save_light_sources(fd, mode, RANGE_LEVEL);
582 savemonchn(fd, fmon, mode);
583 save_worm(fd, mode); /* save worm information */
584 savetrapchn(fd, ftrap, mode);
585 saveobjchn(fd, fobj, mode);
586 saveobjchn(fd, level.buriedobjlist, mode);
587 saveobjchn(fd, billobjs, mode);
588 if (release_data(mode)) {
591 for (y = 0; y < ROWNO; y++)
592 for (x = 0; x < COLNO; x++)
593 level.monsters[x][y] = 0;
596 fobj = level.buriedobjlist = billobjs = 0;
597 /* level.bonesinfo = 0; -- handled by savecemetery() */
599 save_engravings(fd, mode);
600 savedamage(fd, mode); /* pending shop wall and/or floor repair */
601 save_regions(fd, mode);
602 if (mode != FREE_SAVE)
607 savelevl(fd, rlecomp)
612 struct rm *prm, *rgrm;
617 /* perform run-length encoding of rm structs */
619 rgrm = &levl[0][0]; /* start matching at first rm */
622 for (y = 0; y < ROWNO; y++) {
623 for (x = 0; x < COLNO; x++) {
625 if (prm->glyph == rgrm->glyph && prm->typ == rgrm->typ
626 && prm->seenv == rgrm->seenv
627 && prm->horizontal == rgrm->horizontal
628 && prm->flags == rgrm->flags && prm->lit == rgrm->lit
629 && prm->waslit == rgrm->waslit
630 && prm->roomno == rgrm->roomno && prm->edge == rgrm->edge
631 && prm->candig == rgrm->candig) {
634 match = 254; /* undo this match */
638 /* run has been broken, write out run-length encoding */
640 bwrite(fd, (genericptr_t) &match, sizeof (uchar));
641 bwrite(fd, (genericptr_t) rgrm, sizeof (struct rm));
642 /* start encoding again. we have at least 1 rm
643 in the next run, viz. this one. */
650 bwrite(fd, (genericptr_t) &match, sizeof (uchar));
651 bwrite(fd, (genericptr_t) rgrm, sizeof (struct rm));
657 #endif /* ?RLECOMP */
658 bwrite(fd, (genericptr_t) levl, sizeof levl);
666 (*saveprocs.save_bufon)(fd);
675 (*saveprocs.save_bufoff)(fd);
679 /* flush run and buffer */
684 (*saveprocs.save_bflush)(fd);
692 register unsigned num;
694 (*saveprocs.save_bwrite)(fd, loc, num);
702 (*saveprocs.save_bclose)(fd);
706 static int bw_fd = -1;
707 static FILE *bw_FILE = 0;
708 static boolean buffering = FALSE;
717 panic("double buffering unexpected");
719 if ((bw_FILE = fdopen(fd, "w")) == 0)
720 panic("buffering of file %d failed", fd);
740 if (fflush(bw_FILE) == EOF)
741 panic("flush of savefile failed!");
748 def_bwrite(fd, loc, num)
750 register genericptr_t loc;
751 register unsigned num;
756 bytes_counted += num;
764 panic("unbuffered write to fd %d (!= %d)", fd, bw_fd);
766 failed = (fwrite(loc, (int) num, 1, bw_FILE) != 1);
770 /* lint wants 3rd arg of write to be an int; lint -p an unsigned */
771 #if defined(BSD) || defined(ULTRIX) || defined(WIN32) || defined(_MSC_VER)
772 failed = ((long) write(fd, loc, (int) num) != (long) num);
773 #else /* e.g. SYSV, __TURBOC__ */
774 failed = ((long) write(fd, loc, num) != (long) num);
779 #if defined(UNIX) || defined(VMS) || defined(__EMX__)
780 if (program_state.done_hup)
781 nh_terminate(EXIT_FAILURE);
784 panic("cannot write %u bytes to file #%d", num, fd);
795 (void) fclose(bw_FILE);
805 /* The runs of zero-run compression are flushed after the game state or a
806 * level is written out. This adds a couple bytes to a save file, where
807 * the runs could be mashed together, but it allows gluing together game
808 * state and level files to form a save file, and it means the flushing
809 * does not need to be specifically called for every other time a level
810 * file is written out.
813 #define RLESC '\0' /* Leading character for run of LRESC's */
814 #define flushoutrun(ln) (zerocomp_bputc(RLESC), zerocomp_bputc(ln), ln = -1)
816 #ifndef ZEROCOMP_BUFSIZ
817 #define ZEROCOMP_BUFSIZ BUFSZ
819 static NEARDATA unsigned char outbuf[ZEROCOMP_BUFSIZ];
820 static NEARDATA unsigned short outbufp = 0;
821 static NEARDATA short outrunlength = -1;
822 static NEARDATA int bwritefd;
823 static NEARDATA boolean compressing = FALSE;
827 HUP printf("outbufp %d outrunlength %d\n", outbufp,outrunlength);
839 if (outbufp >= sizeof outbuf) {
840 (void) write(bwritefd, outbuf, sizeof outbuf);
843 outbuf[outbufp++] = (unsigned char) c;
862 panic("closing file with buffered data still unwritten");
869 /* flush run and buffer */
875 if (outrunlength >= 0) { /* flush run */
876 flushoutrun(outrunlength);
884 if (write(fd, outbuf, outbufp) != outbufp) {
885 #if defined(UNIX) || defined(VMS) || defined(__EMX__)
886 if (program_state.done_hup)
887 nh_terminate(EXIT_FAILURE);
890 zerocomp_bclose(fd); /* panic (outbufp != 0) */
897 zerocomp_bwrite(fd, loc, num)
900 register unsigned num;
902 register unsigned char *bp = (unsigned char *) loc;
906 bytes_counted += num;
910 if ((unsigned) write(fd, loc, num) != num) {
911 #if defined(UNIX) || defined(VMS) || defined(__EMX__)
912 if (program_state.done_hup)
913 nh_terminate(EXIT_FAILURE);
916 panic("cannot write %u bytes to file #%d", num, fd);
920 for (; num; num--, bp++) {
921 if (*bp == RLESC) { /* One more char in run */
922 if (++outrunlength == 0xFF) {
923 flushoutrun(outrunlength);
925 } else { /* end of run */
926 if (outrunlength >= 0) { /* flush run */
927 flushoutrun(outrunlength);
943 #endif /* ZEROCOMP */
947 register int fd, mode;
949 s_level *tmplev, *tmplev2;
952 for (tmplev = sp_levchn; tmplev; tmplev = tmplev->next)
954 if (perform_bwrite(mode))
955 bwrite(fd, (genericptr_t) &cnt, sizeof cnt);
957 for (tmplev = sp_levchn; tmplev; tmplev = tmplev2) {
958 tmplev2 = tmplev->next;
959 if (perform_bwrite(mode))
960 bwrite(fd, (genericptr_t) tmplev, sizeof *tmplev);
961 if (release_data(mode))
962 free((genericptr_t) tmplev);
964 if (release_data(mode))
968 /* used when saving a level and also when saving dungeon overview data */
970 savecemetery(fd, mode, cemeteryaddr)
973 struct cemetery **cemeteryaddr;
975 struct cemetery *thisbones, *nextbones;
978 flag = *cemeteryaddr ? 0 : -1;
979 if (perform_bwrite(mode))
980 bwrite(fd, (genericptr_t) &flag, sizeof flag);
981 nextbones = *cemeteryaddr;
982 while ((thisbones = nextbones) != 0) {
983 nextbones = thisbones->next;
984 if (perform_bwrite(mode))
985 bwrite(fd, (genericptr_t) thisbones, sizeof *thisbones);
986 if (release_data(mode))
987 free((genericptr_t) thisbones);
989 if (release_data(mode))
995 register int fd, mode;
997 register struct damage *damageptr, *tmp_dam;
1000 damageptr = level.damagelist;
1001 for (tmp_dam = damageptr; tmp_dam; tmp_dam = tmp_dam->next)
1003 if (perform_bwrite(mode))
1004 bwrite(fd, (genericptr_t) &xl, sizeof xl);
1007 if (perform_bwrite(mode))
1008 bwrite(fd, (genericptr_t) damageptr, sizeof *damageptr);
1009 tmp_dam = damageptr;
1010 damageptr = damageptr->next;
1011 if (release_data(mode))
1012 free((genericptr_t) tmp_dam);
1014 if (release_data(mode))
1015 level.damagelist = 0;
1023 int buflen, zerobuf = 0;
1025 buflen = (int) sizeof (struct obj);
1026 bwrite(fd, (genericptr_t) &buflen, sizeof buflen);
1027 bwrite(fd, (genericptr_t) otmp, buflen);
1029 buflen = ONAME(otmp) ? (int) strlen(ONAME(otmp)) + 1 : 0;
1030 bwrite(fd, (genericptr_t) &buflen, sizeof buflen);
1032 bwrite(fd, (genericptr_t) ONAME(otmp), buflen);
1034 /* defer to savemon() for this one */
1036 savemon(fd, OMONST(otmp));
1038 bwrite(fd, (genericptr_t) &zerobuf, sizeof zerobuf);
1040 buflen = OMID(otmp) ? (int) sizeof (unsigned) : 0;
1041 bwrite(fd, (genericptr_t) &buflen, sizeof buflen);
1043 bwrite(fd, (genericptr_t) OMID(otmp), buflen);
1045 /* TODO: post 3.6.x, get rid of this */
1046 buflen = OLONG(otmp) ? (int) sizeof (long) : 0;
1047 bwrite(fd, (genericptr_t) &buflen, sizeof buflen);
1049 bwrite(fd, (genericptr_t) OLONG(otmp), buflen);
1051 buflen = OMAILCMD(otmp) ? (int) strlen(OMAILCMD(otmp)) + 1 : 0;
1052 bwrite(fd, (genericptr_t) &buflen, sizeof buflen);
1054 bwrite(fd, (genericptr_t) OMAILCMD(otmp), buflen);
1059 saveobjchn(fd, otmp, mode)
1060 register int fd, mode;
1061 register struct obj *otmp;
1063 register struct obj *otmp2;
1068 if (perform_bwrite(mode)) {
1071 if (Has_contents(otmp))
1072 saveobjchn(fd, otmp->cobj, mode);
1073 if (release_data(mode)) {
1075 * If these are on the floor, the discarding could be
1076 * due to game save, or we could just be changing levels.
1077 * Always invalidate the pointer, but ensure that we have
1078 * the o_id in order to restore the pointer on reload.
1080 if (otmp == context.victual.piece) {
1081 context.victual.o_id = otmp->o_id;
1082 context.victual.piece = (struct obj *) 0;
1084 if (otmp == context.tin.tin) {
1085 context.tin.o_id = otmp->o_id;
1086 context.tin.tin = (struct obj *) 0;
1088 if (otmp == context.spbook.book) {
1089 context.spbook.o_id = otmp->o_id;
1090 context.spbook.book = (struct obj *) 0;
1092 otmp->where = OBJ_FREE; /* set to free so dealloc will work */
1093 otmp->nobj = NULL; /* nobj saved into otmp2 */
1094 otmp->cobj = NULL; /* contents handled above */
1095 otmp->timed = 0; /* not timed any more */
1096 otmp->lamplit = 0; /* caller handled lights */
1101 if (perform_bwrite(mode))
1102 bwrite(fd, (genericptr_t) &minusone, sizeof (int));
1112 mtmp->mtemplit = 0; /* normally clear; if set here then a panic save
1113 * is being written while bhit() was executing */
1114 buflen = (int) sizeof (struct monst);
1115 bwrite(fd, (genericptr_t) &buflen, sizeof buflen);
1116 bwrite(fd, (genericptr_t) mtmp, buflen);
1118 buflen = MNAME(mtmp) ? (int) strlen(MNAME(mtmp)) + 1 : 0;
1119 bwrite(fd, (genericptr_t) &buflen, sizeof buflen);
1121 bwrite(fd, (genericptr_t) MNAME(mtmp), buflen);
1122 buflen = EGD(mtmp) ? (int) sizeof (struct egd) : 0;
1123 bwrite(fd, (genericptr_t) &buflen, sizeof buflen);
1125 bwrite(fd, (genericptr_t) EGD(mtmp), buflen);
1126 buflen = EPRI(mtmp) ? (int) sizeof (struct epri) : 0;
1127 bwrite(fd, (genericptr_t) &buflen, sizeof buflen);
1129 bwrite(fd, (genericptr_t) EPRI(mtmp), buflen);
1130 buflen = ESHK(mtmp) ? (int) sizeof (struct eshk) : 0;
1131 bwrite(fd, (genericptr_t) &buflen, sizeof(int));
1133 bwrite(fd, (genericptr_t) ESHK(mtmp), buflen);
1134 buflen = EMIN(mtmp) ? (int) sizeof (struct emin) : 0;
1135 bwrite(fd, (genericptr_t) &buflen, sizeof(int));
1137 bwrite(fd, (genericptr_t) EMIN(mtmp), buflen);
1138 buflen = EDOG(mtmp) ? (int) sizeof (struct edog) : 0;
1139 bwrite(fd, (genericptr_t) &buflen, sizeof(int));
1141 bwrite(fd, (genericptr_t) EDOG(mtmp), buflen);
1142 /* mcorpsenm is inline int rather than pointer to something,
1143 so doesn't need to be preceded by a length field */
1144 bwrite(fd, (genericptr_t) &MCORPSENM(mtmp), sizeof MCORPSENM(mtmp));
1149 savemonchn(fd, mtmp, mode)
1150 register int fd, mode;
1151 register struct monst *mtmp;
1153 register struct monst *mtmp2;
1158 if (perform_bwrite(mode)) {
1159 mtmp->mnum = monsndx(mtmp->data);
1161 forget_temple_entry(mtmp); /* EPRI() */
1165 saveobjchn(fd, mtmp->minvent, mode);
1166 if (release_data(mode)) {
1167 if (mtmp == context.polearm.hitmon) {
1168 context.polearm.m_id = mtmp->m_id;
1169 context.polearm.hitmon = NULL;
1171 mtmp->nmon = NULL; /* nmon saved into mtmp2 */
1172 dealloc_monst(mtmp);
1176 if (perform_bwrite(mode))
1177 bwrite(fd, (genericptr_t) &minusone, sizeof (int));
1180 /* save traps; ftrap is the only trap chain so the 2nd arg is superfluous */
1182 savetrapchn(fd, trap, mode)
1184 register struct trap *trap;
1187 static struct trap zerotrap;
1188 register struct trap *trap2;
1191 trap2 = trap->ntrap;
1192 if (perform_bwrite(mode))
1193 bwrite(fd, (genericptr_t) trap, sizeof *trap);
1194 if (release_data(mode))
1198 if (perform_bwrite(mode))
1199 bwrite(fd, (genericptr_t) &zerotrap, sizeof zerotrap);
1202 /* save all the fruit names and ID's; this is used only in saving whole games
1203 * (not levels) and in saving bones levels. When saving a bones level,
1204 * we only want to save the fruits which exist on the bones level; the bones
1205 * level routine marks nonexistent fruits by making the fid negative.
1208 savefruitchn(fd, mode)
1211 static struct fruit zerofruit;
1212 register struct fruit *f2, *f1;
1217 if (f1->fid >= 0 && perform_bwrite(mode))
1218 bwrite(fd, (genericptr_t) f1, sizeof *f1);
1219 if (release_data(mode))
1223 if (perform_bwrite(mode))
1224 bwrite(fd, (genericptr_t) &zerofruit, sizeof zerofruit);
1225 if (release_data(mode))
1230 store_plname_in_file(fd)
1233 int plsiztmp = PL_NSIZ;
1236 /* bwrite() before bufon() uses plain write() */
1237 bwrite(fd, (genericptr_t) &plsiztmp, sizeof plsiztmp);
1238 bwrite(fd, (genericptr_t) plname, plsiztmp);
1244 save_msghistory(fd, mode)
1248 int msgcount = 0, msglen;
1250 boolean init = TRUE;
1252 if (perform_bwrite(mode)) {
1253 /* ask window port for each message in sequence */
1254 while ((msg = getmsghistory(init)) != 0) {
1256 msglen = strlen(msg);
1259 /* sanity: truncate if necessary (shouldn't happen);
1260 no need to modify msg[] since terminator isn't written */
1261 if (msglen > BUFSZ - 1)
1263 bwrite(fd, (genericptr_t) &msglen, sizeof msglen);
1264 bwrite(fd, (genericptr_t) msg, msglen);
1267 bwrite(fd, (genericptr_t) &minusone, sizeof (int));
1269 debugpline1("Stored %d messages into savefile.", msgcount);
1270 /* note: we don't attempt to handle release_data() here */
1274 store_savefileinfo(fd)
1277 /* sfcap (decl.c) describes the savefile feature capabilities
1278 * that are supported by this port/platform build.
1280 * sfsaveinfo (decl.c) describes the savefile info that actually
1281 * gets written into the savefile, and is used to determine the
1282 * save file being written.
1284 * sfrestinfo (decl.c) describes the savefile info that is
1285 * being used to read the information from an existing savefile.
1289 /* bwrite() before bufon() uses plain write() */
1290 bwrite(fd, (genericptr_t) &sfsaveinfo, (unsigned) sizeof sfsaveinfo);
1296 set_savepref(suitename)
1297 const char *suitename;
1299 if (!strcmpi(suitename, "externalcomp")) {
1300 saveprocs.name = "externalcomp";
1301 saveprocs.save_bufon = def_bufon;
1302 saveprocs.save_bufoff = def_bufoff;
1303 saveprocs.save_bflush = def_bflush;
1304 saveprocs.save_bwrite = def_bwrite;
1305 saveprocs.save_bclose = def_bclose;
1306 sfsaveinfo.sfi1 |= SFI1_EXTERNALCOMP;
1307 sfsaveinfo.sfi1 &= ~SFI1_ZEROCOMP;
1309 if (!strcmpi(suitename, "!rlecomp")) {
1310 sfsaveinfo.sfi1 &= ~SFI1_RLECOMP;
1313 if (!strcmpi(suitename, "zerocomp")) {
1314 saveprocs.name = "zerocomp";
1315 saveprocs.save_bufon = zerocomp_bufon;
1316 saveprocs.save_bufoff = zerocomp_bufoff;
1317 saveprocs.save_bflush = zerocomp_bflush;
1318 saveprocs.save_bwrite = zerocomp_bwrite;
1319 saveprocs.save_bclose = zerocomp_bclose;
1320 sfsaveinfo.sfi1 |= SFI1_ZEROCOMP;
1321 sfsaveinfo.sfi1 &= ~SFI1_EXTERNALCOMP;
1325 if (!strcmpi(suitename, "rlecomp")) {
1326 sfsaveinfo.sfi1 |= SFI1_RLECOMP;
1331 /* also called by prscore(); this probably belongs in dungeon.c... */
1335 #ifdef FREE_ALL_MEMORY
1336 savelevchn(0, FREE_SAVE);
1337 save_dungeon(0, FALSE, TRUE);
1345 #if defined(UNIX) && defined(MAIL)
1349 free_menu_coloring();
1350 free_invbuf(); /* let_to_name (invent.c) */
1351 free_youbuf(); /* You_buf,&c (pline.c) */
1353 tmp_at(DISP_FREEMEM, 0); /* temporary display effects */
1354 #ifdef FREE_ALL_MEMORY
1355 #define free_current_level() savelev(-1, -1, FREE_SAVE)
1356 #define freeobjchn(X) (saveobjchn(0, X, FREE_SAVE), X = 0)
1357 #define freemonchn(X) (savemonchn(0, X, FREE_SAVE), X = 0)
1358 #define freefruitchn() savefruitchn(0, FREE_SAVE)
1359 #define freenames() savenames(0, FREE_SAVE)
1360 #define free_killers() save_killers(0, FREE_SAVE)
1361 #define free_oracles() save_oracles(0, FREE_SAVE)
1362 #define free_waterlevel() save_waterlevel(0, FREE_SAVE)
1363 #define free_timers(R) save_timers(0, FREE_SAVE, R)
1364 #define free_light_sources(R) save_light_sources(0, FREE_SAVE, R)
1365 #define free_animals() mon_animal_list(FALSE)
1367 /* move-specific data */
1368 dmonsfree(); /* release dead monsters */
1370 /* level-specific data */
1371 free_current_level();
1373 /* game-state data [ought to reorganize savegamestate() to handle this] */
1375 free_timers(RANGE_GLOBAL);
1376 free_light_sources(RANGE_GLOBAL);
1378 freeobjchn(migrating_objs);
1379 freemonchn(migrating_mons);
1380 freemonchn(mydogs); /* ascension or dungeon escape */
1381 /* freelevchn(); -- [folded into free_dungeons()] */
1389 /* some pointers in iflags */
1390 if (iflags.wc_font_map)
1391 free((genericptr_t) iflags.wc_font_map), iflags.wc_font_map = 0;
1392 if (iflags.wc_font_message)
1393 free((genericptr_t) iflags.wc_font_message),
1394 iflags.wc_font_message = 0;
1395 if (iflags.wc_font_text)
1396 free((genericptr_t) iflags.wc_font_text), iflags.wc_font_text = 0;
1397 if (iflags.wc_font_menu)
1398 free((genericptr_t) iflags.wc_font_menu), iflags.wc_font_menu = 0;
1399 if (iflags.wc_font_status)
1400 free((genericptr_t) iflags.wc_font_status), iflags.wc_font_status = 0;
1401 if (iflags.wc_tile_file)
1402 free((genericptr_t) iflags.wc_tile_file), iflags.wc_tile_file = 0;
1403 free_autopickup_exceptions();
1406 /* free_pickinv_cache(); -- now done from really_done()... */
1408 #endif /* FREE_ALL_MEMORY */
1409 if (VIA_WINDOWPORT())
1412 dumplogfreemessages();
1415 /* last, because it frees data that might be used by panic() to provide
1416 feedback to the user; conceivably other freeing might trigger panic */
1417 sysopt_release(); /* SYSCF strings */
1426 char to[PATHLEN], from[PATHLEN];
1428 Sprintf(from, "%s%s", permbones, alllevels);
1429 Sprintf(to, "%s%s", levels, alllevels);
1430 set_levelfile_name(from, lev);
1431 set_levelfile_name(to, lev);
1432 if (iflags.checkspace) {
1433 while (level_info[lev].size > freediskspace(to))
1434 if (!swapout_oldest())
1438 pline("Swapping in `%s'.", from);
1442 (void) unlink(from);
1443 level_info[lev].where = ACTIVE;
1450 char to[PATHLEN], from[PATHLEN];
1456 for (i = 1, oldtime = 0, oldest = 0; i <= maxledgerno(); i++)
1457 if (level_info[i].where == ACTIVE
1458 && (!oldtime || level_info[i].time < oldtime)) {
1460 oldtime = level_info[i].time;
1464 Sprintf(from, "%s%s", levels, alllevels);
1465 Sprintf(to, "%s%s", permbones, alllevels);
1466 set_levelfile_name(from, oldest);
1467 set_levelfile_name(to, oldest);
1469 pline("Swapping out `%s'.", from);
1473 (void) unlink(from);
1474 level_info[oldest].where = SWAPPED;
1483 if (_copyfile(from, to))
1484 panic("Can't copy %s to %s", from, to);
1486 char buf[BUFSIZ]; /* this is system interaction, therefore
1487 * BUFSIZ instead of NetHack's BUFSZ */
1488 int nfrom, nto, fdfrom, fdto;
1490 if ((fdfrom = open(from, O_RDONLY | O_BINARY, FCMASK)) < 0)
1491 panic("Can't copy from %s !?", from);
1492 if ((fdto = open(to, O_WRONLY | O_BINARY | O_CREAT | O_TRUNC, FCMASK)) < 0)
1493 panic("Can't copy to %s", to);
1495 nfrom = read(fdfrom, buf, BUFSIZ);
1496 nto = write(fdto, buf, nfrom);
1498 panic("Copyfile failed!");
1499 } while (nfrom == BUFSIZ);
1500 (void) nhclose(fdfrom);
1501 (void) nhclose(fdto);
1505 /* see comment in bones.c */
1513 #endif /* MFLOPPY */