xref: /openbsd/games/hack/hack.save.c (revision df69c215)
1 /*	$OpenBSD: hack.save.c,v 1.14 2019/06/28 13:32:52 deraadt Exp $	*/
2 
3 /*
4  * Copyright (c) 1985, Stichting Centrum voor Wiskunde en Informatica,
5  * Amsterdam
6  * All rights reserved.
7  *
8  * Redistribution and use in source and binary forms, with or without
9  * modification, are permitted provided that the following conditions are
10  * met:
11  *
12  * - Redistributions of source code must retain the above copyright notice,
13  * this list of conditions and the following disclaimer.
14  *
15  * - Redistributions in binary form must reproduce the above copyright
16  * notice, this list of conditions and the following disclaimer in the
17  * documentation and/or other materials provided with the distribution.
18  *
19  * - Neither the name of the Stichting Centrum voor Wiskunde en
20  * Informatica, nor the names of its contributors may be used to endorse or
21  * promote products derived from this software without specific prior
22  * written permission.
23  *
24  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
25  * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
26  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
27  * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
28  * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
29  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
30  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
31  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
32  * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
33  * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
34  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
35  */
36 
37 /*
38  * Copyright (c) 1982 Jay Fenlason <hack@gnu.org>
39  * All rights reserved.
40  *
41  * Redistribution and use in source and binary forms, with or without
42  * modification, are permitted provided that the following conditions
43  * are met:
44  * 1. Redistributions of source code must retain the above copyright
45  *    notice, this list of conditions and the following disclaimer.
46  * 2. Redistributions in binary form must reproduce the above copyright
47  *    notice, this list of conditions and the following disclaimer in the
48  *    documentation and/or other materials provided with the distribution.
49  * 3. The name of the author may not be used to endorse or promote products
50  *    derived from this software without specific prior written permission.
51  *
52  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
53  * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
54  * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL
55  * THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
56  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
57  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
58  * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
59  * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
60  * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
61  * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
62  */
63 
64 #include <signal.h>
65 #include <stdio.h>
66 #include <stdlib.h>
67 #include <unistd.h>
68 
69 #include "hack.h"
70 
71 extern char genocided[60];	/* defined in Decl.c */
72 extern char fut_geno[60];	/* idem */
73 extern char SAVEF[], nul[];
74 extern char pl_character[PL_CSIZ];
75 
76 static int dosave0(int);
77 
78 int
dosave(void)79 dosave(void)
80 {
81 	if(dosave0(0)) {
82 		settty("Be seeing you ...\n");
83 		exit(0);
84 	}
85 	return(0);
86 }
87 
88 void
hackhangup(int notused)89 hackhangup(int notused)
90 {
91 	(void) dosave0(1);
92 	exit(1);
93 }
94 
95 /* returns 1 if save successful */
96 static int
dosave0(int hu)97 dosave0(int hu)
98 {
99 	int fd, ofd;
100 	int tmp;		/* not register ! */
101 
102 	(void) signal(SIGHUP, SIG_IGN);
103 	(void) signal(SIGINT, SIG_IGN);
104 	if((fd = open(SAVEF, O_CREAT | O_TRUNC | O_WRONLY, FMASK)) == -1) {
105 		if(!hu) pline("Cannot open save file. (Continue or Quit)");
106 		(void) unlink(SAVEF);		/* ab@unido */
107 		return(0);
108 	}
109 	if(flags.moonphase == FULL_MOON)	/* ut-sally!fletcher */
110 		u.uluck--;			/* and unido!ab */
111 	savelev(fd,dlevel);
112 	saveobjchn(fd, invent);
113 	saveobjchn(fd, fcobj);
114 	savemonchn(fd, fallen_down);
115 	tmp = getuid();
116 	bwrite(fd, &tmp, sizeof tmp);
117 	bwrite(fd, &flags, sizeof(struct flag));
118 	bwrite(fd, &dlevel, sizeof dlevel);
119 	bwrite(fd, &maxdlevel, sizeof maxdlevel);
120 	bwrite(fd, &moves, sizeof moves);
121 	bwrite(fd, &u, sizeof(struct you));
122 	if(u.ustuck)
123 		bwrite(fd, &(u.ustuck->m_id), sizeof u.ustuck->m_id);
124 	bwrite(fd, pl_character, sizeof pl_character);
125 	bwrite(fd, genocided, sizeof genocided);
126 	bwrite(fd, fut_geno, sizeof fut_geno);
127 	savenames(fd);
128 	for(tmp = 1; tmp <= maxdlevel; tmp++) {
129 		extern int hackpid;
130 		extern boolean level_exists[];
131 
132 		if(tmp == dlevel || !level_exists[tmp]) continue;
133 		glo(tmp);
134 		if((ofd = open(lock, O_RDONLY)) == -1) {
135 		    if(!hu) pline("Error while saving: cannot read %s.", lock);
136 		    (void) close(fd);
137 		    (void) unlink(SAVEF);
138 		    if(!hu) done("tricked");
139 		    return(0);
140 		}
141 		getlev(ofd, hackpid, tmp);
142 		(void) close(ofd);
143 		bwrite(fd, &tmp, sizeof tmp);		/* level number */
144 		savelev(fd,tmp);			/* actual level */
145 		(void) unlink(lock);
146 	}
147 	(void) close(fd);
148 	glo(dlevel);
149 	(void) unlink(lock);	/* get rid of current level --jgm */
150 	glo(0);
151 	(void) unlink(lock);
152 	return(1);
153 }
154 
155 int
dorecover(int fd)156 dorecover(int fd)
157 {
158 	int nfd;
159 	int tmp;		/* not a register ! */
160 	unsigned mid;		/* idem */
161 	struct obj *otmp;
162 	extern boolean restoring;
163 
164 	restoring = TRUE;
165 	getlev(fd, 0, 0);
166 	invent = restobjchn(fd);
167 	for(otmp = invent; otmp; otmp = otmp->nobj)
168 		if(otmp->owornmask)
169 			setworn(otmp, otmp->owornmask);
170 	fcobj = restobjchn(fd);
171 	fallen_down = restmonchn(fd);
172 	mread(fd, (char *) &tmp, sizeof tmp);
173 	if(tmp != getuid()) {		/* strange ... */
174 		(void) close(fd);
175 		(void) unlink(SAVEF);
176 		puts("Saved game was not yours.");
177 		restoring = FALSE;
178 		return(0);
179 	}
180 	mread(fd, (char *) &flags, sizeof(struct flag));
181 	mread(fd, (char *) &dlevel, sizeof dlevel);
182 	mread(fd, (char *) &maxdlevel, sizeof maxdlevel);
183 	mread(fd, (char *) &moves, sizeof moves);
184 	mread(fd, (char *) &u, sizeof(struct you));
185 	if(u.ustuck)
186 		mread(fd, (char *) &mid, sizeof mid);
187 	mread(fd, (char *) pl_character, sizeof pl_character);
188 	mread(fd, (char *) genocided, sizeof genocided);
189 	mread(fd, (char *) fut_geno, sizeof fut_geno);
190 	restnames(fd);
191 	while(1) {
192 		if(read(fd, (char *) &tmp, sizeof tmp) != sizeof tmp)
193 			break;
194 		getlev(fd, 0, tmp);
195 		glo(tmp);
196 		if((nfd = open(lock, O_CREAT | O_TRUNC | O_WRONLY, FMASK)) == -1)
197 			panic("Cannot open temp file %s!\n", lock);
198 		savelev(nfd,tmp);
199 		(void) close(nfd);
200 	}
201 	(void) lseek(fd, (off_t)0, SEEK_SET);
202 	getlev(fd, 0, 0);
203 	(void) close(fd);
204 	(void) unlink(SAVEF);
205 	if(Punished) {
206 		for(otmp = fobj; otmp; otmp = otmp->nobj)
207 			if(otmp->olet == CHAIN_SYM) goto chainfnd;
208 		panic("Cannot find the iron chain?");
209 	chainfnd:
210 		uchain = otmp;
211 		if(!uball){
212 			for(otmp = fobj; otmp; otmp = otmp->nobj)
213 				if(otmp->olet == BALL_SYM && otmp->spe)
214 					goto ballfnd;
215 			panic("Cannot find the iron ball?");
216 		ballfnd:
217 			uball = otmp;
218 		}
219 	}
220 	if(u.ustuck) {
221 		struct monst *mtmp;
222 
223 		for(mtmp = fmon; mtmp; mtmp = mtmp->nmon)
224 			if(mtmp->m_id == mid) goto monfnd;
225 		panic("Cannot find the monster ustuck.");
226 	monfnd:
227 		u.ustuck = mtmp;
228 	}
229 #ifndef QUEST
230 	setsee();  /* only to recompute seelx etc. - these weren't saved */
231 #endif /* QUEST */
232 	docrt();
233 	restoring = FALSE;
234 	return(1);
235 }
236 
237 struct obj *
restobjchn(int fd)238 restobjchn(int fd)
239 {
240 	struct obj *otmp, *otmp2;
241 	struct obj *first = 0;
242 	int xl;
243 	while(1) {
244 		mread(fd, (char *) &xl, sizeof(xl));
245 		if(xl == -1) break;
246 		otmp = newobj(xl);
247 		if(!first) first = otmp;
248 		else otmp2->nobj = otmp;
249 		mread(fd, (char *) otmp, (unsigned) xl + sizeof(struct obj));
250 		if(!otmp->o_id) otmp->o_id = flags.ident++;
251 		otmp2 = otmp;
252 	}
253 	if(first && otmp2->nobj){
254 		impossible("Restobjchn: error reading objchn.");
255 		otmp2->nobj = 0;
256 	}
257 	return(first);
258 }
259 
260 struct monst *
restmonchn(int fd)261 restmonchn(int fd)
262 {
263 	struct monst *mtmp, *mtmp2;
264 	struct monst *first = 0;
265 	int xl;
266 
267 	struct permonst *monbegin;
268 	long differ;
269 
270 	mread(fd, (char *)&monbegin, sizeof(monbegin));
271 	differ = (char *)(&mons[0]) - (char *)(monbegin);
272 
273 	while(1) {
274 		mread(fd, (char *) &xl, sizeof(xl));
275 		if(xl == -1) break;
276 		mtmp = newmonst(xl);
277 		if(!first) first = mtmp;
278 		else mtmp2->nmon = mtmp;
279 		mread(fd, (char *) mtmp, (unsigned) xl + sizeof(struct monst));
280 		if(!mtmp->m_id)
281 			mtmp->m_id = flags.ident++;
282 		mtmp->data = (struct permonst *)
283 			((char *) mtmp->data + differ);
284 		if(mtmp->minvent)
285 			mtmp->minvent = restobjchn(fd);
286 		mtmp2 = mtmp;
287 	}
288 	if(first && mtmp2->nmon){
289 		impossible("Restmonchn: error reading monchn.");
290 		mtmp2->nmon = 0;
291 	}
292 	return(first);
293 }
294