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