OSDN Git Service

update year to 2020
[jnethack/source.git] / src / restore.c
1 /* NetHack 3.6  restore.c       $NHDT-Date: 1575245087 2019/12/02 00:04:47 $  $NHDT-Branch: NetHack-3.6 $:$NHDT-Revision: 1.136 $ */
2 /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
3 /*-Copyright (c) Michael Allison, 2009. */
4 /* NetHack may be freely redistributed.  See license for details. */
5
6 /* JNetHack Copyright */
7 /* (c) Issei Numata, Naoki Hamada, Shigehiro Miyashita, 1994-2000  */
8 /* For 3.4-, Copyright (c) SHIRAKATA Kentaro, 2002-2020            */
9 /* JNetHack may be freely redistributed.  See license for details. */
10
11 #include "hack.h"
12 #include "lev.h"
13 #include "tcap.h" /* for TERMLIB and ASCIIGRAPH */
14
15 #if defined(MICRO)
16 extern int dotcnt; /* shared with save */
17 extern int dotrow; /* shared with save */
18 #endif
19
20 #ifdef USE_TILES
21 extern void FDECL(substitute_tiles, (d_level *)); /* from tile.c */
22 #endif
23
24 #ifdef ZEROCOMP
25 STATIC_DCL void NDECL(zerocomp_minit);
26 STATIC_DCL void FDECL(zerocomp_mread, (int, genericptr_t, unsigned int));
27 STATIC_DCL int NDECL(zerocomp_mgetc);
28 #endif
29
30 STATIC_DCL void NDECL(def_minit);
31 STATIC_DCL void FDECL(def_mread, (int, genericptr_t, unsigned int));
32
33 STATIC_DCL void NDECL(find_lev_obj);
34 STATIC_DCL void FDECL(restlevchn, (int));
35 STATIC_DCL void FDECL(restdamage, (int, BOOLEAN_P));
36 STATIC_DCL void FDECL(restobj, (int, struct obj *));
37 STATIC_DCL struct obj *FDECL(restobjchn, (int, BOOLEAN_P, BOOLEAN_P));
38 STATIC_OVL void FDECL(restmon, (int, struct monst *));
39 STATIC_DCL struct monst *FDECL(restmonchn, (int, BOOLEAN_P));
40 STATIC_DCL struct fruit *FDECL(loadfruitchn, (int));
41 STATIC_DCL void FDECL(freefruitchn, (struct fruit *));
42 STATIC_DCL void FDECL(ghostfruit, (struct obj *));
43 STATIC_DCL boolean FDECL(restgamestate, (int, unsigned int *, unsigned int *));
44 STATIC_DCL void FDECL(restlevelstate, (unsigned int, unsigned int));
45 STATIC_DCL int FDECL(restlevelfile, (int, XCHAR_P));
46 STATIC_OVL void FDECL(restore_msghistory, (int));
47 STATIC_DCL void FDECL(reset_oattached_mids, (BOOLEAN_P));
48 STATIC_DCL void FDECL(rest_levl, (int, BOOLEAN_P));
49
50 static struct restore_procs {
51     const char *name;
52     int mread_flags;
53     void NDECL((*restore_minit));
54     void FDECL((*restore_mread), (int, genericptr_t, unsigned int));
55     void FDECL((*restore_bclose), (int));
56 } restoreprocs = {
57 #if !defined(ZEROCOMP) || (defined(COMPRESS) || defined(ZLIB_COMP))
58     "externalcomp", 0, def_minit, def_mread, def_bclose,
59 #else
60     "zerocomp", 0, zerocomp_minit, zerocomp_mread, zerocomp_bclose,
61 #endif
62 };
63
64 /*
65  * Save a mapping of IDs from ghost levels to the current level.  This
66  * map is used by the timer routines when restoring ghost levels.
67  */
68 #define N_PER_BUCKET 64
69 struct bucket {
70     struct bucket *next;
71     struct {
72         unsigned gid; /* ghost ID */
73         unsigned nid; /* new ID */
74     } map[N_PER_BUCKET];
75 };
76
77 STATIC_DCL void NDECL(clear_id_mapping);
78 STATIC_DCL void FDECL(add_id_mapping, (unsigned, unsigned));
79
80 static int n_ids_mapped = 0;
81 static struct bucket *id_map = 0;
82
83 #ifdef AMII_GRAPHICS
84 void FDECL(amii_setpens, (int)); /* use colors from save file */
85 extern int amii_numcolors;
86 #endif
87
88 #include "display.h"
89
90 boolean restoring = FALSE;
91 static NEARDATA struct fruit *oldfruit;
92 static NEARDATA long omoves;
93
94 #define Is_IceBox(o) ((o)->otyp == ICE_BOX ? TRUE : FALSE)
95
96 /* Recalculate level.objects[x][y], since this info was not saved. */
97 STATIC_OVL void
98 find_lev_obj()
99 {
100     register struct obj *fobjtmp = (struct obj *) 0;
101     register struct obj *otmp;
102     int x, y;
103
104     for (x = 0; x < COLNO; x++)
105         for (y = 0; y < ROWNO; y++)
106             level.objects[x][y] = (struct obj *) 0;
107
108     /*
109      * Reverse the entire fobj chain, which is necessary so that we can
110      * place the objects in the proper order.  Make all obj in chain
111      * OBJ_FREE so place_object will work correctly.
112      */
113     while ((otmp = fobj) != 0) {
114         fobj = otmp->nobj;
115         otmp->nobj = fobjtmp;
116         otmp->where = OBJ_FREE;
117         fobjtmp = otmp;
118     }
119     /* fobj should now be empty */
120
121     /* Set level.objects (as well as reversing the chain back again) */
122     while ((otmp = fobjtmp) != 0) {
123         fobjtmp = otmp->nobj;
124         place_object(otmp, otmp->ox, otmp->oy);
125     }
126 }
127
128 /* Things that were marked "in_use" when the game was saved (ex. via the
129  * infamous "HUP" cheat) get used up here.
130  */
131 void
132 inven_inuse(quietly)
133 boolean quietly;
134 {
135     register struct obj *otmp, *otmp2;
136
137     for (otmp = invent; otmp; otmp = otmp2) {
138         otmp2 = otmp->nobj;
139         if (otmp->in_use) {
140             if (!quietly)
141 /*JP
142                 pline("Finishing off %s...", xname(otmp));
143 */
144                 pline("%s\82ð\8eg\82¢\8fI\82¦\82½\81D\81D\81D", xname(otmp));
145             useup(otmp);
146         }
147     }
148 }
149
150 STATIC_OVL void
151 restlevchn(fd)
152 register int fd;
153 {
154     int cnt;
155     s_level *tmplev, *x;
156
157     sp_levchn = (s_level *) 0;
158     mread(fd, (genericptr_t) &cnt, sizeof(int));
159     for (; cnt > 0; cnt--) {
160         tmplev = (s_level *) alloc(sizeof(s_level));
161         mread(fd, (genericptr_t) tmplev, sizeof(s_level));
162         if (!sp_levchn)
163             sp_levchn = tmplev;
164         else {
165             for (x = sp_levchn; x->next; x = x->next)
166                 ;
167             x->next = tmplev;
168         }
169         tmplev->next = (s_level *) 0;
170     }
171 }
172
173 STATIC_OVL void
174 restdamage(fd, ghostly)
175 int fd;
176 boolean ghostly;
177 {
178     int counter;
179     struct damage *tmp_dam;
180
181     mread(fd, (genericptr_t) &counter, sizeof(counter));
182     if (!counter)
183         return;
184     tmp_dam = (struct damage *) alloc(sizeof(struct damage));
185     while (--counter >= 0) {
186         char damaged_shops[5], *shp = (char *) 0;
187
188         mread(fd, (genericptr_t) tmp_dam, sizeof(*tmp_dam));
189         if (ghostly)
190             tmp_dam->when += (monstermoves - omoves);
191         Strcpy(damaged_shops,
192                in_rooms(tmp_dam->place.x, tmp_dam->place.y, SHOPBASE));
193         if (u.uz.dlevel) {
194             /* when restoring, there are two passes over the current
195              * level.  the first time, u.uz isn't set, so neither is
196              * shop_keeper().  just wait and process the damage on
197              * the second pass.
198              */
199             for (shp = damaged_shops; *shp; shp++) {
200                 struct monst *shkp = shop_keeper(*shp);
201
202                 if (shkp && inhishop(shkp)
203                     && repair_damage(shkp, tmp_dam, (int *) 0, TRUE))
204                     break;
205             }
206         }
207         if (!shp || !*shp) {
208             tmp_dam->next = level.damagelist;
209             level.damagelist = tmp_dam;
210             tmp_dam = (struct damage *) alloc(sizeof(*tmp_dam));
211         }
212     }
213     free((genericptr_t) tmp_dam);
214 }
215
216 /* restore one object */
217 STATIC_OVL void
218 restobj(fd, otmp)
219 int fd;
220 struct obj *otmp;
221 {
222     int buflen;
223
224     mread(fd, (genericptr_t) otmp, sizeof(struct obj));
225
226     /* next object pointers are invalid; otmp->cobj needs to be left
227        as is--being non-null is key to restoring container contents */
228     otmp->nobj = otmp->nexthere = (struct obj *) 0;
229     /* non-null oextra needs to be reconstructed */
230     if (otmp->oextra) {
231         otmp->oextra = newoextra();
232
233         /* oname - object's name */
234         mread(fd, (genericptr_t) &buflen, sizeof(buflen));
235         if (buflen > 0) { /* includes terminating '\0' */
236             new_oname(otmp, buflen);
237             mread(fd, (genericptr_t) ONAME(otmp), buflen);
238         }
239         /* omonst - corpse or statue might retain full monster details */
240         mread(fd, (genericptr_t) &buflen, sizeof(buflen));
241         if (buflen > 0) {
242             newomonst(otmp);
243             /* this is actually a monst struct, so we
244                can just defer to restmon() here */
245             restmon(fd, OMONST(otmp));
246         }
247         /* omid - monster id number, connecting corpse to ghost */
248         mread(fd, (genericptr_t) &buflen, sizeof(buflen));
249         if (buflen > 0) {
250             newomid(otmp);
251             mread(fd, (genericptr_t) OMID(otmp), buflen);
252         }
253         /* olong - temporary gold */
254         mread(fd, (genericptr_t) &buflen, sizeof(buflen));
255         if (buflen > 0) {
256             newolong(otmp);
257             mread(fd, (genericptr_t) OLONG(otmp), buflen);
258         }
259         /* omailcmd - feedback mechanism for scroll of mail */
260         mread(fd, (genericptr_t) &buflen, sizeof(buflen));
261         if (buflen > 0) {
262             char *omailcmd = (char *) alloc(buflen);
263
264             mread(fd, (genericptr_t) omailcmd, buflen);
265             new_omailcmd(otmp, omailcmd);
266             free((genericptr_t) omailcmd);
267         }
268     }
269 }
270
271 STATIC_OVL struct obj *
272 restobjchn(fd, ghostly, frozen)
273 register int fd;
274 boolean ghostly, frozen;
275 {
276     register struct obj *otmp, *otmp2 = 0;
277     register struct obj *first = (struct obj *) 0;
278     int buflen;
279
280     while (1) {
281         mread(fd, (genericptr_t) &buflen, sizeof buflen);
282         if (buflen == -1)
283             break;
284
285         otmp = newobj();
286         restobj(fd, otmp);
287         if (!first)
288             first = otmp;
289         else
290             otmp2->nobj = otmp;
291
292         if (ghostly) {
293             unsigned nid = context.ident++;
294             add_id_mapping(otmp->o_id, nid);
295             otmp->o_id = nid;
296         }
297         if (ghostly && otmp->otyp == SLIME_MOLD)
298             ghostfruit(otmp);
299         /* Ghost levels get object age shifted from old player's clock
300          * to new player's clock.  Assumption: new player arrived
301          * immediately after old player died.
302          */
303         if (ghostly && !frozen && !age_is_relative(otmp))
304             otmp->age = monstermoves - omoves + otmp->age;
305
306         /* get contents of a container or statue */
307         if (Has_contents(otmp)) {
308             struct obj *otmp3;
309
310             otmp->cobj = restobjchn(fd, ghostly, Is_IceBox(otmp));
311             /* restore container back pointers */
312             for (otmp3 = otmp->cobj; otmp3; otmp3 = otmp3->nobj)
313                 otmp3->ocontainer = otmp;
314         } else if (SchroedingersBox(otmp)) {
315             struct obj *catcorpse;
316
317             /*
318              * TODO:  Remove this after 3.6.x save compatibility is dropped.
319              *
320              * As of 3.6.2, SchroedingersBox() always has a cat corpse in it.
321              * For 3.6.[01], it was empty and its weight was falsified
322              * to have the value it would have had if there was one inside.
323              * Put a non-rotting cat corpse in this box to convert to 3.6.2.
324              *
325              * [Note: after this fix up, future save/restore of this object
326              * will take the Has_contents() code path above.]
327              */
328             if ((catcorpse = mksobj(CORPSE, TRUE, FALSE)) != 0) {
329                 otmp->spe = 1; /* flag for special SchroedingersBox */
330                 set_corpsenm(catcorpse, PM_HOUSECAT);
331                 (void) stop_timer(ROT_CORPSE, obj_to_any(catcorpse));
332                 add_to_container(otmp, catcorpse);
333                 otmp->owt = weight(otmp);
334             }
335         }
336         if (otmp->bypass)
337             otmp->bypass = 0;
338         if (!ghostly) {
339             /* fix the pointers */
340             if (otmp->o_id == context.victual.o_id)
341                 context.victual.piece = otmp;
342             if (otmp->o_id == context.tin.o_id)
343                 context.tin.tin = otmp;
344             if (otmp->o_id == context.spbook.o_id)
345                 context.spbook.book = otmp;
346         }
347         otmp2 = otmp;
348     }
349     if (first && otmp2->nobj) {
350         impossible("Restobjchn: error reading objchn.");
351         otmp2->nobj = 0;
352     }
353
354     return first;
355 }
356
357 /* restore one monster */
358 STATIC_OVL void
359 restmon(fd, mtmp)
360 int fd;
361 struct monst *mtmp;
362 {
363     int buflen;
364
365     mread(fd, (genericptr_t) mtmp, sizeof(struct monst));
366
367     /* next monster pointer is invalid */
368     mtmp->nmon = (struct monst *) 0;
369     /* non-null mextra needs to be reconstructed */
370     if (mtmp->mextra) {
371         mtmp->mextra = newmextra();
372
373         /* mname - monster's name */
374         mread(fd, (genericptr_t) &buflen, sizeof(buflen));
375         if (buflen > 0) { /* includes terminating '\0' */
376             new_mname(mtmp, buflen);
377             mread(fd, (genericptr_t) MNAME(mtmp), buflen);
378         }
379         /* egd - vault guard */
380         mread(fd, (genericptr_t) &buflen, sizeof(buflen));
381         if (buflen > 0) {
382             newegd(mtmp);
383             mread(fd, (genericptr_t) EGD(mtmp), sizeof(struct egd));
384         }
385         /* epri - temple priest */
386         mread(fd, (genericptr_t) &buflen, sizeof(buflen));
387         if (buflen > 0) {
388             newepri(mtmp);
389             mread(fd, (genericptr_t) EPRI(mtmp), sizeof(struct epri));
390         }
391         /* eshk - shopkeeper */
392         mread(fd, (genericptr_t) &buflen, sizeof(buflen));
393         if (buflen > 0) {
394             neweshk(mtmp);
395             mread(fd, (genericptr_t) ESHK(mtmp), sizeof(struct eshk));
396         }
397         /* emin - minion */
398         mread(fd, (genericptr_t) &buflen, sizeof(buflen));
399         if (buflen > 0) {
400             newemin(mtmp);
401             mread(fd, (genericptr_t) EMIN(mtmp), sizeof(struct emin));
402         }
403         /* edog - pet */
404         mread(fd, (genericptr_t) &buflen, sizeof(buflen));
405         if (buflen > 0) {
406             newedog(mtmp);
407             mread(fd, (genericptr_t) EDOG(mtmp), sizeof(struct edog));
408         }
409         /* mcorpsenm - obj->corpsenm for mimic posing as corpse or
410            statue (inline int rather than pointer to something) */
411         mread(fd, (genericptr_t) &MCORPSENM(mtmp), sizeof MCORPSENM(mtmp));
412     } /* mextra */
413 }
414
415 STATIC_OVL struct monst *
416 restmonchn(fd, ghostly)
417 register int fd;
418 boolean ghostly;
419 {
420     register struct monst *mtmp, *mtmp2 = 0;
421     register struct monst *first = (struct monst *) 0;
422     int offset, buflen;
423
424     while (1) {
425         mread(fd, (genericptr_t) &buflen, sizeof(buflen));
426         if (buflen == -1)
427             break;
428
429         mtmp = newmonst();
430         restmon(fd, mtmp);
431         if (!first)
432             first = mtmp;
433         else
434             mtmp2->nmon = mtmp;
435
436         if (ghostly) {
437             unsigned nid = context.ident++;
438             add_id_mapping(mtmp->m_id, nid);
439             mtmp->m_id = nid;
440         }
441         offset = mtmp->mnum;
442         mtmp->data = &mons[offset];
443         if (ghostly) {
444             int mndx = monsndx(mtmp->data);
445             if (propagate(mndx, TRUE, ghostly) == 0) {
446                 /* cookie to trigger purge in getbones() */
447                 mtmp->mhpmax = DEFUNCT_MONSTER;
448             }
449         }
450         if (mtmp->minvent) {
451             struct obj *obj;
452             mtmp->minvent = restobjchn(fd, ghostly, FALSE);
453             /* restore monster back pointer */
454             for (obj = mtmp->minvent; obj; obj = obj->nobj)
455                 obj->ocarry = mtmp;
456         }
457         if (mtmp->mw) {
458             struct obj *obj;
459
460             for (obj = mtmp->minvent; obj; obj = obj->nobj)
461                 if (obj->owornmask & W_WEP)
462                     break;
463             if (obj)
464                 mtmp->mw = obj;
465             else {
466                 MON_NOWEP(mtmp);
467                 impossible("bad monster weapon restore");
468             }
469         }
470
471         if (mtmp->isshk)
472             restshk(mtmp, ghostly);
473         if (mtmp->ispriest)
474             restpriest(mtmp, ghostly);
475
476         if (!ghostly) {
477             if (mtmp->m_id == context.polearm.m_id)
478                 context.polearm.hitmon = mtmp;
479         }
480         mtmp2 = mtmp;
481     }
482     if (first && mtmp2->nmon) {
483         impossible("Restmonchn: error reading monchn.");
484         mtmp2->nmon = 0;
485     }
486     return first;
487 }
488
489 STATIC_OVL struct fruit *
490 loadfruitchn(fd)
491 int fd;
492 {
493     register struct fruit *flist, *fnext;
494
495     flist = 0;
496     while (fnext = newfruit(), mread(fd, (genericptr_t) fnext, sizeof *fnext),
497            fnext->fid != 0) {
498         fnext->nextf = flist;
499         flist = fnext;
500     }
501     dealloc_fruit(fnext);
502     return flist;
503 }
504
505 STATIC_OVL void
506 freefruitchn(flist)
507 register struct fruit *flist;
508 {
509     register struct fruit *fnext;
510
511     while (flist) {
512         fnext = flist->nextf;
513         dealloc_fruit(flist);
514         flist = fnext;
515     }
516 }
517
518 STATIC_OVL void
519 ghostfruit(otmp)
520 register struct obj *otmp;
521 {
522     register struct fruit *oldf;
523
524     for (oldf = oldfruit; oldf; oldf = oldf->nextf)
525         if (oldf->fid == otmp->spe)
526             break;
527
528     if (!oldf)
529         impossible("no old fruit?");
530     else
531         otmp->spe = fruitadd(oldf->fname, (struct fruit *) 0);
532 }
533
534 #ifdef SYSCF
535 #define SYSOPT_CHECK_SAVE_UID sysopt.check_save_uid
536 #else
537 #define SYSOPT_CHECK_SAVE_UID TRUE
538 #endif
539
540 STATIC_OVL
541 boolean
542 restgamestate(fd, stuckid, steedid)
543 register int fd;
544 unsigned int *stuckid, *steedid;
545 {
546     struct flag newgameflags;
547 #ifdef SYSFLAGS
548     struct sysflag newgamesysflags;
549 #endif
550     struct context_info newgamecontext; /* all 0, but has some pointers */
551     struct obj *otmp;
552     struct obj *bc_obj;
553     char timebuf[15];
554     unsigned long uid;
555     boolean defer_perm_invent;
556
557     mread(fd, (genericptr_t) &uid, sizeof uid);
558     if (SYSOPT_CHECK_SAVE_UID
559         && uid != (unsigned long) getuid()) { /* strange ... */
560         /* for wizard mode, issue a reminder; for others, treat it
561            as an attempt to cheat and refuse to restore this file */
562 /*JP
563         pline("Saved game was not yours.");
564 */
565         pline("\83Z\81[\83u\82³\82ê\82½\83Q\81[\83\80\82Í\82 \82È\82½\82Ì\82à\82Ì\82Å\82Í\82È\82¢\81D");
566         if (!wizard)
567             return FALSE;
568     }
569
570     newgamecontext = context; /* copy statically init'd context */
571     mread(fd, (genericptr_t) &context, sizeof (struct context_info));
572     context.warntype.species = (context.warntype.speciesidx >= LOW_PM)
573                                   ? &mons[context.warntype.speciesidx]
574                                   : (struct permonst *) 0;
575     /* context.victual.piece, .tin.tin, .spellbook.book, and .polearm.hitmon
576        are pointers which get set to Null during save and will be recovered
577        via corresponding o_id or m_id while objs or mons are being restored */
578
579     /* we want to be able to revert to command line/environment/config
580        file option values instead of keeping old save file option values
581        if partial restore fails and we resort to starting a new game */
582     newgameflags = flags;
583     mread(fd, (genericptr_t) &flags, sizeof (struct flag));
584     /* avoid keeping permanent inventory window up to date during restore
585        (setworn() calls update_inventory); attempting to include the cost
586        of unpaid items before shopkeeper's bill is available is a no-no;
587        named fruit names aren't accessible yet either
588        [3.6.2: moved perm_invent from flags to iflags to keep it out of
589        save files; retaining the override here is simpler than trying to
590        to figure out where it really belongs now] */
591     defer_perm_invent = iflags.perm_invent;
592     iflags.perm_invent = FALSE;
593     /* wizard and discover are actually flags.debug and flags.explore;
594        player might be overriding the save file values for them;
595        in the discover case, we don't want to set that for a normal
596        game until after the save file has been removed */
597     iflags.deferred_X = (newgameflags.explore && !discover);
598     if (newgameflags.debug) {
599         /* authorized by startup code; wizard mode exists and is allowed */
600         wizard = TRUE, discover = iflags.deferred_X = FALSE;
601     } else if (wizard) {
602         /* specified by save file; check authorization now */
603         set_playmode();
604     }
605 #ifdef SYSFLAGS
606     newgamesysflags = sysflags;
607     mread(fd, (genericptr_t) &sysflags, sizeof(struct sysflag));
608 #endif
609
610     role_init(); /* Reset the initial role, race, gender, and alignment */
611 #ifdef AMII_GRAPHICS
612     amii_setpens(amii_numcolors); /* use colors from save file */
613 #endif
614     mread(fd, (genericptr_t) &u, sizeof(struct you));
615
616 #define ReadTimebuf(foo)                   \
617     mread(fd, (genericptr_t) timebuf, 14); \
618     timebuf[14] = '\0';                    \
619     foo = time_from_yyyymmddhhmmss(timebuf);
620
621     ReadTimebuf(ubirthday);
622     mread(fd, &urealtime.realtime, sizeof urealtime.realtime);
623     ReadTimebuf(urealtime.start_timing); /** [not used] **/
624     /* current time is the time to use for next urealtime.realtime update */
625     urealtime.start_timing = getnow();
626
627     set_uasmon();
628 #ifdef CLIPPING
629     cliparound(u.ux, u.uy);
630 #endif
631     if (u.uhp <= 0 && (!Upolyd || u.mh <= 0)) {
632         u.ux = u.uy = 0; /* affects pline() [hence You()] */
633 #if 0 /*JP:T*/
634         You("were not healthy enough to survive restoration.");
635 #else
636         You("\8dÄ\8aJ\82Å\82«\82é\82Ù\82Ç\8c\92\8dN\82Å\82Í\82È\82©\82Á\82½\81D");
637 #endif
638         /* wiz1_level.dlevel is used by mklev.c to see if lots of stuff is
639          * uninitialized, so we only have to set it and not the other stuff.
640          */
641         wiz1_level.dlevel = 0;
642         u.uz.dnum = 0;
643         u.uz.dlevel = 1;
644         /* revert to pre-restore option settings */
645         iflags.deferred_X = FALSE;
646         iflags.perm_invent = defer_perm_invent;
647         flags = newgameflags;
648 #ifdef SYSFLAGS
649         sysflags = newgamesysflags;
650 #endif
651         context = newgamecontext;
652         return FALSE;
653     }
654     /* in case hangup save occurred in midst of level change */
655     assign_level(&u.uz0, &u.uz);
656
657     /* this stuff comes after potential aborted restore attempts */
658     restore_killers(fd);
659     restore_timers(fd, RANGE_GLOBAL, FALSE, 0L);
660     restore_light_sources(fd);
661     invent = restobjchn(fd, FALSE, FALSE);
662
663     /* restore dangling (not on floor or in inventory) ball and/or chain */
664     bc_obj = restobjchn(fd, FALSE, FALSE);
665     while (bc_obj) {
666         struct obj *nobj = bc_obj->nobj;
667
668         if (bc_obj->owornmask)
669             setworn(bc_obj, bc_obj->owornmask);
670         bc_obj->nobj = (struct obj *) 0;
671         bc_obj = nobj;
672     }
673
674     migrating_objs = restobjchn(fd, FALSE, FALSE);
675     migrating_mons = restmonchn(fd, FALSE);
676     mread(fd, (genericptr_t) mvitals, sizeof mvitals);
677
678     /*
679      * There are some things after this that can have unintended display
680      * side-effects too early in the game.
681      * Disable see_monsters() here, re-enable it at the top of moveloop()
682      */
683     defer_see_monsters = TRUE;
684
685     /* this comes after inventory has been loaded */
686     for (otmp = invent; otmp; otmp = otmp->nobj)
687         if (otmp->owornmask)
688             setworn(otmp, otmp->owornmask);
689
690     /* reset weapon so that player will get a reminder about "bashing"
691        during next fight when bare-handed or wielding an unconventional
692        item; for pick-axe, we aren't able to distinguish between having
693        applied or wielded it, so be conservative and assume the former */
694     otmp = uwep;   /* `uwep' usually init'd by setworn() in loop above */
695     uwep = 0;      /* clear it and have setuwep() reinit */
696     setuwep(otmp); /* (don't need any null check here) */
697     if (!uwep || uwep->otyp == PICK_AXE || uwep->otyp == GRAPPLING_HOOK)
698         unweapon = TRUE;
699
700     restore_dungeon(fd);
701     restlevchn(fd);
702     mread(fd, (genericptr_t) &moves, sizeof moves);
703     mread(fd, (genericptr_t) &monstermoves, sizeof monstermoves);
704     mread(fd, (genericptr_t) &quest_status, sizeof (struct q_score));
705     mread(fd, (genericptr_t) spl_book, (MAXSPELL + 1) * sizeof (struct spell));
706     restore_artifacts(fd);
707     restore_oracles(fd);
708     if (u.ustuck)
709         mread(fd, (genericptr_t) stuckid, sizeof *stuckid);
710     if (u.usteed)
711         mread(fd, (genericptr_t) steedid, sizeof *steedid);
712     mread(fd, (genericptr_t) pl_character, sizeof pl_character);
713
714     mread(fd, (genericptr_t) pl_fruit, sizeof pl_fruit);
715     freefruitchn(ffruit); /* clean up fruit(s) made by initoptions() */
716     ffruit = loadfruitchn(fd);
717
718     restnames(fd);
719     restore_waterlevel(fd);
720     restore_msghistory(fd);
721     /* must come after all mons & objs are restored */
722     relink_timers(FALSE);
723     relink_light_sources(FALSE);
724     /* inventory display is now viable */
725     iflags.perm_invent = defer_perm_invent;
726     return TRUE;
727 }
728
729 /* update game state pointers to those valid for the current level (so we
730  * don't dereference a wild u.ustuck when saving the game state, for instance)
731  */
732 STATIC_OVL void
733 restlevelstate(stuckid, steedid)
734 unsigned int stuckid, steedid;
735 {
736     register struct monst *mtmp;
737
738     if (stuckid) {
739         for (mtmp = fmon; mtmp; mtmp = mtmp->nmon)
740             if (mtmp->m_id == stuckid)
741                 break;
742         if (!mtmp)
743             panic("Cannot find the monster ustuck.");
744         u.ustuck = mtmp;
745     }
746     if (steedid) {
747         for (mtmp = fmon; mtmp; mtmp = mtmp->nmon)
748             if (mtmp->m_id == steedid)
749                 break;
750         if (!mtmp)
751             panic("Cannot find the monster usteed.");
752         u.usteed = mtmp;
753         remove_monster(mtmp->mx, mtmp->my);
754     }
755 }
756
757 /*ARGSUSED*/
758 STATIC_OVL int
759 restlevelfile(fd, ltmp)
760 int fd; /* fd used in MFLOPPY only */
761 xchar ltmp;
762 {
763     int nfd;
764     char whynot[BUFSZ];
765
766 #ifndef MFLOPPY
767     nhUse(fd);
768 #endif
769     nfd = create_levelfile(ltmp, whynot);
770     if (nfd < 0) {
771         /* BUG: should suppress any attempt to write a panic
772            save file if file creation is now failing... */
773         panic("restlevelfile: %s", whynot);
774     }
775 #ifdef MFLOPPY
776     if (!savelev(nfd, ltmp, COUNT_SAVE)) {
777         /* The savelev can't proceed because the size required
778          * is greater than the available disk space.
779          */
780 /*JP
781         pline("Not enough space on `%s' to restore your game.", levels);
782 */
783         pline("\83Q\81[\83\80\82ð\8dÄ\8aJ\82·\82é\82½\82ß\82Ì'%s'\82Ì\82½\82ß\82Ì\83X\83y\81[\83X\82ª\82È\82¢\81D", levels);
784
785         /* Remove levels and bones that may have been created.
786          */
787         (void) nhclose(nfd);
788 #ifdef AMIGA
789         clearlocks();
790 #else /* !AMIGA */
791         eraseall(levels, alllevels);
792         eraseall(levels, allbones);
793
794         /* Perhaps the person would like to play without a
795          * RAMdisk.
796          */
797         if (ramdisk) {
798             /* PlaywoRAMdisk may not return, but if it does
799              * it is certain that ramdisk will be 0.
800              */
801             playwoRAMdisk();
802             /* Rewind save file and try again */
803             (void) lseek(fd, (off_t) 0, 0);
804             (void) validate(fd, (char *) 0); /* skip version etc */
805             return dorecover(fd);            /* 0 or 1 */
806         }
807 #endif /* ?AMIGA */
808 /*JP
809         pline("Be seeing you...");
810 */
811         pline("\82Ü\82½\89ï\82¢\82Ü\82µ\82å\82¤\81D\81D\81D");
812         nh_terminate(EXIT_SUCCESS);
813     }
814 #endif /* MFLOPPY */
815     bufon(nfd);
816     savelev(nfd, ltmp, WRITE_SAVE | FREE_SAVE);
817     bclose(nfd);
818     return 2;
819 }
820
821 int
822 dorecover(fd)
823 register int fd;
824 {
825     unsigned int stuckid = 0, steedid = 0; /* not a register */
826     xchar ltmp;
827     int rtmp;
828     struct obj *otmp;
829
830     restoring = TRUE;
831     get_plname_from_file(fd, plname);
832     getlev(fd, 0, (xchar) 0, FALSE);
833     if (!restgamestate(fd, &stuckid, &steedid)) {
834         display_nhwindow(WIN_MESSAGE, TRUE);
835         savelev(-1, 0, FREE_SAVE); /* discard current level */
836         (void) nhclose(fd);
837         (void) delete_savefile();
838         restoring = FALSE;
839         return 0;
840     }
841     restlevelstate(stuckid, steedid);
842 #ifdef INSURANCE
843     savestateinlock();
844 #endif
845     rtmp = restlevelfile(fd, ledger_no(&u.uz));
846     if (rtmp < 2)
847         return rtmp; /* dorecover called recursively */
848
849     /* these pointers won't be valid while we're processing the
850      * other levels, but they'll be reset again by restlevelstate()
851      * afterwards, and in the meantime at least u.usteed may mislead
852      * place_monster() on other levels
853      */
854     u.ustuck = (struct monst *) 0;
855     u.usteed = (struct monst *) 0;
856
857 #ifdef MICRO
858 #ifdef AMII_GRAPHICS
859     {
860         extern struct window_procs amii_procs;
861         if (WINDOWPORT("amii") {
862             extern winid WIN_BASE;
863             clear_nhwindow(WIN_BASE); /* hack until there's a hook for this */
864         }
865     }
866 #else
867         clear_nhwindow(WIN_MAP);
868 #endif
869     clear_nhwindow(WIN_MESSAGE);
870 #if 0 /*JP:T*/
871     You("return to level %d in %s%s.", depth(&u.uz),
872         dungeons[u.uz.dnum].dname,
873         flags.debug ? " while in debug mode"
874                     : flags.explore ? " while in explore mode" : "");
875 #else
876     You("%s%s\82Ì\92n\89º%d\8aK\82É\96ß\82Á\82Ä\82«\82½\81D",
877         flags.debug ? "\83E\83B\83U\81[\83h\83\82\81[\83h\92\86\82Ì"
878                     : flags.explore ? "\92T\8c\9f\83\82\81[\83h\92\86\82Ì" : "",
879         dungeons[u.uz.dnum].dname, depth(&u.uz));
880 #endif
881     curs(WIN_MAP, 1, 1);
882     dotcnt = 0;
883     dotrow = 2;
884     if (!WINDOWPORT("X11"))
885         putstr(WIN_MAP, 0, "Restoring:");
886 #endif
887     restoreprocs.mread_flags = 1; /* return despite error */
888     while (1) {
889         mread(fd, (genericptr_t) &ltmp, sizeof ltmp);
890         if (restoreprocs.mread_flags == -1)
891             break;
892         getlev(fd, 0, ltmp, FALSE);
893 #ifdef MICRO
894         curs(WIN_MAP, 1 + dotcnt++, dotrow);
895         if (dotcnt >= (COLNO - 1)) {
896             dotrow++;
897             dotcnt = 0;
898         }
899         if (!WINDOWPORT("X11")) {
900             putstr(WIN_MAP, 0, ".");
901         }
902         mark_synch();
903 #endif
904         rtmp = restlevelfile(fd, ltmp);
905         if (rtmp < 2)
906             return rtmp; /* dorecover called recursively */
907     }
908     restoreprocs.mread_flags = 0;
909
910 #ifdef BSD
911     (void) lseek(fd, 0L, 0);
912 #else
913     (void) lseek(fd, (off_t) 0, 0);
914 #endif
915     (void) validate(fd, (char *) 0); /* skip version and savefile info */
916     get_plname_from_file(fd, plname);
917
918     getlev(fd, 0, (xchar) 0, FALSE);
919     (void) nhclose(fd);
920
921     /* Now set the restore settings to match the
922      * settings used by the save file output routines
923      */
924     reset_restpref();
925
926     restlevelstate(stuckid, steedid);
927     program_state.something_worth_saving = 1; /* useful data now exists */
928
929     if (!wizard && !discover)
930         (void) delete_savefile();
931     if (Is_rogue_level(&u.uz))
932         assign_graphics(ROGUESET);
933 #ifdef USE_TILES
934     substitute_tiles(&u.uz);
935 #endif
936 #ifdef MFLOPPY
937     gameDiskPrompt();
938 #endif
939     max_rank_sz(); /* to recompute mrank_sz (botl.c) */
940     /* take care of iron ball & chain */
941     for (otmp = fobj; otmp; otmp = otmp->nobj)
942         if (otmp->owornmask)
943             setworn(otmp, otmp->owornmask);
944
945     if ((uball && !uchain) || (uchain && !uball)) {
946         impossible("restgamestate: lost ball & chain");
947         /* poor man's unpunish() */
948         setworn((struct obj *) 0, W_CHAIN);
949         setworn((struct obj *) 0, W_BALL);
950     }
951
952     /* in_use processing must be after:
953      *    + The inventory has been read so that freeinv() works.
954      *    + The current level has been restored so billing information
955      *      is available.
956      */
957     inven_inuse(FALSE);
958
959     load_qtlist(); /* re-load the quest text info */
960     /* Set up the vision internals, after levl[] data is loaded
961        but before docrt(). */
962     reglyph_darkroom();
963     vision_reset();
964     vision_full_recalc = 1; /* recompute vision (not saved) */
965
966     run_timers(); /* expire all timers that have gone off while away */
967     docrt();
968     restoring = FALSE;
969     clear_nhwindow(WIN_MESSAGE);
970
971     /* Success! */
972     welcome(FALSE);
973     check_special_room(FALSE);
974     return 1;
975 }
976
977 void
978 restcemetery(fd, cemeteryaddr)
979 int fd;
980 struct cemetery **cemeteryaddr;
981 {
982     struct cemetery *bonesinfo, **bonesaddr;
983     int flag;
984
985     mread(fd, (genericptr_t) &flag, sizeof flag);
986     if (flag == 0) {
987         bonesaddr = cemeteryaddr;
988         do {
989             bonesinfo = (struct cemetery *) alloc(sizeof *bonesinfo);
990             mread(fd, (genericptr_t) bonesinfo, sizeof *bonesinfo);
991             *bonesaddr = bonesinfo;
992             bonesaddr = &(*bonesaddr)->next;
993         } while (*bonesaddr);
994     } else {
995         *cemeteryaddr = 0;
996     }
997 }
998
999 /*ARGSUSED*/
1000 STATIC_OVL void
1001 rest_levl(fd, rlecomp)
1002 int fd;
1003 boolean rlecomp;
1004 {
1005 #ifdef RLECOMP
1006     short i, j;
1007     uchar len;
1008     struct rm r;
1009
1010     if (rlecomp) {
1011         (void) memset((genericptr_t) &r, 0, sizeof(r));
1012         i = 0;
1013         j = 0;
1014         len = 0;
1015         while (i < ROWNO) {
1016             while (j < COLNO) {
1017                 if (len > 0) {
1018                     levl[j][i] = r;
1019                     len -= 1;
1020                     j += 1;
1021                 } else {
1022                     mread(fd, (genericptr_t) &len, sizeof(uchar));
1023                     mread(fd, (genericptr_t) &r, sizeof(struct rm));
1024                 }
1025             }
1026             j = 0;
1027             i += 1;
1028         }
1029         return;
1030     }
1031 #else /* !RLECOMP */
1032     nhUse(rlecomp);
1033 #endif /* ?RLECOMP */
1034     mread(fd, (genericptr_t) levl, sizeof levl);
1035 }
1036
1037 void
1038 trickery(reason)
1039 char *reason;
1040 {
1041 /*JP
1042     pline("Strange, this map is not as I remember it.");
1043 */
1044     pline("\96­\82¾\81C\82±\82Ì\92n\90}\82Í\8e\84\82ª\8ao\82¦\82Ä\82¢\82½\82à\82Ì\82Æ\88á\82¤\81D");
1045 /*JP
1046     pline("Somebody is trying some trickery here...");
1047 */
1048     pline("\82¾\82ê\82©\82ª\82±\82±\82Å\82¢\82©\82³\82Ü\82ð\82µ\82æ\82¤\82Æ\82µ\82½\82æ\82¤\82¾\81D\81D\81D");
1049 /*JP
1050     pline("This game is void.");
1051 */
1052     pline("\82±\82Ì\83Q\81[\83\80\82Í\96³\8cø\82Æ\82È\82é\81D");
1053     Strcpy(killer.name, reason ? reason : "");
1054     done(TRICKED);
1055 }
1056
1057 void
1058 getlev(fd, pid, lev, ghostly)
1059 int fd, pid;
1060 xchar lev;
1061 boolean ghostly;
1062 {
1063     register struct trap *trap;
1064     register struct monst *mtmp;
1065     long elapsed;
1066     branch *br;
1067     int hpid;
1068     xchar dlvl;
1069     int x, y;
1070 #ifdef TOS
1071     short tlev;
1072 #endif
1073
1074     if (ghostly)
1075         clear_id_mapping();
1076
1077 #if defined(MSDOS) || defined(OS2)
1078     setmode(fd, O_BINARY);
1079 #endif
1080     /* Load the old fruit info.  We have to do it first, so the
1081      * information is available when restoring the objects.
1082      */
1083     if (ghostly)
1084         oldfruit = loadfruitchn(fd);
1085
1086     /* First some sanity checks */
1087     mread(fd, (genericptr_t) &hpid, sizeof(hpid));
1088 /* CHECK:  This may prevent restoration */
1089 #ifdef TOS
1090     mread(fd, (genericptr_t) &tlev, sizeof(tlev));
1091     dlvl = tlev & 0x00ff;
1092 #else
1093     mread(fd, (genericptr_t) &dlvl, sizeof(dlvl));
1094 #endif
1095     if ((pid && pid != hpid) || (lev && dlvl != lev)) {
1096         char trickbuf[BUFSZ];
1097
1098         if (pid && pid != hpid)
1099             Sprintf(trickbuf, "PID (%d) doesn't match saved PID (%d)!", hpid,
1100                     pid);
1101         else
1102             Sprintf(trickbuf, "This is level %d, not %d!", dlvl, lev);
1103         if (wizard)
1104             pline1(trickbuf);
1105         trickery(trickbuf);
1106     }
1107     restcemetery(fd, &level.bonesinfo);
1108     rest_levl(fd,
1109               (boolean) ((sfrestinfo.sfi1 & SFI1_RLECOMP) == SFI1_RLECOMP));
1110     mread(fd, (genericptr_t) lastseentyp, sizeof(lastseentyp));
1111     mread(fd, (genericptr_t) &omoves, sizeof(omoves));
1112     elapsed = monstermoves - omoves;
1113     mread(fd, (genericptr_t) &upstair, sizeof(stairway));
1114     mread(fd, (genericptr_t) &dnstair, sizeof(stairway));
1115     mread(fd, (genericptr_t) &upladder, sizeof(stairway));
1116     mread(fd, (genericptr_t) &dnladder, sizeof(stairway));
1117     mread(fd, (genericptr_t) &sstairs, sizeof(stairway));
1118     mread(fd, (genericptr_t) &updest, sizeof(dest_area));
1119     mread(fd, (genericptr_t) &dndest, sizeof(dest_area));
1120     mread(fd, (genericptr_t) &level.flags, sizeof(level.flags));
1121     mread(fd, (genericptr_t) doors, sizeof(doors));
1122     rest_rooms(fd); /* No joke :-) */
1123     if (nroom)
1124         doorindex = rooms[nroom - 1].fdoor + rooms[nroom - 1].doorct;
1125     else
1126         doorindex = 0;
1127
1128     restore_timers(fd, RANGE_LEVEL, ghostly, elapsed);
1129     restore_light_sources(fd);
1130     fmon = restmonchn(fd, ghostly);
1131
1132     rest_worm(fd); /* restore worm information */
1133     ftrap = 0;
1134     while (trap = newtrap(),
1135            mread(fd, (genericptr_t) trap, sizeof(struct trap)),
1136            trap->tx != 0) { /* need "!= 0" to work around DICE 3.0 bug */
1137         trap->ntrap = ftrap;
1138         ftrap = trap;
1139     }
1140     dealloc_trap(trap);
1141     fobj = restobjchn(fd, ghostly, FALSE);
1142     find_lev_obj();
1143     /* restobjchn()'s `frozen' argument probably ought to be a callback
1144        routine so that we can check for objects being buried under ice */
1145     level.buriedobjlist = restobjchn(fd, ghostly, FALSE);
1146     billobjs = restobjchn(fd, ghostly, FALSE);
1147     rest_engravings(fd);
1148
1149     /* reset level.monsters for new level */
1150     for (x = 0; x < COLNO; x++)
1151         for (y = 0; y < ROWNO; y++)
1152             level.monsters[x][y] = (struct monst *) 0;
1153     for (mtmp = fmon; mtmp; mtmp = mtmp->nmon) {
1154         if (mtmp->isshk)
1155             set_residency(mtmp, FALSE);
1156         place_monster(mtmp, mtmp->mx, mtmp->my);
1157         if (mtmp->wormno)
1158             place_wsegs(mtmp, NULL);
1159
1160         /* regenerate monsters while on another level */
1161         if (!u.uz.dlevel)
1162             continue;
1163         if (ghostly) {
1164             /* reset peaceful/malign relative to new character;
1165                shopkeepers will reset based on name */
1166             if (!mtmp->isshk)
1167                 mtmp->mpeaceful =
1168                     (is_unicorn(mtmp->data)
1169                      && sgn(u.ualign.type) == sgn(mtmp->data->maligntyp))
1170                         ? TRUE
1171                         : peace_minded(mtmp->data);
1172             set_malign(mtmp);
1173         } else if (elapsed > 0L) {
1174             mon_catchup_elapsed_time(mtmp, elapsed);
1175         }
1176         /* update shape-changers in case protection against
1177            them is different now than when the level was saved */
1178         restore_cham(mtmp);
1179         /* give hiders a chance to hide before their next move */
1180         if (ghostly || (elapsed > 00 && elapsed > (long) rnd(10)))
1181             hide_monst(mtmp);
1182     }
1183
1184     restdamage(fd, ghostly);
1185     rest_regions(fd, ghostly);
1186     if (ghostly) {
1187         /* Now get rid of all the temp fruits... */
1188         freefruitchn(oldfruit), oldfruit = 0;
1189
1190         if (lev > ledger_no(&medusa_level)
1191             && lev < ledger_no(&stronghold_level) && xdnstair == 0) {
1192             coord cc;
1193
1194             mazexy(&cc);
1195             xdnstair = cc.x;
1196             ydnstair = cc.y;
1197             levl[cc.x][cc.y].typ = STAIRS;
1198         }
1199
1200         br = Is_branchlev(&u.uz);
1201         if (br && u.uz.dlevel == 1) {
1202             d_level ltmp;
1203
1204             if (on_level(&u.uz, &br->end1))
1205                 assign_level(&ltmp, &br->end2);
1206             else
1207                 assign_level(&ltmp, &br->end1);
1208
1209             switch (br->type) {
1210             case BR_STAIR:
1211             case BR_NO_END1:
1212             case BR_NO_END2: /* OK to assign to sstairs if it's not used */
1213                 assign_level(&sstairs.tolev, &ltmp);
1214                 break;
1215             case BR_PORTAL: /* max of 1 portal per level */
1216                 for (trap = ftrap; trap; trap = trap->ntrap)
1217                     if (trap->ttyp == MAGIC_PORTAL)
1218                         break;
1219                 if (!trap)
1220                     panic("getlev: need portal but none found");
1221                 assign_level(&trap->dst, &ltmp);
1222                 break;
1223             }
1224         } else if (!br) {
1225             struct trap *ttmp = 0;
1226
1227             /* Remove any dangling portals. */
1228             for (trap = ftrap; trap; trap = ttmp) {
1229                 ttmp = trap->ntrap;
1230                 if (trap->ttyp == MAGIC_PORTAL)
1231                     deltrap(trap);
1232             }
1233         }
1234     }
1235
1236     /* must come after all mons & objs are restored */
1237     relink_timers(ghostly);
1238     relink_light_sources(ghostly);
1239     reset_oattached_mids(ghostly);
1240
1241     if (ghostly)
1242         clear_id_mapping();
1243 }
1244
1245 void
1246 get_plname_from_file(fd, plbuf)
1247 int fd;
1248 char *plbuf;
1249 {
1250     int pltmpsiz = 0;
1251 _pragma_ignore(-Wunused-result)
1252     (void) read(fd, (genericptr_t) &pltmpsiz, sizeof(pltmpsiz));
1253     (void) read(fd, (genericptr_t) plbuf, pltmpsiz);
1254 _pragma_pop
1255     return;
1256 }
1257
1258 STATIC_OVL void
1259 restore_msghistory(fd)
1260 register int fd;
1261 {
1262     int msgsize, msgcount = 0;
1263     char msg[BUFSZ];
1264
1265     while (1) {
1266         mread(fd, (genericptr_t) &msgsize, sizeof(msgsize));
1267         if (msgsize == -1)
1268             break;
1269         if (msgsize > (BUFSZ - 1))
1270             panic("restore_msghistory: msg too big (%d)", msgsize);
1271         mread(fd, (genericptr_t) msg, msgsize);
1272         msg[msgsize] = '\0';
1273         putmsghistory(msg, TRUE);
1274         ++msgcount;
1275     }
1276     if (msgcount)
1277         putmsghistory((char *) 0, TRUE);
1278     debugpline1("Read %d messages from savefile.", msgcount);
1279 }
1280
1281 /* Clear all structures for object and monster ID mapping. */
1282 STATIC_OVL void
1283 clear_id_mapping()
1284 {
1285     struct bucket *curr;
1286
1287     while ((curr = id_map) != 0) {
1288         id_map = curr->next;
1289         free((genericptr_t) curr);
1290     }
1291     n_ids_mapped = 0;
1292 }
1293
1294 /* Add a mapping to the ID map. */
1295 STATIC_OVL void
1296 add_id_mapping(gid, nid)
1297 unsigned gid, nid;
1298 {
1299     int idx;
1300
1301     idx = n_ids_mapped % N_PER_BUCKET;
1302     /* idx is zero on first time through, as well as when a new bucket is */
1303     /* needed */
1304     if (idx == 0) {
1305         struct bucket *gnu = (struct bucket *) alloc(sizeof(struct bucket));
1306         gnu->next = id_map;
1307         id_map = gnu;
1308     }
1309
1310     id_map->map[idx].gid = gid;
1311     id_map->map[idx].nid = nid;
1312     n_ids_mapped++;
1313 }
1314
1315 /*
1316  * Global routine to look up a mapping.  If found, return TRUE and fill
1317  * in the new ID value.  Otherwise, return false and return -1 in the new
1318  * ID.
1319  */
1320 boolean
1321 lookup_id_mapping(gid, nidp)
1322 unsigned gid, *nidp;
1323 {
1324     int i;
1325     struct bucket *curr;
1326
1327     if (n_ids_mapped)
1328         for (curr = id_map; curr; curr = curr->next) {
1329             /* first bucket might not be totally full */
1330             if (curr == id_map) {
1331                 i = n_ids_mapped % N_PER_BUCKET;
1332                 if (i == 0)
1333                     i = N_PER_BUCKET;
1334             } else
1335                 i = N_PER_BUCKET;
1336
1337             while (--i >= 0)
1338                 if (gid == curr->map[i].gid) {
1339                     *nidp = curr->map[i].nid;
1340                     return TRUE;
1341                 }
1342         }
1343
1344     return FALSE;
1345 }
1346
1347 STATIC_OVL void
1348 reset_oattached_mids(ghostly)
1349 boolean ghostly;
1350 {
1351     struct obj *otmp;
1352     unsigned oldid, nid;
1353     for (otmp = fobj; otmp; otmp = otmp->nobj) {
1354         if (ghostly && has_omonst(otmp)) {
1355             struct monst *mtmp = OMONST(otmp);
1356
1357             mtmp->m_id = 0;
1358             mtmp->mpeaceful = mtmp->mtame = 0; /* pet's owner died! */
1359         }
1360         if (ghostly && has_omid(otmp)) {
1361             (void) memcpy((genericptr_t) &oldid, (genericptr_t) OMID(otmp),
1362                           sizeof(oldid));
1363             if (lookup_id_mapping(oldid, &nid))
1364                 (void) memcpy((genericptr_t) OMID(otmp), (genericptr_t) &nid,
1365                               sizeof(nid));
1366             else
1367                 free_omid(otmp);
1368         }
1369     }
1370 }
1371
1372 #ifdef SELECTSAVED
1373 /* put up a menu listing each character from this player's saved games;
1374    returns 1: use plname[], 0: new game, -1: quit */
1375 int
1376 restore_menu(bannerwin)
1377 winid bannerwin; /* if not WIN_ERR, clear window and show copyright in menu */
1378 {
1379     winid tmpwin;
1380     anything any;
1381     char **saved;
1382     menu_item *chosen_game = (menu_item *) 0;
1383     int k, clet, ch = 0; /* ch: 0 => new game */
1384
1385     *plname = '\0';
1386     saved = get_saved_games(); /* array of character names */
1387     if (saved && *saved) {
1388         tmpwin = create_nhwindow(NHW_MENU);
1389         start_menu(tmpwin);
1390         any = zeroany; /* no selection */
1391         if (bannerwin != WIN_ERR) {
1392             /* for tty; erase copyright notice and redo it in the menu */
1393             clear_nhwindow(bannerwin);
1394             /* COPYRIGHT_BANNER_[ABCD] */
1395             for (k = 1; k <= 4; ++k)
1396                 add_menu(tmpwin, NO_GLYPH, &any, 0, 0, ATR_NONE,
1397                          copyright_banner_line(k), MENU_UNSELECTED);
1398             add_menu(tmpwin, NO_GLYPH, &any, 0, 0, ATR_NONE, "",
1399                      MENU_UNSELECTED);
1400         }
1401 #if 0 /*JP:T*/
1402         add_menu(tmpwin, NO_GLYPH, &any, 0, 0, ATR_NONE,
1403                  "Select one of your saved games", MENU_UNSELECTED);
1404 #else
1405         add_menu(tmpwin, NO_GLYPH, &any, 0, 0, ATR_NONE,
1406                  "\83Z\81[\83u\82µ\82½\83Q\81[\83\80\82ð\88ê\82Â\91I\82ñ\82¾\82­\82¾\82³\82¢", MENU_UNSELECTED);
1407 #endif
1408         for (k = 0; saved[k]; ++k) {
1409             any.a_int = k + 1;
1410             add_menu(tmpwin, NO_GLYPH, &any, 0, 0, ATR_NONE, saved[k],
1411                      MENU_UNSELECTED);
1412         }
1413         clet = (k <= 'n' - 'a') ? 'n' : 0; /* new game */
1414         any.a_int = -1;                    /* not >= 0 */
1415 #if 0 /*JP:T*/
1416         add_menu(tmpwin, NO_GLYPH, &any, clet, 0, ATR_NONE,
1417                  "Start a new character", MENU_UNSELECTED);
1418 #else
1419         add_menu(tmpwin, NO_GLYPH, &any, clet, 0, ATR_NONE,
1420                  "\90V\82µ\82¢\83L\83\83\83\89\83N\83^\82Å\8en\82ß\82é", MENU_UNSELECTED);
1421 #endif
1422         clet = (k + 1 <= 'q' - 'a') ? 'q' : 0; /* quit */
1423         any.a_int = -2;
1424 #if 0 /*JP:T*/
1425         add_menu(tmpwin, NO_GLYPH, &any, clet, 0, ATR_NONE,
1426                  "Never mind (quit)", MENU_SELECTED);
1427 #else
1428         add_menu(tmpwin, NO_GLYPH, &any, clet, 0, ATR_NONE,
1429                  "\82â\82ß\82é", MENU_SELECTED);
1430 #endif
1431         /* no prompt on end_menu, as we've done our own at the top */
1432         end_menu(tmpwin, (char *) 0);
1433         if (select_menu(tmpwin, PICK_ONE, &chosen_game) > 0) {
1434             ch = chosen_game->item.a_int;
1435             if (ch > 0)
1436                 Strcpy(plname, saved[ch - 1]);
1437             else if (ch < 0)
1438                 ++ch; /* -1 -> 0 (new game), -2 -> -1 (quit) */
1439             free((genericptr_t) chosen_game);
1440         } else {
1441             ch = -1; /* quit menu without making a selection => quit */
1442         }
1443         destroy_nhwindow(tmpwin);
1444         if (bannerwin != WIN_ERR) {
1445             /* for tty; clear the menu away and put subset of copyright back
1446              */
1447             clear_nhwindow(bannerwin);
1448             /* COPYRIGHT_BANNER_A, preceding "Who are you?" prompt */
1449             if (ch == 0)
1450                 putstr(bannerwin, 0, copyright_banner_line(1));
1451         }
1452     }
1453     free_saved_games(saved);
1454     return (ch > 0) ? 1 : ch;
1455 }
1456 #endif /* SELECTSAVED */
1457
1458 void
1459 minit()
1460 {
1461     (*restoreprocs.restore_minit)();
1462     return;
1463 }
1464
1465 void
1466 mread(fd, buf, len)
1467 register int fd;
1468 register genericptr_t buf;
1469 register unsigned int len;
1470 {
1471     (*restoreprocs.restore_mread)(fd, buf, len);
1472     return;
1473 }
1474
1475 /* examine the version info and the savefile_info data
1476    that immediately follows it.
1477    Return 0 if it passed the checks.
1478    Return 1 if it failed the version check.
1479    Return 2 if it failed the savefile feature check.
1480    Return -1 if it failed for some unknown reason.
1481  */
1482 int
1483 validate(fd, name)
1484 int fd;
1485 const char *name;
1486 {
1487     int rlen;
1488     struct savefile_info sfi;
1489     unsigned long compatible;
1490     boolean verbose = name ? TRUE : FALSE, reslt = FALSE;
1491
1492     if (!(reslt = uptodate(fd, name)))
1493         return 1;
1494
1495     rlen = read(fd, (genericptr_t) &sfi, sizeof sfi);
1496     minit(); /* ZEROCOMP */
1497     if (rlen == 0) {
1498         if (verbose) {
1499             pline("File \"%s\" is empty during save file feature check?",
1500                   name);
1501             wait_synch();
1502         }
1503         return -1;
1504     }
1505
1506     compatible = (sfi.sfi1 & sfcap.sfi1);
1507
1508     if ((sfi.sfi1 & SFI1_ZEROCOMP) == SFI1_ZEROCOMP) {
1509         if ((compatible & SFI1_ZEROCOMP) != SFI1_ZEROCOMP) {
1510             if (verbose) {
1511                 pline("File \"%s\" has incompatible ZEROCOMP compression.",
1512                       name);
1513                 wait_synch();
1514             }
1515             return 2;
1516         } else if ((sfrestinfo.sfi1 & SFI1_ZEROCOMP) != SFI1_ZEROCOMP) {
1517             set_restpref("zerocomp");
1518         }
1519     }
1520
1521     if ((sfi.sfi1 & SFI1_EXTERNALCOMP) == SFI1_EXTERNALCOMP) {
1522         if ((compatible & SFI1_EXTERNALCOMP) != SFI1_EXTERNALCOMP) {
1523             if (verbose) {
1524                 pline("File \"%s\" lacks required internal compression.",
1525                       name);
1526                 wait_synch();
1527             }
1528             return 2;
1529         } else if ((sfrestinfo.sfi1 & SFI1_EXTERNALCOMP)
1530                    != SFI1_EXTERNALCOMP) {
1531             set_restpref("externalcomp");
1532         }
1533     }
1534
1535     /* RLECOMP check must be last, after ZEROCOMP or INTERNALCOMP adjustments
1536      */
1537     if ((sfi.sfi1 & SFI1_RLECOMP) == SFI1_RLECOMP) {
1538         if ((compatible & SFI1_RLECOMP) != SFI1_RLECOMP) {
1539             if (verbose) {
1540                 pline("File \"%s\" has incompatible run-length compression.",
1541                       name);
1542                 wait_synch();
1543             }
1544             return 2;
1545         } else if ((sfrestinfo.sfi1 & SFI1_RLECOMP) != SFI1_RLECOMP) {
1546             set_restpref("rlecomp");
1547         }
1548     }
1549     /* savefile does not have RLECOMP level location compression, so adjust */
1550     else
1551         set_restpref("!rlecomp");
1552
1553     return 0;
1554 }
1555
1556 void
1557 reset_restpref()
1558 {
1559 #ifdef ZEROCOMP
1560     if (iflags.zerocomp)
1561         set_restpref("zerocomp");
1562     else
1563 #endif
1564         set_restpref("externalcomp");
1565 #ifdef RLECOMP
1566     if (iflags.rlecomp)
1567         set_restpref("rlecomp");
1568     else
1569 #endif
1570         set_restpref("!rlecomp");
1571 }
1572
1573 void
1574 set_restpref(suitename)
1575 const char *suitename;
1576 {
1577     if (!strcmpi(suitename, "externalcomp")) {
1578         restoreprocs.name = "externalcomp";
1579         restoreprocs.restore_mread = def_mread;
1580         restoreprocs.restore_minit = def_minit;
1581         sfrestinfo.sfi1 |= SFI1_EXTERNALCOMP;
1582         sfrestinfo.sfi1 &= ~SFI1_ZEROCOMP;
1583         def_minit();
1584     }
1585     if (!strcmpi(suitename, "!rlecomp")) {
1586         sfrestinfo.sfi1 &= ~SFI1_RLECOMP;
1587     }
1588 #ifdef ZEROCOMP
1589     if (!strcmpi(suitename, "zerocomp")) {
1590         restoreprocs.name = "zerocomp";
1591         restoreprocs.restore_mread = zerocomp_mread;
1592         restoreprocs.restore_minit = zerocomp_minit;
1593         sfrestinfo.sfi1 |= SFI1_ZEROCOMP;
1594         sfrestinfo.sfi1 &= ~SFI1_EXTERNALCOMP;
1595         zerocomp_minit();
1596     }
1597 #endif
1598 #ifdef RLECOMP
1599     if (!strcmpi(suitename, "rlecomp")) {
1600         sfrestinfo.sfi1 |= SFI1_RLECOMP;
1601     }
1602 #endif
1603 }
1604
1605 #ifdef ZEROCOMP
1606 #define RLESC '\0' /* Leading character for run of RLESC's */
1607
1608 #ifndef ZEROCOMP_BUFSIZ
1609 #define ZEROCOMP_BUFSIZ BUFSZ
1610 #endif
1611 static NEARDATA unsigned char inbuf[ZEROCOMP_BUFSIZ];
1612 static NEARDATA unsigned short inbufp = 0;
1613 static NEARDATA unsigned short inbufsz = 0;
1614 static NEARDATA short inrunlength = -1;
1615 static NEARDATA int mreadfd;
1616
1617 STATIC_OVL int
1618 zerocomp_mgetc()
1619 {
1620     if (inbufp >= inbufsz) {
1621         inbufsz = read(mreadfd, (genericptr_t) inbuf, sizeof inbuf);
1622         if (!inbufsz) {
1623             if (inbufp > sizeof inbuf)
1624                 error("EOF on file #%d.\n", mreadfd);
1625             inbufp = 1 + sizeof inbuf; /* exactly one warning :-) */
1626             return -1;
1627         }
1628         inbufp = 0;
1629     }
1630     return inbuf[inbufp++];
1631 }
1632
1633 STATIC_OVL void
1634 zerocomp_minit()
1635 {
1636     inbufsz = 0;
1637     inbufp = 0;
1638     inrunlength = -1;
1639 }
1640
1641 STATIC_OVL void
1642 zerocomp_mread(fd, buf, len)
1643 int fd;
1644 genericptr_t buf;
1645 register unsigned len;
1646 {
1647     /*register int readlen = 0;*/
1648     if (fd < 0)
1649         error("Restore error; mread attempting to read file %d.", fd);
1650     mreadfd = fd;
1651     while (len--) {
1652         if (inrunlength > 0) {
1653             inrunlength--;
1654             *(*((char **) &buf))++ = '\0';
1655         } else {
1656             register short ch = zerocomp_mgetc();
1657             if (ch < 0) {
1658                 restoreprocs.mread_flags = -1;
1659                 return;
1660             }
1661             if ((*(*(char **) &buf)++ = (char) ch) == RLESC) {
1662                 inrunlength = zerocomp_mgetc();
1663             }
1664         }
1665         /*readlen++;*/
1666     }
1667 }
1668 #endif /* ZEROCOMP */
1669
1670 STATIC_OVL void
1671 def_minit()
1672 {
1673     return;
1674 }
1675
1676 STATIC_OVL void
1677 def_mread(fd, buf, len)
1678 register int fd;
1679 register genericptr_t buf;
1680 register unsigned int len;
1681 {
1682     register int rlen;
1683 #if defined(BSD) || defined(ULTRIX)
1684 #define readLenType int
1685 #else /* e.g. SYSV, __TURBOC__ */
1686 #define readLenType unsigned
1687 #endif
1688
1689     rlen = read(fd, buf, (readLenType) len);
1690     if ((readLenType) rlen != (readLenType) len) {
1691         if (restoreprocs.mread_flags == 1) { /* means "return anyway" */
1692             restoreprocs.mread_flags = -1;
1693             return;
1694         } else {
1695             pline("Read %d instead of %u bytes.", rlen, len);
1696             if (restoring) {
1697                 (void) nhclose(fd);
1698                 (void) delete_savefile();
1699                 error("Error restoring old game.");
1700             }
1701             panic("Error reading level file.");
1702         }
1703     }
1704 }
1705
1706 /*restore.c*/