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