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) &current_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) &ltmp, sizeof ltmp) < 0)
569 #else
570 		if(read(fd, (genericptr_t) &ltmp, 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(&ltmp, &br->end2);
811 		else
812 		    assign_level(&ltmp, &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, &ltmp);
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, &ltmp);
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