OSDN Git Service

Initial Import
[nethackexpress/trunk.git] / src / restore.c
1 /*      SCCS Id: @(#)restore.c  3.4     2003/09/06      */
2 /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
3 /* NetHack may be freely redistributed.  See license for details. */
4
5 #include "hack.h"
6 #include "lev.h"
7 #include "tcap.h" /* for TERMLIB and ASCIIGRAPH */
8
9 #if defined(MICRO)
10 extern int dotcnt;      /* shared with save */
11 extern int dotrow;      /* shared with save */
12 #endif
13
14 #ifdef USE_TILES
15 extern void FDECL(substitute_tiles, (d_level *));       /* from tile.c */
16 #endif
17
18 #ifdef ZEROCOMP
19 static int NDECL(mgetc);
20 #endif
21 STATIC_DCL void NDECL(find_lev_obj);
22 STATIC_DCL void FDECL(restlevchn, (int));
23 STATIC_DCL void FDECL(restdamage, (int,BOOLEAN_P));
24 STATIC_DCL struct obj *FDECL(restobjchn, (int,BOOLEAN_P,BOOLEAN_P));
25 STATIC_DCL struct monst *FDECL(restmonchn, (int,BOOLEAN_P));
26 STATIC_DCL struct fruit *FDECL(loadfruitchn, (int));
27 STATIC_DCL void FDECL(freefruitchn, (struct fruit *));
28 STATIC_DCL void FDECL(ghostfruit, (struct obj *));
29 STATIC_DCL boolean FDECL(restgamestate, (int, unsigned int *, unsigned int *));
30 STATIC_DCL void FDECL(restlevelstate, (unsigned int, unsigned int));
31 STATIC_DCL int FDECL(restlevelfile, (int,XCHAR_P));
32 STATIC_DCL void FDECL(reset_oattached_mids, (BOOLEAN_P));
33
34 /*
35  * Save a mapping of IDs from ghost levels to the current level.  This
36  * map is used by the timer routines when restoring ghost levels.
37  */
38 #define N_PER_BUCKET 64
39 struct bucket {
40     struct bucket *next;
41     struct {
42         unsigned gid;   /* ghost ID */
43         unsigned nid;   /* new ID */
44     } map[N_PER_BUCKET];
45 };
46
47 STATIC_DCL void NDECL(clear_id_mapping);
48 STATIC_DCL void FDECL(add_id_mapping, (unsigned, unsigned));
49
50 static int n_ids_mapped = 0;
51 static struct bucket *id_map = 0;
52
53
54 #ifdef AMII_GRAPHICS
55 void FDECL( amii_setpens, (int) );      /* use colors from save file */
56 extern int amii_numcolors;
57 #endif
58
59 #include "quest.h"
60
61 boolean restoring = FALSE;
62 static NEARDATA struct fruit *oldfruit;
63 static NEARDATA long omoves;
64
65 #define Is_IceBox(o) ((o)->otyp == ICE_BOX ? TRUE : FALSE)
66
67 /* Recalculate level.objects[x][y], since this info was not saved. */
68 STATIC_OVL void
69 find_lev_obj()
70 {
71         register struct obj *fobjtmp = (struct obj *)0;
72         register struct obj *otmp;
73         int x,y;
74
75         for(x=0; x<COLNO; x++) for(y=0; y<ROWNO; y++)
76                 level.objects[x][y] = (struct obj *)0;
77
78         /*
79          * Reverse the entire fobj chain, which is necessary so that we can
80          * place the objects in the proper order.  Make all obj in chain
81          * OBJ_FREE so place_object will work correctly.
82          */
83         while ((otmp = fobj) != 0) {
84                 fobj = otmp->nobj;
85                 otmp->nobj = fobjtmp;
86                 otmp->where = OBJ_FREE;
87                 fobjtmp = otmp;
88         }
89         /* fobj should now be empty */
90
91         /* Set level.objects (as well as reversing the chain back again) */
92         while ((otmp = fobjtmp) != 0) {
93                 fobjtmp = otmp->nobj;
94                 place_object(otmp, otmp->ox, otmp->oy);
95         }
96 }
97
98 /* Things that were marked "in_use" when the game was saved (ex. via the
99  * infamous "HUP" cheat) get used up here.
100  */
101 void
102 inven_inuse(quietly)
103 boolean quietly;
104 {
105         register struct obj *otmp, *otmp2;
106
107         for (otmp = invent; otmp; otmp = otmp2) {
108             otmp2 = otmp->nobj;
109 #ifndef GOLDOBJ
110             if (otmp->oclass == COIN_CLASS) {
111                 /* in_use gold is created by some menu operations */
112                 if (!otmp->in_use) {
113                     impossible("inven_inuse: !in_use gold in inventory");
114                 }
115                 extract_nobj(otmp, &invent);
116                 otmp->in_use = FALSE;
117                 dealloc_obj(otmp);
118             } else
119 #endif /* GOLDOBJ */
120             if (otmp->in_use) {
121                 if (!quietly) pline("Finishing off %s...", xname(otmp));
122                 useup(otmp);
123             }
124         }
125 }
126
127 STATIC_OVL void
128 restlevchn(fd)
129 register int fd;
130 {
131         int cnt;
132         s_level *tmplev, *x;
133
134         sp_levchn = (s_level *) 0;
135         mread(fd, (genericptr_t) &cnt, sizeof(int));
136         for(; cnt > 0; cnt--) {
137
138             tmplev = (s_level *)alloc(sizeof(s_level));
139             mread(fd, (genericptr_t) tmplev, sizeof(s_level));
140             if(!sp_levchn) sp_levchn = tmplev;
141             else {
142
143                 for(x = sp_levchn; x->next; x = x->next);
144                 x->next = tmplev;
145             }
146             tmplev->next = (s_level *)0;
147         }
148 }
149
150 STATIC_OVL void
151 restdamage(fd, ghostly)
152 int fd;
153 boolean ghostly;
154 {
155         int counter;
156         struct damage *tmp_dam;
157
158         mread(fd, (genericptr_t) &counter, sizeof(counter));
159         if (!counter)
160             return;
161         tmp_dam = (struct damage *)alloc(sizeof(struct damage));
162         while (--counter >= 0) {
163             char damaged_shops[5], *shp = (char *)0;
164
165             mread(fd, (genericptr_t) tmp_dam, sizeof(*tmp_dam));
166             if (ghostly)
167                 tmp_dam->when += (monstermoves - omoves);
168             Strcpy(damaged_shops,
169                    in_rooms(tmp_dam->place.x, tmp_dam->place.y, SHOPBASE));
170             if (u.uz.dlevel) {
171                 /* when restoring, there are two passes over the current
172                  * level.  the first time, u.uz isn't set, so neither is
173                  * shop_keeper().  just wait and process the damage on
174                  * the second pass.
175                  */
176                 for (shp = damaged_shops; *shp; shp++) {
177                     struct monst *shkp = shop_keeper(*shp);
178
179                     if (shkp && inhishop(shkp) &&
180                             repair_damage(shkp, tmp_dam, TRUE))
181                         break;
182                 }
183             }
184             if (!shp || !*shp) {
185                 tmp_dam->next = level.damagelist;
186                 level.damagelist = tmp_dam;
187                 tmp_dam = (struct damage *)alloc(sizeof(*tmp_dam));
188             }
189         }
190         free((genericptr_t)tmp_dam);
191 }
192
193 STATIC_OVL struct obj *
194 restobjchn(fd, ghostly, frozen)
195 register int fd;
196 boolean ghostly, frozen;
197 {
198         register struct obj *otmp, *otmp2 = 0;
199         register struct obj *first = (struct obj *)0;
200         int xl;
201
202         while(1) {
203                 mread(fd, (genericptr_t) &xl, sizeof(xl));
204                 if(xl == -1) break;
205                 otmp = newobj(xl);
206                 if(!first) first = otmp;
207                 else otmp2->nobj = otmp;
208                 mread(fd, (genericptr_t) otmp,
209                                         (unsigned) xl + sizeof(struct obj));
210                 if (ghostly) {
211                     unsigned nid = flags.ident++;
212                     add_id_mapping(otmp->o_id, nid);
213                     otmp->o_id = nid;
214                 }
215                 if (ghostly && otmp->otyp == SLIME_MOLD) ghostfruit(otmp);
216                 /* Ghost levels get object age shifted from old player's clock
217                  * to new player's clock.  Assumption: new player arrived
218                  * immediately after old player died.
219                  */
220                 if (ghostly && !frozen && !age_is_relative(otmp))
221                     otmp->age = monstermoves - omoves + otmp->age;
222
223                 /* get contents of a container or statue */
224                 if (Has_contents(otmp)) {
225                     struct obj *otmp3;
226                     otmp->cobj = restobjchn(fd, ghostly, Is_IceBox(otmp));
227                     /* restore container back pointers */
228                     for (otmp3 = otmp->cobj; otmp3; otmp3 = otmp3->nobj)
229                         otmp3->ocontainer = otmp;
230                 }
231                 if (otmp->bypass) otmp->bypass = 0;
232
233                 otmp2 = otmp;
234         }
235         if(first && otmp2->nobj){
236                 impossible("Restobjchn: error reading objchn.");
237                 otmp2->nobj = 0;
238         }
239
240         return(first);
241 }
242
243 STATIC_OVL struct monst *
244 restmonchn(fd, ghostly)
245 register int fd;
246 boolean ghostly;
247 {
248         register struct monst *mtmp, *mtmp2 = 0;
249         register struct monst *first = (struct monst *)0;
250         int xl;
251         struct permonst *monbegin;
252         boolean moved;
253
254         /* get the original base address */
255         mread(fd, (genericptr_t)&monbegin, sizeof(monbegin));
256         moved = (monbegin != mons);
257
258         while(1) {
259                 mread(fd, (genericptr_t) &xl, sizeof(xl));
260                 if(xl == -1) break;
261                 mtmp = newmonst(xl);
262                 if(!first) first = mtmp;
263                 else mtmp2->nmon = mtmp;
264                 mread(fd, (genericptr_t) mtmp, (unsigned) xl + sizeof(struct monst));
265                 if (ghostly) {
266                         unsigned nid = flags.ident++;
267                         add_id_mapping(mtmp->m_id, nid);
268                         mtmp->m_id = nid;
269                 }
270                 if (moved && mtmp->data) {
271                         int offset = mtmp->data - monbegin;     /*(ptrdiff_t)*/
272                         mtmp->data = mons + offset;  /* new permonst location */
273                 }
274                 if (ghostly) {
275                         int mndx = monsndx(mtmp->data);
276                         if (propagate(mndx, TRUE, ghostly) == 0) {
277                                 /* cookie to trigger purge in getbones() */
278                                 mtmp->mhpmax = DEFUNCT_MONSTER; 
279                         }
280                 }
281                 if(mtmp->minvent) {
282                         struct obj *obj;
283                         mtmp->minvent = restobjchn(fd, ghostly, FALSE);
284                         /* restore monster back pointer */
285                         for (obj = mtmp->minvent; obj; obj = obj->nobj)
286                                 obj->ocarry = mtmp;
287                 }
288                 if (mtmp->mw) {
289                         struct obj *obj;
290
291                         for(obj = mtmp->minvent; obj; obj = obj->nobj)
292                                 if (obj->owornmask & W_WEP) break;
293                         if (obj) mtmp->mw = obj;
294                         else {
295                                 MON_NOWEP(mtmp);
296                                 impossible("bad monster weapon restore");
297                         }
298                 }
299
300                 if (mtmp->isshk) restshk(mtmp, ghostly);
301                 if (mtmp->ispriest) restpriest(mtmp, ghostly);
302
303                 mtmp2 = mtmp;
304         }
305         if(first && mtmp2->nmon){
306                 impossible("Restmonchn: error reading monchn.");
307                 mtmp2->nmon = 0;
308         }
309         return(first);
310 }
311
312 STATIC_OVL struct fruit *
313 loadfruitchn(fd)
314 int fd;
315 {
316         register struct fruit *flist, *fnext;
317
318         flist = 0;
319         while (fnext = newfruit(),
320                mread(fd, (genericptr_t)fnext, sizeof *fnext),
321                fnext->fid != 0) {
322                 fnext->nextf = flist;
323                 flist = fnext;
324         }
325         dealloc_fruit(fnext);
326         return flist;
327 }
328
329 STATIC_OVL void
330 freefruitchn(flist)
331 register struct fruit *flist;
332 {
333         register struct fruit *fnext;
334
335         while (flist) {
336             fnext = flist->nextf;
337             dealloc_fruit(flist);
338             flist = fnext;
339         }
340 }
341
342 STATIC_OVL void
343 ghostfruit(otmp)
344 register struct obj *otmp;
345 {
346         register struct fruit *oldf;
347
348         for (oldf = oldfruit; oldf; oldf = oldf->nextf)
349                 if (oldf->fid == otmp->spe) break;
350
351         if (!oldf) impossible("no old fruit?");
352         else otmp->spe = fruitadd(oldf->fname);
353 }
354
355 STATIC_OVL
356 boolean
357 restgamestate(fd, stuckid, steedid)
358 register int fd;
359 unsigned int *stuckid, *steedid;        /* STEED */
360 {
361         /* discover is actually flags.explore */
362         boolean remember_discover = discover;
363         struct obj *otmp;
364         int uid;
365
366         mread(fd, (genericptr_t) &uid, sizeof uid);
367         if (uid != getuid()) {          /* strange ... */
368             /* for wizard mode, issue a reminder; for others, treat it
369                as an attempt to cheat and refuse to restore this file */
370             pline("Saved game was not yours.");
371 #ifdef WIZARD
372             if (!wizard)
373 #endif
374                 return FALSE;
375         }
376
377         mread(fd, (genericptr_t) &flags, sizeof(struct flag));
378         flags.bypasses = 0;     /* never use the saved value of bypasses */
379         if (remember_discover) discover = remember_discover;
380
381         role_init();    /* Reset the initial role, race, gender, and alignment */
382 #ifdef AMII_GRAPHICS
383         amii_setpens(amii_numcolors);   /* use colors from save file */
384 #endif
385         mread(fd, (genericptr_t) &u, sizeof(struct you));
386         set_uasmon();
387 #ifdef CLIPPING
388         cliparound(u.ux, u.uy);
389 #endif
390         if(u.uhp <= 0 && (!Upolyd || u.mh <= 0)) {
391             u.ux = u.uy = 0;    /* affects pline() [hence You()] */
392             You("were not healthy enough to survive restoration.");
393             /* wiz1_level.dlevel is used by mklev.c to see if lots of stuff is
394              * uninitialized, so we only have to set it and not the other stuff.
395              */
396             wiz1_level.dlevel = 0;
397             u.uz.dnum = 0;
398             u.uz.dlevel = 1;
399             return(FALSE);
400         }
401
402         /* this stuff comes after potential aborted restore attempts */
403         restore_timers(fd, RANGE_GLOBAL, FALSE, 0L);
404         restore_light_sources(fd);
405         invent = restobjchn(fd, FALSE, FALSE);
406         migrating_objs = restobjchn(fd, FALSE, FALSE);
407         migrating_mons = restmonchn(fd, FALSE);
408         mread(fd, (genericptr_t) mvitals, sizeof(mvitals));
409
410         /* this comes after inventory has been loaded */
411         for(otmp = invent; otmp; otmp = otmp->nobj)
412                 if(otmp->owornmask)
413                         setworn(otmp, otmp->owornmask);
414         /* reset weapon so that player will get a reminder about "bashing"
415            during next fight when bare-handed or wielding an unconventional
416            item; for pick-axe, we aren't able to distinguish between having
417            applied or wielded it, so be conservative and assume the former */
418         otmp = uwep;    /* `uwep' usually init'd by setworn() in loop above */
419         uwep = 0;       /* clear it and have setuwep() reinit */
420         setuwep(otmp);  /* (don't need any null check here) */
421         if (!uwep || uwep->otyp == PICK_AXE || uwep->otyp == GRAPPLING_HOOK)
422             unweapon = TRUE;
423
424         restore_dungeon(fd);
425         restlevchn(fd);
426         mread(fd, (genericptr_t) &moves, sizeof moves);
427         mread(fd, (genericptr_t) &monstermoves, sizeof monstermoves);
428         mread(fd, (genericptr_t) &quest_status, sizeof(struct q_score));
429         mread(fd, (genericptr_t) spl_book,
430                                 sizeof(struct spell) * (MAXSPELL + 1));
431         restore_artifacts(fd);
432         restore_oracles(fd);
433         if (u.ustuck)
434                 mread(fd, (genericptr_t) stuckid, sizeof (*stuckid));
435 #ifdef STEED
436         if (u.usteed)
437                 mread(fd, (genericptr_t) steedid, sizeof (*steedid));
438 #endif
439         mread(fd, (genericptr_t) pl_character, sizeof pl_character);
440
441         mread(fd, (genericptr_t) pl_fruit, sizeof pl_fruit);
442         mread(fd, (genericptr_t) &current_fruit, sizeof current_fruit);
443         freefruitchn(ffruit);   /* clean up fruit(s) made by initoptions() */
444         ffruit = loadfruitchn(fd);
445
446         restnames(fd);
447         restore_waterlevel(fd);
448         /* must come after all mons & objs are restored */
449         relink_timers(FALSE);
450         relink_light_sources(FALSE);
451         return(TRUE);
452 }
453
454 /* update game state pointers to those valid for the current level (so we
455  * don't dereference a wild u.ustuck when saving the game state, for instance)
456  */
457 STATIC_OVL void
458 restlevelstate(stuckid, steedid)
459 unsigned int stuckid, steedid;  /* STEED */
460 {
461         register struct monst *mtmp;
462
463         if (stuckid) {
464                 for (mtmp = fmon; mtmp; mtmp = mtmp->nmon)
465                         if (mtmp->m_id == stuckid) break;
466                 if (!mtmp) panic("Cannot find the monster ustuck.");
467                 u.ustuck = mtmp;
468         }
469 #ifdef STEED
470         if (steedid) {
471                 for (mtmp = fmon; mtmp; mtmp = mtmp->nmon)
472                         if (mtmp->m_id == steedid) break;
473                 if (!mtmp) panic("Cannot find the monster usteed.");
474                 u.usteed = mtmp;
475                 remove_monster(mtmp->mx, mtmp->my);
476         }
477 #endif
478 }
479
480 /*ARGSUSED*/    /* fd used in MFLOPPY only */
481 STATIC_OVL int
482 restlevelfile(fd, ltmp)
483 register int fd;
484 xchar ltmp;
485 #if defined(macintosh) && (defined(__SC__) || defined(__MRC__))
486 # pragma unused(fd)
487 #endif
488 {
489         register int nfd;
490         char whynot[BUFSZ];
491
492         nfd = create_levelfile(ltmp, whynot);
493         if (nfd < 0) {
494                 /* BUG: should suppress any attempt to write a panic
495                    save file if file creation is now failing... */
496                 panic("restlevelfile: %s", whynot);
497         }
498 #ifdef MFLOPPY
499         if (!savelev(nfd, ltmp, COUNT_SAVE)) {
500
501                 /* The savelev can't proceed because the size required
502                  * is greater than the available disk space.
503                  */
504                 pline("Not enough space on `%s' to restore your game.",
505                         levels);
506
507                 /* Remove levels and bones that may have been created.
508                  */
509                 (void) close(nfd);
510 # ifdef AMIGA
511                 clearlocks();
512 # else
513                 eraseall(levels, alllevels);
514                 eraseall(levels, allbones);
515
516                 /* Perhaps the person would like to play without a
517                  * RAMdisk.
518                  */
519                 if (ramdisk) {
520                         /* PlaywoRAMdisk may not return, but if it does
521                          * it is certain that ramdisk will be 0.
522                          */
523                         playwoRAMdisk();
524                         /* Rewind save file and try again */
525                         (void) lseek(fd, (off_t)0, 0);
526                         (void) uptodate(fd, (char *)0); /* skip version */
527                         return dorecover(fd);   /* 0 or 1 */
528                 } else {
529 # endif
530                         pline("Be seeing you...");
531                         terminate(EXIT_SUCCESS);
532 # ifndef AMIGA
533                 }
534 # endif
535         }
536 #endif
537         bufon(nfd);
538         savelev(nfd, ltmp, WRITE_SAVE | FREE_SAVE);
539         bclose(nfd);
540         return(2);
541 }
542
543 int
544 dorecover(fd)
545 register int fd;
546 {
547         unsigned int stuckid = 0, steedid = 0;  /* not a register */
548         xchar ltmp;
549         int rtmp;
550         struct obj *otmp;
551
552 #ifdef STORE_PLNAME_IN_FILE
553         mread(fd, (genericptr_t) plname, PL_NSIZ);
554 #endif
555
556         restoring = TRUE;
557         getlev(fd, 0, (xchar)0, FALSE);
558         if (!restgamestate(fd, &stuckid, &steedid)) {
559                 display_nhwindow(WIN_MESSAGE, TRUE);
560                 savelev(-1, 0, FREE_SAVE);      /* discard current level */
561                 (void) close(fd);
562                 (void) delete_savefile();
563                 restoring = FALSE;
564                 return(0);
565         }
566         restlevelstate(stuckid, steedid);
567 #ifdef INSURANCE
568         savestateinlock();
569 #endif
570         rtmp = restlevelfile(fd, ledger_no(&u.uz));
571         if (rtmp < 2) return(rtmp);  /* dorecover called recursively */
572
573         /* these pointers won't be valid while we're processing the
574          * other levels, but they'll be reset again by restlevelstate()
575          * afterwards, and in the meantime at least u.usteed may mislead
576          * place_monster() on other levels
577          */
578         u.ustuck = (struct monst *)0;
579 #ifdef STEED
580         u.usteed = (struct monst *)0;
581 #endif
582
583 #ifdef MICRO
584 # ifdef AMII_GRAPHICS
585         {
586         extern struct window_procs amii_procs;
587         if(windowprocs.win_init_nhwindows== amii_procs.win_init_nhwindows){
588             extern winid WIN_BASE;
589             clear_nhwindow(WIN_BASE);   /* hack until there's a hook for this */
590         }
591         }
592 # else
593         clear_nhwindow(WIN_MAP);
594 # endif
595         clear_nhwindow(WIN_MESSAGE);
596         You("return to level %d in %s%s.",
597                 depth(&u.uz), dungeons[u.uz.dnum].dname,
598                 flags.debug ? " while in debug mode" :
599                 flags.explore ? " while in explore mode" : "");
600         curs(WIN_MAP, 1, 1);
601         dotcnt = 0;
602         dotrow = 2;
603         if (strncmpi("X11", windowprocs.name, 3))
604           putstr(WIN_MAP, 0, "Restoring:");
605 #endif
606         while(1) {
607 #ifdef ZEROCOMP
608                 if(mread(fd, (genericptr_t) &ltmp, sizeof ltmp) < 0)
609 #else
610                 if(read(fd, (genericptr_t) &ltmp, sizeof ltmp) != sizeof ltmp)
611 #endif
612                         break;
613                 getlev(fd, 0, ltmp, FALSE);
614 #ifdef MICRO
615                 curs(WIN_MAP, 1+dotcnt++, dotrow);
616                 if (dotcnt >= (COLNO - 1)) {
617                         dotrow++;
618                         dotcnt = 0;
619                 }
620                 if (strncmpi("X11", windowprocs.name, 3)){
621                   putstr(WIN_MAP, 0, ".");
622                 }
623                 mark_synch();
624 #endif
625                 rtmp = restlevelfile(fd, ltmp);
626                 if (rtmp < 2) return(rtmp);  /* dorecover called recursively */
627         }
628
629 #ifdef BSD
630         (void) lseek(fd, 0L, 0);
631 #else
632         (void) lseek(fd, (off_t)0, 0);
633 #endif
634         (void) uptodate(fd, (char *)0);         /* skip version info */
635 #ifdef STORE_PLNAME_IN_FILE
636         mread(fd, (genericptr_t) plname, PL_NSIZ);
637 #endif
638         getlev(fd, 0, (xchar)0, FALSE);
639         (void) close(fd);
640
641         if (!wizard && !discover)
642                 (void) delete_savefile();
643 #ifdef REINCARNATION
644         if (Is_rogue_level(&u.uz)) assign_rogue_graphics(TRUE);
645 #endif
646 #ifdef USE_TILES
647         substitute_tiles(&u.uz);
648 #endif
649         restlevelstate(stuckid, steedid);
650 #ifdef MFLOPPY
651         gameDiskPrompt();
652 #endif
653         max_rank_sz(); /* to recompute mrank_sz (botl.c) */
654         /* take care of iron ball & chain */
655         for(otmp = fobj; otmp; otmp = otmp->nobj)
656                 if(otmp->owornmask)
657                         setworn(otmp, otmp->owornmask);
658
659         /* in_use processing must be after:
660          *    + The inventory has been read so that freeinv() works.
661          *    + The current level has been restored so billing information
662          *      is available.
663          */
664         inven_inuse(FALSE);
665
666         load_qtlist();  /* re-load the quest text info */
667         reset_attribute_clock();
668         /* Set up the vision internals, after levl[] data is loaded */
669         /* but before docrt().                                      */
670         vision_reset();
671         vision_full_recalc = 1; /* recompute vision (not saved) */
672
673         run_timers();   /* expire all timers that have gone off while away */
674         docrt();
675         restoring = FALSE;
676         clear_nhwindow(WIN_MESSAGE);
677         program_state.something_worth_saving++; /* useful data now exists */
678
679         /* Success! */
680         welcome(FALSE);
681         return(1);
682 }
683
684 void
685 trickery(reason)
686 char *reason;
687 {
688         pline("Strange, this map is not as I remember it.");
689         pline("Somebody is trying some trickery here...");
690         pline("This game is void.");
691         killer = reason;
692         done(TRICKED);
693 }
694
695 void
696 getlev(fd, pid, lev, ghostly)
697 int fd, pid;
698 xchar lev;
699 boolean ghostly;
700 {
701         register struct trap *trap;
702         register struct monst *mtmp;
703         branch *br;
704         int hpid;
705         xchar dlvl;
706         int x, y;
707 #ifdef TOS
708         short tlev;
709 #endif
710
711         if (ghostly)
712             clear_id_mapping();
713
714 #if defined(MSDOS) || defined(OS2)
715         setmode(fd, O_BINARY);
716 #endif
717         /* Load the old fruit info.  We have to do it first, so the
718          * information is available when restoring the objects.
719          */
720         if (ghostly) oldfruit = loadfruitchn(fd);
721
722         /* First some sanity checks */
723         mread(fd, (genericptr_t) &hpid, sizeof(hpid));
724 /* CHECK:  This may prevent restoration */
725 #ifdef TOS
726         mread(fd, (genericptr_t) &tlev, sizeof(tlev));
727         dlvl=tlev&0x00ff;
728 #else
729         mread(fd, (genericptr_t) &dlvl, sizeof(dlvl));
730 #endif
731         if ((pid && pid != hpid) || (lev && dlvl != lev)) {
732             char trickbuf[BUFSZ];
733
734             if (pid && pid != hpid)
735                 Sprintf(trickbuf, "PID (%d) doesn't match saved PID (%d)!",
736                         hpid, pid);
737             else
738                 Sprintf(trickbuf, "This is level %d, not %d!", dlvl, lev);
739 #ifdef WIZARD
740             if (wizard) pline(trickbuf);
741 #endif
742             trickery(trickbuf);
743         }
744
745 #ifdef RLECOMP
746         {
747                 short   i, j;
748                 uchar   len;
749                 struct rm r;
750                 
751 #if defined(MAC)
752                 /* Suppress warning about used before set */
753                 (void) memset((genericptr_t) &r, 0, sizeof(r));
754 #endif
755                 i = 0; j = 0; len = 0;
756                 while(i < ROWNO) {
757                     while(j < COLNO) {
758                         if(len > 0) {
759                             levl[j][i] = r;
760                             len -= 1;
761                             j += 1;
762                         } else {
763                             mread(fd, (genericptr_t)&len, sizeof(uchar));
764                             mread(fd, (genericptr_t)&r, sizeof(struct rm));
765                         }
766                     }
767                     j = 0;
768                     i += 1;
769                 }
770         }
771 #else
772         mread(fd, (genericptr_t) levl, sizeof(levl));
773 #endif  /* RLECOMP */
774
775         mread(fd, (genericptr_t)&omoves, sizeof(omoves));
776         mread(fd, (genericptr_t)&upstair, sizeof(stairway));
777         mread(fd, (genericptr_t)&dnstair, sizeof(stairway));
778         mread(fd, (genericptr_t)&upladder, sizeof(stairway));
779         mread(fd, (genericptr_t)&dnladder, sizeof(stairway));
780         mread(fd, (genericptr_t)&sstairs, sizeof(stairway));
781         mread(fd, (genericptr_t)&updest, sizeof(dest_area));
782         mread(fd, (genericptr_t)&dndest, sizeof(dest_area));
783         mread(fd, (genericptr_t)&level.flags, sizeof(level.flags));
784         mread(fd, (genericptr_t)doors, sizeof(doors));
785         rest_rooms(fd);         /* No joke :-) */
786         if (nroom)
787             doorindex = rooms[nroom - 1].fdoor + rooms[nroom - 1].doorct;
788         else
789             doorindex = 0;
790
791         restore_timers(fd, RANGE_LEVEL, ghostly, monstermoves - omoves);
792         restore_light_sources(fd);
793         fmon = restmonchn(fd, ghostly);
794
795         /* regenerate animals while on another level */
796         if (u.uz.dlevel) {
797             register struct monst *mtmp2;
798
799             for (mtmp = fmon; mtmp; mtmp = mtmp2) {
800                 mtmp2 = mtmp->nmon;
801                 if (ghostly) {
802                         /* reset peaceful/malign relative to new character */
803                         if(!mtmp->isshk)
804                                 /* shopkeepers will reset based on name */
805                                 mtmp->mpeaceful = peace_minded(mtmp->data);
806                         set_malign(mtmp);
807                 } else if (monstermoves > omoves)
808                         mon_catchup_elapsed_time(mtmp, monstermoves - omoves);
809
810                 /* update shape-changers in case protection against
811                    them is different now than when the level was saved */
812                 restore_cham(mtmp);
813             }
814         }
815
816         rest_worm(fd);  /* restore worm information */
817         ftrap = 0;
818         while (trap = newtrap(),
819                mread(fd, (genericptr_t)trap, sizeof(struct trap)),
820                trap->tx != 0) { /* need "!= 0" to work around DICE 3.0 bug */
821                 trap->ntrap = ftrap;
822                 ftrap = trap;
823         }
824         dealloc_trap(trap);
825         fobj = restobjchn(fd, ghostly, FALSE);
826         find_lev_obj();
827         /* restobjchn()'s `frozen' argument probably ought to be a callback
828            routine so that we can check for objects being buried under ice */
829         level.buriedobjlist = restobjchn(fd, ghostly, FALSE);
830         billobjs = restobjchn(fd, ghostly, FALSE);
831         rest_engravings(fd);
832
833         /* reset level.monsters for new level */
834         for (x = 0; x < COLNO; x++)
835             for (y = 0; y < ROWNO; y++)
836                 level.monsters[x][y] = (struct monst *) 0;
837         for (mtmp = level.monlist; mtmp; mtmp = mtmp->nmon) {
838             if (mtmp->isshk)
839                 set_residency(mtmp, FALSE);
840             place_monster(mtmp, mtmp->mx, mtmp->my);
841             if (mtmp->wormno) place_wsegs(mtmp);
842         }
843         restdamage(fd, ghostly);
844
845         rest_regions(fd, ghostly);
846         if (ghostly) {
847             /* Now get rid of all the temp fruits... */
848             freefruitchn(oldfruit),  oldfruit = 0;
849
850             if (lev > ledger_no(&medusa_level) &&
851                         lev < ledger_no(&stronghold_level) && xdnstair == 0) {
852                 coord cc;
853
854                 mazexy(&cc);
855                 xdnstair = cc.x;
856                 ydnstair = cc.y;
857                 levl[cc.x][cc.y].typ = STAIRS;
858             }
859
860             br = Is_branchlev(&u.uz);
861             if (br && u.uz.dlevel == 1) {
862                 d_level ltmp;
863
864                 if (on_level(&u.uz, &br->end1))
865                     assign_level(&ltmp, &br->end2);
866                 else
867                     assign_level(&ltmp, &br->end1);
868
869                 switch(br->type) {
870                 case BR_STAIR:
871                 case BR_NO_END1:
872                 case BR_NO_END2: /* OK to assign to sstairs if it's not used */
873                     assign_level(&sstairs.tolev, &ltmp);
874                     break;              
875                 case BR_PORTAL: /* max of 1 portal per level */
876                     {
877                         register struct trap *ttmp;
878                         for(ttmp = ftrap; ttmp; ttmp = ttmp->ntrap)
879                             if (ttmp->ttyp == MAGIC_PORTAL)
880                                 break;
881                         if (!ttmp) panic("getlev: need portal but none found");
882                         assign_level(&ttmp->dst, &ltmp);
883                     }
884                     break;
885                 }
886             } else if (!br) {
887                 /* Remove any dangling portals. */
888                 register struct trap *ttmp;
889                 for (ttmp = ftrap; ttmp; ttmp = ttmp->ntrap)
890                     if (ttmp->ttyp == MAGIC_PORTAL) {
891                         deltrap(ttmp);
892                         break; /* max of 1 portal/level */
893                     }
894             }
895         }
896
897         /* must come after all mons & objs are restored */
898         relink_timers(ghostly);
899         relink_light_sources(ghostly);
900         reset_oattached_mids(ghostly);
901
902         if (ghostly)
903             clear_id_mapping();
904 }
905
906
907 /* Clear all structures for object and monster ID mapping. */
908 STATIC_OVL void
909 clear_id_mapping()
910 {
911     struct bucket *curr;
912
913     while ((curr = id_map) != 0) {
914         id_map = curr->next;
915         free((genericptr_t) curr);
916     }
917     n_ids_mapped = 0;
918 }
919
920 /* Add a mapping to the ID map. */
921 STATIC_OVL void
922 add_id_mapping(gid, nid)
923     unsigned gid, nid;
924 {
925     int idx;
926
927     idx = n_ids_mapped % N_PER_BUCKET;
928     /* idx is zero on first time through, as well as when a new bucket is */
929     /* needed */
930     if (idx == 0) {
931         struct bucket *gnu = (struct bucket *) alloc(sizeof(struct bucket));
932         gnu->next = id_map;
933         id_map = gnu;
934     }
935
936     id_map->map[idx].gid = gid;
937     id_map->map[idx].nid = nid;
938     n_ids_mapped++;
939 }
940
941 /*
942  * Global routine to look up a mapping.  If found, return TRUE and fill
943  * in the new ID value.  Otherwise, return false and return -1 in the new
944  * ID.
945  */
946 boolean
947 lookup_id_mapping(gid, nidp)
948     unsigned gid, *nidp;
949 {
950     int i;
951     struct bucket *curr;
952
953     if (n_ids_mapped)
954         for (curr = id_map; curr; curr = curr->next) {
955             /* first bucket might not be totally full */
956             if (curr == id_map) {
957                 i = n_ids_mapped % N_PER_BUCKET;
958                 if (i == 0) i = N_PER_BUCKET;
959             } else
960                 i = N_PER_BUCKET;
961
962             while (--i >= 0)
963                 if (gid == curr->map[i].gid) {
964                     *nidp = curr->map[i].nid;
965                     return TRUE;
966                 }
967         }
968
969     return FALSE;
970 }
971
972 STATIC_OVL void
973 reset_oattached_mids(ghostly)
974 boolean ghostly;
975 {
976     struct obj *otmp;
977     unsigned oldid, nid;
978     for (otmp = fobj; otmp; otmp = otmp->nobj) {
979         if (ghostly && otmp->oattached == OATTACHED_MONST && otmp->oxlth) {
980             struct monst *mtmp = (struct monst *)otmp->oextra;
981
982             mtmp->m_id = 0;
983             mtmp->mpeaceful = mtmp->mtame = 0;  /* pet's owner died! */
984         }
985         if (ghostly && otmp->oattached == OATTACHED_M_ID) {
986             (void) memcpy((genericptr_t)&oldid, (genericptr_t)otmp->oextra,
987                                                                 sizeof(oldid));
988             if (lookup_id_mapping(oldid, &nid))
989                 (void) memcpy((genericptr_t)otmp->oextra, (genericptr_t)&nid,
990                                                                 sizeof(nid));
991             else
992                 otmp->oattached = OATTACHED_NOTHING;
993         }
994     }
995 }
996
997
998 #ifdef ZEROCOMP
999 #define RLESC '\0'      /* Leading character for run of RLESC's */
1000
1001 #ifndef ZEROCOMP_BUFSIZ
1002 #define ZEROCOMP_BUFSIZ BUFSZ
1003 #endif
1004 static NEARDATA unsigned char inbuf[ZEROCOMP_BUFSIZ];
1005 static NEARDATA unsigned short inbufp = 0;
1006 static NEARDATA unsigned short inbufsz = 0;
1007 static NEARDATA short inrunlength = -1;
1008 static NEARDATA int mreadfd;
1009
1010 static int
1011 mgetc()
1012 {
1013     if (inbufp >= inbufsz) {
1014         inbufsz = read(mreadfd, (genericptr_t)inbuf, sizeof inbuf);
1015         if (!inbufsz) {
1016             if (inbufp > sizeof inbuf)
1017                 error("EOF on file #%d.\n", mreadfd);
1018             inbufp = 1 + sizeof inbuf;  /* exactly one warning :-) */
1019             return -1;
1020         }
1021         inbufp = 0;
1022     }
1023     return inbuf[inbufp++];
1024 }
1025
1026 void
1027 minit()
1028 {
1029     inbufsz = 0;
1030     inbufp = 0;
1031     inrunlength = -1;
1032 }
1033
1034 int
1035 mread(fd, buf, len)
1036 int fd;
1037 genericptr_t buf;
1038 register unsigned len;
1039 {
1040     /*register int readlen = 0;*/
1041     if (fd < 0) error("Restore error; mread attempting to read file %d.", fd);
1042     mreadfd = fd;
1043     while (len--) {
1044         if (inrunlength > 0) {
1045             inrunlength--;
1046             *(*((char **)&buf))++ = '\0';
1047         } else {
1048             register short ch = mgetc();
1049             if (ch < 0) return -1; /*readlen;*/
1050             if ((*(*(char **)&buf)++ = (char)ch) == RLESC) {
1051                 inrunlength = mgetc();
1052             }
1053         }
1054         /*readlen++;*/
1055     }
1056     return 0; /*readlen;*/
1057 }
1058
1059 #else /* ZEROCOMP */
1060
1061 void
1062 minit()
1063 {
1064     return;
1065 }
1066
1067 void
1068 mread(fd, buf, len)
1069 register int fd;
1070 register genericptr_t buf;
1071 register unsigned int len;
1072 {
1073         register int rlen;
1074
1075 #if defined(BSD) || defined(ULTRIX)
1076         rlen = read(fd, buf, (int) len);
1077         if(rlen != len){
1078 #else /* e.g. SYSV, __TURBOC__ */
1079         rlen = read(fd, buf, (unsigned) len);
1080         if((unsigned)rlen != len){
1081 #endif
1082                 pline("Read %d instead of %u bytes.", rlen, len);
1083                 if(restoring) {
1084                         (void) close(fd);
1085                         (void) delete_savefile();
1086                         error("Error restoring old game.");
1087                 }
1088                 panic("Error reading level file.");
1089         }
1090 }
1091 #endif /* ZEROCOMP */
1092
1093 /*restore.c*/