Source:NetHack 3.4.3/src/restore.c

From NetHackWiki
(Redirected from Source:Ref/inven inuse)
Jump to: navigation, search

Below is the full text to src/restore.c from NetHack 3.4.3. To link to a particular line, write [[restore.c#line123]], for example.

Top of file[edit]

  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. */

The NetHack General Public License applies to screenshots, source code and other content from NetHack.

This content was modified from the original NetHack source code distribution (by splitting up NetHack content between wiki pages, and possibly further editing). See the page history for a list of who changed it, and on what dates.

  1. #include "hack.h"
  2. #include "lev.h"
  3. #include "tcap.h" /* for TERMLIB and ASCIIGRAPH */
  4.  
  5. #if defined(MICRO)
  6. extern int dotcnt;	/* shared with save */
  7. extern int dotrow;	/* shared with save */
  8. #endif
  9.  
  10. #ifdef USE_TILES
  11. extern void FDECL(substitute_tiles, (d_level *));       /* from tile.c */
  12. #endif
  13.  
  14. #ifdef ZEROCOMP
  15. static int NDECL(mgetc);
  16. #endif
  17. STATIC_DCL void NDECL(find_lev_obj);
  18. STATIC_DCL void FDECL(restlevchn, (int));
  19. STATIC_DCL void FDECL(restdamage, (int,BOOLEAN_P));
  20. STATIC_DCL struct obj *FDECL(restobjchn, (int,BOOLEAN_P,BOOLEAN_P));
  21. STATIC_DCL struct monst *FDECL(restmonchn, (int,BOOLEAN_P));
  22. STATIC_DCL struct fruit *FDECL(loadfruitchn, (int));
  23. STATIC_DCL void FDECL(freefruitchn, (struct fruit *));
  24. STATIC_DCL void FDECL(ghostfruit, (struct obj *));
  25. STATIC_DCL boolean FDECL(restgamestate, (int, unsigned int *, unsigned int *));
  26. STATIC_DCL void FDECL(restlevelstate, (unsigned int, unsigned int));
  27. STATIC_DCL int FDECL(restlevelfile, (int,XCHAR_P));
  28. STATIC_DCL void FDECL(reset_oattached_mids, (BOOLEAN_P));
  29.  
  30. /*
  31. * Save a mapping of IDs from ghost levels to the current level.  This
  32. * map is used by the timer routines when restoring ghost levels.
  33. */
  34. #define N_PER_BUCKET 64
  35. struct bucket {
  36. struct bucket *next;
  37. struct {
  38. 	unsigned gid;	/* ghost ID */
  39. 	unsigned nid;	/* new ID */
  40. } map[N_PER_BUCKET];
  41. };
  42.  
  43. STATIC_DCL void NDECL(clear_id_mapping);
  44. STATIC_DCL void FDECL(add_id_mapping, (unsigned, unsigned));
  45.  
  46. static int n_ids_mapped = 0;
  47. static struct bucket *id_map = 0;
  48.  
  49.  
  50. #ifdef AMII_GRAPHICS
  51. void FDECL( amii_setpens, (int) );	/* use colors from save file */
  52. extern int amii_numcolors;
  53. #endif
  54.  
  55. #include "quest.h"
  56.  
  57. boolean restoring = FALSE;
  58. static NEARDATA struct fruit *oldfruit;
  59. static NEARDATA long omoves;
  60.  
  61. #define Is_IceBox(o) ((o)->otyp == ICE_BOX ? TRUE : FALSE)

find_lev_obj[edit]

  1. /* Recalculate level.objects[x][y], since this info was not saved. */
  2. STATIC_OVL void
  3. find_lev_obj()
  4. {
  5. 	register struct obj *fobjtmp = (struct obj *)0;
  6. 	register struct obj *otmp;
  7. 	int x,y;
  8.  
  9. 	for(x=0; x<COLNO; x++) for(y=0; y<ROWNO; y++)
  10. 		level.objects[x][y] = (struct obj *)0;
  11.  
  12. 	/*
  13. 	 * Reverse the entire fobj chain, which is necessary so that we can
  14. 	 * place the objects in the proper order.  Make all obj in chain
  15. 	 * OBJ_FREE so place_object will work correctly.
  16. 	 */
  17. 	while ((otmp = fobj) != 0) {
  18. 		fobj = otmp->nobj;
  19. 		otmp->nobj = fobjtmp;
  20. 		otmp->where = OBJ_FREE;
  21. 		fobjtmp = otmp;
  22. 	}
  23. 	/* fobj should now be empty */
  24.  
  25. 	/* Set level.objects (as well as reversing the chain back again) */
  26. 	while ((otmp = fobjtmp) != 0) {
  27. 		fobjtmp = otmp->nobj;
  28. 		place_object(otmp, otmp->ox, otmp->oy);
  29. 	}
  30. }

inven_inuse[edit]

  1. /* Things that were marked "in_use" when the game was saved (ex. via the
  2. * infamous "HUP" cheat) get used up here.
  3. */
  4. void
  5. inven_inuse(quietly)
  6. boolean quietly;
  7. {
  8. 	register struct obj *otmp, *otmp2;
  9.  
  10. 	for (otmp = invent; otmp; otmp = otmp2) {
  11. 	    otmp2 = otmp->nobj;
  12. #ifndef GOLDOBJ
  13. 	    if (otmp->oclass == COIN_CLASS) {
  14. 		/* in_use gold is created by some menu operations */
  15. 		if (!otmp->in_use) {
  16. 		    impossible("inven_inuse: !in_use gold in inventory");
  17. 		}
  18. 		extract_nobj(otmp, &invent);
  19. 		otmp->in_use = FALSE;
  20. 		dealloc_obj(otmp);
  21. 	    } else
  22. #endif /* GOLDOBJ */
  23. 	    if (otmp->in_use) {
  24. 		if (!quietly) pline("Finishing off %s...", xname(otmp));
  25. 		useup(otmp);
  26. 	    }
  27. 	}
  28. }

restlevchn[edit]

  1. STATIC_OVL void
  2. restlevchn(fd)
  3. register int fd;
  4. {
  5. 	int cnt;
  6. 	s_level	*tmplev, *x;
  7.  
  8. 	sp_levchn = (s_level *) 0;
  9. 	mread(fd, (genericptr_t) &cnt, sizeof(int));
  10. 	for(; cnt > 0; cnt--) {
  11.  
  12. 	    tmplev = (s_level *)alloc(sizeof(s_level));
  13. 	    mread(fd, (genericptr_t) tmplev, sizeof(s_level));
  14. 	    if(!sp_levchn) sp_levchn = tmplev;
  15. 	    else {
  16.  
  17. 		for(x = sp_levchn; x->next; x = x->next);
  18. 		x->next = tmplev;
  19. 	    }
  20. 	    tmplev->next = (s_level *)0;
  21. 	}
  22. }

restdamage[edit]

  1. STATIC_OVL void
  2. restdamage(fd, ghostly)
  3. int fd;
  4. boolean ghostly;
  5. {
  6. 	int counter;
  7. 	struct damage *tmp_dam;
  8.  
  9. 	mread(fd, (genericptr_t) &counter, sizeof(counter));
  10. 	if (!counter)
  11. 	    return;
  12. 	tmp_dam = (struct damage *)alloc(sizeof(struct damage));
  13. 	while (--counter >= 0) {
  14. 	    char damaged_shops[5], *shp = (char *)0;
  15.  
  16. 	    mread(fd, (genericptr_t) tmp_dam, sizeof(*tmp_dam));
  17. 	    if (ghostly)
  18. 		tmp_dam->when += (monstermoves - omoves);
  19. 	    Strcpy(damaged_shops,
  20. 		   in_rooms(tmp_dam->place.x, tmp_dam->place.y, SHOPBASE));
  21. 	    if (u.uz.dlevel) {
  22. 		/* when restoring, there are two passes over the current
  23. 		 * level.  the first time, u.uz isn't set, so neither is
  24. 		 * shop_keeper().  just wait and process the damage on
  25. 		 * the second pass.
  26. 		 */
  27. 		for (shp = damaged_shops; *shp; shp++) {
  28. 		    struct monst *shkp = shop_keeper(*shp);
  29.  
  30. 		    if (shkp && inhishop(shkp) &&
  31. 			    repair_damage(shkp, tmp_dam, TRUE))
  32. 			break;
  33. 		}
  34. 	    }
  35. 	    if (!shp || !*shp) {
  36. 		tmp_dam->next = level.damagelist;
  37. 		level.damagelist = tmp_dam;
  38. 		tmp_dam = (struct damage *)alloc(sizeof(*tmp_dam));
  39. 	    }
  40. 	}
  41. 	free((genericptr_t)tmp_dam);
  42. }

restobjchn[edit]

The restobjchn function returns a linked list of type struct obj. Each dungeon level has an object chain containing all objects on the floor, and each container has an object chain of its contents.

  1. STATIC_OVL struct obj *
  2. restobjchn(fd, ghostly, frozen)
  3. register int fd;
  4. boolean ghostly, frozen;
  5. {
  6. 	register struct obj *otmp, *otmp2 = 0;
  7. 	register struct obj *first = (struct obj *)0;
  8. 	int xl;
  9.  
  10. 	while(1) {
  11. 		mread(fd, (genericptr_t) &xl, sizeof(xl));
  12. 		if(xl == -1) break;
  13. 		otmp = newobj(xl);

xl is the first block to be read from disk for each object. If it's -1, it indicates the end of the object chain. Otherwise, it contains the length of the oextra field in struct obj. Since sizeof(xl) depends on int width on a given processor, savefiles will not necessarily be portable between systems.

  1. 		if(!first) first = otmp;
  2. 		else otmp2->nobj = otmp;
  3. 		mread(fd, (genericptr_t) otmp,
  4. 					(unsigned) xl + sizeof(struct obj));

Reads xl + sizeof(struct obj) bytes directly into the struct. mread() appears to be a wrapper around a variety of implementations of the read() system call.

  1. 		if (ghostly) {
  2. 		    unsigned nid = flags.ident++;
  3. 		    add_id_mapping(otmp->o_id, nid);
  4. 		    otmp->o_id = nid;
  5. 		}
  6. 		if (ghostly && otmp->otyp == SLIME_MOLD) ghostfruit(otmp);
  7. 		/* Ghost levels get object age shifted from old player's clock
  8. 		 * to new player's clock.  Assumption: new player arrived
  9. 		 * immediately after old player died.
  10. 		 */
  11. 		if (ghostly && !frozen && !age_is_relative(otmp))
  12. 		    otmp->age = monstermoves - omoves + otmp->age;
  13.  
  14. 		/* get contents of a container or statue */
  15. 		if (Has_contents(otmp)) {
  16. 		    struct obj *otmp3;
  17. 		    otmp->cobj = restobjchn(fd, ghostly, Is_IceBox(otmp));
  18. 		    /* restore container back pointers */
  19. 		    for (otmp3 = otmp->cobj; otmp3; otmp3 = otmp3->nobj)
  20. 			otmp3->ocontainer = otmp;
  21. 		}

Recursive call for populating the contents of containers.

  1. 		if (otmp->bypass) otmp->bypass = 0;
  2.  
  3. 		otmp2 = otmp;
  4. 	}
  5. 	if(first && otmp2->nobj){
  6. 		impossible("Restobjchn: error reading objchn.");
  7. 		otmp2->nobj = 0;
  8. 	}
  9.  
  10. 	return(first);
  11. }

restmonchn[edit]

  1. STATIC_OVL struct monst *
  2. restmonchn(fd, ghostly)
  3. register int fd;
  4. boolean ghostly;
  5. {
  6. 	register struct monst *mtmp, *mtmp2 = 0;
  7. 	register struct monst *first = (struct monst *)0;
  8. 	int xl;
  9. 	struct permonst *monbegin;
  10. 	boolean moved;
  11.  
  12. 	/* get the original base address */
  13. 	mread(fd, (genericptr_t)&monbegin, sizeof(monbegin));
  14. 	moved = (monbegin != mons);
  15.  
  16. 	while(1) {
  17. 		mread(fd, (genericptr_t) &xl, sizeof(xl));
  18. 		if(xl == -1) break;
  19. 		mtmp = newmonst(xl);
  20. 		if(!first) first = mtmp;
  21. 		else mtmp2->nmon = mtmp;
  22. 		mread(fd, (genericptr_t) mtmp, (unsigned) xl + sizeof(struct monst));
  23. 		if (ghostly) {
  24. 			unsigned nid = flags.ident++;
  25. 			add_id_mapping(mtmp->m_id, nid);
  26. 			mtmp->m_id = nid;
  27. 		}
  28. 		if (moved && mtmp->data) {
  29. 			int offset = mtmp->data - monbegin;	/*(ptrdiff_t)*/
  30. 			mtmp->data = mons + offset;  /* new permonst location */
  31. 		}
  32. 		if (ghostly) {
  33. 			int mndx = monsndx(mtmp->data);
  34. 			if (propagate(mndx, TRUE, ghostly) == 0) {
  35. 				/* cookie to trigger purge in getbones() */
  36. 				mtmp->mhpmax = DEFUNCT_MONSTER;	
  37. 			}
  38. 		}
  39. 		if(mtmp->minvent) {
  40. 			struct obj *obj;
  41. 			mtmp->minvent = restobjchn(fd, ghostly, FALSE);
  42. 			/* restore monster back pointer */
  43. 			for (obj = mtmp->minvent; obj; obj = obj->nobj)
  44. 				obj->ocarry = mtmp;
  45. 		}
  46. 		if (mtmp->mw) {
  47. 			struct obj *obj;
  48.  
  49. 			for(obj = mtmp->minvent; obj; obj = obj->nobj)
  50. 				if (obj->owornmask & W_WEP) break;
  51. 			if (obj) mtmp->mw = obj;
  52. 			else {
  53. 				MON_NOWEP(mtmp);
  54. 				impossible("bad monster weapon restore");
  55. 			}
  56. 		}
  57.  
  58. 		if (mtmp->isshk) restshk(mtmp, ghostly);
  59. 		if (mtmp->ispriest) restpriest(mtmp, ghostly);
  60.  
  61. 		mtmp2 = mtmp;
  62. 	}
  63. 	if(first && mtmp2->nmon){
  64. 		impossible("Restmonchn: error reading monchn.");
  65. 		mtmp2->nmon = 0;
  66. 	}
  67. 	return(first);
  68. }

loadfruitchn[edit]

  1. STATIC_OVL struct fruit *
  2. loadfruitchn(fd)
  3. int fd;
  4. {
  5. 	register struct fruit *flist, *fnext;
  6.  
  7. 	flist = 0;
  8. 	while (fnext = newfruit(),
  9. 	       mread(fd, (genericptr_t)fnext, sizeof *fnext),
  10. 	       fnext->fid != 0) {
  11. 		fnext->nextf = flist;
  12. 		flist = fnext;
  13. 	}
  14. 	dealloc_fruit(fnext);
  15. 	return flist;
  16. }

freefruitchn[edit]

  1. STATIC_OVL void
  2. freefruitchn(flist)
  3. register struct fruit *flist;
  4. {
  5. 	register struct fruit *fnext;
  6.  
  7. 	while (flist) {
  8. 	    fnext = flist->nextf;
  9. 	    dealloc_fruit(flist);
  10. 	    flist = fnext;
  11. 	}
  12. }

ghostfruit[edit]

  1. STATIC_OVL void
  2. ghostfruit(otmp)
  3. register struct obj *otmp;
  4. {
  5. 	register struct fruit *oldf;
  6.  
  7. 	for (oldf = oldfruit; oldf; oldf = oldf->nextf)
  8. 		if (oldf->fid == otmp->spe) break;
  9.  
  10. 	if (!oldf) impossible("no old fruit?");
  11. 	else otmp->spe = fruitadd(oldf->fname);
  12. }

restgamestate[edit]

  1. STATIC_OVL
  2. boolean
  3. restgamestate(fd, stuckid, steedid)
  4. register int fd;
  5. unsigned int *stuckid, *steedid;	/* STEED */
  6. {
  7. 	/* discover is actually flags.explore */
  8. 	boolean remember_discover = discover;
  9. 	struct obj *otmp;
  10. 	int uid;
  11.  
  12. 	mread(fd, (genericptr_t) &uid, sizeof uid);
  13. 	if (uid != getuid()) {		/* strange ... */
  14. 	    /* for wizard mode, issue a reminder; for others, treat it
  15. 	       as an attempt to cheat and refuse to restore this file */
  16. 	    pline("Saved game was not yours.");
  17. #ifdef WIZARD
  18. 	    if (!wizard)
  19. #endif
  20. 		return FALSE;
  21. 	}
  22.  
  23. 	mread(fd, (genericptr_t) &flags, sizeof(struct flag));
  24. 	flags.bypasses = 0;	/* never use the saved value of bypasses */
  25. 	if (remember_discover) discover = remember_discover;
  26.  
  27. 	role_init();	/* Reset the initial role, race, gender, and alignment */
  28. #ifdef AMII_GRAPHICS
  29. 	amii_setpens(amii_numcolors);	/* use colors from save file */
  30. #endif
  31. 	mread(fd, (genericptr_t) &u, sizeof(struct you));
  32. 	set_uasmon();
  33. #ifdef CLIPPING
  34. 	cliparound(u.ux, u.uy);
  35. #endif
  36. 	if(u.uhp <= 0 && (!Upolyd || u.mh <= 0)) {
  37. 	    u.ux = u.uy = 0;	/* affects pline() [hence You()] */
  38. 	    You("were not healthy enough to survive restoration.");
  39. 	    /* wiz1_level.dlevel is used by mklev.c to see if lots of stuff is
  40. 	     * uninitialized, so we only have to set it and not the other stuff.
  41. 	     */
  42. 	    wiz1_level.dlevel = 0;
  43. 	    u.uz.dnum = 0;
  44. 	    u.uz.dlevel = 1;
  45. 	    return(FALSE);
  46. 	}
  47.  
  48. 	/* this stuff comes after potential aborted restore attempts */
  49. 	restore_timers(fd, RANGE_GLOBAL, FALSE, 0L);
  50. 	restore_light_sources(fd);
  51. 	invent = restobjchn(fd, FALSE, FALSE);
  52. 	migrating_objs = restobjchn(fd, FALSE, FALSE);
  53. 	migrating_mons = restmonchn(fd, FALSE);
  54. 	mread(fd, (genericptr_t) mvitals, sizeof(mvitals));
  55.  
  56. 	/* this comes after inventory has been loaded */
  57. 	for(otmp = invent; otmp; otmp = otmp->nobj)
  58. 		if(otmp->owornmask)
  59. 			setworn(otmp, otmp->owornmask);
  60. 	/* reset weapon so that player will get a reminder about "bashing"
  61. 	   during next fight when bare-handed or wielding an unconventional
  62. 	   item; for pick-axe, we aren't able to distinguish between having
  63. 	   applied or wielded it, so be conservative and assume the former */
  64. 	otmp = uwep;	/* `uwep' usually init'd by setworn() in loop above */
  65. 	uwep = 0;	/* clear it and have setuwep() reinit */
  66. 	setuwep(otmp);	/* (don't need any null check here) */
  67. 	if (!uwep || uwep->otyp == PICK_AXE || uwep->otyp == GRAPPLING_HOOK)
  68. 	    unweapon = TRUE;
  69.  
  70. 	restore_dungeon(fd);
  71. 	restlevchn(fd);
  72. 	mread(fd, (genericptr_t) &moves, sizeof moves);
  73. 	mread(fd, (genericptr_t) &monstermoves, sizeof monstermoves);
  74. 	mread(fd, (genericptr_t) &quest_status, sizeof(struct q_score));
  75. 	mread(fd, (genericptr_t) spl_book,
  76. 				sizeof(struct spell) * (MAXSPELL + 1));
  77. 	restore_artifacts(fd);
  78. 	restore_oracles(fd);
  79. 	if (u.ustuck)
  80. 		mread(fd, (genericptr_t) stuckid, sizeof (*stuckid));
  81. #ifdef STEED
  82. 	if (u.usteed)
  83. 		mread(fd, (genericptr_t) steedid, sizeof (*steedid));
  84. #endif
  85. 	mread(fd, (genericptr_t) pl_character, sizeof pl_character);
  86.  
  87. 	mread(fd, (genericptr_t) pl_fruit, sizeof pl_fruit);
  88. 	mread(fd, (genericptr_t) &current_fruit, sizeof current_fruit);
  89. 	freefruitchn(ffruit);	/* clean up fruit(s) made by initoptions() */
  90. 	ffruit = loadfruitchn(fd);
  91.  
  92. 	restnames(fd);
  93. 	restore_waterlevel(fd);
  94. 	/* must come after all mons & objs are restored */
  95. 	relink_timers(FALSE);
  96. 	relink_light_sources(FALSE);
  97. 	return(TRUE);
  98. }

restlevelstate[edit]

  1. /* update game state pointers to those valid for the current level (so we
  2. * don't dereference a wild u.ustuck when saving the game state, for instance)
  3. */
  4. STATIC_OVL void
  5. restlevelstate(stuckid, steedid)
  6. unsigned int stuckid, steedid;	/* STEED */
  7. {
  8. 	register struct monst *mtmp;
  9.  
  10. 	if (stuckid) {
  11. 		for (mtmp = fmon; mtmp; mtmp = mtmp->nmon)
  12. 			if (mtmp->m_id == stuckid) break;
  13. 		if (!mtmp) panic("Cannot find the monster ustuck.");
  14. 		u.ustuck = mtmp;
  15. 	}
  16. #ifdef STEED
  17. 	if (steedid) {
  18. 		for (mtmp = fmon; mtmp; mtmp = mtmp->nmon)
  19. 			if (mtmp->m_id == steedid) break;
  20. 		if (!mtmp) panic("Cannot find the monster usteed.");
  21. 		u.usteed = mtmp;
  22. 		remove_monster(mtmp->mx, mtmp->my);
  23. 	}
  24. #endif
  25. }
  26.  
  27. /*ARGSUSED*/	/* fd used in MFLOPPY only */

restlevelfile[edit]

  1. STATIC_OVL int
  2. restlevelfile(fd, ltmp)
  3. register int fd;
  4. xchar ltmp;
  5. #if defined(macintosh) && (defined(__SC__) || defined(__MRC__))
  6. # pragma unused(fd)
  7. #endif
  8. {
  9. 	register int nfd;
  10. 	char whynot[BUFSZ];
  11.  
  12. 	nfd = create_levelfile(ltmp, whynot);
  13. 	if (nfd < 0) {
  14. 		/* BUG: should suppress any attempt to write a panic
  15. 		   save file if file creation is now failing... */
  16. 		panic("restlevelfile: %s", whynot);
  17. 	}
  18. #ifdef MFLOPPY
  19. 	if (!savelev(nfd, ltmp, COUNT_SAVE)) {
  20.  
  21. 		/* The savelev can't proceed because the size required
  22. 		 * is greater than the available disk space.
  23. 		 */
  24. 		pline("Not enough space on `%s' to restore your game.",
  25. 			levels);
  26.  
  27. 		/* Remove levels and bones that may have been created.
  28. 		 */
  29. 		(void) close(nfd);
  30. # ifdef AMIGA
  31. 		clearlocks();
  32. # else
  33. 		eraseall(levels, alllevels);
  34. 		eraseall(levels, allbones);
  35.  
  36. 		/* Perhaps the person would like to play without a
  37. 		 * RAMdisk.
  38. 		 */
  39. 		if (ramdisk) {
  40. 			/* PlaywoRAMdisk may not return, but if it does
  41. 			 * it is certain that ramdisk will be 0.
  42. 			 */
  43. 			playwoRAMdisk();
  44. 			/* Rewind save file and try again */
  45. 			(void) lseek(fd, (off_t)0, 0);
  46. 			(void) uptodate(fd, (char *)0);	/* skip version */
  47. 			return dorecover(fd);	/* 0 or 1 */
  48. 		} else {
  49. # endif
  50. 			pline("Be seeing you...");
  51. 			terminate(EXIT_SUCCESS);
  52. # ifndef AMIGA
  53. 		}
  54. # endif
  55. 	}
  56. #endif
  57. 	bufon(nfd);
  58. 	savelev(nfd, ltmp, WRITE_SAVE | FREE_SAVE);
  59. 	bclose(nfd);
  60. 	return(2);
  61. }

dorecover[edit]

  1. int
  2. dorecover(fd)
  3. register int fd;
  4. {
  5. 	unsigned int stuckid = 0, steedid = 0;	/* not a register */
  6. 	xchar ltmp;
  7. 	int rtmp;
  8. 	struct obj *otmp;
  9.  
  10. #ifdef STORE_PLNAME_IN_FILE
  11. 	mread(fd, (genericptr_t) plname, PL_NSIZ);
  12. #endif
  13.  
  14. 	restoring = TRUE;
  15. 	getlev(fd, 0, (xchar)0, FALSE);
  16. 	if (!restgamestate(fd, &stuckid, &steedid)) {
  17. 		display_nhwindow(WIN_MESSAGE, TRUE);
  18. 		savelev(-1, 0, FREE_SAVE);	/* discard current level */
  19. 		(void) close(fd);
  20. 		(void) delete_savefile();
  21. 		restoring = FALSE;
  22. 		return(0);
  23. 	}
  24. 	restlevelstate(stuckid, steedid);
  25. #ifdef INSURANCE
  26. 	savestateinlock();
  27. #endif
  28. 	rtmp = restlevelfile(fd, ledger_no(&u.uz));
  29. 	if (rtmp < 2) return(rtmp);  /* dorecover called recursively */
  30.  
  31. 	/* these pointers won't be valid while we're processing the
  32. 	 * other levels, but they'll be reset again by restlevelstate()
  33. 	 * afterwards, and in the meantime at least u.usteed may mislead
  34. 	 * place_monster() on other levels
  35. 	 */
  36. 	u.ustuck = (struct monst *)0;
  37. #ifdef STEED
  38. 	u.usteed = (struct monst *)0;
  39. #endif
  40.  
  41. #ifdef MICRO
  42. # ifdef AMII_GRAPHICS
  43. 	{
  44. 	extern struct window_procs amii_procs;
  45. 	if(windowprocs.win_init_nhwindows== amii_procs.win_init_nhwindows){
  46. 	    extern winid WIN_BASE;
  47. 	    clear_nhwindow(WIN_BASE);	/* hack until there's a hook for this */
  48. 	}
  49. 	}
  50. # else
  51. 	clear_nhwindow(WIN_MAP);
  52. # endif
  53. 	clear_nhwindow(WIN_MESSAGE);
  54. 	You("return to level %d in %s%s.",
  55. 		depth(&u.uz), dungeons[u.uz.dnum].dname,
  56. 		flags.debug ? " while in debug mode" :
  57. 		flags.explore ? " while in explore mode" : "");
  58. 	curs(WIN_MAP, 1, 1);
  59. 	dotcnt = 0;
  60. 	dotrow = 2;
  61. 	if (strncmpi("X11", windowprocs.name, 3))
  62. 	  putstr(WIN_MAP, 0, "Restoring:");
  63. #endif
  64. 	while(1) {
  65. #ifdef ZEROCOMP
  66. 		if(mread(fd, (genericptr_t) &ltmp, sizeof ltmp) < 0)
  67. #else
  68. 		if(read(fd, (genericptr_t) &ltmp, sizeof ltmp) != sizeof ltmp)
  69. #endif
  70. 			break;
  71. 		getlev(fd, 0, ltmp, FALSE);
  72. #ifdef MICRO
  73. 		curs(WIN_MAP, 1+dotcnt++, dotrow);
  74. 		if (dotcnt >= (COLNO - 1)) {
  75. 			dotrow++;
  76. 			dotcnt = 0;
  77. 		}
  78. 		if (strncmpi("X11", windowprocs.name, 3)){
  79. 		  putstr(WIN_MAP, 0, ".");
  80. 		}
  81. 		mark_synch();
  82. #endif
  83. 		rtmp = restlevelfile(fd, ltmp);
  84. 		if (rtmp < 2) return(rtmp);  /* dorecover called recursively */
  85. 	}
  86.  
  87. #ifdef BSD
  88. 	(void) lseek(fd, 0L, 0);
  89. #else
  90. 	(void) lseek(fd, (off_t)0, 0);
  91. #endif
  92. 	(void) uptodate(fd, (char *)0);		/* skip version info */
  93. #ifdef STORE_PLNAME_IN_FILE
  94. 	mread(fd, (genericptr_t) plname, PL_NSIZ);
  95. #endif
  96. 	getlev(fd, 0, (xchar)0, FALSE);
  97. 	(void) close(fd);
  98.  
  99. 	if (!wizard && !discover)
  100. 		(void) delete_savefile();
  101. #ifdef REINCARNATION
  102. 	if (Is_rogue_level(&u.uz)) assign_rogue_graphics(TRUE);
  103. #endif
  104. #ifdef USE_TILES
  105. 	substitute_tiles(&u.uz);
  106. #endif
  107. 	restlevelstate(stuckid, steedid);
  108. #ifdef MFLOPPY
  109. 	gameDiskPrompt();
  110. #endif
  111. 	max_rank_sz(); /* to recompute mrank_sz (botl.c) */
  112. 	/* take care of iron ball & chain */
  113. 	for(otmp = fobj; otmp; otmp = otmp->nobj)
  114. 		if(otmp->owornmask)
  115. 			setworn(otmp, otmp->owornmask);
  116.  
  117. 	/* in_use processing must be after:
  118. 	 *    + The inventory has been read so that freeinv() works.
  119. 	 *    + The current level has been restored so billing information
  120. 	 *	is available.
  121. 	 */
  122. 	inven_inuse(FALSE);
  123.  
  124. 	load_qtlist();	/* re-load the quest text info */
  125. 	reset_attribute_clock();
  126. 	/* Set up the vision internals, after levl[] data is loaded */
  127. 	/* but before docrt().					    */
  128. 	vision_reset();
  129. 	vision_full_recalc = 1;	/* recompute vision (not saved) */
  130.  
  131. 	run_timers();	/* expire all timers that have gone off while away */
  132. 	docrt();
  133. 	restoring = FALSE;
  134. 	clear_nhwindow(WIN_MESSAGE);
  135. 	program_state.something_worth_saving++;	/* useful data now exists */
  136.  
  137. 	/* Success! */
  138. 	welcome(FALSE);
  139. 	return(1);
  140. }

trickery[edit]

  1. void
  2. trickery(reason)
  3. char *reason;
  4. {
  5. 	pline("Strange, this map is not as I remember it.");
  6. 	pline("Somebody is trying some trickery here...");
  7. 	pline("This game is void.");
  8. 	killer = reason;
  9. 	done(TRICKED);
  10. }

getlev[edit]

  1. void
  2. getlev(fd, pid, lev, ghostly)
  3. int fd, pid;
  4. xchar lev;
  5. boolean ghostly;
  6. {
  7. 	register struct trap *trap;
  8. 	register struct monst *mtmp;
  9. 	branch *br;
  10. 	int hpid;
  11. 	xchar dlvl;
  12. 	int x, y;
  13. #ifdef TOS
  14. 	short tlev;
  15. #endif
  16.  
  17. 	if (ghostly)
  18. 	    clear_id_mapping();
  19.  
  20. #if defined(MSDOS) || defined(OS2)
  21. 	setmode(fd, O_BINARY);
  22. #endif
  23. 	/* Load the old fruit info.  We have to do it first, so the
  24. 	 * information is available when restoring the objects.
  25. 	 */
  26. 	if (ghostly) oldfruit = loadfruitchn(fd);
  27.  
  28. 	/* First some sanity checks */
  29. 	mread(fd, (genericptr_t) &hpid, sizeof(hpid));
  30. /* CHECK:  This may prevent restoration */
  31. #ifdef TOS
  32. 	mread(fd, (genericptr_t) &tlev, sizeof(tlev));
  33. 	dlvl=tlev&0x00ff;
  34. #else
  35. 	mread(fd, (genericptr_t) &dlvl, sizeof(dlvl));
  36. #endif
  37. 	if ((pid && pid != hpid) || (lev && dlvl != lev)) {
  38. 	    char trickbuf[BUFSZ];
  39.  
  40. 	    if (pid && pid != hpid)
  41. 		Sprintf(trickbuf, "PID (%d) doesn't match saved PID (%d)!",
  42. 			hpid, pid);
  43. 	    else
  44. 		Sprintf(trickbuf, "This is level %d, not %d!", dlvl, lev);
  45. #ifdef WIZARD
  46. 	    if (wizard) pline(trickbuf);
  47. #endif
  48. 	    trickery(trickbuf);
  49. 	}
  50.  
  51. #ifdef RLECOMP
  52. 	{
  53. 		short	i, j;
  54. 		uchar	len;
  55. 		struct rm r;
  56.  
  57. #if defined(MAC)
  58. 		/* Suppress warning about used before set */
  59. 		(void) memset((genericptr_t) &r, 0, sizeof(r));
  60. #endif
  61. 		i = 0; j = 0; len = 0;
  62. 		while(i < ROWNO) {
  63. 		    while(j < COLNO) {
  64. 			if(len > 0) {
  65. 			    levl[j][i] = r;
  66. 			    len -= 1;
  67. 			    j += 1;
  68. 			} else {
  69. 			    mread(fd, (genericptr_t)&len, sizeof(uchar));
  70. 			    mread(fd, (genericptr_t)&r, sizeof(struct rm));
  71. 			}
  72. 		    }
  73. 		    j = 0;
  74. 		    i += 1;
  75. 		}
  76. 	}
  77. #else
  78. 	mread(fd, (genericptr_t) levl, sizeof(levl));
  79. #endif	/* RLECOMP */
  80.  
  81. 	mread(fd, (genericptr_t)&omoves, sizeof(omoves));
  82. 	mread(fd, (genericptr_t)&upstair, sizeof(stairway));
  83. 	mread(fd, (genericptr_t)&dnstair, sizeof(stairway));
  84. 	mread(fd, (genericptr_t)&upladder, sizeof(stairway));
  85. 	mread(fd, (genericptr_t)&dnladder, sizeof(stairway));
  86. 	mread(fd, (genericptr_t)&sstairs, sizeof(stairway));
  87. 	mread(fd, (genericptr_t)&updest, sizeof(dest_area));
  88. 	mread(fd, (genericptr_t)&dndest, sizeof(dest_area));
  89. 	mread(fd, (genericptr_t)&level.flags, sizeof(level.flags));
  90. 	mread(fd, (genericptr_t)doors, sizeof(doors));
  91. 	rest_rooms(fd);		/* No joke :-) */
  92. 	if (nroom)
  93. 	    doorindex = rooms[nroom - 1].fdoor + rooms[nroom - 1].doorct;
  94. 	else
  95. 	    doorindex = 0;
  96.  
  97. 	restore_timers(fd, RANGE_LEVEL, ghostly, monstermoves - omoves);
  98. 	restore_light_sources(fd);
  99. 	fmon = restmonchn(fd, ghostly);
  100.  
  101. 	/* regenerate animals while on another level */
  102. 	if (u.uz.dlevel) {
  103. 	    register struct monst *mtmp2;
  104.  
  105. 	    for (mtmp = fmon; mtmp; mtmp = mtmp2) {
  106. 		mtmp2 = mtmp->nmon;
  107. 		if (ghostly) {
  108. 			/* reset peaceful/malign relative to new character */
  109. 			if(!mtmp->isshk)
  110. 				/* shopkeepers will reset based on name */
  111. 				mtmp->mpeaceful = peace_minded(mtmp->data);
  112. 			set_malign(mtmp);
  113. 		} else if (monstermoves > omoves)
  114. 			mon_catchup_elapsed_time(mtmp, monstermoves - omoves);
  115.  
  116. 		/* update shape-changers in case protection against
  117. 		   them is different now than when the level was saved */
  118. 		restore_cham(mtmp);
  119. 	    }
  120. 	}
  121.  
  122. 	rest_worm(fd);	/* restore worm information */
  123. 	ftrap = 0;
  124. 	while (trap = newtrap(),
  125. 	       mread(fd, (genericptr_t)trap, sizeof(struct trap)),
  126. 	       trap->tx != 0) {	/* need "!= 0" to work around DICE 3.0 bug */
  127. 		trap->ntrap = ftrap;
  128. 		ftrap = trap;
  129. 	}
  130. 	dealloc_trap(trap);
  131. 	fobj = restobjchn(fd, ghostly, FALSE);
  132. 	find_lev_obj();
  133. 	/* restobjchn()'s `frozen' argument probably ought to be a callback
  134. 	   routine so that we can check for objects being buried under ice */
  135. 	level.buriedobjlist = restobjchn(fd, ghostly, FALSE);
  136. 	billobjs = restobjchn(fd, ghostly, FALSE);
  137. 	rest_engravings(fd);
  138.  
  139. 	/* reset level.monsters for new level */
  140. 	for (x = 0; x < COLNO; x++)
  141. 	    for (y = 0; y < ROWNO; y++)
  142. 		level.monsters[x][y] = (struct monst *) 0;
  143. 	for (mtmp = level.monlist; mtmp; mtmp = mtmp->nmon) {
  144. 	    if (mtmp->isshk)
  145. 		set_residency(mtmp, FALSE);
  146. 	    place_monster(mtmp, mtmp->mx, mtmp->my);
  147. 	    if (mtmp->wormno) place_wsegs(mtmp);
  148. 	}
  149. 	restdamage(fd, ghostly);
  150.  
  151. 	rest_regions(fd, ghostly);
  152. 	if (ghostly) {
  153. 	    /* Now get rid of all the temp fruits... */
  154. 	    freefruitchn(oldfruit),  oldfruit = 0;
  155.  
  156. 	    if (lev > ledger_no(&medusa_level) &&
  157. 			lev < ledger_no(&stronghold_level) && xdnstair == 0) {
  158. 		coord cc;
  159.  
  160. 		mazexy(&cc);
  161. 		xdnstair = cc.x;
  162. 		ydnstair = cc.y;
  163. 		levl[cc.x][cc.y].typ = STAIRS;
  164. 	    }
  165.  
  166. 	    br = Is_branchlev(&u.uz);
  167. 	    if (br && u.uz.dlevel == 1) {
  168. 		d_level ltmp;
  169.  
  170. 		if (on_level(&u.uz, &br->end1))
  171. 		    assign_level(&ltmp, &br->end2);
  172. 		else
  173. 		    assign_level(&ltmp, &br->end1);
  174.  
  175. 		switch(br->type) {
  176. 		case BR_STAIR:
  177. 		case BR_NO_END1:
  178. 		case BR_NO_END2: /* OK to assign to sstairs if it's not used */
  179. 		    assign_level(&sstairs.tolev, &ltmp);
  180. 		    break;		
  181. 		case BR_PORTAL: /* max of 1 portal per level */
  182. 		    {
  183. 			register struct trap *ttmp;
  184. 			for(ttmp = ftrap; ttmp; ttmp = ttmp->ntrap)
  185. 			    if (ttmp->ttyp == MAGIC_PORTAL)
  186. 				break;
  187. 			if (!ttmp) panic("getlev: need portal but none found");
  188. 			assign_level(&ttmp->dst, &ltmp);
  189. 		    }
  190. 		    break;
  191. 		}
  192. 	    } else if (!br) {
  193. 		/* Remove any dangling portals. */
  194. 		register struct trap *ttmp;
  195. 		for (ttmp = ftrap; ttmp; ttmp = ttmp->ntrap)
  196. 		    if (ttmp->ttyp == MAGIC_PORTAL) {
  197. 			deltrap(ttmp);
  198. 			break; /* max of 1 portal/level */
  199. 		    }
  200. 	    }
  201. 	}
  202.  
  203. 	/* must come after all mons & objs are restored */
  204. 	relink_timers(ghostly);
  205. 	relink_light_sources(ghostly);
  206. 	reset_oattached_mids(ghostly);
  207.  
  208. 	if (ghostly)
  209. 	    clear_id_mapping();
  210. }

clear_id_mapping[edit]

  1. /* Clear all structures for object and monster ID mapping. */
  2. STATIC_OVL void
  3. clear_id_mapping()
  4. {
  5. struct bucket *curr;
  6.  
  7. while ((curr = id_map) != 0) {
  8. 	id_map = curr->next;
  9. 	free((genericptr_t) curr);
  10. }
  11. n_ids_mapped = 0;
  12. }

add_id_mapping[edit]

  1. /* Add a mapping to the ID map. */
  2. STATIC_OVL void
  3. add_id_mapping(gid, nid)
  4. unsigned gid, nid;
  5. {
  6. int idx;
  7.  
  8. idx = n_ids_mapped % N_PER_BUCKET;
  9. /* idx is zero on first time through, as well as when a new bucket is */
  10. /* needed */
  11. if (idx == 0) {
  12. 	struct bucket *gnu = (struct bucket *) alloc(sizeof(struct bucket));
  13. 	gnu->next = id_map;
  14. 	id_map = gnu;
  15. }
  16.  
  17. id_map->map[idx].gid = gid;
  18. id_map->map[idx].nid = nid;
  19. n_ids_mapped++;
  20. }

lookup_id_mapping[edit]

  1. /*
  2. * Global routine to look up a mapping.  If found, return TRUE and fill
  3. * in the new ID value.  Otherwise, return false and return -1 in the new
  4. * ID.
  5. */
  6. boolean
  7. lookup_id_mapping(gid, nidp)
  8. unsigned gid, *nidp;
  9. {
  10. int i;
  11. struct bucket *curr;
  12.  
  13. if (n_ids_mapped)
  14. 	for (curr = id_map; curr; curr = curr->next) {
  15. 	    /* first bucket might not be totally full */
  16. 	    if (curr == id_map) {
  17. 		i = n_ids_mapped % N_PER_BUCKET;
  18. 		if (i == 0) i = N_PER_BUCKET;
  19. 	    } else
  20. 		i = N_PER_BUCKET;
  21.  
  22. 	    while (--i >= 0)
  23. 		if (gid == curr->map[i].gid) {
  24. 		    *nidp = curr->map[i].nid;
  25. 		    return TRUE;
  26. 		}
  27. 	}
  28.  
  29. return FALSE;
  30. }

reset_oattached_mids[edit]

  1. STATIC_OVL void
  2. reset_oattached_mids(ghostly)
  3. boolean ghostly;
  4. {
  5. struct obj *otmp;
  6. unsigned oldid, nid;
  7. for (otmp = fobj; otmp; otmp = otmp->nobj) {
  8. 	if (ghostly && otmp->oattached == OATTACHED_MONST && otmp->oxlth) {
  9. 	    struct monst *mtmp = (struct monst *)otmp->oextra;
  10.  
  11. 	    mtmp->m_id = 0;
  12. 	    mtmp->mpeaceful = mtmp->mtame = 0;	/* pet's owner died! */
  13. 	}
  14. 	if (ghostly && otmp->oattached == OATTACHED_M_ID) {
  15. 	    (void) memcpy((genericptr_t)&oldid, (genericptr_t)otmp->oextra,
  16. 								sizeof(oldid));
  17. 	    if (lookup_id_mapping(oldid, &nid))
  18. 		(void) memcpy((genericptr_t)otmp->oextra, (genericptr_t)&nid,
  19. 								sizeof(nid));
  20. 	    else
  21. 		otmp->oattached = OATTACHED_NOTHING;
  22. 	}
  23. }
  24. }


  1. #ifdef ZEROCOMP
  2. #define RLESC '\0'	/* Leading character for run of RLESC's */
  3.  
  4. #ifndef ZEROCOMP_BUFSIZ
  5. #define ZEROCOMP_BUFSIZ BUFSZ
  6. #endif
  7. static NEARDATA unsigned char inbuf[ZEROCOMP_BUFSIZ];
  8. static NEARDATA unsigned short inbufp = 0;
  9. static NEARDATA unsigned short inbufsz = 0;
  10. static NEARDATA short inrunlength = -1;
  11. static NEARDATA int mreadfd;

mgetc[edit]

(mgetc is only used if ZEROCOMP is defined. It's called by mread.)

  1. static int
  2. mgetc()
  3. {
  4. if (inbufp >= inbufsz) {
  5. 	inbufsz = read(mreadfd, (genericptr_t)inbuf, sizeof inbuf);
  6. 	if (!inbufsz) {
  7. 	    if (inbufp > sizeof inbuf)
  8. 		error("EOF on file #%d.\n", mreadfd);
  9. 	    inbufp = 1 + sizeof inbuf;  /* exactly one warning :-) */
  10. 	    return -1;
  11. 	}
  12. 	inbufp = 0;
  13. }
  14. return inbuf[inbufp++];
  15. }

minit[edit]

(This version of minit is used only if ZEROCOMP is #defined.)

  1. void
  2. minit()
  3. {
  4. inbufsz = 0;
  5. inbufp = 0;
  6. inrunlength = -1;
  7. }

mread[edit]

(This version of mread is used only if ZEROCOMP is #defined.)

  1. int
  2. mread(fd, buf, len)
  3. int fd;
  4. genericptr_t buf;
  5. register unsigned len;
  6. {
  7. /*register int readlen = 0;*/
  8. if (fd < 0) error("Restore error; mread attempting to read file %d.", fd);
  9. mreadfd = fd;
  10. while (len--) {
  11. 	if (inrunlength > 0) {
  12. 	    inrunlength--;
  13. 	    *(*((char **)&buf))++ = '\0';
  14. 	} else {
  15. 	    register short ch = mgetc();
  16. 	    if (ch < 0) return -1; /*readlen;*/
  17. 	    if ((*(*(char **)&buf)++ = (char)ch) == RLESC) {
  18. 		inrunlength = mgetc();
  19. 	    }
  20. 	}
  21. 	/*readlen++;*/
  22. }
  23. return 0; /*readlen;*/
  24. }


  1. #else /* ZEROCOMP */

minit[edit]

(This version of minit is used only if ZEROCOMP is not #defined.)

  1. void
  2. minit()
  3. {
  4. return;
  5. }

mread[edit]

(This version of mread is used only if ZEROCOMP is not #defined.)

  1. void
  2. mread(fd, buf, len)
  3. register int fd;
  4. register genericptr_t buf;
  5. register unsigned int len;
  6. {
  7. 	register int rlen;
  8.  
  9. #if defined(BSD) || defined(ULTRIX)
  10. 	rlen = read(fd, buf, (int) len);
  11. 	if(rlen != len){
  12. #else /* e.g. SYSV, __TURBOC__ */
  13. 	rlen = read(fd, buf, (unsigned) len);
  14. 	if((unsigned)rlen != len){
  15. #endif
  16. 		pline("Read %d instead of %u bytes.", rlen, len);
  17. 		if(restoring) {
  18. 			(void) close(fd);
  19. 			(void) delete_savefile();
  20. 			error("Error restoring old game.");
  21. 		}
  22. 		panic("Error reading level file.");
  23. 	}
  24. }


  1. #endif /* ZEROCOMP */
  2.  
  3. /*restore.c*/