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