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. */
7 #include "tcap.h" /* for TERMLIB and ASCIIGRAPH */
10 extern int dotcnt; /* shared with save */
11 extern int dotrow; /* shared with save */
15 extern void FDECL(substitute_tiles, (d_level *)); /* from tile.c */
19 static int NDECL(mgetc);
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));
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.
38 #define N_PER_BUCKET 64
42 unsigned gid; /* ghost ID */
43 unsigned nid; /* new ID */
47 STATIC_DCL void NDECL(clear_id_mapping);
48 STATIC_DCL void FDECL(add_id_mapping, (unsigned, unsigned));
50 static int n_ids_mapped = 0;
51 static struct bucket *id_map = 0;
55 void FDECL( amii_setpens, (int) ); /* use colors from save file */
56 extern int amii_numcolors;
61 boolean restoring = FALSE;
62 static NEARDATA struct fruit *oldfruit;
63 static NEARDATA long omoves;
65 #define Is_IceBox(o) ((o)->otyp == ICE_BOX ? TRUE : FALSE)
67 /* Recalculate level.objects[x][y], since this info was not saved. */
71 register struct obj *fobjtmp = (struct obj *)0;
72 register struct obj *otmp;
75 for(x=0; x<COLNO; x++) for(y=0; y<ROWNO; y++)
76 level.objects[x][y] = (struct obj *)0;
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.
83 while ((otmp = fobj) != 0) {
86 otmp->where = OBJ_FREE;
89 /* fobj should now be empty */
91 /* Set level.objects (as well as reversing the chain back again) */
92 while ((otmp = fobjtmp) != 0) {
94 place_object(otmp, otmp->ox, otmp->oy);
98 /* Things that were marked "in_use" when the game was saved (ex. via the
99 * infamous "HUP" cheat) get used up here.
105 register struct obj *otmp, *otmp2;
107 for (otmp = invent; otmp; otmp = otmp2) {
110 if (otmp->oclass == COIN_CLASS) {
111 /* in_use gold is created by some menu operations */
113 impossible("inven_inuse: !in_use gold in inventory");
115 extract_nobj(otmp, &invent);
116 otmp->in_use = FALSE;
121 if (!quietly) pline("Finishing off %s...", xname(otmp));
134 sp_levchn = (s_level *) 0;
135 mread(fd, (genericptr_t) &cnt, sizeof(int));
136 for(; cnt > 0; cnt--) {
138 tmplev = (s_level *)alloc(sizeof(s_level));
139 mread(fd, (genericptr_t) tmplev, sizeof(s_level));
140 if(!sp_levchn) sp_levchn = tmplev;
143 for(x = sp_levchn; x->next; x = x->next);
146 tmplev->next = (s_level *)0;
151 restdamage(fd, ghostly)
156 struct damage *tmp_dam;
158 mread(fd, (genericptr_t) &counter, sizeof(counter));
161 tmp_dam = (struct damage *)alloc(sizeof(struct damage));
162 while (--counter >= 0) {
163 char damaged_shops[5], *shp = (char *)0;
165 mread(fd, (genericptr_t) tmp_dam, sizeof(*tmp_dam));
167 tmp_dam->when += (monstermoves - omoves);
168 Strcpy(damaged_shops,
169 in_rooms(tmp_dam->place.x, tmp_dam->place.y, SHOPBASE));
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
176 for (shp = damaged_shops; *shp; shp++) {
177 struct monst *shkp = shop_keeper(*shp);
179 if (shkp && inhishop(shkp) &&
180 repair_damage(shkp, tmp_dam, TRUE))
185 tmp_dam->next = level.damagelist;
186 level.damagelist = tmp_dam;
187 tmp_dam = (struct damage *)alloc(sizeof(*tmp_dam));
190 free((genericptr_t)tmp_dam);
193 STATIC_OVL struct obj *
194 restobjchn(fd, ghostly, frozen)
196 boolean ghostly, frozen;
198 register struct obj *otmp, *otmp2 = 0;
199 register struct obj *first = (struct obj *)0;
203 mread(fd, (genericptr_t) &xl, sizeof(xl));
206 if(!first) first = otmp;
207 else otmp2->nobj = otmp;
208 mread(fd, (genericptr_t) otmp,
209 (unsigned) xl + sizeof(struct obj));
211 unsigned nid = flags.ident++;
212 add_id_mapping(otmp->o_id, nid);
215 if (ghostly && otmp->otyp == SLIME_MOLD) ghostfruit(otmp);
216 /* Ghost levels get object age shifted from old player's clock
217 * to new player's clock. Assumption: new player arrived
218 * immediately after old player died.
220 if (ghostly && !frozen && !age_is_relative(otmp))
221 otmp->age = monstermoves - omoves + otmp->age;
223 /* get contents of a container or statue */
224 if (Has_contents(otmp)) {
226 otmp->cobj = restobjchn(fd, ghostly, Is_IceBox(otmp));
227 /* restore container back pointers */
228 for (otmp3 = otmp->cobj; otmp3; otmp3 = otmp3->nobj)
229 otmp3->ocontainer = otmp;
231 if (otmp->bypass) otmp->bypass = 0;
235 if(first && otmp2->nobj){
236 impossible("Restobjchn: error reading objchn.");
243 STATIC_OVL struct monst *
244 restmonchn(fd, ghostly)
248 register struct monst *mtmp, *mtmp2 = 0;
249 register struct monst *first = (struct monst *)0;
251 struct permonst *monbegin;
254 /* get the original base address */
255 mread(fd, (genericptr_t)&monbegin, sizeof(monbegin));
256 moved = (monbegin != mons);
259 mread(fd, (genericptr_t) &xl, sizeof(xl));
262 if(!first) first = mtmp;
263 else mtmp2->nmon = mtmp;
264 mread(fd, (genericptr_t) mtmp, (unsigned) xl + sizeof(struct monst));
266 unsigned nid = flags.ident++;
267 add_id_mapping(mtmp->m_id, nid);
270 if (moved && mtmp->data) {
271 int offset = mtmp->data - monbegin; /*(ptrdiff_t)*/
272 mtmp->data = mons + offset; /* new permonst location */
275 int mndx = monsndx(mtmp->data);
276 if (propagate(mndx, TRUE, ghostly) == 0) {
277 /* cookie to trigger purge in getbones() */
278 mtmp->mhpmax = DEFUNCT_MONSTER;
283 mtmp->minvent = restobjchn(fd, ghostly, FALSE);
284 /* restore monster back pointer */
285 for (obj = mtmp->minvent; obj; obj = obj->nobj)
291 for(obj = mtmp->minvent; obj; obj = obj->nobj)
292 if (obj->owornmask & W_WEP) break;
293 if (obj) mtmp->mw = obj;
296 impossible("bad monster weapon restore");
300 if (mtmp->isshk) restshk(mtmp, ghostly);
301 if (mtmp->ispriest) restpriest(mtmp, ghostly);
305 if(first && mtmp2->nmon){
306 impossible("Restmonchn: error reading monchn.");
312 STATIC_OVL struct fruit *
316 register struct fruit *flist, *fnext;
319 while (fnext = newfruit(),
320 mread(fd, (genericptr_t)fnext, sizeof *fnext),
322 fnext->nextf = flist;
325 dealloc_fruit(fnext);
331 register struct fruit *flist;
333 register struct fruit *fnext;
336 fnext = flist->nextf;
337 dealloc_fruit(flist);
344 register struct obj *otmp;
346 register struct fruit *oldf;
348 for (oldf = oldfruit; oldf; oldf = oldf->nextf)
349 if (oldf->fid == otmp->spe) break;
351 if (!oldf) impossible("no old fruit?");
352 else otmp->spe = fruitadd(oldf->fname);
357 restgamestate(fd, stuckid, steedid)
359 unsigned int *stuckid, *steedid; /* STEED */
361 /* discover is actually flags.explore */
362 boolean remember_discover = discover;
366 mread(fd, (genericptr_t) &uid, sizeof uid);
367 if (uid != getuid()) { /* strange ... */
368 /* for wizard mode, issue a reminder; for others, treat it
369 as an attempt to cheat and refuse to restore this file */
370 pline("Saved game was not yours.");
377 mread(fd, (genericptr_t) &flags, sizeof(struct flag));
378 flags.bypasses = 0; /* never use the saved value of bypasses */
379 if (remember_discover) discover = remember_discover;
381 role_init(); /* Reset the initial role, race, gender, and alignment */
383 amii_setpens(amii_numcolors); /* use colors from save file */
385 mread(fd, (genericptr_t) &u, sizeof(struct you));
388 cliparound(u.ux, u.uy);
390 if(u.uhp <= 0 && (!Upolyd || u.mh <= 0)) {
391 u.ux = u.uy = 0; /* affects pline() [hence You()] */
392 You("were not healthy enough to survive restoration.");
393 /* wiz1_level.dlevel is used by mklev.c to see if lots of stuff is
394 * uninitialized, so we only have to set it and not the other stuff.
396 wiz1_level.dlevel = 0;
402 /* this stuff comes after potential aborted restore attempts */
403 restore_timers(fd, RANGE_GLOBAL, FALSE, 0L);
404 restore_light_sources(fd);
405 invent = restobjchn(fd, FALSE, FALSE);
406 migrating_objs = restobjchn(fd, FALSE, FALSE);
407 migrating_mons = restmonchn(fd, FALSE);
408 mread(fd, (genericptr_t) mvitals, sizeof(mvitals));
410 /* this comes after inventory has been loaded */
411 for(otmp = invent; otmp; otmp = otmp->nobj)
413 setworn(otmp, otmp->owornmask);
414 /* reset weapon so that player will get a reminder about "bashing"
415 during next fight when bare-handed or wielding an unconventional
416 item; for pick-axe, we aren't able to distinguish between having
417 applied or wielded it, so be conservative and assume the former */
418 otmp = uwep; /* `uwep' usually init'd by setworn() in loop above */
419 uwep = 0; /* clear it and have setuwep() reinit */
420 setuwep(otmp); /* (don't need any null check here) */
421 if (!uwep || uwep->otyp == PICK_AXE || uwep->otyp == GRAPPLING_HOOK)
426 mread(fd, (genericptr_t) &moves, sizeof moves);
427 mread(fd, (genericptr_t) &monstermoves, sizeof monstermoves);
428 mread(fd, (genericptr_t) &quest_status, sizeof(struct q_score));
429 mread(fd, (genericptr_t) spl_book,
430 sizeof(struct spell) * (MAXSPELL + 1));
431 restore_artifacts(fd);
434 mread(fd, (genericptr_t) stuckid, sizeof (*stuckid));
437 mread(fd, (genericptr_t) steedid, sizeof (*steedid));
439 mread(fd, (genericptr_t) pl_character, sizeof pl_character);
441 mread(fd, (genericptr_t) pl_fruit, sizeof pl_fruit);
442 mread(fd, (genericptr_t) ¤t_fruit, sizeof current_fruit);
443 freefruitchn(ffruit); /* clean up fruit(s) made by initoptions() */
444 ffruit = loadfruitchn(fd);
447 restore_waterlevel(fd);
448 /* must come after all mons & objs are restored */
449 relink_timers(FALSE);
450 relink_light_sources(FALSE);
454 /* update game state pointers to those valid for the current level (so we
455 * don't dereference a wild u.ustuck when saving the game state, for instance)
458 restlevelstate(stuckid, steedid)
459 unsigned int stuckid, steedid; /* STEED */
461 register struct monst *mtmp;
464 for (mtmp = fmon; mtmp; mtmp = mtmp->nmon)
465 if (mtmp->m_id == stuckid) break;
466 if (!mtmp) panic("Cannot find the monster ustuck.");
471 for (mtmp = fmon; mtmp; mtmp = mtmp->nmon)
472 if (mtmp->m_id == steedid) break;
473 if (!mtmp) panic("Cannot find the monster usteed.");
475 remove_monster(mtmp->mx, mtmp->my);
480 /*ARGSUSED*/ /* fd used in MFLOPPY only */
482 restlevelfile(fd, ltmp)
485 #if defined(macintosh) && (defined(__SC__) || defined(__MRC__))
492 nfd = create_levelfile(ltmp, whynot);
494 /* BUG: should suppress any attempt to write a panic
495 save file if file creation is now failing... */
496 panic("restlevelfile: %s", whynot);
499 if (!savelev(nfd, ltmp, COUNT_SAVE)) {
501 /* The savelev can't proceed because the size required
502 * is greater than the available disk space.
504 pline("Not enough space on `%s' to restore your game.",
507 /* Remove levels and bones that may have been created.
513 eraseall(levels, alllevels);
514 eraseall(levels, allbones);
516 /* Perhaps the person would like to play without a
520 /* PlaywoRAMdisk may not return, but if it does
521 * it is certain that ramdisk will be 0.
524 /* Rewind save file and try again */
525 (void) lseek(fd, (off_t)0, 0);
526 (void) uptodate(fd, (char *)0); /* skip version */
527 return dorecover(fd); /* 0 or 1 */
530 pline("Be seeing you...");
531 terminate(EXIT_SUCCESS);
538 savelev(nfd, ltmp, WRITE_SAVE | FREE_SAVE);
547 unsigned int stuckid = 0, steedid = 0; /* not a register */
552 #ifdef STORE_PLNAME_IN_FILE
553 mread(fd, (genericptr_t) plname, PL_NSIZ);
557 getlev(fd, 0, (xchar)0, FALSE);
558 if (!restgamestate(fd, &stuckid, &steedid)) {
559 display_nhwindow(WIN_MESSAGE, TRUE);
560 savelev(-1, 0, FREE_SAVE); /* discard current level */
562 (void) delete_savefile();
566 restlevelstate(stuckid, steedid);
570 rtmp = restlevelfile(fd, ledger_no(&u.uz));
571 if (rtmp < 2) return(rtmp); /* dorecover called recursively */
573 /* these pointers won't be valid while we're processing the
574 * other levels, but they'll be reset again by restlevelstate()
575 * afterwards, and in the meantime at least u.usteed may mislead
576 * place_monster() on other levels
578 u.ustuck = (struct monst *)0;
580 u.usteed = (struct monst *)0;
584 # ifdef AMII_GRAPHICS
586 extern struct window_procs amii_procs;
587 if(windowprocs.win_init_nhwindows== amii_procs.win_init_nhwindows){
588 extern winid WIN_BASE;
589 clear_nhwindow(WIN_BASE); /* hack until there's a hook for this */
593 clear_nhwindow(WIN_MAP);
595 clear_nhwindow(WIN_MESSAGE);
596 You("return to level %d in %s%s.",
597 depth(&u.uz), dungeons[u.uz.dnum].dname,
598 flags.debug ? " while in debug mode" :
599 flags.explore ? " while in explore mode" : "");
603 if (strncmpi("X11", windowprocs.name, 3))
604 putstr(WIN_MAP, 0, "Restoring:");
608 if(mread(fd, (genericptr_t) <mp, sizeof ltmp) < 0)
610 if(read(fd, (genericptr_t) <mp, sizeof ltmp) != sizeof ltmp)
613 getlev(fd, 0, ltmp, FALSE);
615 curs(WIN_MAP, 1+dotcnt++, dotrow);
616 if (dotcnt >= (COLNO - 1)) {
620 if (strncmpi("X11", windowprocs.name, 3)){
621 putstr(WIN_MAP, 0, ".");
625 rtmp = restlevelfile(fd, ltmp);
626 if (rtmp < 2) return(rtmp); /* dorecover called recursively */
630 (void) lseek(fd, 0L, 0);
632 (void) lseek(fd, (off_t)0, 0);
634 (void) uptodate(fd, (char *)0); /* skip version info */
635 #ifdef STORE_PLNAME_IN_FILE
636 mread(fd, (genericptr_t) plname, PL_NSIZ);
638 getlev(fd, 0, (xchar)0, FALSE);
641 if (!wizard && !discover)
642 (void) delete_savefile();
644 if (Is_rogue_level(&u.uz)) assign_rogue_graphics(TRUE);
647 substitute_tiles(&u.uz);
649 restlevelstate(stuckid, steedid);
653 max_rank_sz(); /* to recompute mrank_sz (botl.c) */
654 /* take care of iron ball & chain */
655 for(otmp = fobj; otmp; otmp = otmp->nobj)
657 setworn(otmp, otmp->owornmask);
659 /* in_use processing must be after:
660 * + The inventory has been read so that freeinv() works.
661 * + The current level has been restored so billing information
666 load_qtlist(); /* re-load the quest text info */
667 reset_attribute_clock();
668 /* Set up the vision internals, after levl[] data is loaded */
669 /* but before docrt(). */
671 vision_full_recalc = 1; /* recompute vision (not saved) */
673 run_timers(); /* expire all timers that have gone off while away */
676 clear_nhwindow(WIN_MESSAGE);
677 program_state.something_worth_saving++; /* useful data now exists */
688 pline("Strange, this map is not as I remember it.");
689 pline("Somebody is trying some trickery here...");
690 pline("This game is void.");
696 getlev(fd, pid, lev, ghostly)
701 register struct trap *trap;
702 register struct monst *mtmp;
714 #if defined(MSDOS) || defined(OS2)
715 setmode(fd, O_BINARY);
717 /* Load the old fruit info. We have to do it first, so the
718 * information is available when restoring the objects.
720 if (ghostly) oldfruit = loadfruitchn(fd);
722 /* First some sanity checks */
723 mread(fd, (genericptr_t) &hpid, sizeof(hpid));
724 /* CHECK: This may prevent restoration */
726 mread(fd, (genericptr_t) &tlev, sizeof(tlev));
729 mread(fd, (genericptr_t) &dlvl, sizeof(dlvl));
731 if ((pid && pid != hpid) || (lev && dlvl != lev)) {
732 char trickbuf[BUFSZ];
734 if (pid && pid != hpid)
735 Sprintf(trickbuf, "PID (%d) doesn't match saved PID (%d)!",
738 Sprintf(trickbuf, "This is level %d, not %d!", dlvl, lev);
740 if (wizard) pline(trickbuf);
752 /* Suppress warning about used before set */
753 (void) memset((genericptr_t) &r, 0, sizeof(r));
755 i = 0; j = 0; len = 0;
763 mread(fd, (genericptr_t)&len, sizeof(uchar));
764 mread(fd, (genericptr_t)&r, sizeof(struct rm));
772 mread(fd, (genericptr_t) levl, sizeof(levl));
775 mread(fd, (genericptr_t)&omoves, sizeof(omoves));
776 mread(fd, (genericptr_t)&upstair, sizeof(stairway));
777 mread(fd, (genericptr_t)&dnstair, sizeof(stairway));
778 mread(fd, (genericptr_t)&upladder, sizeof(stairway));
779 mread(fd, (genericptr_t)&dnladder, sizeof(stairway));
780 mread(fd, (genericptr_t)&sstairs, sizeof(stairway));
781 mread(fd, (genericptr_t)&updest, sizeof(dest_area));
782 mread(fd, (genericptr_t)&dndest, sizeof(dest_area));
783 mread(fd, (genericptr_t)&level.flags, sizeof(level.flags));
784 mread(fd, (genericptr_t)doors, sizeof(doors));
785 rest_rooms(fd); /* No joke :-) */
787 doorindex = rooms[nroom - 1].fdoor + rooms[nroom - 1].doorct;
791 restore_timers(fd, RANGE_LEVEL, ghostly, monstermoves - omoves);
792 restore_light_sources(fd);
793 fmon = restmonchn(fd, ghostly);
795 /* regenerate animals while on another level */
797 register struct monst *mtmp2;
799 for (mtmp = fmon; mtmp; mtmp = mtmp2) {
802 /* reset peaceful/malign relative to new character */
804 /* shopkeepers will reset based on name */
805 mtmp->mpeaceful = peace_minded(mtmp->data);
807 } else if (monstermoves > omoves)
808 mon_catchup_elapsed_time(mtmp, monstermoves - omoves);
810 /* update shape-changers in case protection against
811 them is different now than when the level was saved */
816 rest_worm(fd); /* restore worm information */
818 while (trap = newtrap(),
819 mread(fd, (genericptr_t)trap, sizeof(struct trap)),
820 trap->tx != 0) { /* need "!= 0" to work around DICE 3.0 bug */
825 fobj = restobjchn(fd, ghostly, FALSE);
827 /* restobjchn()'s `frozen' argument probably ought to be a callback
828 routine so that we can check for objects being buried under ice */
829 level.buriedobjlist = restobjchn(fd, ghostly, FALSE);
830 billobjs = restobjchn(fd, ghostly, FALSE);
833 /* reset level.monsters for new level */
834 for (x = 0; x < COLNO; x++)
835 for (y = 0; y < ROWNO; y++)
836 level.monsters[x][y] = (struct monst *) 0;
837 for (mtmp = level.monlist; mtmp; mtmp = mtmp->nmon) {
839 set_residency(mtmp, FALSE);
840 place_monster(mtmp, mtmp->mx, mtmp->my);
841 if (mtmp->wormno) place_wsegs(mtmp);
843 restdamage(fd, ghostly);
845 rest_regions(fd, ghostly);
847 /* Now get rid of all the temp fruits... */
848 freefruitchn(oldfruit), oldfruit = 0;
850 if (lev > ledger_no(&medusa_level) &&
851 lev < ledger_no(&stronghold_level) && xdnstair == 0) {
857 levl[cc.x][cc.y].typ = STAIRS;
860 br = Is_branchlev(&u.uz);
861 if (br && u.uz.dlevel == 1) {
864 if (on_level(&u.uz, &br->end1))
865 assign_level(<mp, &br->end2);
867 assign_level(<mp, &br->end1);
872 case BR_NO_END2: /* OK to assign to sstairs if it's not used */
873 assign_level(&sstairs.tolev, <mp);
875 case BR_PORTAL: /* max of 1 portal per level */
877 register struct trap *ttmp;
878 for(ttmp = ftrap; ttmp; ttmp = ttmp->ntrap)
879 if (ttmp->ttyp == MAGIC_PORTAL)
881 if (!ttmp) panic("getlev: need portal but none found");
882 assign_level(&ttmp->dst, <mp);
887 /* Remove any dangling portals. */
888 register struct trap *ttmp;
889 for (ttmp = ftrap; ttmp; ttmp = ttmp->ntrap)
890 if (ttmp->ttyp == MAGIC_PORTAL) {
892 break; /* max of 1 portal/level */
897 /* must come after all mons & objs are restored */
898 relink_timers(ghostly);
899 relink_light_sources(ghostly);
900 reset_oattached_mids(ghostly);
907 /* Clear all structures for object and monster ID mapping. */
913 while ((curr = id_map) != 0) {
915 free((genericptr_t) curr);
920 /* Add a mapping to the ID map. */
922 add_id_mapping(gid, nid)
927 idx = n_ids_mapped % N_PER_BUCKET;
928 /* idx is zero on first time through, as well as when a new bucket is */
931 struct bucket *gnu = (struct bucket *) alloc(sizeof(struct bucket));
936 id_map->map[idx].gid = gid;
937 id_map->map[idx].nid = nid;
942 * Global routine to look up a mapping. If found, return TRUE and fill
943 * in the new ID value. Otherwise, return false and return -1 in the new
947 lookup_id_mapping(gid, nidp)
954 for (curr = id_map; curr; curr = curr->next) {
955 /* first bucket might not be totally full */
956 if (curr == id_map) {
957 i = n_ids_mapped % N_PER_BUCKET;
958 if (i == 0) i = N_PER_BUCKET;
963 if (gid == curr->map[i].gid) {
964 *nidp = curr->map[i].nid;
973 reset_oattached_mids(ghostly)
978 for (otmp = fobj; otmp; otmp = otmp->nobj) {
979 if (ghostly && otmp->oattached == OATTACHED_MONST && otmp->oxlth) {
980 struct monst *mtmp = (struct monst *)otmp->oextra;
983 mtmp->mpeaceful = mtmp->mtame = 0; /* pet's owner died! */
985 if (ghostly && otmp->oattached == OATTACHED_M_ID) {
986 (void) memcpy((genericptr_t)&oldid, (genericptr_t)otmp->oextra,
988 if (lookup_id_mapping(oldid, &nid))
989 (void) memcpy((genericptr_t)otmp->oextra, (genericptr_t)&nid,
992 otmp->oattached = OATTACHED_NOTHING;
999 #define RLESC '\0' /* Leading character for run of RLESC's */
1001 #ifndef ZEROCOMP_BUFSIZ
1002 #define ZEROCOMP_BUFSIZ BUFSZ
1004 static NEARDATA unsigned char inbuf[ZEROCOMP_BUFSIZ];
1005 static NEARDATA unsigned short inbufp = 0;
1006 static NEARDATA unsigned short inbufsz = 0;
1007 static NEARDATA short inrunlength = -1;
1008 static NEARDATA int mreadfd;
1013 if (inbufp >= inbufsz) {
1014 inbufsz = read(mreadfd, (genericptr_t)inbuf, sizeof inbuf);
1016 if (inbufp > sizeof inbuf)
1017 error("EOF on file #%d.\n", mreadfd);
1018 inbufp = 1 + sizeof inbuf; /* exactly one warning :-) */
1023 return inbuf[inbufp++];
1038 register unsigned len;
1040 /*register int readlen = 0;*/
1041 if (fd < 0) error("Restore error; mread attempting to read file %d.", fd);
1044 if (inrunlength > 0) {
1046 *(*((char **)&buf))++ = '\0';
1048 register short ch = mgetc();
1049 if (ch < 0) return -1; /*readlen;*/
1050 if ((*(*(char **)&buf)++ = (char)ch) == RLESC) {
1051 inrunlength = mgetc();
1056 return 0; /*readlen;*/
1059 #else /* ZEROCOMP */
1070 register genericptr_t buf;
1071 register unsigned int len;
1075 #if defined(BSD) || defined(ULTRIX)
1076 rlen = read(fd, buf, (int) len);
1078 #else /* e.g. SYSV, __TURBOC__ */
1079 rlen = read(fd, buf, (unsigned) len);
1080 if((unsigned)rlen != len){
1082 pline("Read %d instead of %u bytes.", rlen, len);
1085 (void) delete_savefile();
1086 error("Error restoring old game.");
1088 panic("Error reading level file.");
1091 #endif /* ZEROCOMP */