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. */
11 #if !defined(LSC) && !defined(O_WRONLY) && !defined(AZTEC_C)
17 static int count_only;
21 int dotcnt, dotrow; /* also used in restore */
24 STATIC_DCL void FDECL(savelevchn, (int, int));
25 STATIC_DCL void FDECL(savedamage, (int, int));
26 STATIC_DCL void FDECL(saveobj, (int, struct obj *));
27 STATIC_DCL void FDECL(saveobjchn, (int, struct obj *, int));
28 STATIC_DCL void FDECL(savemon, (int, struct monst *));
29 STATIC_DCL void FDECL(savemonchn, (int, struct monst *, int));
30 STATIC_DCL void FDECL(savetrapchn, (int, struct trap *, int));
31 STATIC_DCL void FDECL(savegamestate, (int, int));
32 STATIC_OVL void FDECL(save_msghistory, (int, int));
34 STATIC_DCL void FDECL(savelev0, (int, XCHAR_P, int));
35 STATIC_DCL boolean NDECL(swapout_oldest);
36 STATIC_DCL void FDECL(copyfile, (char *, char *));
38 STATIC_DCL void FDECL(savelevl, (int fd, BOOLEAN_P));
39 STATIC_DCL void FDECL(def_bufon, (int));
40 STATIC_DCL void FDECL(def_bufoff, (int));
41 STATIC_DCL void FDECL(def_bflush, (int));
42 STATIC_DCL void FDECL(def_bwrite, (int, genericptr_t, unsigned int));
44 STATIC_DCL void FDECL(zerocomp_bufon, (int));
45 STATIC_DCL void FDECL(zerocomp_bufoff, (int));
46 STATIC_DCL void FDECL(zerocomp_bflush, (int));
47 STATIC_DCL void FDECL(zerocomp_bwrite, (int, genericptr_t, unsigned int));
48 STATIC_DCL void FDECL(zerocomp_bputc, (int));
51 static struct save_procs {
53 void FDECL((*save_bufon), (int));
54 void FDECL((*save_bufoff), (int));
55 void FDECL((*save_bflush), (int));
56 void FDECL((*save_bwrite), (int, genericptr_t, unsigned int));
57 void FDECL((*save_bclose), (int));
59 #if !defined(ZEROCOMP) || (defined(COMPRESS) || defined(ZLIB_COMP))
60 "externalcomp", def_bufon, def_bufoff, def_bflush, def_bwrite, def_bclose,
62 "zerocomp", zerocomp_bufon, zerocomp_bufoff,
63 zerocomp_bflush, zerocomp_bwrite, zerocomp_bclose,
67 static long nulls[sizeof(struct trap) + sizeof(struct fruit)];
69 #if defined(UNIX) || defined(VMS) || defined(__EMX__) || defined(WIN32)
70 #define HUP if (!program_state.done_hup)
75 /* need to preserve these during save to avoid accessing freed memory */
76 static unsigned ustuck_id = 0, usteed_id = 0;
81 clear_nhwindow(WIN_MESSAGE);
83 if (yn("Really save?") == 'n') {
85 if(yn("
\96{
\93\96\82É
\95Û
\91¶
\82·
\82é
\81H") == 'n') {
86 clear_nhwindow(WIN_MESSAGE);
90 clear_nhwindow(WIN_MESSAGE);
94 pline("
\95Û
\91¶
\92\86\81D
\81D
\81D");
95 #if defined(UNIX) || defined(VMS) || defined(__EMX__)
96 program_state.done_hup = 0;
99 u.uhp = -1; /* universal game's over indicator */
100 /* make sure they see the Saving message */
101 display_nhwindow(WIN_MESSAGE, TRUE);
103 exit_nhwindows("Be seeing you...");
105 exit_nhwindows("
\82Ü
\82½
\89ï
\82¢
\82Ü
\82µ
\82å
\82¤
\81D
\81D
\81D");
106 terminate(EXIT_SUCCESS);
113 /* returns 1 if save successful */
118 register int fd, ofd;
123 /* we may get here via hangup signal, in which case we want to fix up
124 a few of things before saving so that they won't be restored in
125 an improper state; these will be no-ops for normal save sequence */
127 if (iflags.save_uinwater)
128 u.uinwater = 1, iflags.save_uinwater = 0;
129 if (iflags.save_uburied)
130 u.uburied = 1, iflags.save_uburied = 0;
132 if (!program_state.something_worth_saving || !SAVEF[0])
134 fq_save = fqname(SAVEF, SAVEPREFIX, 1); /* level files take 0 */
136 #if defined(UNIX) || defined(VMS)
137 sethanguphandler((void FDECL((*), (int) )) SIG_IGN);
140 (void) signal(SIGINT, SIG_IGN);
143 #if defined(MICRO) && defined(MFLOPPY)
144 if (!saveDiskPrompt(0))
148 HUP if (iflags.window_inited)
150 nh_uncompress(fq_save);
151 fd = open_savefile();
154 clear_nhwindow(WIN_MESSAGE);
156 There("seems to be an old save file.");
158 pline("
\91O
\82É
\83Z
\81[
\83u
\82µ
\82½
\83t
\83@
\83C
\83\8b\82ª
\82 \82è
\82Ü
\82·
\81D");
160 if (yn("Overwrite the old file?") == 'n') {
162 if (yn("
\8cÃ
\82¢
\83t
\83@
\83C
\83\8b\82É
\8fã
\8f\91\82«
\82µ
\82Ü
\82·
\82©
\81H") == 'n') {
163 nh_compress(fq_save);
169 HUP mark_synch(); /* flush any buffered screen output */
171 fd = create_savefile();
173 HUP pline("Cannot open save file.");
174 (void) delete_savefile(); /* ab@unido */
178 vision_recalc(2); /* shut down vision to prevent problems
179 in the event of an impossible() call */
181 /* undo date-dependent luck adjustments made at startup time */
182 if (flags.moonphase == FULL_MOON) /* ut-sally!fletcher */
183 change_luck(-1); /* and unido!ab */
186 if (iflags.window_inited)
187 HUP clear_nhwindow(WIN_MESSAGE);
193 if (strncmpi("X11", windowprocs.name, 3))
194 putstr(WIN_MAP, 0, "Saving:");
197 /* make sure there is enough disk space */
198 if (iflags.checkspace) {
201 savelev(fd, ledger_no(&u.uz), COUNT_SAVE);
202 savegamestate(fd, COUNT_SAVE);
203 needed = bytes_counted;
205 for (ltmp = 1; ltmp <= maxledgerno(); ltmp++)
206 if (ltmp != ledger_no(&u.uz) && level_info[ltmp].where)
207 needed += level_info[ltmp].size + (sizeof ltmp);
208 fds = freediskspace(fq_save);
212 There("is insufficient space on SAVE disk.");
213 pline("Require %ld bytes but only have %ld.", needed, fds);
217 (void) delete_savefile();
226 store_savefileinfo(fd);
227 store_plname_in_file(fd);
228 ustuck_id = (u.ustuck ? u.ustuck->m_id : 0);
229 usteed_id = (u.usteed ? u.usteed->m_id : 0);
230 savelev(fd, ledger_no(&u.uz), WRITE_SAVE | FREE_SAVE);
231 savegamestate(fd, WRITE_SAVE | FREE_SAVE);
233 /* While copying level files around, zero out u.uz to keep
234 * parts of the restore code from completely initializing all
235 * in-core data structures, since all we're doing is copying.
236 * This also avoids at least one nasty core dump.
239 u.uz.dnum = u.uz.dlevel = 0;
240 /* these pointers are no longer valid, and at least u.usteed
241 * may mislead place_monster() on other levels
243 u.ustuck = (struct monst *) 0;
244 u.usteed = (struct monst *) 0;
246 for (ltmp = (xchar) 1; ltmp <= maxledgerno(); ltmp++) {
247 if (ltmp == ledger_no(&uz_save))
249 if (!(level_info[ltmp].flags & LFILE_EXISTS))
252 curs(WIN_MAP, 1 + dotcnt++, dotrow);
253 if (dotcnt >= (COLNO - 1)) {
257 if (strncmpi("X11", windowprocs.name, 3)) {
258 putstr(WIN_MAP, 0, ".");
262 ofd = open_levelfile(ltmp, whynot);
266 (void) delete_savefile();
267 HUP Strcpy(killer.name, whynot);
271 minit(); /* ZEROCOMP */
272 getlev(ofd, hackpid, ltmp, FALSE);
274 bwrite(fd, (genericptr_t) <mp, sizeof ltmp); /* level number*/
275 savelev(fd, ltmp, WRITE_SAVE | FREE_SAVE); /* actual level*/
276 delete_levelfile(ltmp);
282 /* get rid of current level --jgm */
283 delete_levelfile(ledger_no(&u.uz));
285 nh_compress(fq_save);
286 /* this should probably come sooner... */
287 program_state.something_worth_saving = 0;
292 savegamestate(fd, mode)
293 register int fd, mode;
298 count_only = (mode & COUNT_SAVE);
300 uid = (unsigned long) getuid();
301 bwrite(fd, (genericptr_t) &uid, sizeof uid);
302 bwrite(fd, (genericptr_t) &context, sizeof(struct context_info));
303 bwrite(fd, (genericptr_t) &flags, sizeof(struct flag));
305 bwrite(fd, (genericptr_t) &sysflags, sizeof(struct sysflag));
307 urealtime.finish_time = getnow();
308 urealtime.realtime += (long) (urealtime.finish_time
309 - urealtime.start_timing);
310 bwrite(fd, (genericptr_t) &u, sizeof(struct you));
311 bwrite(fd, yyyymmddhhmmss(ubirthday), 14);
312 bwrite(fd, (genericptr_t) &urealtime.realtime, sizeof urealtime.realtime);
313 bwrite(fd, yyyymmddhhmmss(urealtime.start_timing), 14); /** Why? **/
314 /* this is the value to use for the next update of urealtime.realtime */
315 urealtime.start_timing = urealtime.finish_time;
316 save_killers(fd, mode);
318 /* must come before migrating_objs and migrating_mons are freed */
319 save_timers(fd, mode, RANGE_GLOBAL);
320 save_light_sources(fd, mode, RANGE_GLOBAL);
322 saveobjchn(fd, invent, mode);
324 /* prevent loss of ball & chain when swallowed */
325 uball->nobj = uchain;
326 uchain->nobj = (struct obj *) 0;
327 saveobjchn(fd, uball, mode);
329 saveobjchn(fd, (struct obj *) 0, mode);
332 saveobjchn(fd, migrating_objs, mode);
333 savemonchn(fd, migrating_mons, mode);
334 if (release_data(mode)) {
339 bwrite(fd, (genericptr_t) mvitals, sizeof(mvitals));
341 save_dungeon(fd, (boolean) !!perform_bwrite(mode),
342 (boolean) !!release_data(mode));
343 savelevchn(fd, mode);
344 bwrite(fd, (genericptr_t) &moves, sizeof moves);
345 bwrite(fd, (genericptr_t) &monstermoves, sizeof monstermoves);
346 bwrite(fd, (genericptr_t) &quest_status, sizeof(struct q_score));
347 bwrite(fd, (genericptr_t) spl_book,
348 sizeof(struct spell) * (MAXSPELL + 1));
350 save_oracles(fd, mode);
352 bwrite(fd, (genericptr_t) &ustuck_id, sizeof ustuck_id);
354 bwrite(fd, (genericptr_t) &usteed_id, sizeof usteed_id);
355 bwrite(fd, (genericptr_t) pl_character, sizeof pl_character);
356 bwrite(fd, (genericptr_t) pl_fruit, sizeof pl_fruit);
357 savefruitchn(fd, mode);
359 save_waterlevel(fd, mode);
360 save_msghistory(fd, mode);
365 tricked_fileremoved(fd, whynot)
371 pline("Probably someone removed it.");
372 Strcpy(killer.name, whynot);
384 static boolean havestate = TRUE;
387 /* When checkpointing is on, the full state needs to be written
388 * on each checkpoint. When checkpointing is off, only the pid
389 * needs to be in the level.0 file, so it does not need to be
390 * constantly rewritten. When checkpointing is turned off during
391 * a game, however, the file has to be rewritten once to truncate
392 * it and avoid restoring from outdated information.
394 * Restricting havestate to this routine means that an additional
395 * noop pid rewriting will take place on the first "checkpoint" after
396 * the game is started or restored, if checkpointing is off.
398 if (flags.ins_chkpt || havestate) {
399 /* save the rest of the current game state in the lock file,
400 * following the original int pid, the current level number,
401 * and the current savefile name, which should not be subject
402 * to any internal compression schemes since they must be
403 * readable by an external utility
405 fd = open_levelfile(0, whynot);
406 if (tricked_fileremoved(fd, whynot))
409 (void) read(fd, (genericptr_t) &hpid, sizeof(hpid));
410 if (hackpid != hpid) {
411 Sprintf(whynot, "Level #0 pid (%d) doesn't match ours (%d)!",
414 Strcpy(killer.name, whynot);
419 fd = create_levelfile(0, whynot);
422 Strcpy(killer.name, whynot);
426 (void) write(fd, (genericptr_t) &hackpid, sizeof(hackpid));
427 if (flags.ins_chkpt) {
428 int currlev = ledger_no(&u.uz);
430 (void) write(fd, (genericptr_t) &currlev, sizeof(currlev));
431 save_savefile_name(fd);
433 store_savefileinfo(fd);
434 store_plname_in_file(fd);
436 ustuck_id = (u.ustuck ? u.ustuck->m_id : 0);
437 usteed_id = (u.usteed ? u.usteed->m_id : 0);
438 savegamestate(fd, WRITE_SAVE);
442 havestate = flags.ins_chkpt;
448 savelev(fd, lev, mode)
453 if (mode & COUNT_SAVE) {
455 savelev0(fd, lev, COUNT_SAVE);
456 /* probably bytes_counted will be filled in again by an
457 * immediately following WRITE_SAVE anyway, but we'll
458 * leave it out of checkspace just in case */
459 if (iflags.checkspace) {
460 while (bytes_counted > freediskspace(levels))
461 if (!swapout_oldest())
465 if (mode & (WRITE_SAVE | FREE_SAVE)) {
467 savelev0(fd, lev, mode);
469 if (mode != FREE_SAVE) {
470 level_info[lev].where = ACTIVE;
471 level_info[lev].time = moves;
472 level_info[lev].size = bytes_counted;
478 savelev0(fd, lev, mode)
481 savelev(fd, lev, mode)
491 /* if we're tearing down the current level without saving anything
492 (which happens upon entrance to the endgame or after an aborted
493 restore attempt) then we don't want to do any actual I/O */
494 if (mode == FREE_SAVE)
497 /* purge any dead monsters (necessary if we're starting
498 a panic save rather than a normal one, or sometimes
499 when changing levels without taking time -- e.g.
500 create statue trap then immediately level teleport) */
501 if (iflags.purge_monsters)
505 panic("Save on bad file!"); /* impossible */
507 count_only = (mode & COUNT_SAVE);
509 if (lev >= 0 && lev <= maxledgerno())
510 level_info[lev].flags |= VISITED;
511 bwrite(fd, (genericptr_t) &hackpid, sizeof(hackpid));
515 bwrite(fd, (genericptr_t) &tlev, sizeof(tlev));
517 bwrite(fd, (genericptr_t) &lev, sizeof(lev));
519 savecemetery(fd, mode, &level.bonesinfo);
521 (boolean) ((sfsaveinfo.sfi1 & SFI1_RLECOMP) == SFI1_RLECOMP));
522 bwrite(fd, (genericptr_t) lastseentyp, sizeof(lastseentyp));
523 bwrite(fd, (genericptr_t) &monstermoves, sizeof(monstermoves));
524 bwrite(fd, (genericptr_t) &upstair, sizeof(stairway));
525 bwrite(fd, (genericptr_t) &dnstair, sizeof(stairway));
526 bwrite(fd, (genericptr_t) &upladder, sizeof(stairway));
527 bwrite(fd, (genericptr_t) &dnladder, sizeof(stairway));
528 bwrite(fd, (genericptr_t) &sstairs, sizeof(stairway));
529 bwrite(fd, (genericptr_t) &updest, sizeof(dest_area));
530 bwrite(fd, (genericptr_t) &dndest, sizeof(dest_area));
531 bwrite(fd, (genericptr_t) &level.flags, sizeof(level.flags));
532 bwrite(fd, (genericptr_t) doors, sizeof(doors));
533 save_rooms(fd); /* no dynamic memory to reclaim */
535 /* from here on out, saving also involves allocated memory cleanup */
537 /* this comes before the map, so need cleanup here if we skipped */
538 if (mode == FREE_SAVE)
539 savecemetery(fd, mode, &level.bonesinfo);
540 /* must be saved before mons, objs, and buried objs */
541 save_timers(fd, mode, RANGE_LEVEL);
542 save_light_sources(fd, mode, RANGE_LEVEL);
544 savemonchn(fd, fmon, mode);
545 save_worm(fd, mode); /* save worm information */
546 savetrapchn(fd, ftrap, mode);
547 saveobjchn(fd, fobj, mode);
548 saveobjchn(fd, level.buriedobjlist, mode);
549 saveobjchn(fd, billobjs, mode);
550 if (release_data(mode)) {
554 level.buriedobjlist = 0;
556 /* level.bonesinfo = 0; -- handled by savecemetery() */
558 save_engravings(fd, mode);
559 savedamage(fd, mode);
560 save_regions(fd, mode);
561 if (mode != FREE_SAVE)
566 savelevl(fd, rlecomp)
571 struct rm *prm, *rgrm;
576 /* perform run-length encoding of rm structs */
578 rgrm = &levl[0][0]; /* start matching at first rm */
581 for (y = 0; y < ROWNO; y++) {
582 for (x = 0; x < COLNO; x++) {
584 if (prm->glyph == rgrm->glyph && prm->typ == rgrm->typ
585 && prm->seenv == rgrm->seenv
586 && prm->horizontal == rgrm->horizontal
587 && prm->flags == rgrm->flags && prm->lit == rgrm->lit
588 && prm->waslit == rgrm->waslit
589 && prm->roomno == rgrm->roomno && prm->edge == rgrm->edge
590 && prm->candig == rgrm->candig) {
593 match = 254; /* undo this match */
597 /* the run has been broken,
598 * write out run-length encoding */
600 bwrite(fd, (genericptr_t) &match, sizeof(uchar));
601 bwrite(fd, (genericptr_t) rgrm, sizeof(struct rm));
602 /* start encoding again. we have at least 1 rm
603 * in the next run, viz. this one. */
610 bwrite(fd, (genericptr_t) &match, sizeof(uchar));
611 bwrite(fd, (genericptr_t) rgrm, sizeof(struct rm));
617 #endif /* ?RLECOMP */
618 bwrite(fd, (genericptr_t) levl, sizeof levl);
626 (*saveprocs.save_bufon)(fd);
635 (*saveprocs.save_bufoff)(fd);
639 /* flush run and buffer */
644 (*saveprocs.save_bflush)(fd);
652 register unsigned num;
654 (*saveprocs.save_bwrite)(fd, loc, num);
662 (*saveprocs.save_bclose)(fd);
666 static int bw_fd = -1;
667 static FILE *bw_FILE = 0;
668 static boolean buffering = FALSE;
677 panic("double buffering unexpected");
679 if ((bw_FILE = fdopen(fd, "w")) == 0)
680 panic("buffering of file %d failed", fd);
700 if (fflush(bw_FILE) == EOF)
701 panic("flush of savefile failed!");
708 def_bwrite(fd, loc, num)
710 register genericptr_t loc;
711 register unsigned num;
716 bytes_counted += num;
724 panic("unbuffered write to fd %d (!= %d)", fd, bw_fd);
726 failed = (fwrite(loc, (int) num, 1, bw_FILE) != 1);
730 /* lint wants 3rd arg of write to be an int; lint -p an unsigned */
731 #if defined(BSD) || defined(ULTRIX) || defined(WIN32) || defined(_MSC_VER)
732 failed = ((long) write(fd, loc, (int) num) != (long) num);
733 #else /* e.g. SYSV, __TURBOC__ */
734 failed = ((long) write(fd, loc, num) != (long) num);
739 #if defined(UNIX) || defined(VMS) || defined(__EMX__)
740 if (program_state.done_hup)
741 terminate(EXIT_FAILURE);
744 panic("cannot write %u bytes to file #%d", num, fd);
755 (void) fclose(bw_FILE);
765 /* The runs of zero-run compression are flushed after the game state or a
766 * level is written out. This adds a couple bytes to a save file, where
767 * the runs could be mashed together, but it allows gluing together game
768 * state and level files to form a save file, and it means the flushing
769 * does not need to be specifically called for every other time a level
770 * file is written out.
773 #define RLESC '\0' /* Leading character for run of LRESC's */
774 #define flushoutrun(ln) (zerocomp_bputc(RLESC), zerocomp_bputc(ln), ln = -1)
776 #ifndef ZEROCOMP_BUFSIZ
777 #define ZEROCOMP_BUFSIZ BUFSZ
779 static NEARDATA unsigned char outbuf[ZEROCOMP_BUFSIZ];
780 static NEARDATA unsigned short outbufp = 0;
781 static NEARDATA short outrunlength = -1;
782 static NEARDATA int bwritefd;
783 static NEARDATA boolean compressing = FALSE;
787 HUP printf("outbufp %d outrunlength %d\n", outbufp,outrunlength);
799 if (outbufp >= sizeof outbuf) {
800 (void) write(bwritefd, outbuf, sizeof outbuf);
803 outbuf[outbufp++] = (unsigned char) c;
822 panic("closing file with buffered data still unwritten");
829 /* flush run and buffer */
835 if (outrunlength >= 0) { /* flush run */
836 flushoutrun(outrunlength);
844 if (write(fd, outbuf, outbufp) != outbufp) {
845 #if defined(UNIX) || defined(VMS) || defined(__EMX__)
846 if (program_state.done_hup)
847 terminate(EXIT_FAILURE);
850 zerocomp_bclose(fd); /* panic (outbufp != 0) */
857 zerocomp_bwrite(fd, loc, num)
860 register unsigned num;
862 register unsigned char *bp = (unsigned char *) loc;
866 bytes_counted += num;
870 if ((unsigned) write(fd, loc, num) != num) {
871 #if defined(UNIX) || defined(VMS) || defined(__EMX__)
872 if (program_state.done_hup)
873 terminate(EXIT_FAILURE);
876 panic("cannot write %u bytes to file #%d", num, fd);
880 for (; num; num--, bp++) {
881 if (*bp == RLESC) { /* One more char in run */
882 if (++outrunlength == 0xFF) {
883 flushoutrun(outrunlength);
885 } else { /* end of run */
886 if (outrunlength >= 0) { /* flush run */
887 flushoutrun(outrunlength);
903 #endif /* ZEROCOMP */
907 register int fd, mode;
909 s_level *tmplev, *tmplev2;
912 for (tmplev = sp_levchn; tmplev; tmplev = tmplev->next)
914 if (perform_bwrite(mode))
915 bwrite(fd, (genericptr_t) &cnt, sizeof(int));
917 for (tmplev = sp_levchn; tmplev; tmplev = tmplev2) {
918 tmplev2 = tmplev->next;
919 if (perform_bwrite(mode))
920 bwrite(fd, (genericptr_t) tmplev, sizeof(s_level));
921 if (release_data(mode))
922 free((genericptr_t) tmplev);
924 if (release_data(mode))
928 /* used when saving a level and also when saving dungeon overview data */
930 savecemetery(fd, mode, cemeteryaddr)
933 struct cemetery **cemeteryaddr;
935 struct cemetery *thisbones, *nextbones;
938 flag = *cemeteryaddr ? 0 : -1;
939 if (perform_bwrite(mode))
940 bwrite(fd, (genericptr_t) &flag, sizeof flag);
941 nextbones = *cemeteryaddr;
942 while ((thisbones = nextbones) != 0) {
943 nextbones = thisbones->next;
944 if (perform_bwrite(mode))
945 bwrite(fd, (genericptr_t) thisbones, sizeof *thisbones);
946 if (release_data(mode))
947 free((genericptr_t) thisbones);
949 if (release_data(mode))
955 register int fd, mode;
957 register struct damage *damageptr, *tmp_dam;
960 damageptr = level.damagelist;
961 for (tmp_dam = damageptr; tmp_dam; tmp_dam = tmp_dam->next)
963 if (perform_bwrite(mode))
964 bwrite(fd, (genericptr_t) &xl, sizeof(xl));
967 if (perform_bwrite(mode))
968 bwrite(fd, (genericptr_t) damageptr, sizeof(*damageptr));
970 damageptr = damageptr->next;
971 if (release_data(mode))
972 free((genericptr_t) tmp_dam);
974 if (release_data(mode))
975 level.damagelist = 0;
983 int buflen, zerobuf = 0;
985 buflen = sizeof(struct obj);
986 bwrite(fd, (genericptr_t) &buflen, sizeof(int));
987 bwrite(fd, (genericptr_t) otmp, buflen);
990 buflen = strlen(ONAME(otmp)) + 1;
993 bwrite(fd, (genericptr_t) &buflen, sizeof buflen);
995 bwrite(fd, (genericptr_t) ONAME(otmp), buflen);
997 /* defer to savemon() for this one */
999 savemon(fd, OMONST(otmp));
1001 bwrite(fd, (genericptr_t) &zerobuf, sizeof zerobuf);
1004 buflen = sizeof(unsigned);
1007 bwrite(fd, (genericptr_t) &buflen, sizeof buflen);
1009 bwrite(fd, (genericptr_t) OMID(otmp), buflen);
1012 buflen = sizeof(long);
1015 bwrite(fd, (genericptr_t) &buflen, sizeof buflen);
1017 bwrite(fd, (genericptr_t) OLONG(otmp), buflen);
1020 buflen = strlen(OMAILCMD(otmp)) + 1;
1023 bwrite(fd, (genericptr_t) &buflen, sizeof buflen);
1025 bwrite(fd, (genericptr_t) OMAILCMD(otmp), buflen);
1030 saveobjchn(fd, otmp, mode)
1031 register int fd, mode;
1032 register struct obj *otmp;
1034 register struct obj *otmp2;
1039 if (perform_bwrite(mode)) {
1042 if (Has_contents(otmp))
1043 saveobjchn(fd, otmp->cobj, mode);
1044 if (release_data(mode)) {
1045 /* if (otmp->oclass == FOOD_CLASS)
1046 * food_disappears(otmp);
1049 * If these are on the floor, the discarding could
1050 * be because of a game save, or we could just be changing levels.
1051 * Always invalidate the pointer, but ensure that we have
1052 * the o_id in order to restore the pointer on reload.
1054 if (otmp == context.victual.piece) {
1055 /* Store the o_id of the victual if mismatched */
1056 if (context.victual.o_id != otmp->o_id)
1057 context.victual.o_id = otmp->o_id;
1058 /* invalidate the pointer; on reload it will get restored */
1059 context.victual.piece = (struct obj *) 0;
1061 if (otmp == context.tin.tin) {
1062 /* Store the o_id of your tin */
1063 if (context.tin.o_id != otmp->o_id)
1064 context.tin.o_id = otmp->o_id;
1065 /* invalidate the pointer; on reload it will get restored */
1066 context.tin.tin = (struct obj *) 0;
1068 /* if (otmp->oclass == SPBOOK_CLASS)
1069 * book_disappears(otmp);
1071 if (otmp == context.spbook.book) {
1072 /* Store the o_id of your spellbook */
1073 if (context.spbook.o_id != otmp->o_id)
1074 context.spbook.o_id = otmp->o_id;
1075 /* invalidate the pointer; on reload it will get restored */
1076 context.spbook.book = (struct obj *) 0;
1078 otmp->where = OBJ_FREE; /* set to free so dealloc will work */
1079 otmp->nobj = NULL; /* nobj saved into otmp2 */
1080 otmp->cobj = NULL; /* contents handled above */
1081 otmp->timed = 0; /* not timed any more */
1082 otmp->lamplit = 0; /* caller handled lights */
1087 if (perform_bwrite(mode))
1088 bwrite(fd, (genericptr_t) &minusone, sizeof(int));
1098 buflen = sizeof(struct monst);
1099 bwrite(fd, (genericptr_t) &buflen, sizeof(int));
1100 bwrite(fd, (genericptr_t) mtmp, buflen);
1103 buflen = strlen(MNAME(mtmp)) + 1;
1106 bwrite(fd, (genericptr_t) &buflen, sizeof buflen);
1108 bwrite(fd, (genericptr_t) MNAME(mtmp), buflen);
1111 buflen = sizeof(struct egd);
1114 bwrite(fd, (genericptr_t) &buflen, sizeof(int));
1116 bwrite(fd, (genericptr_t) EGD(mtmp), buflen);
1119 buflen = sizeof(struct epri);
1122 bwrite(fd, (genericptr_t) &buflen, sizeof(int));
1124 bwrite(fd, (genericptr_t) EPRI(mtmp), buflen);
1127 buflen = sizeof(struct eshk);
1130 bwrite(fd, (genericptr_t) &buflen, sizeof(int));
1132 bwrite(fd, (genericptr_t) ESHK(mtmp), buflen);
1135 buflen = sizeof(struct emin);
1138 bwrite(fd, (genericptr_t) &buflen, sizeof(int));
1140 bwrite(fd, (genericptr_t) EMIN(mtmp), buflen);
1143 buflen = sizeof(struct edog);
1146 bwrite(fd, (genericptr_t) &buflen, sizeof(int));
1148 bwrite(fd, (genericptr_t) EDOG(mtmp), buflen);
1150 /* mcorpsenm is inline int rather than pointer to something,
1151 so doesn't need to be preceded by a length field */
1152 bwrite(fd, (genericptr_t) &MCORPSENM(mtmp), sizeof MCORPSENM(mtmp));
1157 savemonchn(fd, mtmp, mode)
1158 register int fd, mode;
1159 register struct monst *mtmp;
1161 register struct monst *mtmp2;
1166 if (perform_bwrite(mode)) {
1167 mtmp->mnum = monsndx(mtmp->data);
1169 forget_temple_entry(mtmp); /* EPRI() */
1173 saveobjchn(fd, mtmp->minvent, mode);
1174 if (release_data(mode)) {
1175 if (mtmp == context.polearm.hitmon) {
1176 context.polearm.m_id = mtmp->m_id;
1177 context.polearm.hitmon = NULL;
1179 mtmp->nmon = NULL; /* nmon saved into mtmp2 */
1180 dealloc_monst(mtmp);
1184 if (perform_bwrite(mode))
1185 bwrite(fd, (genericptr_t) &minusone, sizeof(int));
1189 savetrapchn(fd, trap, mode)
1190 register int fd, mode;
1191 register struct trap *trap;
1193 register struct trap *trap2;
1196 trap2 = trap->ntrap;
1197 if (perform_bwrite(mode))
1198 bwrite(fd, (genericptr_t) trap, sizeof(struct trap));
1199 if (release_data(mode))
1203 if (perform_bwrite(mode))
1204 bwrite(fd, (genericptr_t) nulls, sizeof(struct trap));
1207 /* save all the fruit names and ID's; this is used only in saving whole games
1208 * (not levels) and in saving bones levels. When saving a bones level,
1209 * we only want to save the fruits which exist on the bones level; the bones
1210 * level routine marks nonexistent fruits by making the fid negative.
1213 savefruitchn(fd, mode)
1214 register int fd, mode;
1216 register struct fruit *f2, *f1;
1221 if (f1->fid >= 0 && perform_bwrite(mode))
1222 bwrite(fd, (genericptr_t) f1, sizeof(struct fruit));
1223 if (release_data(mode))
1227 if (perform_bwrite(mode))
1228 bwrite(fd, (genericptr_t) nulls, sizeof(struct fruit));
1229 if (release_data(mode))
1234 store_plname_in_file(fd)
1237 int plsiztmp = PL_NSIZ;
1239 /* bwrite() before bufon() uses plain write() */
1240 bwrite(fd, (genericptr_t) &plsiztmp, sizeof(plsiztmp));
1241 bwrite(fd, (genericptr_t) plname, plsiztmp);
1247 save_msghistory(fd, mode)
1251 int msgcount = 0, msglen;
1253 boolean init = TRUE;
1255 if (perform_bwrite(mode)) {
1256 /* ask window port for each message in sequence */
1257 while ((msg = getmsghistory(init)) != 0) {
1259 msglen = strlen(msg);
1260 /* sanity: truncate if necessary (shouldn't happen);
1261 no need to modify msg[] since terminator isn't written */
1262 if (msglen > BUFSZ - 1)
1264 bwrite(fd, (genericptr_t) &msglen, sizeof(msglen));
1265 bwrite(fd, (genericptr_t) msg, msglen);
1268 bwrite(fd, (genericptr_t) &minusone, sizeof(int));
1270 debugpline1("Stored %d messages into savefile.", msgcount);
1271 /* note: we don't attempt to handle release_data() here */
1275 store_savefileinfo(fd)
1278 /* sfcap (decl.c) describes the savefile feature capabilities
1279 * that are supported by this port/platform build.
1281 * sfsaveinfo (decl.c) describes the savefile info that actually
1282 * gets written into the savefile, and is used to determine the
1283 * save file being written.
1285 * sfrestinfo (decl.c) describes the savefile info that is
1286 * being used to read the information from an existing savefile.
1291 /* bwrite() before bufon() uses plain write() */
1292 bwrite(fd, (genericptr_t) &sfsaveinfo, (unsigned) (sizeof sfsaveinfo));
1298 set_savepref(suitename)
1299 const char *suitename;
1301 if (!strcmpi(suitename, "externalcomp")) {
1302 saveprocs.name = "externalcomp";
1303 saveprocs.save_bufon = def_bufon;
1304 saveprocs.save_bufoff = def_bufoff;
1305 saveprocs.save_bflush = def_bflush;
1306 saveprocs.save_bwrite = def_bwrite;
1307 saveprocs.save_bclose = def_bclose;
1308 sfsaveinfo.sfi1 |= SFI1_EXTERNALCOMP;
1309 sfsaveinfo.sfi1 &= ~SFI1_ZEROCOMP;
1311 if (!strcmpi(suitename, "!rlecomp")) {
1312 sfsaveinfo.sfi1 &= ~SFI1_RLECOMP;
1315 if (!strcmpi(suitename, "zerocomp")) {
1316 saveprocs.name = "zerocomp";
1317 saveprocs.save_bufon = zerocomp_bufon;
1318 saveprocs.save_bufoff = zerocomp_bufoff;
1319 saveprocs.save_bflush = zerocomp_bflush;
1320 saveprocs.save_bwrite = zerocomp_bwrite;
1321 saveprocs.save_bclose = zerocomp_bclose;
1322 sfsaveinfo.sfi1 |= SFI1_ZEROCOMP;
1323 sfsaveinfo.sfi1 &= ~SFI1_EXTERNALCOMP;
1327 if (!strcmpi(suitename, "rlecomp")) {
1328 sfsaveinfo.sfi1 |= SFI1_RLECOMP;
1333 /* also called by prscore(); this probably belongs in dungeon.c... */
1337 #ifdef FREE_ALL_MEMORY
1338 savelevchn(0, FREE_SAVE);
1339 save_dungeon(0, FALSE, TRUE);
1348 free_menu_coloring();
1349 free_invbuf(); /* let_to_name (invent.c) */
1350 free_youbuf(); /* You_buf,&c (pline.c) */
1352 tmp_at(DISP_FREEMEM, 0); /* temporary display effects */
1353 #ifdef FREE_ALL_MEMORY
1354 #define freeobjchn(X) (saveobjchn(0, X, FREE_SAVE), X = 0)
1355 #define freemonchn(X) (savemonchn(0, X, FREE_SAVE), X = 0)
1356 #define freetrapchn(X) (savetrapchn(0, X, FREE_SAVE), X = 0)
1357 #define freefruitchn() savefruitchn(0, FREE_SAVE)
1358 #define freenames() savenames(0, FREE_SAVE)
1359 #define free_killers() save_killers(0, FREE_SAVE)
1360 #define free_oracles() save_oracles(0, FREE_SAVE)
1361 #define free_waterlevel() save_waterlevel(0, FREE_SAVE)
1362 #define free_worm() save_worm(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_engravings() save_engravings(0, FREE_SAVE)
1366 #define freedamage() savedamage(0, FREE_SAVE)
1367 #define free_animals() mon_animal_list(FALSE)
1369 /* move-specific data */
1370 dmonsfree(); /* release dead monsters */
1372 /* level-specific data */
1373 free_timers(RANGE_LEVEL);
1374 free_light_sources(RANGE_LEVEL);
1377 free_worm(); /* release worm segment information */
1380 freeobjchn(level.buriedobjlist);
1381 freeobjchn(billobjs);
1385 /* game-state data */
1387 free_timers(RANGE_GLOBAL);
1388 free_light_sources(RANGE_GLOBAL);
1390 freeobjchn(migrating_objs);
1391 freemonchn(migrating_mons);
1392 freemonchn(mydogs); /* ascension or dungeon escape */
1393 /* freelevchn(); -- [folded into free_dungeons()] */
1401 /* some pointers in iflags */
1402 if (iflags.wc_font_map)
1403 free(iflags.wc_font_map);
1404 if (iflags.wc_font_message)
1405 free(iflags.wc_font_message);
1406 if (iflags.wc_font_text)
1407 free(iflags.wc_font_text);
1408 if (iflags.wc_font_menu)
1409 free(iflags.wc_font_menu);
1410 if (iflags.wc_font_status)
1411 free(iflags.wc_font_status);
1412 if (iflags.wc_tile_file)
1413 free(iflags.wc_tile_file);
1414 free_autopickup_exceptions();
1417 /* free_pickinv_cache(); -- now done from really_done()... */
1419 #endif /* FREE_ALL_MEMORY */
1420 #ifdef STATUS_VIA_WINDOWPORT
1424 /* last, because it frees data that might be used by panic() to provide
1425 feedback to the user; conceivably other freeing might trigger panic */
1426 sysopt_release(); /* SYSCF strings */
1435 char to[PATHLEN], from[PATHLEN];
1437 Sprintf(from, "%s%s", permbones, alllevels);
1438 Sprintf(to, "%s%s", levels, alllevels);
1439 set_levelfile_name(from, lev);
1440 set_levelfile_name(to, lev);
1441 if (iflags.checkspace) {
1442 while (level_info[lev].size > freediskspace(to))
1443 if (!swapout_oldest())
1447 pline("Swapping in `%s'.", from);
1451 (void) unlink(from);
1452 level_info[lev].where = ACTIVE;
1459 char to[PATHLEN], from[PATHLEN];
1465 for (i = 1, oldtime = 0, oldest = 0; i <= maxledgerno(); i++)
1466 if (level_info[i].where == ACTIVE
1467 && (!oldtime || level_info[i].time < oldtime)) {
1469 oldtime = level_info[i].time;
1473 Sprintf(from, "%s%s", levels, alllevels);
1474 Sprintf(to, "%s%s", permbones, alllevels);
1475 set_levelfile_name(from, oldest);
1476 set_levelfile_name(to, oldest);
1478 pline("Swapping out `%s'.", from);
1482 (void) unlink(from);
1483 level_info[oldest].where = SWAPPED;
1492 if (_copyfile(from, to))
1493 panic("Can't copy %s to %s", from, to);
1495 char buf[BUFSIZ]; /* this is system interaction, therefore
1496 * BUFSIZ instead of NetHack's BUFSZ */
1497 int nfrom, nto, fdfrom, fdto;
1499 if ((fdfrom = open(from, O_RDONLY | O_BINARY, FCMASK)) < 0)
1500 panic("Can't copy from %s !?", from);
1501 if ((fdto = open(to, O_WRONLY | O_BINARY | O_CREAT | O_TRUNC, FCMASK)) < 0)
1502 panic("Can't copy to %s", to);
1504 nfrom = read(fdfrom, buf, BUFSIZ);
1505 nto = write(fdto, buf, nfrom);
1507 panic("Copyfile failed!");
1508 } while (nfrom == BUFSIZ);
1509 (void) nhclose(fdfrom);
1510 (void) nhclose(fdto);
1514 /* see comment in bones.c */
1522 #endif /* MFLOPPY */