1 /* SCCS Id: @(#)save.c 3.4 2003/11/14 */
2 /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
3 /* NetHack may be freely redistributed. See license for details. */
12 #if !defined(LSC) && !defined(O_WRONLY) && !defined(AZTEC_C)
18 static int count_only
;
21 /*WAC boolean here to keep track of quit status*/
25 int dotcnt
, dotrow
; /* also used in restore */
29 STATIC_DCL
void bputc(int);
31 STATIC_DCL
void savelevchn(int,int);
32 STATIC_DCL
void savedamage(int,int);
33 STATIC_DCL
void saveobjchn(int,struct obj
*,int);
34 STATIC_DCL
void savemonchn(int,struct monst
*,int);
35 STATIC_DCL
void savetrapchn(int,struct trap
*,int);
36 STATIC_DCL
void savegamestate(int,int);
38 STATIC_DCL
void savelev0(int,XCHAR_P
,int);
39 STATIC_DCL boolean
swapout_oldest(void);
40 STATIC_DCL
void copyfile(char *,char *);
43 static long nulls
[10];
48 #if defined(UNIX) || defined(VMS) || defined(__EMX__) || defined(WIN32)
49 #define HUP if (!program_state.done_hup)
54 #if defined(STATUS_COLORS) && defined(TEXTCOLOR)
55 extern const struct percent_color_option
*hp_colors
;
56 extern const struct percent_color_option
*pw_colors
;
57 extern const struct text_color_option
*text_colors
;
61 extern struct menucoloring
*menu_colorings
;
64 /* need to preserve these during save to avoid accessing freed memory */
65 static unsigned ustuck_id
= 0, usteed_id
= 0;
75 if (iflags
.debug_fuzzer
) return 0;
77 clear_nhwindow(WIN_MESSAGE
);
78 if(yn("Really save?") == 'n') {
79 clear_nhwindow(WIN_MESSAGE
);
80 if(multi
> 0) nomul(0, 0, FALSE
);
82 clear_nhwindow(WIN_MESSAGE
);
85 #if defined(UNIX) || defined(VMS) || defined(__EMX__)
86 program_state
.done_hup
= 0;
90 if (flags
.keep_savefile
)
91 if(yn("Really quit?") == 'n') saverestore
= TRUE
;
92 if(dosave0() && !saverestore
) {
96 program_state
.something_worth_saving
= 0;
97 u
.uhp
= -1; /* universal game's over indicator */
98 /* make sure they see the Saving message */
99 display_nhwindow(WIN_MESSAGE
, TRUE
);
100 exit_nhwindows("Be seeing you...");
101 terminate(EXIT_SUCCESS
);
104 else (void)doredraw();*/
108 /*WAC pulled this from pcmain.c - restore game from the file just saved*/
109 fd
= create_levelfile(0);
111 raw_print("Cannot create lock file");
114 write(fd
, (void *) &hackpid
, sizeof(hackpid
));
118 level_info
[0].where
= ACTIVE
;
121 fd
= restore_saved_game();
122 if (fd
>= 0) dorecover(fd
);
123 check_special_room(FALSE
);
125 /*WAC correct these after restore*/
126 if(flags
.moonphase
== FULL_MOON
)
128 if(flags
.moonphase
== NEW_MOON
)
129 u
.ualign
.record
+= 3;
130 if (u
.ualign
.record
> u
.alignlim
) u
.ualign
.record
= u
.alignlim
;
133 u
.ualign
.record
+= 10;
134 if (u
.ualign
.record
> u
.alignlim
) u
.ualign
.record
= u
.alignlim
;
136 if(iflags
.window_inited
)
137 clear_nhwindow(WIN_MESSAGE
);
147 /* returns 1 if save successful */
152 register int fd
, ofd
;
159 fq_save
= fqname(SAVEF
, SAVEPREFIX
, 1); /* level files take 0 */
162 #if defined(UNIX) || defined(VMS)
163 sethanguphandler((void (*)(int) ) SIG_IGN
);
165 (void) signal(SIGINT
, SIG_IGN
);
168 #if defined(MICRO) && defined(MFLOPPY)
169 if (!saveDiskPrompt(0)) return 0;
172 HUP
if (iflags
.window_inited
) {
173 uncompress_area(fq_save
, SAVEF
);
174 fd
= open_savefile();
177 clear_nhwindow(WIN_MESSAGE
);
178 There("seems to be an old save file.");
179 if (yn("Overwrite the old file?") == 'n') {
180 compress_area(fq_save
, SAVEF
);
182 /*WAC don't restore if you didn't save*/
190 HUP
mark_synch(); /* flush any buffered screen output */
192 fd
= create_savefile();
194 HUP
pline("Cannot open save file.");
195 (void) delete_savefile(); /* ab@unido */
203 vision_recalc(2); /* shut down vision to prevent problems
204 in the event of an impossible() call */
206 /* undo date-dependent luck adjustments made at startup time */
207 if(flags
.moonphase
== FULL_MOON
) /* ut-sally!fletcher */
208 change_luck(-1); /* and unido!ab */
209 if(flags
.moonphase
== NEW_MOON
) /* ut-sally!fletcher */
210 u
.ualign
.record
+= 3;
211 if (u
.ualign
.record
> u
.alignlim
) u
.ualign
.record
= u
.alignlim
;
214 u
.ualign
.record
+= 10;
215 if (u
.ualign
.record
> u
.alignlim
) u
.ualign
.record
= u
.alignlim
;
217 if(iflags
.window_inited
)
218 HUP
clear_nhwindow(WIN_MESSAGE
);
220 #if defined(MICRO) && defined(TTY_GRAPHICS)
221 if (!strncmpi("tty", windowprocs
.name
, 3)) {
225 putstr(WIN_MAP
, 0, "Saving:");
229 /* make sure there is enough disk space */
230 if (iflags
.checkspace
) {
233 savelev(fd
, ledger_no(&u
.uz
), COUNT_SAVE
);
234 savegamestate(fd
, COUNT_SAVE
);
235 needed
= bytes_counted
;
237 for (ltmp
= 1; ltmp
<= maxledgerno(); ltmp
++)
238 if (ltmp
!= ledger_no(&u
.uz
) && level_info
[ltmp
].where
)
239 needed
+= level_info
[ltmp
].size
+ (sizeof ltmp
);
240 fds
= freediskspace(fq_save
);
243 There("is insufficient space on SAVE disk.");
244 pline("Require %ld bytes but only have %ld.", needed
, fds
);
248 (void) delete_savefile();
256 if (u
.hangupcheat
< 2) u
.hangupcheat
= 0;
259 #ifdef STORE_PLNAME_IN_FILE
260 bwrite(fd
, (void *) plname
, PL_NSIZ
);
261 bwrite(fd
, (void *) plalias
, PL_NSIZ
);
263 ustuck_id
= (u
.ustuck
? u
.ustuck
->m_id
: 0);
264 usteed_id
= (u
.usteed
? u
.usteed
->m_id
: 0);
266 savelev(fd
, ledger_no(&u
.uz
), WRITE_SAVE
| FREE_SAVE
);
267 /*Keep things from beeing freed if not restoring*/
270 if (saverestore) savegamestate(fd, WRITE_SAVE);
274 savegamestate(fd
, WRITE_SAVE
| FREE_SAVE
);
276 /* While copying level files around, zero out u.uz to keep
277 * parts of the restore code from completely initializing all
278 * in-core data structures, since all we're doing is copying.
279 * This also avoids at least one nasty core dump.
282 u
.uz
.dnum
= u
.uz
.dlevel
= 0;
283 /* these pointers are no longer valid, and at least u.usteed
284 * may mislead place_monster() on other levels
286 setustuck((struct monst
*)0);
287 u
.usteed
= (struct monst
*)0;
289 for(ltmp
= (xchar
)1; ltmp
<= maxledgerno(); ltmp
++) {
290 if (ltmp
== ledger_no(&uz_save
)) continue;
291 if (!(level_info
[ltmp
].flags
& LFILE_EXISTS
)) continue;
292 #if defined(MICRO) && defined(TTY_GRAPHICS)
293 curs(WIN_MAP
, 1 + dotcnt
++, dotrow
);
294 if (dotcnt
>= (COLNO
- 1)) {
298 putstr(WIN_MAP
, 0, ".");
301 ofd
= open_levelfile(ltmp
, whynot
);
303 HUP
pline("%s", whynot
);
305 /*(void) delete_savefile();
308 pline("Something is wrong here. This would have been a trickery, but I'm not that cruel. --Amy");
311 minit(); /* ZEROCOMP */
312 getlev(ofd
, hackpid
, ltmp
, FALSE
);
314 bwrite(fd
, (void *) <mp
, sizeof ltmp
); /* level number*/
315 savelev(fd
, ltmp
, WRITE_SAVE
| FREE_SAVE
); /* actual level*/
316 delete_levelfile(ltmp
);
322 /* get rid of current level --jgm */
324 delete_levelfile(ledger_no(&u
.uz
));
329 compress_area(FILE_AREA_SAVE
, fq_save
);
333 #ifndef HANGUPHANDLING
335 #if defined(UNIX) || defined(VMS) || defined (__EMX__) || defined(WIN32)
338 hangup(sig_unused
) /* called as signal() handler, so sent at least one arg */
341 # ifdef NOSAVEONHANGUP
342 (void) signal(SIGINT
, SIG_IGN
);
345 terminate(EXIT_FAILURE
);
347 # else /* SAVEONHANGUP */
348 if (!program_state
.done_hup
++) {
349 if (program_state
.something_worth_saving
) {
353 u
.hanguppenalty
+= 10; /* unfortunately we can't determine if you hanged up during a prompt! --Amy */
354 if (multi
) u
.hangupparalysis
+= abs(multi
);
355 if (u
.hangupparalysis
> 5) u
.hangupparalysis
= 5; /* sanity check */
362 /* don't call exit when already within an exit handler;
363 that would cancel any other pending user-mode handlers */
364 if (!program_state
.exiting
)
368 terminate(EXIT_FAILURE
);
376 #endif /* HANGUPHANDLING */
379 savegamestate(fd
, mode
)
380 register int fd
, mode
;
383 struct obj
* bc_objs
= (struct obj
*)0;
384 #if defined(RECORD_REALTIME) || defined(REALTIME_ON_BOTL)
389 count_only
= (mode
& COUNT_SAVE
);
392 bwrite(fd
, (void *) &uid
, sizeof uid
);
393 bwrite(fd
, (void *) &flags
, sizeof(struct flag
));
394 bwrite(fd
, (void *) &u
, sizeof(struct you
));
396 /* save random monsters*/
399 int monstcursor
= PM_PLAYERMON
+ 1;
400 while (monstcursor
< NUMMONS
) {
401 bwrite(fd
, (void *) &mons
[monstcursor
], sizeof(struct permonst
));
406 /* must come before migrating_objs and migrating_mons are freed */
407 save_timers(fd
, mode
, RANGE_GLOBAL
);
408 save_light_sources(fd
, mode
, RANGE_GLOBAL
);
411 uchain
->nobj
= bc_objs
;
415 uball
->nobj
= bc_objs
;
418 saveobjchn(fd
, invent
, mode
);
419 saveobjchn(fd
, bc_objs
, mode
);
420 saveobjchn(fd
, migrating_objs
, mode
);
421 savemonchn(fd
, migrating_mons
, mode
);
422 if (release_data(mode
)) {
427 bwrite(fd
, (void *) mvitals
, sizeof(mvitals
));
429 save_dungeon(fd
, (boolean
)!!perform_bwrite(mode
),
430 (boolean
)!!release_data(mode
));
431 savelevchn(fd
, mode
);
432 bwrite(fd
, (void *) &moves
, sizeof moves
);
433 bwrite(fd
, (void *) &monstermoves
, sizeof monstermoves
);
434 bwrite(fd
, (void *) &quest_status
, sizeof(struct q_score
));
435 bwrite(fd
, (void *) spl_book
,
436 sizeof(struct spell
) * (MAXSPELL
+ 1));
437 bwrite(fd
, (void *) tech_list
,
438 sizeof(struct tech
) * (MAXTECH
+ 1));
439 save_oracles(fd
, mode
);
441 bwrite(fd
, (void *) &ustuck_id
, sizeof ustuck_id
);
443 bwrite(fd
, (void *) &usteed_id
, sizeof usteed_id
);
444 bwrite(fd
, (void *) pl_character
, sizeof pl_character
);
445 bwrite(fd
, (void *) pl_fruit
, sizeof pl_fruit
);
446 bwrite(fd
, (void *) ¤t_fruit
, sizeof current_fruit
);
447 savefruitchn(fd
, mode
);
450 save_waterlevel(fd
, mode
);
451 #ifdef RECORD_ACHIEVE
452 bwrite(fd
, (void *) &achieve
, sizeof achieve
);
453 bwrite(fd
, (void *) &achieveX
, sizeof achieveX
);
455 #if defined(RECORD_REALTIME) || defined(REALTIME_ON_BOTL)
456 realtime
= get_realtime();
457 bwrite(fd
, (void *) &realtime
, sizeof realtime
);
468 static boolean havestate
= TRUE
;
471 /* When checkpointing is on, the full state needs to be written
472 * on each checkpoint. When checkpointing is off, only the pid
473 * needs to be in the level.0 file, so it does not need to be
474 * constantly rewritten. When checkpointing is turned off during
475 * a game, however, the file has to be rewritten once to truncate
476 * it and avoid restoring from outdated information.
478 * Restricting havestate to this routine means that an additional
479 * noop pid rewriting will take place on the first "checkpoint" after
480 * the game is started or restored, if checkpointing is off.
482 if (flags
.ins_chkpt
|| havestate
) {
483 /* save the rest of the current game state in the lock file,
484 * following the original int pid, the current level number,
485 * and the current savefile name, which should not be subject
486 * to any internal compression schemes since they must be
487 * readable by an external utility
489 fd
= open_levelfile(0, whynot
);
492 pline("Probably someone removed it.");
498 (void) read(fd
, (void *) &hpid
, sizeof(hpid
));
499 if (hackpid
!= hpid
) {
501 "Level #0 pid (%d) doesn't match ours (%d)!",
509 fd
= create_levelfile(0, whynot
);
516 (void) write(fd
, (void *) &hackpid
, sizeof(hackpid
));
517 if (flags
.ins_chkpt
) {
518 int currlev
= ledger_no(&u
.uz
);
520 (void) write(fd
, (void *) &currlev
, sizeof(currlev
));
521 save_savefile_name(fd
);
523 #ifdef STORE_PLNAME_IN_FILE
524 bwrite(fd
, (void *) plname
, PL_NSIZ
);
525 bwrite(fd
, (void *) plalias
, PL_NSIZ
);
527 ustuck_id
= (u
.ustuck
? u
.ustuck
->m_id
: 0);
528 usteed_id
= (u
.usteed
? u
.usteed
->m_id
: 0);
529 savegamestate(fd
, WRITE_SAVE
);
533 havestate
= flags
.ins_chkpt
;
539 savelev(fd
, lev
, mode
)
544 if (mode
& COUNT_SAVE
) {
546 savelev0(fd
, lev
, COUNT_SAVE
);
547 /* probably bytes_counted will be filled in again by an
548 * immediately following WRITE_SAVE anyway, but we'll
549 * leave it out of checkspace just in case */
550 if (iflags
.checkspace
) {
551 while (bytes_counted
> freediskspace(levels
))
552 if (!swapout_oldest())
556 if (mode
& (WRITE_SAVE
| FREE_SAVE
)) {
558 savelev0(fd
, lev
, mode
);
560 if (mode
!= FREE_SAVE
) {
561 level_info
[lev
].where
= ACTIVE
;
562 level_info
[lev
].time
= moves
;
563 level_info
[lev
].size
= bytes_counted
;
569 savelev0(fd
,lev
,mode
)
582 /* if we're tearing down the current level without saving anything
583 (which happens upon entrance to the endgame or after an aborted
584 restore attempt) then we don't want to do any actual I/O */
585 if (mode
== FREE_SAVE
) goto skip_lots
;
586 if (iflags
.purge_monsters
) {
587 /* purge any dead monsters (necessary if we're starting
588 * a panic save rather than a normal one, or sometimes
589 * when changing levels without taking time -- e.g.
590 * create statue trap then immediately level teleport) */
594 if(fd
< 0) panic("Save on bad file!"); /* impossible */
596 count_only
= (mode
& COUNT_SAVE
);
598 if (lev
>= 0 && lev
<= maxledgerno())
599 level_info
[lev
].flags
|= VISITED
;
600 bwrite(fd
,(void *) &hackpid
,sizeof(hackpid
));
602 tlev
=lev
; tlev
&= 0x00ff;
603 bwrite(fd
,(void *) &tlev
,sizeof(tlev
));
605 bwrite(fd
,(void *) &lev
,sizeof(lev
));
609 /* perform run-length encoding of rm structs */
610 struct rm
*prm
, *rgrm
;
614 rgrm
= &levl
[0][0]; /* start matching at first rm */
617 for (y
= 0; y
< ROWNO
; y
++) {
618 for (x
= 0; x
< COLNO
; x
++) {
620 #ifdef DISPLAY_LAYERS
621 if (prm
->mem_bg
== rgrm
->mem_bg
622 && prm
->mem_trap
== rgrm
->mem_trap
623 && prm
->mem_obj
== rgrm
->mem_obj
624 && prm
->mem_corpse
== rgrm
->mem_corpse
625 && prm
->mem_invis
== rgrm
->mem_invis
627 if (prm
->glyph
== rgrm
->glyph
629 && prm
->typ
== rgrm
->typ
630 && prm
->seenv
== rgrm
->seenv
631 && prm
->horizontal
== rgrm
->horizontal
632 && prm
->flags
== rgrm
->flags
633 && prm
->lit
== rgrm
->lit
634 && prm
->waslit
== rgrm
->waslit
635 && prm
->roomno
== rgrm
->roomno
636 && prm
->edge
== rgrm
->edge
) {
639 match
= 254; /* undo this match */
643 /* the run has been broken,
644 * write out run-length encoding */
646 bwrite(fd
, (void *)&match
, sizeof(uchar
));
647 bwrite(fd
, (void *)rgrm
, sizeof(struct rm
));
648 /* start encoding again. we have at least 1 rm
649 * in the next run, viz. this one. */
656 bwrite(fd
, (void *)&match
, sizeof(uchar
));
657 bwrite(fd
, (void *)rgrm
, sizeof(struct rm
));
661 bwrite(fd
,(void *) levl
,sizeof(levl
));
664 bwrite(fd
,(void *) &monstermoves
,sizeof(monstermoves
));
665 bwrite(fd
,(void *) &upstair
,sizeof(stairway
));
666 bwrite(fd
,(void *) &dnstair
,sizeof(stairway
));
667 bwrite(fd
,(void *) &upladder
,sizeof(stairway
));
668 bwrite(fd
,(void *) &dnladder
,sizeof(stairway
));
669 bwrite(fd
,(void *) &sstairs
,sizeof(stairway
));
670 bwrite(fd
,(void *) &updest
,sizeof(dest_area
));
671 bwrite(fd
,(void *) &dndest
,sizeof(dest_area
));
672 bwrite(fd
,(void *) &level
.flags
,sizeof(level
.flags
));
673 bwrite(fd
, (void *) doors
, sizeof(doors
));
674 save_rooms(fd
); /* no dynamic memory to reclaim */
676 /* from here on out, saving also involves allocated memory cleanup */
678 /* must be saved before mons, objs, and buried objs */
679 save_timers(fd
, mode
, RANGE_LEVEL
);
680 save_light_sources(fd
, mode
, RANGE_LEVEL
);
682 savemonchn(fd
, fmon
, mode
);
683 save_worm(fd
, mode
); /* save worm information */
684 savetrapchn(fd
, ftrap
, mode
);
685 saveobjchn(fd
, fobj
, mode
);
686 saveobjchn(fd
, level
.buriedobjlist
, mode
);
687 saveobjchn(fd
, billobjs
, mode
);
688 if (release_data(mode
)) {
692 level
.buriedobjlist
= 0;
695 save_engravings(fd
, mode
);
696 savedamage(fd
, mode
);
697 save_regions(fd
, mode
);
698 if (mode
!= FREE_SAVE
) bflush(fd
);
702 /* The runs of zero-run compression are flushed after the game state or a
703 * level is written out. This adds a couple bytes to a save file, where
704 * the runs could be mashed together, but it allows gluing together game
705 * state and level files to form a save file, and it means the flushing
706 * does not need to be specifically called for every other time a level
707 * file is written out.
710 #define RLESC '\0' /* Leading character for run of LRESC's */
711 #define flushoutrun(ln) (bputc(RLESC), bputc(ln), ln = -1)
713 #ifndef ZEROCOMP_BUFSIZ
714 # define ZEROCOMP_BUFSIZ BUFSZ
716 static NEARDATA
unsigned char outbuf
[ZEROCOMP_BUFSIZ
];
717 static NEARDATA
unsigned short outbufp
= 0;
718 static NEARDATA
short outrunlength
= -1;
719 static NEARDATA
int bwritefd
;
720 static NEARDATA boolean compressing
= FALSE
;
724 HUP printf("outbufp %d outrunlength %d\n", outbufp,outrunlength);
736 if (outbufp
>= sizeof outbuf
) {
737 (void) write(bwritefd
, outbuf
, sizeof outbuf
);
740 outbuf
[outbufp
++] = (unsigned char)c
;
759 panic("closing file with buffered data still unwritten");
767 bflush(fd
) /* flush run and buffer */
771 if (outrunlength
>= 0) { /* flush run */
772 flushoutrun(outrunlength
);
775 if (count_only
) outbufp
= 0;
779 if (write(fd
, outbuf
, outbufp
) != outbufp
) {
780 #if defined(UNIX) || defined(VMS) || defined(__EMX__)
781 if (program_state
.done_hup
)
782 terminate(EXIT_FAILURE
);
785 bclose(fd
); /* panic (outbufp != 0) */
795 register unsigned num
;
797 register unsigned char *bp
= (unsigned char *)loc
;
801 bytes_counted
+= num
;
802 if (count_only
) return;
804 if ((unsigned) write(fd
, loc
, num
) != num
) {
805 #if defined(UNIX) || defined(VMS) || defined(__EMX__)
806 if (program_state
.done_hup
)
807 terminate(EXIT_FAILURE
);
810 panic("cannot write %u bytes to file #%d", num
, fd
);
814 for (; num
; num
--, bp
++) {
815 if (*bp
== RLESC
) { /* One more char in run */
816 if (++outrunlength
== 0xFF) {
817 flushoutrun(outrunlength
);
819 } else { /* end of run */
820 if (outrunlength
>= 0) { /* flush run */
821 flushoutrun(outrunlength
);
840 static int bw_fd
= -1;
841 static FILE *bw_FILE
= 0;
842 static boolean buffering
= FALSE
;
850 panic("double buffering unexpected");
852 if((bw_FILE
= fdopen(fd
, "w")) == 0)
853 panic("buffering of file %d failed", fd
);
872 if(fflush(bw_FILE
) == EOF
)
873 panic("flush of savefile failed!");
883 register unsigned num
;
888 bytes_counted
+= num
;
889 if (count_only
) return;
895 panic("unbuffered write to fd %d (!= %d)", fd
, bw_fd
);
897 failed
= (fwrite(loc
, (int)num
, 1, bw_FILE
) != 1);
901 /* lint wants the 3rd arg of write to be an int; lint -p an unsigned */
902 #if defined(BSD) || defined(ULTRIX)
903 failed
= (write(fd
, loc
, (int)num
) != (int)num
);
904 #else /* e.g. SYSV, __TURBOC__ */
905 failed
= (write(fd
, loc
, num
) != num
);
910 #if defined(UNIX) || defined(VMS) || defined(__EMX__)
911 if (program_state
.done_hup
)
912 terminate(EXIT_FAILURE
);
915 panic("cannot write %u bytes to file #%d", num
, fd
);
926 (void) fclose(bw_FILE
);
934 #endif /* ZEROCOMP */
938 register int fd
, mode
;
940 s_level
*tmplev
, *tmplev2
;
943 for (tmplev
= sp_levchn
; tmplev
; tmplev
= tmplev
->next
) cnt
++;
944 if (perform_bwrite(mode
))
945 bwrite(fd
, (void *) &cnt
, sizeof(int));
947 for (tmplev
= sp_levchn
; tmplev
; tmplev
= tmplev2
) {
948 tmplev2
= tmplev
->next
;
949 if (perform_bwrite(mode
))
950 bwrite(fd
, (void *) tmplev
, sizeof(s_level
));
951 if (release_data(mode
))
952 free((void *) tmplev
);
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
, (void *) &xl
, sizeof(xl
));
972 if (perform_bwrite(mode
))
973 bwrite(fd
, (void *) damageptr
, sizeof(*damageptr
));
975 damageptr
= damageptr
->next
;
976 if (release_data(mode
))
977 free((void *)tmp_dam
);
979 if (release_data(mode
))
980 level
.damagelist
= 0;
984 saveobjchn(fd
, otmp
, mode
)
985 register int fd
, mode
;
986 register struct obj
*otmp
;
988 register struct obj
*otmp2
;
994 if (perform_bwrite(mode
)) {
995 xl
= otmp
->oxlth
+ otmp
->onamelth
;
996 bwrite(fd
, (void *) &xl
, sizeof(int));
997 bwrite(fd
, (void *) otmp
, xl
+ sizeof(struct obj
));
999 if (Has_contents(otmp
))
1000 saveobjchn(fd
,otmp
->cobj
,mode
);
1001 if (release_data(mode
)) {
1002 if (otmp
->oclass
== FOOD_CLASS
) food_disappears(otmp
);
1003 if (otmp
->oclass
== SPBOOK_CLASS
) book_disappears(otmp
);
1004 otmp
->where
= OBJ_FREE
; /* set to free so dealloc will work */
1005 otmp
->timed
= 0; /* not timed any more */
1006 otmp
->lamplit
= 0; /* caller handled lights */
1011 if (perform_bwrite(mode
))
1012 bwrite(fd
, (void *) &minusone
, sizeof(int));
1016 savemonchn(fd
, mtmp
, mode
)
1017 register int fd
, mode
;
1018 register struct monst
*mtmp
;
1020 register struct monst
*mtmp2
;
1023 struct permonst
*monbegin
= &mons
[0];
1025 if (perform_bwrite(mode
))
1026 bwrite(fd
, (void *) &monbegin
, sizeof(monbegin
));
1031 if (perform_bwrite(mode
)) {
1032 xl
= mtmp
->mxlth
+ mtmp
->mnamelth
;
1033 bwrite(fd
, (void *) &xl
, sizeof(int));
1034 bwrite(fd
, (void *) mtmp
, xl
+ sizeof(struct monst
));
1037 saveobjchn(fd
,mtmp
->minvent
,mode
);
1038 if (release_data(mode
))
1039 dealloc_monst(mtmp
);
1042 if (perform_bwrite(mode
))
1043 bwrite(fd
, (void *) &minusone
, sizeof(int));
1047 savetrapchn(fd
, trap
, mode
)
1048 register int fd
, mode
;
1049 register struct trap
*trap
;
1051 register struct trap
*trap2
;
1052 static struct trap zerotrap
;
1055 trap2
= trap
->ntrap
;
1056 if (perform_bwrite(mode
))
1057 bwrite(fd
, (void *) trap
, sizeof(struct trap
));
1058 if (release_data(mode
))
1062 if (perform_bwrite(mode
))
1063 bwrite(fd
, (void *) &zerotrap
, sizeof(struct trap
));
1066 /* save all the fruit names and ID's; this is used only in saving whole games
1067 * (not levels) and in saving bones levels. When saving a bones level,
1068 * we only want to save the fruits which exist on the bones level; the bones
1069 * level routine marks nonexistent fruits by making the fid negative.
1072 savefruitchn(fd
, mode
)
1073 register int fd
, mode
;
1075 register struct fruit
*f2
, *f1
;
1076 static struct fruit zerofruit
;
1081 if (f1
->fid
>= 0 && perform_bwrite(mode
))
1082 bwrite(fd
, (void *) f1
, sizeof(struct fruit
));
1083 if (release_data(mode
))
1087 if (perform_bwrite(mode
))
1088 bwrite(fd
, (void *) &zerofruit
, sizeof(struct fruit
));
1089 if (release_data(mode
))
1093 #if defined(STATUS_COLORS) && defined(TEXTCOLOR)
1096 free_percent_color_options(list_head
)
1097 const struct percent_color_option
*list_head
;
1099 if (list_head
== NULL
) return;
1100 free_percent_color_options(list_head
->next
);
1105 free_text_color_options(list_head
)
1106 const struct text_color_option
*list_head
;
1108 if (list_head
== NULL
) return;
1109 free_text_color_options(list_head
->next
);
1110 free(list_head
->text
);
1115 free_status_colors()
1117 free_percent_color_options(hp_colors
); hp_colors
= NULL
;
1118 free_percent_color_options(pw_colors
); pw_colors
= NULL
;
1119 free_text_color_options(text_colors
); text_colors
= NULL
;
1123 /* also called by prscore(); this probably belongs in dungeon.c... */
1125 * [ALI] Also called by init_dungeons() for the sake of the GTK interface
1126 * and the display_score callback of the proxy interface. For this purpose,
1127 * the previous dungeon must be discarded.
1132 #if defined(FREE_ALL_MEMORY) || defined(GTK_GRAPHICS) || defined(PROXY_GRAPHICS)
1133 savelevchn(0, FREE_SAVE
);
1134 save_dungeon(0, FALSE
, TRUE
);
1141 free_menu_coloring()
1143 struct menucoloring
*tmp
= menu_colorings
;
1146 struct menucoloring
*tmp2
= tmp
->next
;
1147 #ifdef USE_REGEX_MATCH
1148 (void) regfree(&tmp
->match
);
1162 #if defined(STATUS_COLORS) && defined(TEXTCOLOR)
1163 free_status_colors();
1166 free_invbuf(); /* let_to_name (invent.c) */
1167 free_youbuf(); /* You_buf,&c (pline.c) */
1170 free_menu_coloring();
1172 tmp_at(DISP_FREEMEM
, 0); /* temporary display effects */
1173 #ifdef FREE_ALL_MEMORY
1174 # define freeobjchn(X) (saveobjchn(0, X, FREE_SAVE), X = 0)
1175 # define freemonchn(X) (savemonchn(0, X, FREE_SAVE), X = 0)
1176 # define freetrapchn(X) (savetrapchn(0, X, FREE_SAVE), X = 0)
1177 # define freefruitchn() savefruitchn(0, FREE_SAVE)
1178 # define freenames() savenames(0, FREE_SAVE)
1179 # define free_oracles() save_oracles(0, FREE_SAVE)
1180 # define free_waterlevel() save_waterlevel(0, FREE_SAVE)
1181 # define free_worm() save_worm(0, FREE_SAVE)
1182 # define free_timers(R) save_timers(0, FREE_SAVE, R)
1183 # define free_light_sources(R) save_light_sources(0, FREE_SAVE, R);
1184 # define free_engravings() save_engravings(0, FREE_SAVE)
1185 # define freedamage() savedamage(0, FREE_SAVE)
1186 # define free_animals() mon_animal_list(FALSE)
1188 /* move-specific data */
1189 dmonsfree(); /* release dead monsters */
1191 /* level-specific data */
1192 free_timers(RANGE_LEVEL
);
1193 free_light_sources(RANGE_LEVEL
);
1195 free_worm(); /* release worm segment information */
1198 freeobjchn(level
.buriedobjlist
);
1199 freeobjchn(billobjs
);
1203 /* game-state data */
1204 free_timers(RANGE_GLOBAL
);
1205 free_light_sources(RANGE_GLOBAL
);
1207 freeobjchn(migrating_objs
);
1208 freemonchn(migrating_mons
);
1209 freemonchn(mydogs
); /* ascension or dungeon escape */
1210 /* freelevchn(); [folded into free_dungeons()] */
1218 /* some pointers in iflags */
1219 if (iflags
.wc_font_map
) free(iflags
.wc_font_map
);
1220 if (iflags
.wc_font_message
) free(iflags
.wc_font_message
);
1221 if (iflags
.wc_font_text
) free(iflags
.wc_font_text
);
1222 if (iflags
.wc_font_menu
) free(iflags
.wc_font_menu
);
1223 if (iflags
.wc_font_status
) free(iflags
.wc_font_status
);
1224 if (iflags
.wc_tile_file
) free(iflags
.wc_tile_file
);
1225 #ifdef AUTOPICKUP_EXCEPTIONS
1226 free_autopickup_exceptions();
1229 #endif /* FREE_ALL_MEMORY */
1238 char to
[PATHLEN
], from
[PATHLEN
];
1240 sprintf(from
, "%s%s", permbones
, alllevels
);
1241 sprintf(to
, "%s%s", levels
, alllevels
);
1242 set_levelfile_name(from
, lev
);
1243 set_levelfile_name(to
, lev
);
1244 if (iflags
.checkspace
) {
1245 while (level_info
[lev
].size
> freediskspace(to
))
1246 if (!swapout_oldest())
1251 pline("Swapping in `%s'.", from
);
1256 (void) unlink(from
);
1257 level_info
[lev
].where
= ACTIVE
;
1263 char to
[PATHLEN
], from
[PATHLEN
];
1269 for (i
= 1, oldtime
= 0, oldest
= 0; i
<= maxledgerno(); i
++)
1270 if (level_info
[i
].where
== ACTIVE
1271 && (!oldtime
|| level_info
[i
].time
< oldtime
)) {
1273 oldtime
= level_info
[i
].time
;
1277 sprintf(from
, "%s%s", levels
, alllevels
);
1278 sprintf(to
, "%s%s", permbones
, alllevels
);
1279 set_levelfile_name(from
, oldest
);
1280 set_levelfile_name(to
, oldest
);
1283 pline("Swapping out `%s'.", from
);
1288 (void) unlink(from
);
1289 level_info
[oldest
].where
= SWAPPED
;
1299 if (_copyfile(from
, to
))
1300 panic("Can't copy %s to %s", from
, to
);
1302 char buf
[BUFSIZ
]; /* this is system interaction, therefore
1303 * BUFSIZ instead of NetHack's BUFSZ */
1304 int nfrom
, nto
, fdfrom
, fdto
;
1306 if ((fdfrom
= open(from
, O_RDONLY
| O_BINARY
, FCMASK
)) < 0)
1307 panic("Can't copy from %s !?", from
);
1308 if ((fdto
= open(to
, O_WRONLY
| O_BINARY
| O_CREAT
| O_TRUNC
, FCMASK
)) < 0)
1309 panic("Can't copy to %s", to
);
1311 nfrom
= read(fdfrom
, buf
, BUFSIZ
);
1312 nto
= write(fdto
, buf
, nfrom
);
1314 panic("Copyfile failed!");
1315 } while (nfrom
== BUFSIZ
);
1316 (void) close(fdfrom
);
1322 co_false() /* see comment in bones.c */
1328 #endif /* MFLOPPY */