xref: /dragonfly/games/hack/hack.save.c (revision 4318c66eac379e15105fe145d406dfef81b795f6)
1 /*        $NetBSD: hack.save.c,v 1.16 2011/08/06 20:42:43 dholland 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 <stdlib.h>
66 #include <unistd.h>
67 #include <fcntl.h>
68 #include "hack.h"
69 #include "extern.h"
70 
71 static int dosave0(int);
72 
73 int
dosave(void)74 dosave(void)
75 {
76           if (dosave0(0)) {
77                     settty("Be seeing you ...\n");
78                     exit(0);
79           }
80           return (0);
81 }
82 
83 #ifndef NOSAVEONHANGUP
84 void
hang_up(int n __unused)85 hang_up(int n __unused)
86 {
87           (void) dosave0(1);
88           exit(1);
89 }
90 #endif    /* NOSAVEONHANGUP */
91 
92 /* returns 1 if save successful */
93 static int
dosave0(int hu)94 dosave0(int hu)
95 {
96           int                 fd, ofd;
97           int             tmp;          /* not ! */
98 
99           (void) signal(SIGHUP, SIG_IGN);
100           (void) signal(SIGINT, SIG_IGN);
101           if ((fd = creat(SAVEF, FMASK)) < 0) {
102                     if (!hu)
103                               pline("Cannot open save file. (Continue or Quit)");
104                     (void) unlink(SAVEF);         /* ab@unido */
105                     return (0);
106           }
107           if (flags.moonphase == FULL_MOON)       /* ut-sally!fletcher */
108                     u.uluck--;          /* and unido!ab */
109           savelev(fd, dlevel);
110           saveobjchn(fd, invent);
111           saveobjchn(fd, fcobj);
112           savemonchn(fd, fallen_down);
113           tmp = getuid();
114           bwrite(fd, &tmp, sizeof tmp);
115           bwrite(fd, &flags, sizeof(struct flag));
116           bwrite(fd, &dlevel, sizeof dlevel);
117           bwrite(fd, &maxdlevel, sizeof maxdlevel);
118           bwrite(fd, &moves, sizeof moves);
119           bwrite(fd, &u, sizeof(struct you));
120           if (u.ustuck)
121                     bwrite(fd, &(u.ustuck->m_id), sizeof u.ustuck->m_id);
122           bwrite(fd, pl_character, sizeof pl_character);
123           bwrite(fd, genocided, sizeof genocided);
124           bwrite(fd, fut_geno, sizeof fut_geno);
125           savenames(fd);
126           for (tmp = 1; tmp <= maxdlevel; tmp++) {
127 
128                     if (tmp == dlevel || !level_exists[tmp])
129                               continue;
130                     glo(tmp);
131                     if ((ofd = open(lock, O_RDONLY)) < 0) {
132                               if (!hu)
133                                         pline("Error while saving: cannot read %s.", lock);
134                               (void) close(fd);
135                               (void) unlink(SAVEF);
136                               if (!hu)
137                                         done("tricked");
138                               return (0);
139                     }
140                     getlev(ofd, hackpid, tmp);
141                     (void) close(ofd);
142                     bwrite(fd, &tmp, sizeof tmp); /* level number */
143                     savelev(fd, tmp);   /* actual level */
144                     (void) unlink(lock);
145           }
146           (void) close(fd);
147           glo(dlevel);
148           (void) unlink(lock);          /* get rid of current level --jgm */
149           glo(0);
150           (void) unlink(lock);
151           return (1);
152 }
153 
154 int
dorecover(int fd)155 dorecover(int fd)
156 {
157           int nfd;
158           int             tmp;          /* not a ! */
159           unsigned        mid;          /* idem */
160           struct obj     *otmp;
161 
162           restoring = TRUE;
163           getlev(fd, 0, 0);
164           invent = restobjchn(fd);
165           for (otmp = invent; otmp; otmp = otmp->nobj)
166                     if (otmp->owornmask)
167                               setworn(otmp, otmp->owornmask);
168           fcobj = restobjchn(fd);
169           fallen_down = restmonchn(fd);
170           mread(fd, &tmp, sizeof tmp);
171           if (tmp != (int) getuid()) {  /* strange ... */
172                     (void) close(fd);
173                     (void) unlink(SAVEF);
174                     puts("Saved game was not yours.");
175                     restoring = FALSE;
176                     return (0);
177           }
178           mread(fd, &flags, sizeof(struct flag));
179           mread(fd, &dlevel, sizeof dlevel);
180           mread(fd, &maxdlevel, sizeof maxdlevel);
181           mread(fd, &moves, sizeof moves);
182           mread(fd, &u, sizeof(struct you));
183           if (u.ustuck)
184                     mread(fd, &mid, sizeof mid);
185           mread(fd, pl_character, sizeof pl_character);
186           mread(fd, genocided, sizeof genocided);
187           mread(fd, fut_geno, sizeof fut_geno);
188           restnames(fd);
189           while (1) {
190                     if (read(fd, &tmp, sizeof tmp) != sizeof tmp)
191                               break;
192                     getlev(fd, 0, tmp);
193                     glo(tmp);
194                     if ((nfd = creat(lock, FMASK)) < 0)
195                               panic("Cannot open temp file %s!\n", lock);
196                     savelev(nfd, tmp);
197                     (void) close(nfd);
198           }
199           (void) lseek(fd, (off_t) 0, SEEK_SET);
200           getlev(fd, 0, 0);
201           (void) close(fd);
202           (void) unlink(SAVEF);
203           if (Punished) {
204                     for (otmp = fobj; otmp; otmp = otmp->nobj)
205                               if (otmp->olet == CHAIN_SYM)
206                                         goto chainfnd;
207                     panic("Cannot find the iron chain?");
208 chainfnd:
209                     uchain = otmp;
210                     if (!uball) {
211                               for (otmp = fobj; otmp; otmp = otmp->nobj)
212                                         if (otmp->olet == BALL_SYM && otmp->spe)
213                                                   goto ballfnd;
214                               panic("Cannot find the iron ball?");
215           ballfnd:
216                               uball = otmp;
217                     }
218           }
219           if (u.ustuck) {
220                     struct monst   *mtmp;
221 
222                     for (mtmp = fmon; mtmp; mtmp = mtmp->nmon)
223                               if (mtmp->m_id == mid)
224                                         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
231                                          * weren't saved */
232 #endif    /* QUEST */
233           docrt();
234           restoring = FALSE;
235           return (1);
236 }
237 
238 struct obj     *
restobjchn(int fd)239 restobjchn(int fd)
240 {
241           struct obj     *otmp, *otmp2 = NULL;
242           struct obj     *first = 0;
243           int             xl;
244           while (1) {
245                     mread(fd, &xl, sizeof(xl));
246                     if (xl == -1)
247                               break;
248                     otmp = newobj(xl);
249                     if (!first)
250                               first = otmp;
251                     else
252                               otmp2->nobj = otmp;
253                     mread(fd, otmp, (unsigned) xl + sizeof(struct obj));
254                     if (!otmp->o_id)
255                               otmp->o_id = flags.ident++;
256                     otmp2 = otmp;
257           }
258           if (first && otmp2->nobj) {
259                     impossible("Restobjchn: error reading objchn.");
260                     otmp2->nobj = 0;
261           }
262           return (first);
263 }
264 
265 struct monst   *
restmonchn(int fd)266 restmonchn(int fd)
267 {
268           struct monst   *mtmp, *mtmp2 = NULL;
269           struct monst   *first = 0;
270           int             xl;
271 
272           struct permonst *monbegin;
273           long            differ;
274 
275           mread(fd, &monbegin, sizeof(monbegin));
276           differ = (const char *) (&mons[0]) - (const char *) (monbegin);
277 
278 #ifdef lint
279           /* suppress "used before set" warning from lint */
280           mtmp2 = 0;
281 #endif    /* lint */
282           while (1) {
283                     mread(fd, &xl, sizeof(xl));
284                     if (xl == -1)
285                               break;
286                     mtmp = newmonst(xl);
287                     if (!first)
288                               first = mtmp;
289                     else
290                               mtmp2->nmon = mtmp;
291                     mread(fd, mtmp, (unsigned) xl + sizeof(struct monst));
292                     if (!mtmp->m_id)
293                               mtmp->m_id = flags.ident++;
294                     mtmp->data = (const struct permonst *)
295                               ((const char *) mtmp->data + differ);
296                     if (mtmp->minvent)
297                               mtmp->minvent = restobjchn(fd);
298                     mtmp2 = mtmp;
299           }
300           if (first && mtmp2->nmon) {
301                     impossible("Restmonchn: error reading monchn.");
302                     mtmp2->nmon = 0;
303           }
304           return (first);
305 }
306