1 /* NetHack 3.6 restore.c $NHDT-Date: 1575245087 2019/12/02 00:04:47 $ $NHDT-Branch: NetHack-3.6 $:$NHDT-Revision: 1.136 $ */
2 /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
3 /*-Copyright (c) Michael Allison, 2009. */
4 /* NetHack may be freely redistributed. See license for details. */
6 /* JNetHack Copyright */
7 /* (c) Issei Numata, Naoki Hamada, Shigehiro Miyashita, 1994-2000 */
8 /* For 3.4-, Copyright (c) SHIRAKATA Kentaro, 2002-2020 */
9 /* JNetHack may be freely redistributed. See license for details. */
13 #include "tcap.h" /* for TERMLIB and ASCIIGRAPH */
16 extern int dotcnt; /* shared with save */
17 extern int dotrow; /* shared with save */
21 extern void FDECL(substitute_tiles, (d_level *)); /* from tile.c */
25 STATIC_DCL void NDECL(zerocomp_minit);
26 STATIC_DCL void FDECL(zerocomp_mread, (int, genericptr_t, unsigned int));
27 STATIC_DCL int NDECL(zerocomp_mgetc);
30 STATIC_DCL void NDECL(def_minit);
31 STATIC_DCL void FDECL(def_mread, (int, genericptr_t, unsigned int));
33 STATIC_DCL void NDECL(find_lev_obj);
34 STATIC_DCL void FDECL(restlevchn, (int));
35 STATIC_DCL void FDECL(restdamage, (int, BOOLEAN_P));
36 STATIC_DCL void FDECL(restobj, (int, struct obj *));
37 STATIC_DCL struct obj *FDECL(restobjchn, (int, BOOLEAN_P, BOOLEAN_P));
38 STATIC_OVL void FDECL(restmon, (int, struct monst *));
39 STATIC_DCL struct monst *FDECL(restmonchn, (int, BOOLEAN_P));
40 STATIC_DCL struct fruit *FDECL(loadfruitchn, (int));
41 STATIC_DCL void FDECL(freefruitchn, (struct fruit *));
42 STATIC_DCL void FDECL(ghostfruit, (struct obj *));
43 STATIC_DCL boolean FDECL(restgamestate, (int, unsigned int *, unsigned int *));
44 STATIC_DCL void FDECL(restlevelstate, (unsigned int, unsigned int));
45 STATIC_DCL int FDECL(restlevelfile, (int, XCHAR_P));
46 STATIC_OVL void FDECL(restore_msghistory, (int));
47 STATIC_DCL void FDECL(reset_oattached_mids, (BOOLEAN_P));
48 STATIC_DCL void FDECL(rest_levl, (int, BOOLEAN_P));
50 static struct restore_procs {
53 void NDECL((*restore_minit));
54 void FDECL((*restore_mread), (int, genericptr_t, unsigned int));
55 void FDECL((*restore_bclose), (int));
57 #if !defined(ZEROCOMP) || (defined(COMPRESS) || defined(ZLIB_COMP))
58 "externalcomp", 0, def_minit, def_mread, def_bclose,
60 "zerocomp", 0, zerocomp_minit, zerocomp_mread, zerocomp_bclose,
65 * Save a mapping of IDs from ghost levels to the current level. This
66 * map is used by the timer routines when restoring ghost levels.
68 #define N_PER_BUCKET 64
72 unsigned gid; /* ghost ID */
73 unsigned nid; /* new ID */
77 STATIC_DCL void NDECL(clear_id_mapping);
78 STATIC_DCL void FDECL(add_id_mapping, (unsigned, unsigned));
80 static int n_ids_mapped = 0;
81 static struct bucket *id_map = 0;
84 void FDECL(amii_setpens, (int)); /* use colors from save file */
85 extern int amii_numcolors;
90 boolean restoring = FALSE;
91 static NEARDATA struct fruit *oldfruit;
92 static NEARDATA long omoves;
94 #define Is_IceBox(o) ((o)->otyp == ICE_BOX ? TRUE : FALSE)
96 /* Recalculate level.objects[x][y], since this info was not saved. */
100 register struct obj *fobjtmp = (struct obj *) 0;
101 register struct obj *otmp;
104 for (x = 0; x < COLNO; x++)
105 for (y = 0; y < ROWNO; y++)
106 level.objects[x][y] = (struct obj *) 0;
109 * Reverse the entire fobj chain, which is necessary so that we can
110 * place the objects in the proper order. Make all obj in chain
111 * OBJ_FREE so place_object will work correctly.
113 while ((otmp = fobj) != 0) {
115 otmp->nobj = fobjtmp;
116 otmp->where = OBJ_FREE;
119 /* fobj should now be empty */
121 /* Set level.objects (as well as reversing the chain back again) */
122 while ((otmp = fobjtmp) != 0) {
123 fobjtmp = otmp->nobj;
124 place_object(otmp, otmp->ox, otmp->oy);
128 /* Things that were marked "in_use" when the game was saved (ex. via the
129 * infamous "HUP" cheat) get used up here.
135 register struct obj *otmp, *otmp2;
137 for (otmp = invent; otmp; otmp = otmp2) {
142 pline("Finishing off %s...", xname(otmp));
144 pline("%s
\82ð
\8eg
\82¢
\8fI
\82¦
\82½
\81D
\81D
\81D", xname(otmp));
157 sp_levchn = (s_level *) 0;
158 mread(fd, (genericptr_t) &cnt, sizeof(int));
159 for (; cnt > 0; cnt--) {
160 tmplev = (s_level *) alloc(sizeof(s_level));
161 mread(fd, (genericptr_t) tmplev, sizeof(s_level));
165 for (x = sp_levchn; x->next; x = x->next)
169 tmplev->next = (s_level *) 0;
174 restdamage(fd, ghostly)
179 struct damage *tmp_dam;
181 mread(fd, (genericptr_t) &counter, sizeof(counter));
184 tmp_dam = (struct damage *) alloc(sizeof(struct damage));
185 while (--counter >= 0) {
186 char damaged_shops[5], *shp = (char *) 0;
188 mread(fd, (genericptr_t) tmp_dam, sizeof(*tmp_dam));
190 tmp_dam->when += (monstermoves - omoves);
191 Strcpy(damaged_shops,
192 in_rooms(tmp_dam->place.x, tmp_dam->place.y, SHOPBASE));
194 /* when restoring, there are two passes over the current
195 * level. the first time, u.uz isn't set, so neither is
196 * shop_keeper(). just wait and process the damage on
199 for (shp = damaged_shops; *shp; shp++) {
200 struct monst *shkp = shop_keeper(*shp);
202 if (shkp && inhishop(shkp)
203 && repair_damage(shkp, tmp_dam, (int *) 0, TRUE))
208 tmp_dam->next = level.damagelist;
209 level.damagelist = tmp_dam;
210 tmp_dam = (struct damage *) alloc(sizeof(*tmp_dam));
213 free((genericptr_t) tmp_dam);
216 /* restore one object */
224 mread(fd, (genericptr_t) otmp, sizeof(struct obj));
226 /* next object pointers are invalid; otmp->cobj needs to be left
227 as is--being non-null is key to restoring container contents */
228 otmp->nobj = otmp->nexthere = (struct obj *) 0;
229 /* non-null oextra needs to be reconstructed */
231 otmp->oextra = newoextra();
233 /* oname - object's name */
234 mread(fd, (genericptr_t) &buflen, sizeof(buflen));
235 if (buflen > 0) { /* includes terminating '\0' */
236 new_oname(otmp, buflen);
237 mread(fd, (genericptr_t) ONAME(otmp), buflen);
239 /* omonst - corpse or statue might retain full monster details */
240 mread(fd, (genericptr_t) &buflen, sizeof(buflen));
243 /* this is actually a monst struct, so we
244 can just defer to restmon() here */
245 restmon(fd, OMONST(otmp));
247 /* omid - monster id number, connecting corpse to ghost */
248 mread(fd, (genericptr_t) &buflen, sizeof(buflen));
251 mread(fd, (genericptr_t) OMID(otmp), buflen);
253 /* olong - temporary gold */
254 mread(fd, (genericptr_t) &buflen, sizeof(buflen));
257 mread(fd, (genericptr_t) OLONG(otmp), buflen);
259 /* omailcmd - feedback mechanism for scroll of mail */
260 mread(fd, (genericptr_t) &buflen, sizeof(buflen));
262 char *omailcmd = (char *) alloc(buflen);
264 mread(fd, (genericptr_t) omailcmd, buflen);
265 new_omailcmd(otmp, omailcmd);
266 free((genericptr_t) omailcmd);
271 STATIC_OVL struct obj *
272 restobjchn(fd, ghostly, frozen)
274 boolean ghostly, frozen;
276 register struct obj *otmp, *otmp2 = 0;
277 register struct obj *first = (struct obj *) 0;
281 mread(fd, (genericptr_t) &buflen, sizeof buflen);
293 unsigned nid = context.ident++;
294 add_id_mapping(otmp->o_id, nid);
297 if (ghostly && otmp->otyp == SLIME_MOLD)
299 /* Ghost levels get object age shifted from old player's clock
300 * to new player's clock. Assumption: new player arrived
301 * immediately after old player died.
303 if (ghostly && !frozen && !age_is_relative(otmp))
304 otmp->age = monstermoves - omoves + otmp->age;
306 /* get contents of a container or statue */
307 if (Has_contents(otmp)) {
310 otmp->cobj = restobjchn(fd, ghostly, Is_IceBox(otmp));
311 /* restore container back pointers */
312 for (otmp3 = otmp->cobj; otmp3; otmp3 = otmp3->nobj)
313 otmp3->ocontainer = otmp;
314 } else if (SchroedingersBox(otmp)) {
315 struct obj *catcorpse;
318 * TODO: Remove this after 3.6.x save compatibility is dropped.
320 * As of 3.6.2, SchroedingersBox() always has a cat corpse in it.
321 * For 3.6.[01], it was empty and its weight was falsified
322 * to have the value it would have had if there was one inside.
323 * Put a non-rotting cat corpse in this box to convert to 3.6.2.
325 * [Note: after this fix up, future save/restore of this object
326 * will take the Has_contents() code path above.]
328 if ((catcorpse = mksobj(CORPSE, TRUE, FALSE)) != 0) {
329 otmp->spe = 1; /* flag for special SchroedingersBox */
330 set_corpsenm(catcorpse, PM_HOUSECAT);
331 (void) stop_timer(ROT_CORPSE, obj_to_any(catcorpse));
332 add_to_container(otmp, catcorpse);
333 otmp->owt = weight(otmp);
339 /* fix the pointers */
340 if (otmp->o_id == context.victual.o_id)
341 context.victual.piece = otmp;
342 if (otmp->o_id == context.tin.o_id)
343 context.tin.tin = otmp;
344 if (otmp->o_id == context.spbook.o_id)
345 context.spbook.book = otmp;
349 if (first && otmp2->nobj) {
350 impossible("Restobjchn: error reading objchn.");
357 /* restore one monster */
365 mread(fd, (genericptr_t) mtmp, sizeof(struct monst));
367 /* next monster pointer is invalid */
368 mtmp->nmon = (struct monst *) 0;
369 /* non-null mextra needs to be reconstructed */
371 mtmp->mextra = newmextra();
373 /* mname - monster's name */
374 mread(fd, (genericptr_t) &buflen, sizeof(buflen));
375 if (buflen > 0) { /* includes terminating '\0' */
376 new_mname(mtmp, buflen);
377 mread(fd, (genericptr_t) MNAME(mtmp), buflen);
379 /* egd - vault guard */
380 mread(fd, (genericptr_t) &buflen, sizeof(buflen));
383 mread(fd, (genericptr_t) EGD(mtmp), sizeof(struct egd));
385 /* epri - temple priest */
386 mread(fd, (genericptr_t) &buflen, sizeof(buflen));
389 mread(fd, (genericptr_t) EPRI(mtmp), sizeof(struct epri));
391 /* eshk - shopkeeper */
392 mread(fd, (genericptr_t) &buflen, sizeof(buflen));
395 mread(fd, (genericptr_t) ESHK(mtmp), sizeof(struct eshk));
398 mread(fd, (genericptr_t) &buflen, sizeof(buflen));
401 mread(fd, (genericptr_t) EMIN(mtmp), sizeof(struct emin));
404 mread(fd, (genericptr_t) &buflen, sizeof(buflen));
407 mread(fd, (genericptr_t) EDOG(mtmp), sizeof(struct edog));
409 /* mcorpsenm - obj->corpsenm for mimic posing as corpse or
410 statue (inline int rather than pointer to something) */
411 mread(fd, (genericptr_t) &MCORPSENM(mtmp), sizeof MCORPSENM(mtmp));
415 STATIC_OVL struct monst *
416 restmonchn(fd, ghostly)
420 register struct monst *mtmp, *mtmp2 = 0;
421 register struct monst *first = (struct monst *) 0;
425 mread(fd, (genericptr_t) &buflen, sizeof(buflen));
437 unsigned nid = context.ident++;
438 add_id_mapping(mtmp->m_id, nid);
442 mtmp->data = &mons[offset];
444 int mndx = monsndx(mtmp->data);
445 if (propagate(mndx, TRUE, ghostly) == 0) {
446 /* cookie to trigger purge in getbones() */
447 mtmp->mhpmax = DEFUNCT_MONSTER;
452 mtmp->minvent = restobjchn(fd, ghostly, FALSE);
453 /* restore monster back pointer */
454 for (obj = mtmp->minvent; obj; obj = obj->nobj)
460 for (obj = mtmp->minvent; obj; obj = obj->nobj)
461 if (obj->owornmask & W_WEP)
467 impossible("bad monster weapon restore");
472 restshk(mtmp, ghostly);
474 restpriest(mtmp, ghostly);
477 if (mtmp->m_id == context.polearm.m_id)
478 context.polearm.hitmon = mtmp;
482 if (first && mtmp2->nmon) {
483 impossible("Restmonchn: error reading monchn.");
489 STATIC_OVL struct fruit *
493 register struct fruit *flist, *fnext;
496 while (fnext = newfruit(), mread(fd, (genericptr_t) fnext, sizeof *fnext),
498 fnext->nextf = flist;
501 dealloc_fruit(fnext);
507 register struct fruit *flist;
509 register struct fruit *fnext;
512 fnext = flist->nextf;
513 dealloc_fruit(flist);
520 register struct obj *otmp;
522 register struct fruit *oldf;
524 for (oldf = oldfruit; oldf; oldf = oldf->nextf)
525 if (oldf->fid == otmp->spe)
529 impossible("no old fruit?");
531 otmp->spe = fruitadd(oldf->fname, (struct fruit *) 0);
535 #define SYSOPT_CHECK_SAVE_UID sysopt.check_save_uid
537 #define SYSOPT_CHECK_SAVE_UID TRUE
542 restgamestate(fd, stuckid, steedid)
544 unsigned int *stuckid, *steedid;
546 struct flag newgameflags;
548 struct sysflag newgamesysflags;
550 struct context_info newgamecontext; /* all 0, but has some pointers */
555 boolean defer_perm_invent;
557 mread(fd, (genericptr_t) &uid, sizeof uid);
558 if (SYSOPT_CHECK_SAVE_UID
559 && uid != (unsigned long) getuid()) { /* strange ... */
560 /* for wizard mode, issue a reminder; for others, treat it
561 as an attempt to cheat and refuse to restore this file */
563 pline("Saved game was not yours.");
565 pline("
\83Z
\81[
\83u
\82³
\82ê
\82½
\83Q
\81[
\83\80\82Í
\82 \82È
\82½
\82Ì
\82à
\82Ì
\82Å
\82Í
\82È
\82¢
\81D");
570 newgamecontext = context; /* copy statically init'd context */
571 mread(fd, (genericptr_t) &context, sizeof (struct context_info));
572 context.warntype.species = (context.warntype.speciesidx >= LOW_PM)
573 ? &mons[context.warntype.speciesidx]
574 : (struct permonst *) 0;
575 /* context.victual.piece, .tin.tin, .spellbook.book, and .polearm.hitmon
576 are pointers which get set to Null during save and will be recovered
577 via corresponding o_id or m_id while objs or mons are being restored */
579 /* we want to be able to revert to command line/environment/config
580 file option values instead of keeping old save file option values
581 if partial restore fails and we resort to starting a new game */
582 newgameflags = flags;
583 mread(fd, (genericptr_t) &flags, sizeof (struct flag));
584 /* avoid keeping permanent inventory window up to date during restore
585 (setworn() calls update_inventory); attempting to include the cost
586 of unpaid items before shopkeeper's bill is available is a no-no;
587 named fruit names aren't accessible yet either
588 [3.6.2: moved perm_invent from flags to iflags to keep it out of
589 save files; retaining the override here is simpler than trying to
590 to figure out where it really belongs now] */
591 defer_perm_invent = iflags.perm_invent;
592 iflags.perm_invent = FALSE;
593 /* wizard and discover are actually flags.debug and flags.explore;
594 player might be overriding the save file values for them;
595 in the discover case, we don't want to set that for a normal
596 game until after the save file has been removed */
597 iflags.deferred_X = (newgameflags.explore && !discover);
598 if (newgameflags.debug) {
599 /* authorized by startup code; wizard mode exists and is allowed */
600 wizard = TRUE, discover = iflags.deferred_X = FALSE;
602 /* specified by save file; check authorization now */
606 newgamesysflags = sysflags;
607 mread(fd, (genericptr_t) &sysflags, sizeof(struct sysflag));
610 role_init(); /* Reset the initial role, race, gender, and alignment */
612 amii_setpens(amii_numcolors); /* use colors from save file */
614 mread(fd, (genericptr_t) &u, sizeof(struct you));
616 #define ReadTimebuf(foo) \
617 mread(fd, (genericptr_t) timebuf, 14); \
618 timebuf[14] = '\0'; \
619 foo = time_from_yyyymmddhhmmss(timebuf);
621 ReadTimebuf(ubirthday);
622 mread(fd, &urealtime.realtime, sizeof urealtime.realtime);
623 ReadTimebuf(urealtime.start_timing); /** [not used] **/
624 /* current time is the time to use for next urealtime.realtime update */
625 urealtime.start_timing = getnow();
629 cliparound(u.ux, u.uy);
631 if (u.uhp <= 0 && (!Upolyd || u.mh <= 0)) {
632 u.ux = u.uy = 0; /* affects pline() [hence You()] */
634 You("were not healthy enough to survive restoration.");
636 You("
\8dÄ
\8aJ
\82Å
\82«
\82é
\82Ù
\82Ç
\8c\92\8dN
\82Å
\82Í
\82È
\82©
\82Á
\82½
\81D");
638 /* wiz1_level.dlevel is used by mklev.c to see if lots of stuff is
639 * uninitialized, so we only have to set it and not the other stuff.
641 wiz1_level.dlevel = 0;
644 /* revert to pre-restore option settings */
645 iflags.deferred_X = FALSE;
646 iflags.perm_invent = defer_perm_invent;
647 flags = newgameflags;
649 sysflags = newgamesysflags;
651 context = newgamecontext;
654 /* in case hangup save occurred in midst of level change */
655 assign_level(&u.uz0, &u.uz);
657 /* this stuff comes after potential aborted restore attempts */
659 restore_timers(fd, RANGE_GLOBAL, FALSE, 0L);
660 restore_light_sources(fd);
661 invent = restobjchn(fd, FALSE, FALSE);
663 /* restore dangling (not on floor or in inventory) ball and/or chain */
664 bc_obj = restobjchn(fd, FALSE, FALSE);
666 struct obj *nobj = bc_obj->nobj;
668 if (bc_obj->owornmask)
669 setworn(bc_obj, bc_obj->owornmask);
670 bc_obj->nobj = (struct obj *) 0;
674 migrating_objs = restobjchn(fd, FALSE, FALSE);
675 migrating_mons = restmonchn(fd, FALSE);
676 mread(fd, (genericptr_t) mvitals, sizeof mvitals);
679 * There are some things after this that can have unintended display
680 * side-effects too early in the game.
681 * Disable see_monsters() here, re-enable it at the top of moveloop()
683 defer_see_monsters = TRUE;
685 /* this comes after inventory has been loaded */
686 for (otmp = invent; otmp; otmp = otmp->nobj)
688 setworn(otmp, otmp->owornmask);
690 /* reset weapon so that player will get a reminder about "bashing"
691 during next fight when bare-handed or wielding an unconventional
692 item; for pick-axe, we aren't able to distinguish between having
693 applied or wielded it, so be conservative and assume the former */
694 otmp = uwep; /* `uwep' usually init'd by setworn() in loop above */
695 uwep = 0; /* clear it and have setuwep() reinit */
696 setuwep(otmp); /* (don't need any null check here) */
697 if (!uwep || uwep->otyp == PICK_AXE || uwep->otyp == GRAPPLING_HOOK)
702 mread(fd, (genericptr_t) &moves, sizeof moves);
703 mread(fd, (genericptr_t) &monstermoves, sizeof monstermoves);
704 mread(fd, (genericptr_t) &quest_status, sizeof (struct q_score));
705 mread(fd, (genericptr_t) spl_book, (MAXSPELL + 1) * sizeof (struct spell));
706 restore_artifacts(fd);
709 mread(fd, (genericptr_t) stuckid, sizeof *stuckid);
711 mread(fd, (genericptr_t) steedid, sizeof *steedid);
712 mread(fd, (genericptr_t) pl_character, sizeof pl_character);
714 mread(fd, (genericptr_t) pl_fruit, sizeof pl_fruit);
715 freefruitchn(ffruit); /* clean up fruit(s) made by initoptions() */
716 ffruit = loadfruitchn(fd);
719 restore_waterlevel(fd);
720 restore_msghistory(fd);
721 /* must come after all mons & objs are restored */
722 relink_timers(FALSE);
723 relink_light_sources(FALSE);
724 /* inventory display is now viable */
725 iflags.perm_invent = defer_perm_invent;
729 /* update game state pointers to those valid for the current level (so we
730 * don't dereference a wild u.ustuck when saving the game state, for instance)
733 restlevelstate(stuckid, steedid)
734 unsigned int stuckid, steedid;
736 register struct monst *mtmp;
739 for (mtmp = fmon; mtmp; mtmp = mtmp->nmon)
740 if (mtmp->m_id == stuckid)
743 panic("Cannot find the monster ustuck.");
747 for (mtmp = fmon; mtmp; mtmp = mtmp->nmon)
748 if (mtmp->m_id == steedid)
751 panic("Cannot find the monster usteed.");
753 remove_monster(mtmp->mx, mtmp->my);
759 restlevelfile(fd, ltmp)
760 int fd; /* fd used in MFLOPPY only */
769 nfd = create_levelfile(ltmp, whynot);
771 /* BUG: should suppress any attempt to write a panic
772 save file if file creation is now failing... */
773 panic("restlevelfile: %s", whynot);
776 if (!savelev(nfd, ltmp, COUNT_SAVE)) {
777 /* The savelev can't proceed because the size required
778 * is greater than the available disk space.
781 pline("Not enough space on `%s' to restore your game.", levels);
783 pline("
\83Q
\81[
\83\80\82ð
\8dÄ
\8aJ
\82·
\82é
\82½
\82ß
\82Ì'%s'
\82Ì
\82½
\82ß
\82Ì
\83X
\83y
\81[
\83X
\82ª
\82È
\82¢
\81D", levels);
785 /* Remove levels and bones that may have been created.
791 eraseall(levels, alllevels);
792 eraseall(levels, allbones);
794 /* Perhaps the person would like to play without a
798 /* PlaywoRAMdisk may not return, but if it does
799 * it is certain that ramdisk will be 0.
802 /* Rewind save file and try again */
803 (void) lseek(fd, (off_t) 0, 0);
804 (void) validate(fd, (char *) 0); /* skip version etc */
805 return dorecover(fd); /* 0 or 1 */
809 pline("Be seeing you...");
811 pline("
\82Ü
\82½
\89ï
\82¢
\82Ü
\82µ
\82å
\82¤
\81D
\81D
\81D");
812 nh_terminate(EXIT_SUCCESS);
816 savelev(nfd, ltmp, WRITE_SAVE | FREE_SAVE);
825 unsigned int stuckid = 0, steedid = 0; /* not a register */
831 get_plname_from_file(fd, plname);
832 getlev(fd, 0, (xchar) 0, FALSE);
833 if (!restgamestate(fd, &stuckid, &steedid)) {
834 display_nhwindow(WIN_MESSAGE, TRUE);
835 savelev(-1, 0, FREE_SAVE); /* discard current level */
837 (void) delete_savefile();
841 restlevelstate(stuckid, steedid);
845 rtmp = restlevelfile(fd, ledger_no(&u.uz));
847 return rtmp; /* dorecover called recursively */
849 /* these pointers won't be valid while we're processing the
850 * other levels, but they'll be reset again by restlevelstate()
851 * afterwards, and in the meantime at least u.usteed may mislead
852 * place_monster() on other levels
854 u.ustuck = (struct monst *) 0;
855 u.usteed = (struct monst *) 0;
860 extern struct window_procs amii_procs;
861 if (WINDOWPORT("amii") {
862 extern winid WIN_BASE;
863 clear_nhwindow(WIN_BASE); /* hack until there's a hook for this */
867 clear_nhwindow(WIN_MAP);
869 clear_nhwindow(WIN_MESSAGE);
871 You("return to level %d in %s%s.", depth(&u.uz),
872 dungeons[u.uz.dnum].dname,
873 flags.debug ? " while in debug mode"
874 : flags.explore ? " while in explore mode" : "");
876 You("%s%s
\82Ì
\92n
\89º%d
\8aK
\82É
\96ß
\82Á
\82Ä
\82«
\82½
\81D",
877 flags.debug ? "
\83E
\83B
\83U
\81[
\83h
\83\82\81[
\83h
\92\86\82Ì"
878 : flags.explore ? "
\92T
\8c\9f\83\82\81[
\83h
\92\86\82Ì" : "",
879 dungeons[u.uz.dnum].dname, depth(&u.uz));
884 if (!WINDOWPORT("X11"))
885 putstr(WIN_MAP, 0, "Restoring:");
887 restoreprocs.mread_flags = 1; /* return despite error */
889 mread(fd, (genericptr_t) <mp, sizeof ltmp);
890 if (restoreprocs.mread_flags == -1)
892 getlev(fd, 0, ltmp, FALSE);
894 curs(WIN_MAP, 1 + dotcnt++, dotrow);
895 if (dotcnt >= (COLNO - 1)) {
899 if (!WINDOWPORT("X11")) {
900 putstr(WIN_MAP, 0, ".");
904 rtmp = restlevelfile(fd, ltmp);
906 return rtmp; /* dorecover called recursively */
908 restoreprocs.mread_flags = 0;
911 (void) lseek(fd, 0L, 0);
913 (void) lseek(fd, (off_t) 0, 0);
915 (void) validate(fd, (char *) 0); /* skip version and savefile info */
916 get_plname_from_file(fd, plname);
918 getlev(fd, 0, (xchar) 0, FALSE);
921 /* Now set the restore settings to match the
922 * settings used by the save file output routines
926 restlevelstate(stuckid, steedid);
927 program_state.something_worth_saving = 1; /* useful data now exists */
929 if (!wizard && !discover)
930 (void) delete_savefile();
931 if (Is_rogue_level(&u.uz))
932 assign_graphics(ROGUESET);
934 substitute_tiles(&u.uz);
939 max_rank_sz(); /* to recompute mrank_sz (botl.c) */
940 /* take care of iron ball & chain */
941 for (otmp = fobj; otmp; otmp = otmp->nobj)
943 setworn(otmp, otmp->owornmask);
945 if ((uball && !uchain) || (uchain && !uball)) {
946 impossible("restgamestate: lost ball & chain");
947 /* poor man's unpunish() */
948 setworn((struct obj *) 0, W_CHAIN);
949 setworn((struct obj *) 0, W_BALL);
952 /* in_use processing must be after:
953 * + The inventory has been read so that freeinv() works.
954 * + The current level has been restored so billing information
959 load_qtlist(); /* re-load the quest text info */
960 /* Set up the vision internals, after levl[] data is loaded
961 but before docrt(). */
964 vision_full_recalc = 1; /* recompute vision (not saved) */
966 run_timers(); /* expire all timers that have gone off while away */
969 clear_nhwindow(WIN_MESSAGE);
973 check_special_room(FALSE);
978 restcemetery(fd, cemeteryaddr)
980 struct cemetery **cemeteryaddr;
982 struct cemetery *bonesinfo, **bonesaddr;
985 mread(fd, (genericptr_t) &flag, sizeof flag);
987 bonesaddr = cemeteryaddr;
989 bonesinfo = (struct cemetery *) alloc(sizeof *bonesinfo);
990 mread(fd, (genericptr_t) bonesinfo, sizeof *bonesinfo);
991 *bonesaddr = bonesinfo;
992 bonesaddr = &(*bonesaddr)->next;
993 } while (*bonesaddr);
1001 rest_levl(fd, rlecomp)
1011 (void) memset((genericptr_t) &r, 0, sizeof(r));
1022 mread(fd, (genericptr_t) &len, sizeof(uchar));
1023 mread(fd, (genericptr_t) &r, sizeof(struct rm));
1031 #else /* !RLECOMP */
1033 #endif /* ?RLECOMP */
1034 mread(fd, (genericptr_t) levl, sizeof levl);
1042 pline("Strange, this map is not as I remember it.");
1044 pline("
\96
\82¾
\81C
\82±
\82Ì
\92n
\90}
\82Í
\8e\84\82ª
\8ao
\82¦
\82Ä
\82¢
\82½
\82à
\82Ì
\82Æ
\88á
\82¤
\81D");
1046 pline("Somebody is trying some trickery here...");
1048 pline("
\82¾
\82ê
\82©
\82ª
\82±
\82±
\82Å
\82¢
\82©
\82³
\82Ü
\82ð
\82µ
\82æ
\82¤
\82Æ
\82µ
\82½
\82æ
\82¤
\82¾
\81D
\81D
\81D");
1050 pline("This game is void.");
1052 pline("
\82±
\82Ì
\83Q
\81[
\83\80\82Í
\96³
\8cø
\82Æ
\82È
\82é
\81D");
1053 Strcpy(killer.name, reason ? reason : "");
1058 getlev(fd, pid, lev, ghostly)
1063 register struct trap *trap;
1064 register struct monst *mtmp;
1077 #if defined(MSDOS) || defined(OS2)
1078 setmode(fd, O_BINARY);
1080 /* Load the old fruit info. We have to do it first, so the
1081 * information is available when restoring the objects.
1084 oldfruit = loadfruitchn(fd);
1086 /* First some sanity checks */
1087 mread(fd, (genericptr_t) &hpid, sizeof(hpid));
1088 /* CHECK: This may prevent restoration */
1090 mread(fd, (genericptr_t) &tlev, sizeof(tlev));
1091 dlvl = tlev & 0x00ff;
1093 mread(fd, (genericptr_t) &dlvl, sizeof(dlvl));
1095 if ((pid && pid != hpid) || (lev && dlvl != lev)) {
1096 char trickbuf[BUFSZ];
1098 if (pid && pid != hpid)
1099 Sprintf(trickbuf, "PID (%d) doesn't match saved PID (%d)!", hpid,
1102 Sprintf(trickbuf, "This is level %d, not %d!", dlvl, lev);
1107 restcemetery(fd, &level.bonesinfo);
1109 (boolean) ((sfrestinfo.sfi1 & SFI1_RLECOMP) == SFI1_RLECOMP));
1110 mread(fd, (genericptr_t) lastseentyp, sizeof(lastseentyp));
1111 mread(fd, (genericptr_t) &omoves, sizeof(omoves));
1112 elapsed = monstermoves - omoves;
1113 mread(fd, (genericptr_t) &upstair, sizeof(stairway));
1114 mread(fd, (genericptr_t) &dnstair, sizeof(stairway));
1115 mread(fd, (genericptr_t) &upladder, sizeof(stairway));
1116 mread(fd, (genericptr_t) &dnladder, sizeof(stairway));
1117 mread(fd, (genericptr_t) &sstairs, sizeof(stairway));
1118 mread(fd, (genericptr_t) &updest, sizeof(dest_area));
1119 mread(fd, (genericptr_t) &dndest, sizeof(dest_area));
1120 mread(fd, (genericptr_t) &level.flags, sizeof(level.flags));
1121 mread(fd, (genericptr_t) doors, sizeof(doors));
1122 rest_rooms(fd); /* No joke :-) */
1124 doorindex = rooms[nroom - 1].fdoor + rooms[nroom - 1].doorct;
1128 restore_timers(fd, RANGE_LEVEL, ghostly, elapsed);
1129 restore_light_sources(fd);
1130 fmon = restmonchn(fd, ghostly);
1132 rest_worm(fd); /* restore worm information */
1134 while (trap = newtrap(),
1135 mread(fd, (genericptr_t) trap, sizeof(struct trap)),
1136 trap->tx != 0) { /* need "!= 0" to work around DICE 3.0 bug */
1137 trap->ntrap = ftrap;
1141 fobj = restobjchn(fd, ghostly, FALSE);
1143 /* restobjchn()'s `frozen' argument probably ought to be a callback
1144 routine so that we can check for objects being buried under ice */
1145 level.buriedobjlist = restobjchn(fd, ghostly, FALSE);
1146 billobjs = restobjchn(fd, ghostly, FALSE);
1147 rest_engravings(fd);
1149 /* reset level.monsters for new level */
1150 for (x = 0; x < COLNO; x++)
1151 for (y = 0; y < ROWNO; y++)
1152 level.monsters[x][y] = (struct monst *) 0;
1153 for (mtmp = fmon; mtmp; mtmp = mtmp->nmon) {
1155 set_residency(mtmp, FALSE);
1156 place_monster(mtmp, mtmp->mx, mtmp->my);
1158 place_wsegs(mtmp, NULL);
1160 /* regenerate monsters while on another level */
1164 /* reset peaceful/malign relative to new character;
1165 shopkeepers will reset based on name */
1168 (is_unicorn(mtmp->data)
1169 && sgn(u.ualign.type) == sgn(mtmp->data->maligntyp))
1171 : peace_minded(mtmp->data);
1173 } else if (elapsed > 0L) {
1174 mon_catchup_elapsed_time(mtmp, elapsed);
1176 /* update shape-changers in case protection against
1177 them is different now than when the level was saved */
1179 /* give hiders a chance to hide before their next move */
1180 if (ghostly || (elapsed > 00 && elapsed > (long) rnd(10)))
1184 restdamage(fd, ghostly);
1185 rest_regions(fd, ghostly);
1187 /* Now get rid of all the temp fruits... */
1188 freefruitchn(oldfruit), oldfruit = 0;
1190 if (lev > ledger_no(&medusa_level)
1191 && lev < ledger_no(&stronghold_level) && xdnstair == 0) {
1197 levl[cc.x][cc.y].typ = STAIRS;
1200 br = Is_branchlev(&u.uz);
1201 if (br && u.uz.dlevel == 1) {
1204 if (on_level(&u.uz, &br->end1))
1205 assign_level(<mp, &br->end2);
1207 assign_level(<mp, &br->end1);
1212 case BR_NO_END2: /* OK to assign to sstairs if it's not used */
1213 assign_level(&sstairs.tolev, <mp);
1215 case BR_PORTAL: /* max of 1 portal per level */
1216 for (trap = ftrap; trap; trap = trap->ntrap)
1217 if (trap->ttyp == MAGIC_PORTAL)
1220 panic("getlev: need portal but none found");
1221 assign_level(&trap->dst, <mp);
1225 struct trap *ttmp = 0;
1227 /* Remove any dangling portals. */
1228 for (trap = ftrap; trap; trap = ttmp) {
1230 if (trap->ttyp == MAGIC_PORTAL)
1236 /* must come after all mons & objs are restored */
1237 relink_timers(ghostly);
1238 relink_light_sources(ghostly);
1239 reset_oattached_mids(ghostly);
1246 get_plname_from_file(fd, plbuf)
1251 _pragma_ignore(-Wunused-result)
1252 (void) read(fd, (genericptr_t) &pltmpsiz, sizeof(pltmpsiz));
1253 (void) read(fd, (genericptr_t) plbuf, pltmpsiz);
1259 restore_msghistory(fd)
1262 int msgsize, msgcount = 0;
1266 mread(fd, (genericptr_t) &msgsize, sizeof(msgsize));
1269 if (msgsize > (BUFSZ - 1))
1270 panic("restore_msghistory: msg too big (%d)", msgsize);
1271 mread(fd, (genericptr_t) msg, msgsize);
1272 msg[msgsize] = '\0';
1273 putmsghistory(msg, TRUE);
1277 putmsghistory((char *) 0, TRUE);
1278 debugpline1("Read %d messages from savefile.", msgcount);
1281 /* Clear all structures for object and monster ID mapping. */
1285 struct bucket *curr;
1287 while ((curr = id_map) != 0) {
1288 id_map = curr->next;
1289 free((genericptr_t) curr);
1294 /* Add a mapping to the ID map. */
1296 add_id_mapping(gid, nid)
1301 idx = n_ids_mapped % N_PER_BUCKET;
1302 /* idx is zero on first time through, as well as when a new bucket is */
1305 struct bucket *gnu = (struct bucket *) alloc(sizeof(struct bucket));
1310 id_map->map[idx].gid = gid;
1311 id_map->map[idx].nid = nid;
1316 * Global routine to look up a mapping. If found, return TRUE and fill
1317 * in the new ID value. Otherwise, return false and return -1 in the new
1321 lookup_id_mapping(gid, nidp)
1322 unsigned gid, *nidp;
1325 struct bucket *curr;
1328 for (curr = id_map; curr; curr = curr->next) {
1329 /* first bucket might not be totally full */
1330 if (curr == id_map) {
1331 i = n_ids_mapped % N_PER_BUCKET;
1338 if (gid == curr->map[i].gid) {
1339 *nidp = curr->map[i].nid;
1348 reset_oattached_mids(ghostly)
1352 unsigned oldid, nid;
1353 for (otmp = fobj; otmp; otmp = otmp->nobj) {
1354 if (ghostly && has_omonst(otmp)) {
1355 struct monst *mtmp = OMONST(otmp);
1358 mtmp->mpeaceful = mtmp->mtame = 0; /* pet's owner died! */
1360 if (ghostly && has_omid(otmp)) {
1361 (void) memcpy((genericptr_t) &oldid, (genericptr_t) OMID(otmp),
1363 if (lookup_id_mapping(oldid, &nid))
1364 (void) memcpy((genericptr_t) OMID(otmp), (genericptr_t) &nid,
1373 /* put up a menu listing each character from this player's saved games;
1374 returns 1: use plname[], 0: new game, -1: quit */
1376 restore_menu(bannerwin)
1377 winid bannerwin; /* if not WIN_ERR, clear window and show copyright in menu */
1382 menu_item *chosen_game = (menu_item *) 0;
1383 int k, clet, ch = 0; /* ch: 0 => new game */
1386 saved = get_saved_games(); /* array of character names */
1387 if (saved && *saved) {
1388 tmpwin = create_nhwindow(NHW_MENU);
1390 any = zeroany; /* no selection */
1391 if (bannerwin != WIN_ERR) {
1392 /* for tty; erase copyright notice and redo it in the menu */
1393 clear_nhwindow(bannerwin);
1394 /* COPYRIGHT_BANNER_[ABCD] */
1395 for (k = 1; k <= 4; ++k)
1396 add_menu(tmpwin, NO_GLYPH, &any, 0, 0, ATR_NONE,
1397 copyright_banner_line(k), MENU_UNSELECTED);
1398 add_menu(tmpwin, NO_GLYPH, &any, 0, 0, ATR_NONE, "",
1402 add_menu(tmpwin, NO_GLYPH, &any, 0, 0, ATR_NONE,
1403 "Select one of your saved games", MENU_UNSELECTED);
1405 add_menu(tmpwin, NO_GLYPH, &any, 0, 0, ATR_NONE,
1406 "
\83Z
\81[
\83u
\82µ
\82½
\83Q
\81[
\83\80\82ð
\88ê
\82Â
\91I
\82ñ
\82¾
\82
\82¾
\82³
\82¢", MENU_UNSELECTED);
1408 for (k = 0; saved[k]; ++k) {
1410 add_menu(tmpwin, NO_GLYPH, &any, 0, 0, ATR_NONE, saved[k],
1413 clet = (k <= 'n' - 'a') ? 'n' : 0; /* new game */
1414 any.a_int = -1; /* not >= 0 */
1416 add_menu(tmpwin, NO_GLYPH, &any, clet, 0, ATR_NONE,
1417 "Start a new character", MENU_UNSELECTED);
1419 add_menu(tmpwin, NO_GLYPH, &any, clet, 0, ATR_NONE,
1420 "
\90V
\82µ
\82¢
\83L
\83\83\83\89\83N
\83^
\82Å
\8en
\82ß
\82é", MENU_UNSELECTED);
1422 clet = (k + 1 <= 'q' - 'a') ? 'q' : 0; /* quit */
1425 add_menu(tmpwin, NO_GLYPH, &any, clet, 0, ATR_NONE,
1426 "Never mind (quit)", MENU_SELECTED);
1428 add_menu(tmpwin, NO_GLYPH, &any, clet, 0, ATR_NONE,
1429 "
\82â
\82ß
\82é", MENU_SELECTED);
1431 /* no prompt on end_menu, as we've done our own at the top */
1432 end_menu(tmpwin, (char *) 0);
1433 if (select_menu(tmpwin, PICK_ONE, &chosen_game) > 0) {
1434 ch = chosen_game->item.a_int;
1436 Strcpy(plname, saved[ch - 1]);
1438 ++ch; /* -1 -> 0 (new game), -2 -> -1 (quit) */
1439 free((genericptr_t) chosen_game);
1441 ch = -1; /* quit menu without making a selection => quit */
1443 destroy_nhwindow(tmpwin);
1444 if (bannerwin != WIN_ERR) {
1445 /* for tty; clear the menu away and put subset of copyright back
1447 clear_nhwindow(bannerwin);
1448 /* COPYRIGHT_BANNER_A, preceding "Who are you?" prompt */
1450 putstr(bannerwin, 0, copyright_banner_line(1));
1453 free_saved_games(saved);
1454 return (ch > 0) ? 1 : ch;
1456 #endif /* SELECTSAVED */
1461 (*restoreprocs.restore_minit)();
1468 register genericptr_t buf;
1469 register unsigned int len;
1471 (*restoreprocs.restore_mread)(fd, buf, len);
1475 /* examine the version info and the savefile_info data
1476 that immediately follows it.
1477 Return 0 if it passed the checks.
1478 Return 1 if it failed the version check.
1479 Return 2 if it failed the savefile feature check.
1480 Return -1 if it failed for some unknown reason.
1488 struct savefile_info sfi;
1489 unsigned long compatible;
1490 boolean verbose = name ? TRUE : FALSE, reslt = FALSE;
1492 if (!(reslt = uptodate(fd, name)))
1495 rlen = read(fd, (genericptr_t) &sfi, sizeof sfi);
1496 minit(); /* ZEROCOMP */
1499 pline("File \"%s\" is empty during save file feature check?",
1506 compatible = (sfi.sfi1 & sfcap.sfi1);
1508 if ((sfi.sfi1 & SFI1_ZEROCOMP) == SFI1_ZEROCOMP) {
1509 if ((compatible & SFI1_ZEROCOMP) != SFI1_ZEROCOMP) {
1511 pline("File \"%s\" has incompatible ZEROCOMP compression.",
1516 } else if ((sfrestinfo.sfi1 & SFI1_ZEROCOMP) != SFI1_ZEROCOMP) {
1517 set_restpref("zerocomp");
1521 if ((sfi.sfi1 & SFI1_EXTERNALCOMP) == SFI1_EXTERNALCOMP) {
1522 if ((compatible & SFI1_EXTERNALCOMP) != SFI1_EXTERNALCOMP) {
1524 pline("File \"%s\" lacks required internal compression.",
1529 } else if ((sfrestinfo.sfi1 & SFI1_EXTERNALCOMP)
1530 != SFI1_EXTERNALCOMP) {
1531 set_restpref("externalcomp");
1535 /* RLECOMP check must be last, after ZEROCOMP or INTERNALCOMP adjustments
1537 if ((sfi.sfi1 & SFI1_RLECOMP) == SFI1_RLECOMP) {
1538 if ((compatible & SFI1_RLECOMP) != SFI1_RLECOMP) {
1540 pline("File \"%s\" has incompatible run-length compression.",
1545 } else if ((sfrestinfo.sfi1 & SFI1_RLECOMP) != SFI1_RLECOMP) {
1546 set_restpref("rlecomp");
1549 /* savefile does not have RLECOMP level location compression, so adjust */
1551 set_restpref("!rlecomp");
1560 if (iflags.zerocomp)
1561 set_restpref("zerocomp");
1564 set_restpref("externalcomp");
1567 set_restpref("rlecomp");
1570 set_restpref("!rlecomp");
1574 set_restpref(suitename)
1575 const char *suitename;
1577 if (!strcmpi(suitename, "externalcomp")) {
1578 restoreprocs.name = "externalcomp";
1579 restoreprocs.restore_mread = def_mread;
1580 restoreprocs.restore_minit = def_minit;
1581 sfrestinfo.sfi1 |= SFI1_EXTERNALCOMP;
1582 sfrestinfo.sfi1 &= ~SFI1_ZEROCOMP;
1585 if (!strcmpi(suitename, "!rlecomp")) {
1586 sfrestinfo.sfi1 &= ~SFI1_RLECOMP;
1589 if (!strcmpi(suitename, "zerocomp")) {
1590 restoreprocs.name = "zerocomp";
1591 restoreprocs.restore_mread = zerocomp_mread;
1592 restoreprocs.restore_minit = zerocomp_minit;
1593 sfrestinfo.sfi1 |= SFI1_ZEROCOMP;
1594 sfrestinfo.sfi1 &= ~SFI1_EXTERNALCOMP;
1599 if (!strcmpi(suitename, "rlecomp")) {
1600 sfrestinfo.sfi1 |= SFI1_RLECOMP;
1606 #define RLESC '\0' /* Leading character for run of RLESC's */
1608 #ifndef ZEROCOMP_BUFSIZ
1609 #define ZEROCOMP_BUFSIZ BUFSZ
1611 static NEARDATA unsigned char inbuf[ZEROCOMP_BUFSIZ];
1612 static NEARDATA unsigned short inbufp = 0;
1613 static NEARDATA unsigned short inbufsz = 0;
1614 static NEARDATA short inrunlength = -1;
1615 static NEARDATA int mreadfd;
1620 if (inbufp >= inbufsz) {
1621 inbufsz = read(mreadfd, (genericptr_t) inbuf, sizeof inbuf);
1623 if (inbufp > sizeof inbuf)
1624 error("EOF on file #%d.\n", mreadfd);
1625 inbufp = 1 + sizeof inbuf; /* exactly one warning :-) */
1630 return inbuf[inbufp++];
1642 zerocomp_mread(fd, buf, len)
1645 register unsigned len;
1647 /*register int readlen = 0;*/
1649 error("Restore error; mread attempting to read file %d.", fd);
1652 if (inrunlength > 0) {
1654 *(*((char **) &buf))++ = '\0';
1656 register short ch = zerocomp_mgetc();
1658 restoreprocs.mread_flags = -1;
1661 if ((*(*(char **) &buf)++ = (char) ch) == RLESC) {
1662 inrunlength = zerocomp_mgetc();
1668 #endif /* ZEROCOMP */
1677 def_mread(fd, buf, len)
1679 register genericptr_t buf;
1680 register unsigned int len;
1683 #if defined(BSD) || defined(ULTRIX)
1684 #define readLenType int
1685 #else /* e.g. SYSV, __TURBOC__ */
1686 #define readLenType unsigned
1689 rlen = read(fd, buf, (readLenType) len);
1690 if ((readLenType) rlen != (readLenType) len) {
1691 if (restoreprocs.mread_flags == 1) { /* means "return anyway" */
1692 restoreprocs.mread_flags = -1;
1695 pline("Read %d instead of %u bytes.", rlen, len);
1698 (void) delete_savefile();
1699 error("Error restoring old game.");
1701 panic("Error reading level file.");