1/*	$OpenBSD: hack.lev.c,v 1.10 2016/01/09 18:33:15 mestre 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 <stdlib.h>
65#include <unistd.h>
66
67#include "hack.h"
68
69extern struct obj *billobjs;
70extern char SAVEF[];
71extern int hackpid;
72extern xchar dlevel;
73extern char nul[];
74
75#ifndef NOWORM
76extern struct wseg *wsegs[32], *wheads[32];
77extern long wgrowtime[32];
78#endif /* NOWORM */
79
80boolean level_exists[MAXLEVEL+1];
81
82void
83savelev(int fd, xchar lev)
84{
85#ifndef NOWORM
86	struct wseg *wtmp, *wtmp2;
87	int tmp;
88#endif /* NOWORM */
89
90	if (fd < 0)
91		panic("Save on bad file!");	/* impossible */
92	if (lev >= 0 && lev <= MAXLEVEL)
93		level_exists[(int)lev] = TRUE;
94
95	bwrite(fd, &hackpid,sizeof(hackpid));
96	bwrite(fd, &lev,sizeof(lev));
97	bwrite(fd, levl,sizeof(levl));
98	bwrite(fd, &moves,sizeof(long));
99	bwrite(fd, &xupstair,sizeof(xupstair));
100	bwrite(fd, &yupstair,sizeof(yupstair));
101	bwrite(fd, &xdnstair,sizeof(xdnstair));
102	bwrite(fd, &ydnstair,sizeof(ydnstair));
103	savemonchn(fd, fmon);
104	savegoldchn(fd, fgold);
105	savetrapchn(fd, ftrap);
106	saveobjchn(fd, fobj);
107	saveobjchn(fd, billobjs);
108	billobjs = 0;
109	save_engravings(fd);
110#ifndef QUEST
111	bwrite(fd, rooms,sizeof(rooms));
112	bwrite(fd, doors,sizeof(doors));
113#endif /* QUEST */
114	fgold = 0;
115	ftrap = 0;
116	fmon = 0;
117	fobj = 0;
118#ifndef NOWORM
119	bwrite(fd, wsegs,sizeof(wsegs));
120	for(tmp=1; tmp<32; tmp++){
121		for(wtmp = wsegs[tmp]; wtmp; wtmp = wtmp2){
122			wtmp2 = wtmp->nseg;
123			bwrite(fd, wtmp,sizeof(struct wseg));
124		}
125		wsegs[tmp] = 0;
126	}
127	bwrite(fd, wgrowtime,sizeof(wgrowtime));
128#endif /* NOWORM */
129}
130
131void
132bwrite(int fd, const void *loc, ssize_t num)
133{
134	if(write(fd, loc, num) != num)
135		panic("cannot write %zd bytes to file #%d", num, fd);
136}
137
138void
139saveobjchn(int fd, struct obj *otmp)
140{
141	struct obj *otmp2;
142	unsigned xl;
143	int minusone = -1;
144
145	while(otmp) {
146		otmp2 = otmp->nobj;
147		xl = otmp->onamelth;
148		bwrite(fd, &xl, sizeof(int));
149		bwrite(fd, otmp, xl + sizeof(struct obj));
150		free(otmp);
151		otmp = otmp2;
152	}
153	bwrite(fd, &minusone, sizeof(int));
154}
155
156void
157savemonchn(int fd, struct monst *mtmp)
158{
159	struct monst *mtmp2;
160	unsigned xl;
161	int minusone = -1;
162	struct permonst *monbegin = &mons[0];
163
164	bwrite(fd, &monbegin, sizeof(monbegin));
165
166	while(mtmp) {
167		mtmp2 = mtmp->nmon;
168		xl = mtmp->mxlth + mtmp->mnamelth;
169		bwrite(fd, &xl, sizeof(int));
170		bwrite(fd, mtmp, xl + sizeof(struct monst));
171		if(mtmp->minvent) saveobjchn(fd,mtmp->minvent);
172		free(mtmp);
173		mtmp = mtmp2;
174	}
175	bwrite(fd, &minusone, sizeof(int));
176}
177
178void
179savegoldchn(int fd, struct gold *gold)
180{
181	struct gold *gold2;
182	while(gold) {
183		gold2 = gold->ngold;
184		bwrite(fd, gold, sizeof(struct gold));
185		free(gold);
186		gold = gold2;
187	}
188	bwrite(fd, nul, sizeof(struct gold));
189}
190
191void
192savetrapchn(int fd, struct trap *trap)
193{
194	struct trap *trap2;
195	while(trap) {
196		trap2 = trap->ntrap;
197		bwrite(fd, trap, sizeof(struct trap));
198		free(trap);
199		trap = trap2;
200	}
201	bwrite(fd, nul, sizeof(struct trap));
202}
203
204void
205getlev(int fd, int pid, xchar lev)
206{
207	struct gold *gold;
208	struct trap *trap;
209#ifndef NOWORM
210	struct wseg *wtmp;
211#endif /* NOWORM */
212	int tmp;
213	long omoves;
214	int hpid;
215	xchar dlvl;
216
217	/* First some sanity checks */
218	mread(fd, (char *) &hpid, sizeof(hpid));
219	mread(fd, (char *) &dlvl, sizeof(dlvl));
220	if((pid && pid != hpid) || (lev && dlvl != lev)) {
221		pline("Strange, this map is not as I remember it.");
222		pline("Somebody is trying some trickery here ...");
223		pline("This game is void ...");
224		done("tricked");
225	}
226
227	fgold = 0;
228	ftrap = 0;
229	mread(fd, (char *) levl, sizeof(levl));
230	mread(fd, (char *)&omoves, sizeof(omoves));
231	mread(fd, (char *)&xupstair, sizeof(xupstair));
232	mread(fd, (char *)&yupstair, sizeof(yupstair));
233	mread(fd, (char *)&xdnstair, sizeof(xdnstair));
234	mread(fd, (char *)&ydnstair, sizeof(ydnstair));
235
236	fmon = restmonchn(fd);
237
238	/* regenerate animals while on another level */
239	{ long tmoves = (moves > omoves) ? moves-omoves : 0;
240	  struct monst *mtmp, *mtmp2;
241	  extern char genocided[];
242
243	  for(mtmp = fmon; mtmp; mtmp = mtmp2) {
244		long newhp;		/* tmoves may be very large */
245
246		mtmp2 = mtmp->nmon;
247		if(strchr(genocided, mtmp->data->mlet)) {
248			mondead(mtmp);
249			continue;
250		}
251
252		if(mtmp->mtame && tmoves > 250) {
253			mtmp->mtame = 0;
254			mtmp->mpeaceful = 0;
255		}
256
257		newhp = mtmp->mhp +
258			(strchr(MREGEN, mtmp->data->mlet) ? tmoves : tmoves/20);
259		if(newhp > mtmp->mhpmax)
260			mtmp->mhp = mtmp->mhpmax;
261		else
262			mtmp->mhp = newhp;
263	  }
264	}
265
266	setgd();
267	gold = newgold();
268	mread(fd, (char *)gold, sizeof(struct gold));
269	while(gold->gx) {
270		gold->ngold = fgold;
271		fgold = gold;
272		gold = newgold();
273		mread(fd, (char *)gold, sizeof(struct gold));
274	}
275	free(gold);
276	trap = newtrap();
277	mread(fd, (char *)trap, sizeof(struct trap));
278	while(trap->tx) {
279		trap->ntrap = ftrap;
280		ftrap = trap;
281		trap = newtrap();
282		mread(fd, (char *)trap, sizeof(struct trap));
283	}
284	free(trap);
285	fobj = restobjchn(fd);
286	billobjs = restobjchn(fd);
287	rest_engravings(fd);
288#ifndef QUEST
289	mread(fd, (char *)rooms, sizeof(rooms));
290	mread(fd, (char *)doors, sizeof(doors));
291#endif /* QUEST */
292#ifndef NOWORM
293	mread(fd, (char *)wsegs, sizeof(wsegs));
294	for(tmp = 1; tmp < 32; tmp++) if(wsegs[tmp]){
295		wheads[tmp] = wsegs[tmp] = wtmp = newseg();
296		while(1) {
297			mread(fd, (char *)wtmp, sizeof(struct wseg));
298			if(!wtmp->nseg) break;
299			wheads[tmp]->nseg = wtmp = newseg();
300			wheads[tmp] = wtmp;
301		}
302	}
303	mread(fd, (char *)wgrowtime, sizeof(wgrowtime));
304#endif /* NOWORM */
305}
306
307void
308mread(int fd, char *buf, unsigned len)
309{
310	int rlen;
311	extern boolean restoring;
312
313	rlen = read(fd, buf, (int) len);
314	if(rlen != len){
315		pline("Read %d instead of %u bytes.\n", rlen, len);
316		if(restoring) {
317			(void) unlink(SAVEF);
318			error("Error restoring old game.");
319		}
320		panic("Error reading level file.");
321	}
322}
323
324void
325mklev(void)
326{
327	extern boolean in_mklev;
328
329	if(getbones()) return;
330
331	in_mklev = TRUE;
332	makelevel();
333	in_mklev = FALSE;
334}
335