OSDN Git Service

01c754562bed00b03a339fc66bb9847bf8ff82c6
[jnethack/source.git] / src / restore.c
1 /* NetHack 3.6  restore.c       $NHDT-Date: 1555201698 2019/04/14 00:28:18 $  $NHDT-Branch: NetHack-3.6.2-beta01 $:$NHDT-Revision: 1.129 $ */
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-2019            */
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              * For 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, *tmp_bc;
552     char timebuf[15];
553     unsigned long uid;
554     boolean defer_perm_invent;
555
556     mread(fd, (genericptr_t) &uid, sizeof uid);
557     if (SYSOPT_CHECK_SAVE_UID
558         && uid != (unsigned long) getuid()) { /* strange ... */
559         /* for wizard mode, issue a reminder; for others, treat it
560            as an attempt to cheat and refuse to restore this file */
561 /*JP
562         pline("Saved game was not yours.");
563 */
564         pline("\83Z\81[\83u\82³\82ê\82½\83Q\81[\83\80\82Í\82 \82È\82½\82Ì\82à\82Ì\82Å\82Í\82È\82¢\81D");
565         if (!wizard)
566             return FALSE;
567     }
568
569     newgamecontext = context; /* copy statically init'd context */
570     mread(fd, (genericptr_t) &context, sizeof (struct context_info));
571     context.warntype.species = (context.warntype.speciesidx >= LOW_PM)
572                                   ? &mons[context.warntype.speciesidx]
573                                   : (struct permonst *) 0;
574     /* context.victual.piece, .tin.tin, .spellbook.book, and .polearm.hitmon
575        are pointers which get set to Null during save and will be recovered
576        via corresponding o_id or m_id while objs or mons are being restored */
577
578     /* we want to be able to revert to command line/environment/config
579        file option values instead of keeping old save file option values
580        if partial restore fails and we resort to starting a new game */
581     newgameflags = flags;
582     mread(fd, (genericptr_t) &flags, sizeof (struct flag));
583     /* avoid keeping permanent inventory window up to date during restore
584        (setworn() calls update_inventory); attempting to include the cost
585        of unpaid items before shopkeeper's bill is available is a no-no;
586        named fruit names aren't accessible yet either
587        [3.6.2: moved perm_invent from flags to iflags to keep it out of
588        save files; retaining the override here is simpler than trying to
589        to figure out where it really belongs now] */
590     defer_perm_invent = iflags.perm_invent;
591     iflags.perm_invent = FALSE;
592     /* wizard and discover are actually flags.debug and flags.explore;
593        player might be overriding the save file values for them;
594        in the discover case, we don't want to set that for a normal
595        game until after the save file has been removed */
596     iflags.deferred_X = (newgameflags.explore && !discover);
597     if (newgameflags.debug) {
598         /* authorized by startup code; wizard mode exists and is allowed */
599         wizard = TRUE, discover = iflags.deferred_X = FALSE;
600     } else if (wizard) {
601         /* specified by save file; check authorization now */
602         set_playmode();
603     }
604 #ifdef SYSFLAGS
605     newgamesysflags = sysflags;
606     mread(fd, (genericptr_t) &sysflags, sizeof(struct sysflag));
607 #endif
608
609     role_init(); /* Reset the initial role, race, gender, and alignment */
610 #ifdef AMII_GRAPHICS
611     amii_setpens(amii_numcolors); /* use colors from save file */
612 #endif
613     mread(fd, (genericptr_t) &u, sizeof(struct you));
614
615 #define ReadTimebuf(foo)                   \
616     mread(fd, (genericptr_t) timebuf, 14); \
617     timebuf[14] = '\0';                    \
618     foo = time_from_yyyymmddhhmmss(timebuf);
619
620     ReadTimebuf(ubirthday);
621     mread(fd, &urealtime.realtime, sizeof urealtime.realtime);
622     ReadTimebuf(urealtime.start_timing); /** [not used] **/
623     /* current time is the time to use for next urealtime.realtime update */
624     urealtime.start_timing = getnow();
625
626     set_uasmon();
627 #ifdef CLIPPING
628     cliparound(u.ux, u.uy);
629 #endif
630     if (u.uhp <= 0 && (!Upolyd || u.mh <= 0)) {
631         u.ux = u.uy = 0; /* affects pline() [hence You()] */
632 #if 0 /*JP*/
633         You("were not healthy enough to survive restoration.");
634 #else
635         You("\8dÄ\8aJ\82Å\82«\82é\82Ù\82Ç\8c\92\8dN\82Å\82Í\82È\82©\82Á\82½\81D");
636 #endif
637         /* wiz1_level.dlevel is used by mklev.c to see if lots of stuff is
638          * uninitialized, so we only have to set it and not the other stuff.
639          */
640         wiz1_level.dlevel = 0;
641         u.uz.dnum = 0;
642         u.uz.dlevel = 1;
643         /* revert to pre-restore option settings */
644         iflags.deferred_X = FALSE;
645         iflags.perm_invent = defer_perm_invent;
646         flags = newgameflags;
647 #ifdef SYSFLAGS
648         sysflags = newgamesysflags;
649 #endif
650         context = newgamecontext;
651         return FALSE;
652     }
653     /* in case hangup save occurred in midst of level change */
654     assign_level(&u.uz0, &u.uz);
655
656     /* this stuff comes after potential aborted restore attempts */
657     restore_killers(fd);
658     restore_timers(fd, RANGE_GLOBAL, FALSE, 0L);
659     restore_light_sources(fd);
660     invent = restobjchn(fd, FALSE, FALSE);
661     /* tmp_bc only gets set here if the ball & chain were orphaned
662        because you were swallowed; otherwise they will be on the floor
663        or in your inventory */
664     tmp_bc = restobjchn(fd, FALSE, FALSE);
665     if (tmp_bc) {
666         for (otmp = tmp_bc; otmp; otmp = otmp->nobj) {
667             if (otmp->owornmask)
668                 setworn(otmp, otmp->owornmask);
669         }
670         if (!uball || !uchain)
671             impossible("restgamestate: lost ball & chain");
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     /* reset weapon so that player will get a reminder about "bashing"
690        during next fight when bare-handed or wielding an unconventional
691        item; for pick-axe, we aren't able to distinguish between having
692        applied or wielded it, so be conservative and assume the former */
693     otmp = uwep;   /* `uwep' usually init'd by setworn() in loop above */
694     uwep = 0;      /* clear it and have setuwep() reinit */
695     setuwep(otmp); /* (don't need any null check here) */
696     if (!uwep || uwep->otyp == PICK_AXE || uwep->otyp == GRAPPLING_HOOK)
697         unweapon = TRUE;
698
699     restore_dungeon(fd);
700     restlevchn(fd);
701     mread(fd, (genericptr_t) &moves, sizeof moves);
702     mread(fd, (genericptr_t) &monstermoves, sizeof monstermoves);
703     mread(fd, (genericptr_t) &quest_status, sizeof (struct q_score));
704     mread(fd, (genericptr_t) spl_book, (MAXSPELL + 1) * sizeof (struct spell));
705     restore_artifacts(fd);
706     restore_oracles(fd);
707     if (u.ustuck)
708         mread(fd, (genericptr_t) stuckid, sizeof *stuckid);
709     if (u.usteed)
710         mread(fd, (genericptr_t) steedid, sizeof *steedid);
711     mread(fd, (genericptr_t) pl_character, sizeof pl_character);
712
713     mread(fd, (genericptr_t) pl_fruit, sizeof pl_fruit);
714     freefruitchn(ffruit); /* clean up fruit(s) made by initoptions() */
715     ffruit = loadfruitchn(fd);
716
717     restnames(fd);
718     restore_waterlevel(fd);
719     restore_msghistory(fd);
720     /* must come after all mons & objs are restored */
721     relink_timers(FALSE);
722     relink_light_sources(FALSE);
723     /* inventory display is now viable */
724     iflags.perm_invent = defer_perm_invent;
725     return TRUE;
726 }
727
728 /* update game state pointers to those valid for the current level (so we
729  * don't dereference a wild u.ustuck when saving the game state, for instance)
730  */
731 STATIC_OVL void
732 restlevelstate(stuckid, steedid)
733 unsigned int stuckid, steedid;
734 {
735     register struct monst *mtmp;
736
737     if (stuckid) {
738         for (mtmp = fmon; mtmp; mtmp = mtmp->nmon)
739             if (mtmp->m_id == stuckid)
740                 break;
741         if (!mtmp)
742             panic("Cannot find the monster ustuck.");
743         u.ustuck = mtmp;
744     }
745     if (steedid) {
746         for (mtmp = fmon; mtmp; mtmp = mtmp->nmon)
747             if (mtmp->m_id == steedid)
748                 break;
749         if (!mtmp)
750             panic("Cannot find the monster usteed.");
751         u.usteed = mtmp;
752         remove_monster(mtmp->mx, mtmp->my);
753     }
754 }
755
756 /*ARGSUSED*/
757 STATIC_OVL int
758 restlevelfile(fd, ltmp)
759 int fd; /* fd used in MFLOPPY only */
760 xchar ltmp;
761 {
762     int nfd;
763     char whynot[BUFSZ];
764
765 #ifndef MFLOPPY
766     nhUse(fd);
767 #endif
768     nfd = create_levelfile(ltmp, whynot);
769     if (nfd < 0) {
770         /* BUG: should suppress any attempt to write a panic
771            save file if file creation is now failing... */
772         panic("restlevelfile: %s", whynot);
773     }
774 #ifdef MFLOPPY
775     if (!savelev(nfd, ltmp, COUNT_SAVE)) {
776         /* The savelev can't proceed because the size required
777          * is greater than the available disk space.
778          */
779 /*JP
780         pline("Not enough space on `%s' to restore your game.", levels);
781 */
782         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);
783
784         /* Remove levels and bones that may have been created.
785          */
786         (void) nhclose(nfd);
787 #ifdef AMIGA
788         clearlocks();
789 #else /* !AMIGA */
790         eraseall(levels, alllevels);
791         eraseall(levels, allbones);
792
793         /* Perhaps the person would like to play without a
794          * RAMdisk.
795          */
796         if (ramdisk) {
797             /* PlaywoRAMdisk may not return, but if it does
798              * it is certain that ramdisk will be 0.
799              */
800             playwoRAMdisk();
801             /* Rewind save file and try again */
802             (void) lseek(fd, (off_t) 0, 0);
803             (void) validate(fd, (char *) 0); /* skip version etc */
804             return dorecover(fd);            /* 0 or 1 */
805         }
806 #endif /* ?AMIGA */
807 /*JP
808         pline("Be seeing you...");
809 */
810         pline("\82Ü\82½\89ï\82¢\82Ü\82µ\82å\82¤\81D\81D\81D");
811         nh_terminate(EXIT_SUCCESS);
812     }
813 #endif /* MFLOPPY */
814     bufon(nfd);
815     savelev(nfd, ltmp, WRITE_SAVE | FREE_SAVE);
816     bclose(nfd);
817     return 2;
818 }
819
820 int
821 dorecover(fd)
822 register int fd;
823 {
824     unsigned int stuckid = 0, steedid = 0; /* not a register */
825     xchar ltmp;
826     int rtmp;
827     struct obj *otmp;
828
829     restoring = TRUE;
830     get_plname_from_file(fd, plname);
831     getlev(fd, 0, (xchar) 0, FALSE);
832     if (!restgamestate(fd, &stuckid, &steedid)) {
833         display_nhwindow(WIN_MESSAGE, TRUE);
834         savelev(-1, 0, FREE_SAVE); /* discard current level */
835         (void) nhclose(fd);
836         (void) delete_savefile();
837         restoring = FALSE;
838         return 0;
839     }
840     restlevelstate(stuckid, steedid);
841 #ifdef INSURANCE
842     savestateinlock();
843 #endif
844     rtmp = restlevelfile(fd, ledger_no(&u.uz));
845     if (rtmp < 2)
846         return rtmp; /* dorecover called recursively */
847
848     /* these pointers won't be valid while we're processing the
849      * other levels, but they'll be reset again by restlevelstate()
850      * afterwards, and in the meantime at least u.usteed may mislead
851      * place_monster() on other levels
852      */
853     u.ustuck = (struct monst *) 0;
854     u.usteed = (struct monst *) 0;
855
856 #ifdef MICRO
857 #ifdef AMII_GRAPHICS
858     {
859         extern struct window_procs amii_procs;
860         if (WINDOWPORT("amii") {
861             extern winid WIN_BASE;
862             clear_nhwindow(WIN_BASE); /* hack until there's a hook for this */
863         }
864     }
865 #else
866         clear_nhwindow(WIN_MAP);
867 #endif
868     clear_nhwindow(WIN_MESSAGE);
869 #if 0 /*JP*/
870     You("return to level %d in %s%s.", depth(&u.uz),
871         dungeons[u.uz.dnum].dname,
872         flags.debug ? " while in debug mode"
873                     : flags.explore ? " while in explore mode" : "");
874 #else
875     You("%s%s\82Ì\92n\89º%d\8aK\82É\96ß\82Á\82Ä\82«\82½\81D",
876         flags.debug ? "\83E\83B\83U\81[\83h\83\82\81[\83h\92\86\82Ì"
877                     : flags.explore ? "\92T\8c\9f\83\82\81[\83h\92\86\82Ì" : "",
878         dungeons[u.uz.dnum].dname, depth(&u.uz));
879 #endif
880     curs(WIN_MAP, 1, 1);
881     dotcnt = 0;
882     dotrow = 2;
883     if (!WINDOWPORT("X11"))
884         putstr(WIN_MAP, 0, "Restoring:");
885 #endif
886     restoreprocs.mread_flags = 1; /* return despite error */
887     while (1) {
888         mread(fd, (genericptr_t) &ltmp, sizeof ltmp);
889         if (restoreprocs.mread_flags == -1)
890             break;
891         getlev(fd, 0, ltmp, FALSE);
892 #ifdef MICRO
893         curs(WIN_MAP, 1 + dotcnt++, dotrow);
894         if (dotcnt >= (COLNO - 1)) {
895             dotrow++;
896             dotcnt = 0;
897         }
898         if (!WINDOWPORT("X11")) {
899             putstr(WIN_MAP, 0, ".");
900         }
901         mark_synch();
902 #endif
903         rtmp = restlevelfile(fd, ltmp);
904         if (rtmp < 2)
905             return rtmp; /* dorecover called recursively */
906     }
907     restoreprocs.mread_flags = 0;
908
909 #ifdef BSD
910     (void) lseek(fd, 0L, 0);
911 #else
912     (void) lseek(fd, (off_t) 0, 0);
913 #endif
914     (void) validate(fd, (char *) 0); /* skip version and savefile info */
915     get_plname_from_file(fd, plname);
916
917     getlev(fd, 0, (xchar) 0, FALSE);
918     (void) nhclose(fd);
919
920     /* Now set the restore settings to match the
921      * settings used by the save file output routines
922      */
923     reset_restpref();
924
925     restlevelstate(stuckid, steedid);
926     program_state.something_worth_saving = 1; /* useful data now exists */
927
928     if (!wizard && !discover)
929         (void) delete_savefile();
930     if (Is_rogue_level(&u.uz))
931         assign_graphics(ROGUESET);
932 #ifdef USE_TILES
933     substitute_tiles(&u.uz);
934 #endif
935 #ifdef MFLOPPY
936     gameDiskPrompt();
937 #endif
938     max_rank_sz(); /* to recompute mrank_sz (botl.c) */
939     /* take care of iron ball & chain */
940     for (otmp = fobj; otmp; otmp = otmp->nobj)
941         if (otmp->owornmask)
942             setworn(otmp, otmp->owornmask);
943
944     /* in_use processing must be after:
945      *    + The inventory has been read so that freeinv() works.
946      *    + The current level has been restored so billing information
947      *      is available.
948      */
949     inven_inuse(FALSE);
950
951     load_qtlist(); /* re-load the quest text info */
952     /* Set up the vision internals, after levl[] data is loaded
953        but before docrt(). */
954     reglyph_darkroom();
955     vision_reset();
956     vision_full_recalc = 1; /* recompute vision (not saved) */
957
958     run_timers(); /* expire all timers that have gone off while away */
959     docrt();
960     restoring = FALSE;
961     clear_nhwindow(WIN_MESSAGE);
962
963     /* Success! */
964     welcome(FALSE);
965     check_special_room(FALSE);
966     return 1;
967 }
968
969 void
970 restcemetery(fd, cemeteryaddr)
971 int fd;
972 struct cemetery **cemeteryaddr;
973 {
974     struct cemetery *bonesinfo, **bonesaddr;
975     int flag;
976
977     mread(fd, (genericptr_t) &flag, sizeof flag);
978     if (flag == 0) {
979         bonesaddr = cemeteryaddr;
980         do {
981             bonesinfo = (struct cemetery *) alloc(sizeof *bonesinfo);
982             mread(fd, (genericptr_t) bonesinfo, sizeof *bonesinfo);
983             *bonesaddr = bonesinfo;
984             bonesaddr = &(*bonesaddr)->next;
985         } while (*bonesaddr);
986     } else {
987         *cemeteryaddr = 0;
988     }
989 }
990
991 /*ARGSUSED*/
992 STATIC_OVL void
993 rest_levl(fd, rlecomp)
994 int fd;
995 boolean rlecomp;
996 {
997 #ifdef RLECOMP
998     short i, j;
999     uchar len;
1000     struct rm r;
1001
1002     if (rlecomp) {
1003         (void) memset((genericptr_t) &r, 0, sizeof(r));
1004         i = 0;
1005         j = 0;
1006         len = 0;
1007         while (i < ROWNO) {
1008             while (j < COLNO) {
1009                 if (len > 0) {
1010                     levl[j][i] = r;
1011                     len -= 1;
1012                     j += 1;
1013                 } else {
1014                     mread(fd, (genericptr_t) &len, sizeof(uchar));
1015                     mread(fd, (genericptr_t) &r, sizeof(struct rm));
1016                 }
1017             }
1018             j = 0;
1019             i += 1;
1020         }
1021         return;
1022     }
1023 #else /* !RLECOMP */
1024     nhUse(rlecomp);
1025 #endif /* ?RLECOMP */
1026     mread(fd, (genericptr_t) levl, sizeof levl);
1027 }
1028
1029 void
1030 trickery(reason)
1031 char *reason;
1032 {
1033 /*JP
1034     pline("Strange, this map is not as I remember it.");
1035 */
1036     pline("\96­\82¾\81C\82±\82Ì\92n\90}\82Í\8e\84\82ª\8ao\82¦\82Ä\82¢\82½\82à\82Ì\82Æ\88á\82¤\81D");
1037 /*JP
1038     pline("Somebody is trying some trickery here...");
1039 */
1040     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");
1041 /*JP
1042     pline("This game is void.");
1043 */
1044     pline("\82±\82Ì\83Q\81[\83\80\82Í\96³\8cø\82Æ\82È\82é\81D");
1045     Strcpy(killer.name, reason ? reason : "");
1046     done(TRICKED);
1047 }
1048
1049 void
1050 getlev(fd, pid, lev, ghostly)
1051 int fd, pid;
1052 xchar lev;
1053 boolean ghostly;
1054 {
1055     register struct trap *trap;
1056     register struct monst *mtmp;
1057     long elapsed;
1058     branch *br;
1059     int hpid;
1060     xchar dlvl;
1061     int x, y;
1062 #ifdef TOS
1063     short tlev;
1064 #endif
1065
1066     if (ghostly)
1067         clear_id_mapping();
1068
1069 #if defined(MSDOS) || defined(OS2)
1070     setmode(fd, O_BINARY);
1071 #endif
1072     /* Load the old fruit info.  We have to do it first, so the
1073      * information is available when restoring the objects.
1074      */
1075     if (ghostly)
1076         oldfruit = loadfruitchn(fd);
1077
1078     /* First some sanity checks */
1079     mread(fd, (genericptr_t) &hpid, sizeof(hpid));
1080 /* CHECK:  This may prevent restoration */
1081 #ifdef TOS
1082     mread(fd, (genericptr_t) &tlev, sizeof(tlev));
1083     dlvl = tlev & 0x00ff;
1084 #else
1085     mread(fd, (genericptr_t) &dlvl, sizeof(dlvl));
1086 #endif
1087     if ((pid && pid != hpid) || (lev && dlvl != lev)) {
1088         char trickbuf[BUFSZ];
1089
1090         if (pid && pid != hpid)
1091             Sprintf(trickbuf, "PID (%d) doesn't match saved PID (%d)!", hpid,
1092                     pid);
1093         else
1094             Sprintf(trickbuf, "This is level %d, not %d!", dlvl, lev);
1095         if (wizard)
1096             pline1(trickbuf);
1097         trickery(trickbuf);
1098     }
1099     restcemetery(fd, &level.bonesinfo);
1100     rest_levl(fd,
1101               (boolean) ((sfrestinfo.sfi1 & SFI1_RLECOMP) == SFI1_RLECOMP));
1102     mread(fd, (genericptr_t) lastseentyp, sizeof(lastseentyp));
1103     mread(fd, (genericptr_t) &omoves, sizeof(omoves));
1104     elapsed = monstermoves - omoves;
1105     mread(fd, (genericptr_t) &upstair, sizeof(stairway));
1106     mread(fd, (genericptr_t) &dnstair, sizeof(stairway));
1107     mread(fd, (genericptr_t) &upladder, sizeof(stairway));
1108     mread(fd, (genericptr_t) &dnladder, sizeof(stairway));
1109     mread(fd, (genericptr_t) &sstairs, sizeof(stairway));
1110     mread(fd, (genericptr_t) &updest, sizeof(dest_area));
1111     mread(fd, (genericptr_t) &dndest, sizeof(dest_area));
1112     mread(fd, (genericptr_t) &level.flags, sizeof(level.flags));
1113     mread(fd, (genericptr_t) doors, sizeof(doors));
1114     rest_rooms(fd); /* No joke :-) */
1115     if (nroom)
1116         doorindex = rooms[nroom - 1].fdoor + rooms[nroom - 1].doorct;
1117     else
1118         doorindex = 0;
1119
1120     restore_timers(fd, RANGE_LEVEL, ghostly, elapsed);
1121     restore_light_sources(fd);
1122     fmon = restmonchn(fd, ghostly);
1123
1124     rest_worm(fd); /* restore worm information */
1125     ftrap = 0;
1126     while (trap = newtrap(),
1127            mread(fd, (genericptr_t) trap, sizeof(struct trap)),
1128            trap->tx != 0) { /* need "!= 0" to work around DICE 3.0 bug */
1129         trap->ntrap = ftrap;
1130         ftrap = trap;
1131     }
1132     dealloc_trap(trap);
1133     fobj = restobjchn(fd, ghostly, FALSE);
1134     find_lev_obj();
1135     /* restobjchn()'s `frozen' argument probably ought to be a callback
1136        routine so that we can check for objects being buried under ice */
1137     level.buriedobjlist = restobjchn(fd, ghostly, FALSE);
1138     billobjs = restobjchn(fd, ghostly, FALSE);
1139     rest_engravings(fd);
1140
1141     /* reset level.monsters for new level */
1142     for (x = 0; x < COLNO; x++)
1143         for (y = 0; y < ROWNO; y++)
1144             level.monsters[x][y] = (struct monst *) 0;
1145     for (mtmp = fmon; mtmp; mtmp = mtmp->nmon) {
1146         if (mtmp->isshk)
1147             set_residency(mtmp, FALSE);
1148         place_monster(mtmp, mtmp->mx, mtmp->my);
1149         if (mtmp->wormno)
1150             place_wsegs(mtmp, NULL);
1151
1152         /* regenerate monsters while on another level */
1153         if (!u.uz.dlevel)
1154             continue;
1155         if (ghostly) {
1156             /* reset peaceful/malign relative to new character;
1157                shopkeepers will reset based on name */
1158             if (!mtmp->isshk)
1159                 mtmp->mpeaceful =
1160                     (is_unicorn(mtmp->data)
1161                      && sgn(u.ualign.type) == sgn(mtmp->data->maligntyp))
1162                         ? TRUE
1163                         : peace_minded(mtmp->data);
1164             set_malign(mtmp);
1165         } else if (elapsed > 0L) {
1166             mon_catchup_elapsed_time(mtmp, elapsed);
1167         }
1168         /* update shape-changers in case protection against
1169            them is different now than when the level was saved */
1170         restore_cham(mtmp);
1171         /* give hiders a chance to hide before their next move */
1172         if (ghostly || elapsed > (long) rnd(10))
1173             hide_monst(mtmp);
1174     }
1175
1176     restdamage(fd, ghostly);
1177     rest_regions(fd, ghostly);
1178     if (ghostly) {
1179         /* Now get rid of all the temp fruits... */
1180         freefruitchn(oldfruit), oldfruit = 0;
1181
1182         if (lev > ledger_no(&medusa_level)
1183             && lev < ledger_no(&stronghold_level) && xdnstair == 0) {
1184             coord cc;
1185
1186             mazexy(&cc);
1187             xdnstair = cc.x;
1188             ydnstair = cc.y;
1189             levl[cc.x][cc.y].typ = STAIRS;
1190         }
1191
1192         br = Is_branchlev(&u.uz);
1193         if (br && u.uz.dlevel == 1) {
1194             d_level ltmp;
1195
1196             if (on_level(&u.uz, &br->end1))
1197                 assign_level(&ltmp, &br->end2);
1198             else
1199                 assign_level(&ltmp, &br->end1);
1200
1201             switch (br->type) {
1202             case BR_STAIR:
1203             case BR_NO_END1:
1204             case BR_NO_END2: /* OK to assign to sstairs if it's not used */
1205                 assign_level(&sstairs.tolev, &ltmp);
1206                 break;
1207             case BR_PORTAL: /* max of 1 portal per level */
1208                 for (trap = ftrap; trap; trap = trap->ntrap)
1209                     if (trap->ttyp == MAGIC_PORTAL)
1210                         break;
1211                 if (!trap)
1212                     panic("getlev: need portal but none found");
1213                 assign_level(&trap->dst, &ltmp);
1214                 break;
1215             }
1216         } else if (!br) {
1217             struct trap *ttmp = 0;
1218
1219             /* Remove any dangling portals. */
1220             for (trap = ftrap; trap; trap = ttmp) {
1221                 ttmp = trap->ntrap;
1222                 if (trap->ttyp == MAGIC_PORTAL)
1223                     deltrap(trap);
1224             }
1225         }
1226     }
1227
1228     /* must come after all mons & objs are restored */
1229     relink_timers(ghostly);
1230     relink_light_sources(ghostly);
1231     reset_oattached_mids(ghostly);
1232
1233     if (ghostly)
1234         clear_id_mapping();
1235 }
1236
1237 void
1238 get_plname_from_file(fd, plbuf)
1239 int fd;
1240 char *plbuf;
1241 {
1242     int pltmpsiz = 0;
1243 _pragma_ignore(-Wunused-result)
1244     (void) read(fd, (genericptr_t) &pltmpsiz, sizeof(pltmpsiz));
1245     (void) read(fd, (genericptr_t) plbuf, pltmpsiz);
1246 _pragma_pop
1247     return;
1248 }
1249
1250 STATIC_OVL void
1251 restore_msghistory(fd)
1252 register int fd;
1253 {
1254     int msgsize, msgcount = 0;
1255     char msg[BUFSZ];
1256
1257     while (1) {
1258         mread(fd, (genericptr_t) &msgsize, sizeof(msgsize));
1259         if (msgsize == -1)
1260             break;
1261         if (msgsize > (BUFSZ - 1))
1262             panic("restore_msghistory: msg too big (%d)", msgsize);
1263         mread(fd, (genericptr_t) msg, msgsize);
1264         msg[msgsize] = '\0';
1265         putmsghistory(msg, TRUE);
1266         ++msgcount;
1267     }
1268     if (msgcount)
1269         putmsghistory((char *) 0, TRUE);
1270     debugpline1("Read %d messages from savefile.", msgcount);
1271 }
1272
1273 /* Clear all structures for object and monster ID mapping. */
1274 STATIC_OVL void
1275 clear_id_mapping()
1276 {
1277     struct bucket *curr;
1278
1279     while ((curr = id_map) != 0) {
1280         id_map = curr->next;
1281         free((genericptr_t) curr);
1282     }
1283     n_ids_mapped = 0;
1284 }
1285
1286 /* Add a mapping to the ID map. */
1287 STATIC_OVL void
1288 add_id_mapping(gid, nid)
1289 unsigned gid, nid;
1290 {
1291     int idx;
1292
1293     idx = n_ids_mapped % N_PER_BUCKET;
1294     /* idx is zero on first time through, as well as when a new bucket is */
1295     /* needed */
1296     if (idx == 0) {
1297         struct bucket *gnu = (struct bucket *) alloc(sizeof(struct bucket));
1298         gnu->next = id_map;
1299         id_map = gnu;
1300     }
1301
1302     id_map->map[idx].gid = gid;
1303     id_map->map[idx].nid = nid;
1304     n_ids_mapped++;
1305 }
1306
1307 /*
1308  * Global routine to look up a mapping.  If found, return TRUE and fill
1309  * in the new ID value.  Otherwise, return false and return -1 in the new
1310  * ID.
1311  */
1312 boolean
1313 lookup_id_mapping(gid, nidp)
1314 unsigned gid, *nidp;
1315 {
1316     int i;
1317     struct bucket *curr;
1318
1319     if (n_ids_mapped)
1320         for (curr = id_map; curr; curr = curr->next) {
1321             /* first bucket might not be totally full */
1322             if (curr == id_map) {
1323                 i = n_ids_mapped % N_PER_BUCKET;
1324                 if (i == 0)
1325                     i = N_PER_BUCKET;
1326             } else
1327                 i = N_PER_BUCKET;
1328
1329             while (--i >= 0)
1330                 if (gid == curr->map[i].gid) {
1331                     *nidp = curr->map[i].nid;
1332                     return TRUE;
1333                 }
1334         }
1335
1336     return FALSE;
1337 }
1338
1339 STATIC_OVL void
1340 reset_oattached_mids(ghostly)
1341 boolean ghostly;
1342 {
1343     struct obj *otmp;
1344     unsigned oldid, nid;
1345     for (otmp = fobj; otmp; otmp = otmp->nobj) {
1346         if (ghostly && has_omonst(otmp)) {
1347             struct monst *mtmp = OMONST(otmp);
1348
1349             mtmp->m_id = 0;
1350             mtmp->mpeaceful = mtmp->mtame = 0; /* pet's owner died! */
1351         }
1352         if (ghostly && has_omid(otmp)) {
1353             (void) memcpy((genericptr_t) &oldid, (genericptr_t) OMID(otmp),
1354                           sizeof(oldid));
1355             if (lookup_id_mapping(oldid, &nid))
1356                 (void) memcpy((genericptr_t) OMID(otmp), (genericptr_t) &nid,
1357                               sizeof(nid));
1358             else
1359                 free_omid(otmp);
1360         }
1361     }
1362 }
1363
1364 #ifdef SELECTSAVED
1365 /* put up a menu listing each character from this player's saved games;
1366    returns 1: use plname[], 0: new game, -1: quit */
1367 int
1368 restore_menu(bannerwin)
1369 winid bannerwin; /* if not WIN_ERR, clear window and show copyright in menu */
1370 {
1371     winid tmpwin;
1372     anything any;
1373     char **saved;
1374     menu_item *chosen_game = (menu_item *) 0;
1375     int k, clet, ch = 0; /* ch: 0 => new game */
1376
1377     *plname = '\0';
1378     saved = get_saved_games(); /* array of character names */
1379     if (saved && *saved) {
1380         tmpwin = create_nhwindow(NHW_MENU);
1381         start_menu(tmpwin);
1382         any = zeroany; /* no selection */
1383         if (bannerwin != WIN_ERR) {
1384             /* for tty; erase copyright notice and redo it in the menu */
1385             clear_nhwindow(bannerwin);
1386             /* COPYRIGHT_BANNER_[ABCD] */
1387             for (k = 1; k <= 4; ++k)
1388                 add_menu(tmpwin, NO_GLYPH, &any, 0, 0, ATR_NONE,
1389                          copyright_banner_line(k), MENU_UNSELECTED);
1390             add_menu(tmpwin, NO_GLYPH, &any, 0, 0, ATR_NONE, "",
1391                      MENU_UNSELECTED);
1392         }
1393         add_menu(tmpwin, NO_GLYPH, &any, 0, 0, ATR_NONE,
1394                  "Select one of your saved games", MENU_UNSELECTED);
1395         for (k = 0; saved[k]; ++k) {
1396             any.a_int = k + 1;
1397             add_menu(tmpwin, NO_GLYPH, &any, 0, 0, ATR_NONE, saved[k],
1398                      MENU_UNSELECTED);
1399         }
1400         clet = (k <= 'n' - 'a') ? 'n' : 0; /* new game */
1401         any.a_int = -1;                    /* not >= 0 */
1402         add_menu(tmpwin, NO_GLYPH, &any, clet, 0, ATR_NONE,
1403                  "Start a new character", MENU_UNSELECTED);
1404         clet = (k + 1 <= 'q' - 'a') ? 'q' : 0; /* quit */
1405         any.a_int = -2;
1406         add_menu(tmpwin, NO_GLYPH, &any, clet, 0, ATR_NONE,
1407                  "Never mind (quit)", MENU_SELECTED);
1408         /* no prompt on end_menu, as we've done our own at the top */
1409         end_menu(tmpwin, (char *) 0);
1410         if (select_menu(tmpwin, PICK_ONE, &chosen_game) > 0) {
1411             ch = chosen_game->item.a_int;
1412             if (ch > 0)
1413                 Strcpy(plname, saved[ch - 1]);
1414             else if (ch < 0)
1415                 ++ch; /* -1 -> 0 (new game), -2 -> -1 (quit) */
1416             free((genericptr_t) chosen_game);
1417         } else {
1418             ch = -1; /* quit menu without making a selection => quit */
1419         }
1420         destroy_nhwindow(tmpwin);
1421         if (bannerwin != WIN_ERR) {
1422             /* for tty; clear the menu away and put subset of copyright back
1423              */
1424             clear_nhwindow(bannerwin);
1425             /* COPYRIGHT_BANNER_A, preceding "Who are you?" prompt */
1426             if (ch == 0)
1427                 putstr(bannerwin, 0, copyright_banner_line(1));
1428         }
1429     }
1430     free_saved_games(saved);
1431     return (ch > 0) ? 1 : ch;
1432 }
1433 #endif /* SELECTSAVED */
1434
1435 void
1436 minit()
1437 {
1438     (*restoreprocs.restore_minit)();
1439     return;
1440 }
1441
1442 void
1443 mread(fd, buf, len)
1444 register int fd;
1445 register genericptr_t buf;
1446 register unsigned int len;
1447 {
1448     (*restoreprocs.restore_mread)(fd, buf, len);
1449     return;
1450 }
1451
1452 /* examine the version info and the savefile_info data
1453    that immediately follows it.
1454    Return 0 if it passed the checks.
1455    Return 1 if it failed the version check.
1456    Return 2 if it failed the savefile feature check.
1457    Return -1 if it failed for some unknown reason.
1458  */
1459 int
1460 validate(fd, name)
1461 int fd;
1462 const char *name;
1463 {
1464     int rlen;
1465     struct savefile_info sfi;
1466     unsigned long compatible;
1467     boolean verbose = name ? TRUE : FALSE, reslt = FALSE;
1468
1469     if (!(reslt = uptodate(fd, name)))
1470         return 1;
1471
1472     rlen = read(fd, (genericptr_t) &sfi, sizeof sfi);
1473     minit(); /* ZEROCOMP */
1474     if (rlen == 0) {
1475         if (verbose) {
1476             pline("File \"%s\" is empty during save file feature check?",
1477                   name);
1478             wait_synch();
1479         }
1480         return -1;
1481     }
1482
1483     compatible = (sfi.sfi1 & sfcap.sfi1);
1484
1485     if ((sfi.sfi1 & SFI1_ZEROCOMP) == SFI1_ZEROCOMP) {
1486         if ((compatible & SFI1_ZEROCOMP) != SFI1_ZEROCOMP) {
1487             if (verbose) {
1488                 pline("File \"%s\" has incompatible ZEROCOMP compression.",
1489                       name);
1490                 wait_synch();
1491             }
1492             return 2;
1493         } else if ((sfrestinfo.sfi1 & SFI1_ZEROCOMP) != SFI1_ZEROCOMP) {
1494             set_restpref("zerocomp");
1495         }
1496     }
1497
1498     if ((sfi.sfi1 & SFI1_EXTERNALCOMP) == SFI1_EXTERNALCOMP) {
1499         if ((compatible & SFI1_EXTERNALCOMP) != SFI1_EXTERNALCOMP) {
1500             if (verbose) {
1501                 pline("File \"%s\" lacks required internal compression.",
1502                       name);
1503                 wait_synch();
1504             }
1505             return 2;
1506         } else if ((sfrestinfo.sfi1 & SFI1_EXTERNALCOMP)
1507                    != SFI1_EXTERNALCOMP) {
1508             set_restpref("externalcomp");
1509         }
1510     }
1511
1512     /* RLECOMP check must be last, after ZEROCOMP or INTERNALCOMP adjustments
1513      */
1514     if ((sfi.sfi1 & SFI1_RLECOMP) == SFI1_RLECOMP) {
1515         if ((compatible & SFI1_RLECOMP) != SFI1_RLECOMP) {
1516             if (verbose) {
1517                 pline("File \"%s\" has incompatible run-length compression.",
1518                       name);
1519                 wait_synch();
1520             }
1521             return 2;
1522         } else if ((sfrestinfo.sfi1 & SFI1_RLECOMP) != SFI1_RLECOMP) {
1523             set_restpref("rlecomp");
1524         }
1525     }
1526     /* savefile does not have RLECOMP level location compression, so adjust */
1527     else
1528         set_restpref("!rlecomp");
1529
1530     return 0;
1531 }
1532
1533 void
1534 reset_restpref()
1535 {
1536 #ifdef ZEROCOMP
1537     if (iflags.zerocomp)
1538         set_restpref("zerocomp");
1539     else
1540 #endif
1541         set_restpref("externalcomp");
1542 #ifdef RLECOMP
1543     if (iflags.rlecomp)
1544         set_restpref("rlecomp");
1545     else
1546 #endif
1547         set_restpref("!rlecomp");
1548 }
1549
1550 void
1551 set_restpref(suitename)
1552 const char *suitename;
1553 {
1554     if (!strcmpi(suitename, "externalcomp")) {
1555         restoreprocs.name = "externalcomp";
1556         restoreprocs.restore_mread = def_mread;
1557         restoreprocs.restore_minit = def_minit;
1558         sfrestinfo.sfi1 |= SFI1_EXTERNALCOMP;
1559         sfrestinfo.sfi1 &= ~SFI1_ZEROCOMP;
1560         def_minit();
1561     }
1562     if (!strcmpi(suitename, "!rlecomp")) {
1563         sfrestinfo.sfi1 &= ~SFI1_RLECOMP;
1564     }
1565 #ifdef ZEROCOMP
1566     if (!strcmpi(suitename, "zerocomp")) {
1567         restoreprocs.name = "zerocomp";
1568         restoreprocs.restore_mread = zerocomp_mread;
1569         restoreprocs.restore_minit = zerocomp_minit;
1570         sfrestinfo.sfi1 |= SFI1_ZEROCOMP;
1571         sfrestinfo.sfi1 &= ~SFI1_EXTERNALCOMP;
1572         zerocomp_minit();
1573     }
1574 #endif
1575 #ifdef RLECOMP
1576     if (!strcmpi(suitename, "rlecomp")) {
1577         sfrestinfo.sfi1 |= SFI1_RLECOMP;
1578     }
1579 #endif
1580 }
1581
1582 #ifdef ZEROCOMP
1583 #define RLESC '\0' /* Leading character for run of RLESC's */
1584
1585 #ifndef ZEROCOMP_BUFSIZ
1586 #define ZEROCOMP_BUFSIZ BUFSZ
1587 #endif
1588 static NEARDATA unsigned char inbuf[ZEROCOMP_BUFSIZ];
1589 static NEARDATA unsigned short inbufp = 0;
1590 static NEARDATA unsigned short inbufsz = 0;
1591 static NEARDATA short inrunlength = -1;
1592 static NEARDATA int mreadfd;
1593
1594 STATIC_OVL int
1595 zerocomp_mgetc()
1596 {
1597     if (inbufp >= inbufsz) {
1598         inbufsz = read(mreadfd, (genericptr_t) inbuf, sizeof inbuf);
1599         if (!inbufsz) {
1600             if (inbufp > sizeof inbuf)
1601                 error("EOF on file #%d.\n", mreadfd);
1602             inbufp = 1 + sizeof inbuf; /* exactly one warning :-) */
1603             return -1;
1604         }
1605         inbufp = 0;
1606     }
1607     return inbuf[inbufp++];
1608 }
1609
1610 STATIC_OVL void
1611 zerocomp_minit()
1612 {
1613     inbufsz = 0;
1614     inbufp = 0;
1615     inrunlength = -1;
1616 }
1617
1618 STATIC_OVL void
1619 zerocomp_mread(fd, buf, len)
1620 int fd;
1621 genericptr_t buf;
1622 register unsigned len;
1623 {
1624     /*register int readlen = 0;*/
1625     if (fd < 0)
1626         error("Restore error; mread attempting to read file %d.", fd);
1627     mreadfd = fd;
1628     while (len--) {
1629         if (inrunlength > 0) {
1630             inrunlength--;
1631             *(*((char **) &buf))++ = '\0';
1632         } else {
1633             register short ch = zerocomp_mgetc();
1634             if (ch < 0) {
1635                 restoreprocs.mread_flags = -1;
1636                 return;
1637             }
1638             if ((*(*(char **) &buf)++ = (char) ch) == RLESC) {
1639                 inrunlength = zerocomp_mgetc();
1640             }
1641         }
1642         /*readlen++;*/
1643     }
1644 }
1645 #endif /* ZEROCOMP */
1646
1647 STATIC_OVL void
1648 def_minit()
1649 {
1650     return;
1651 }
1652
1653 STATIC_OVL void
1654 def_mread(fd, buf, len)
1655 register int fd;
1656 register genericptr_t buf;
1657 register unsigned int len;
1658 {
1659     register int rlen;
1660 #if defined(BSD) || defined(ULTRIX)
1661 #define readLenType int
1662 #else /* e.g. SYSV, __TURBOC__ */
1663 #define readLenType unsigned
1664 #endif
1665
1666     rlen = read(fd, buf, (readLenType) len);
1667     if ((readLenType) rlen != (readLenType) len) {
1668         if (restoreprocs.mread_flags == 1) { /* means "return anyway" */
1669             restoreprocs.mread_flags = -1;
1670             return;
1671         } else {
1672             pline("Read %d instead of %u bytes.", rlen, len);
1673             if (restoring) {
1674                 (void) nhclose(fd);
1675                 (void) delete_savefile();
1676                 error("Error restoring old game.");
1677             }
1678             panic("Error reading level file.");
1679         }
1680     }
1681 }
1682
1683 /*restore.c*/