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 substitute_tiles(d_level
*); /* from tile.c */
19 static int mgetc(void);
21 STATIC_DCL
void find_lev_obj(void);
22 STATIC_DCL
void restlevchn(int);
23 STATIC_DCL
void restdamage(int,BOOLEAN_P
);
24 STATIC_DCL
struct obj
*restobjchn(int,BOOLEAN_P
,BOOLEAN_P
);
25 STATIC_DCL
struct monst
*restmonchn(int,BOOLEAN_P
);
26 STATIC_DCL
struct fruit
*loadfruitchn(int);
27 STATIC_DCL
void freefruitchn(struct fruit
*);
28 STATIC_DCL
void ghostfruit(struct obj
*);
29 STATIC_DCL boolean
restgamestate(int, unsigned int *, unsigned int *);
30 STATIC_DCL
void restlevelstate(unsigned int, unsigned int);
31 STATIC_DCL
int restlevelfile(int,XCHAR_P
);
32 STATIC_DCL
void 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 clear_id_mapping(void);
48 STATIC_DCL
void add_id_mapping(unsigned, unsigned);
50 static int n_ids_mapped
= 0;
51 static struct bucket
*id_map
= 0;
55 void 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 || (o)->otyp == DISPERSION_BOX || (o)->otyp == ICE_BOX_OF_HOLDING || (o)->otyp == ICE_BOX_OF_WATERPROOFING || (o)->otyp == ICE_BOX_OF_DIGESTION) ? 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
, (void *) &cnt
, sizeof(int));
136 for(; cnt
> 0; cnt
--) {
138 tmplev
= (s_level
*)alloc(sizeof(s_level
));
139 mread(fd
, (void *) 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
, (void *) &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
, (void *) 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((void *)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
, (void *) &xl
, sizeof(xl
));
206 if(!first
) first
= otmp
;
207 else otmp2
->nobj
= otmp
;
208 mread(fd
, (void *) 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
) && !is_lightsaber(otmp
))
221 otmp
->age
= monstermoves
- omoves
+ otmp
->age
;
222 otmp
->invoketimer
= monstermoves
- omoves
+ otmp
->invoketimer
;
224 /* get contents of a container or statue */
225 if (Has_contents(otmp
)) {
227 otmp
->cobj
= restobjchn(fd
, ghostly
, Is_IceBox(otmp
));
228 /* restore container back pointers */
229 for (otmp3
= otmp
->cobj
; otmp3
; otmp3
= otmp3
->nobj
)
230 otmp3
->ocontainer
= otmp
;
232 if (otmp
->bypass
) otmp
->bypass
= 0;
236 if(first
&& otmp2
->nobj
){
237 impossible("Restobjchn: error reading objchn.");
244 STATIC_OVL
struct monst
*
245 restmonchn(fd
, ghostly
)
249 register struct monst
*mtmp
, *mtmp2
= 0;
250 register struct monst
*first
= (struct monst
*)0;
252 struct permonst
*monbegin
;
255 /* get the original base address */
256 mread(fd
, (void *)&monbegin
, sizeof(monbegin
));
257 moved
= (monbegin
!= mons
);
260 mread(fd
, (void *) &xl
, sizeof(xl
));
263 if(!first
) first
= mtmp
;
264 else mtmp2
->nmon
= mtmp
;
265 mread(fd
, (void *) mtmp
, (unsigned) xl
+ sizeof(struct monst
));
267 unsigned nid
= flags
.ident
++;
268 add_id_mapping(mtmp
->m_id
, nid
);
271 if (moved
&& mtmp
->data
) {
272 int offset
= mtmp
->data
- monbegin
; /*(ptrdiff_t)*/
273 mtmp
->data
= mons
+ offset
; /* new permonst location */
276 int mndx
= monsndx(mtmp
->data
);
277 if (propagate(mndx
, TRUE
, ghostly
) == 0) {
278 /* cookie to trigger purge in getbones() */
279 mtmp
->mhpmax
= DEFUNCT_MONSTER
;
284 mtmp
->minvent
= restobjchn(fd
, ghostly
, FALSE
);
285 /* restore monster back pointer */
286 for (obj
= mtmp
->minvent
; obj
; obj
= obj
->nobj
)
292 for(obj
= mtmp
->minvent
; obj
; obj
= obj
->nobj
)
293 if (obj
->owornmask
& W_WEP
) break;
294 if (obj
) mtmp
->mw
= obj
;
297 /* KMH -- this is more an annoyance than a bug */
298 /* impossible("bad monster weapon restore"); */
302 if (mtmp
->isshk
) restshk(mtmp
, ghostly
);
303 if (mtmp
->ispriest
) restpriest(mtmp
, ghostly
);
304 if (mtmp
->isgyp
&& ghostly
) gypsy_init(mtmp
);
308 if(first
&& mtmp2
->nmon
){
309 impossible("Restmonchn: error reading monchn.");
315 STATIC_OVL
struct fruit
*
319 register struct fruit
*flist
, *fnext
;
322 while (fnext
= newfruit(),
323 mread(fd
, (void *)fnext
, sizeof *fnext
),
325 fnext
->nextf
= flist
;
328 dealloc_fruit(fnext
);
334 register struct fruit
*flist
;
336 register struct fruit
*fnext
;
339 fnext
= flist
->nextf
;
340 dealloc_fruit(flist
);
347 register struct obj
*otmp
;
349 register struct fruit
*oldf
;
351 for (oldf
= oldfruit
; oldf
; oldf
= oldf
->nextf
)
352 if (oldf
->fid
== otmp
->spe
) break;
354 if (!oldf
) impossible("no old fruit?");
355 else otmp
->spe
= fruitadd(oldf
->fname
);
360 restgamestate(fd
, stuckid
, steedid
)
362 unsigned int *stuckid
, *steedid
; /* STEED */
364 /* discover is actually flags.explore */
365 boolean remember_discover
= discover
;
370 mread(fd
, (void *) &uid
, sizeof uid
);
371 if (uid
!= getuid()) { /* strange ... */
372 /* for wizard mode, issue a reminder; for others, treat it
373 as an attempt to cheat and refuse to restore this file
374 Amy edit: bullshit! you stupid bastards who always delete files without even giving a prompt! */
375 pline("Saved game was not yours.");
382 mread(fd
, (void *) &flags
, sizeof(struct flag
));
383 flags
.bypasses
= 0; /* never use the saved value of bypasses */
384 if (remember_discover
) discover
= remember_discover
;
386 monst_globals_init();
388 role_init(); /* Reset the initial role, gender, and alignment */
391 amii_setpens(amii_numcolors
); /* use colors from save file */
393 mread(fd
, (void *) &u
, sizeof(struct you
));
396 cliparound(u
.ux
, u
.uy
);
398 /* reload random monster*/
400 const char *tname
; /* bugfix by Chris_ANG */
403 int monstcursor
= PM_PLAYERMON
+ 1;
404 while (monstcursor
< NUMMONS
) {
405 tname
= mons
[monstcursor
].mname
;
406 mread(fd
, (void *) &mons
[monstcursor
], sizeof(struct permonst
));
407 mons
[monstcursor
].mname
= tname
;
411 mons
[PM_SUIKUN_X
].mname
= u
.strpokshamblert
;
412 mons
[PM_HOUOU_X
].mname
= u
.strpokshamblertp
;
413 mons
[PM_INTERHACK_HORROR_X
].mname
= u
.strshamblerx
;
414 mons
[PM_NHTNG_HORROR_X
].mname
= u
.strshamblerxa
;
415 mons
[PM_PETROGRAPHY_HORROR_X
].mname
= u
.strshamblerza
;
416 mons
[PM_STONE_COLD_HORROR_X
].mname
= u
.strshamblerz
;
417 mons
[PM_MISNAMED_STARLIT_SKY
].mname
= u
.starlit1
;
418 mons
[PM_WRONG_NAMED_STARLIT_SKY
].mname
= u
.starlit2
;
419 mons
[PM_ERRONEOUS_STARLIT_SKY
].mname
= u
.starlit3
;
420 mons
[PM_UNKNOWN_MIMIC_X
].mname
= u
.strandommimic
;
421 mons
[PM_UNKNOWN_PERMAMIMIC_X
].mname
= u
.strandommimicb
;
422 mons
[PM_COLORLESS_MOLD_X
].mname
= u
.strandomfungus
;
423 mons
[PM_COLORLESS_FUNGUS_X
].mname
= u
.strandomfungusb
;
424 mons
[PM_COLORLESS_PATCH_X
].mname
= u
.strandomfungusc
;
425 mons
[PM_COLORLESS_FORCE_FUNGUS_X
].mname
= u
.strandomfungusd
;
426 mons
[PM_COLORLESS_WORT_X
].mname
= u
.strandomfungusd
;
427 mons
[PM_COLORLESS_FORCE_PATCH_X
].mname
= u
.strandomfunguse
;
428 mons
[PM_COLORLESS_WARP_FUNGUS_X
].mname
= u
.strandomfungusf
;
429 mons
[PM_COLORLESS_WARP_PATCH_X
].mname
= u
.strandomfungusg
;
430 mons
[PM_COLORLESS_STALK_X
].mname
= u
.strandomfungush
;
431 mons
[PM_COLORLESS_SPORE_X
].mname
= u
.strandomfungusi
;
432 mons
[PM_COLORLESS_MUSHROOM_X
].mname
= u
.strandomfungusj
;
433 mons
[PM_COLORLESS_GROWTH_X
].mname
= u
.strandomfungusk
;
434 mons
[PM_COLORLESS_COLONY_X
].mname
= u
.strandomfungusl
;
435 mons
[PM_KRONG_SEPHIRAH_X
].mname
= u
.strandomkopb
;
436 mons
[PM_ADULT_TATZELWORM_X
].mname
= u
.strandomdragonb
;
437 mons
[PM_ADULT_AMPHITERE_X
].mname
= u
.strandomdragonc
;
438 mons
[PM_BABY_TATZELWORM_X
].mname
= u
.strandombdragonb
;
439 mons
[PM_BABY_AMPHITERE_X
].mname
= u
.strandombdragonc
;
443 /* who the HELL designed this bullcrap that allows you to hide a death from the logs??? moved to allmain.c --Amy */
445 if(u
.uhp
<= 0 && (!Upolyd
|| u
.mh
<= 0)) {
446 u
.ux
= u
.uy
= 0; /* affects pline() [hence You()] */
447 You("were not healthy enough to survive restoration.");
448 /* wiz1_level.dlevel is used by mklev.c to see if lots of stuff is
449 * uninitialized, so we only have to set it and not the other stuff.
451 wiz1_level
.dlevel
= 0;
458 /* this stuff comes after potential aborted restore attempts */
459 restore_timers(fd
, RANGE_GLOBAL
, FALSE
, 0L);
460 restore_light_sources(fd
);
461 invent
= restobjchn(fd
, FALSE
, FALSE
);
462 bc_obj
= restobjchn(fd
, FALSE
, FALSE
);
464 struct obj
*nobj
= bc_obj
->nobj
;
465 if (bc_obj
->owornmask
) setworn(bc_obj
, bc_obj
->owornmask
);
466 bc_obj
->nobj
= (struct obj
*)0;
469 migrating_objs
= restobjchn(fd
, FALSE
, FALSE
);
470 migrating_mons
= restmonchn(fd
, FALSE
);
471 mread(fd
, (void *) mvitals
, sizeof(mvitals
));
474 * There are some things after this that can have unintended display
475 * side-effects too early in the game.
476 * Disable see_monsters() here, re-enable it at the top of moveloop()
478 defer_see_monsters
= TRUE
;
480 /* this comes after inventory has been loaded */
481 for(otmp
= invent
; otmp
; otmp
= otmp
->nobj
)
485 pline ("obj(%s),", xname(otmp
));
487 setworn(otmp
, otmp
->owornmask
);
491 /* reset weapon so that player will get a reminder about "bashing"
492 during next fight when bare-handed or wielding an unconventional
493 item; for pick-axe, we aren't able to distinguish between having
494 applied or wielded it, so be conservative and assume the former */
495 otmp
= uwep
; /* `uwep' usually init'd by setworn() in loop above */
496 uwep
= 0; /* clear it and have setuwep() reinit */
497 setuwep(otmp
,FALSE
,FALSE
); /* (don't need any null check here) */
498 /* Amy edit: autocursing shit shouldn't autocurse here! */
499 /* KMH, balance patch -- added fishing pole */
500 if (!uwep
|| uwep
->otyp
== PICK_AXE
|| uwep
->otyp
== CONGLOMERATE_PICK
|| uwep
->otyp
== UNWIELDY_PICK
|| uwep
->otyp
== CONUNDRUM_PICK
|| uwep
->otyp
== SHOVEL
|| uwep
->otyp
== MYSTERY_PICK
|| uwep
->otyp
== BRONZE_PICK
|| uwep
->otyp
== BRICK_PICK
|| uwep
->otyp
== MYSTERIOUS_PICK
|| uwep
->otyp
== NANO_PICK
|| uwep
->otyp
== GRAPPLING_HOOK
|| uwep
->otyp
== JACK_KNIFE
||
501 uwep
->otyp
== FISHING_POLE
)
507 mread(fd
, (void *) &moves
, sizeof moves
);
508 mread(fd
, (void *) &monstermoves
, sizeof monstermoves
);
509 mread(fd
, (void *) &quest_status
, sizeof(struct q_score
));
510 mread(fd
, (void *) spl_book
,
511 sizeof(struct spell
) * (MAXSPELL
+ 1));
512 mread(fd
, (void *) tech_list
,
513 sizeof(struct tech
) * (MAXTECH
+ 1));
516 mread(fd
, (void *) stuckid
, sizeof (*stuckid
));
518 mread(fd
, (void *) steedid
, sizeof (*steedid
));
519 mread(fd
, (void *) pl_character
, sizeof (pl_character
));
521 mread(fd
, (void *) pl_fruit
, sizeof pl_fruit
);
522 mread(fd
, (void *) ¤t_fruit
, sizeof current_fruit
);
523 freefruitchn(ffruit
); /* clean up fruit(s) made by initoptions() */
524 ffruit
= loadfruitchn(fd
);
527 restore_artifacts(fd
); /* fix by Chris; again, thanks a lot for figuring this out! --Amy */
528 restore_waterlevel(fd
);
530 #ifdef RECORD_ACHIEVE
531 mread(fd
, (void *) &achieve
, sizeof achieve
);
532 mread(fd
, (void *) &achieveX
, sizeof achieveX
);
534 #if defined(RECORD_REALTIME) || defined(REALTIME_ON_BOTL)
535 mread(fd
, (void *) &realtime_data
.realtime
,
536 sizeof realtime_data
.realtime
);
539 /* must come after all mons & objs are restored */
540 relink_timers(FALSE
);
541 relink_light_sources(FALSE
);
548 /* update game state pointers to those valid for the current level (so we
549 * don't dereference a wild u.ustuck when saving the game state, for instance)
552 restlevelstate(stuckid
, steedid
)
553 unsigned int stuckid
, steedid
; /* STEED */
555 register struct monst
*mtmp
;
557 /* Amy edit: why the hell is this a panic?! that makes the save impossible to load in some cases! these errors
558 * are usually caused by the game segfaulting upon a level change, which simply eats the steed; the real fix for
559 * that is to fix errors that cause segfaults on level change, but panics eating the savegame just isn't a good idea
560 * because they will happen during initialization and then the emergency save will just panic again on load
562 * we have to clear setustuck and u.usteed BEFORE calling impossible, because otherwise bot() is called and
563 * may run functions that depend on those variables... */
566 for (mtmp
= fmon
; mtmp
; mtmp
= mtmp
->nmon
)
567 if (mtmp
->m_id
== stuckid
) break;
569 setustuck((struct monst
*)0);
570 impossible("Cannot find the monster ustuck.");
576 for (mtmp
= fmon
; mtmp
; mtmp
= mtmp
->nmon
)
577 if (mtmp
->m_id
== steedid
) break;
579 u
.usteed
= (struct monst
*)0;
580 impossible("Cannot find the monster usteed.");
583 remove_monster(mtmp
->mx
, mtmp
->my
);
588 /*ARGSUSED*/ /* fd used in MFLOPPY only */
590 restlevelfile(fd
, ltmp
)
600 nfd
= create_levelfile(ltmp
, whynot
);
602 /* BUG: should suppress any attempt to write a panic
603 save file if file creation is now failing... */
604 panic("restlevelfile: %s", whynot
);
607 if (!savelev(nfd
, ltmp
, COUNT_SAVE
)) {
609 /* The savelev can't proceed because the size required
610 * is greater than the available disk space.
612 pline("Not enough space on `%s' to restore your game.",
615 /* Remove levels and bones that may have been created.
621 eraseall(levels
, alllevels
);
622 eraseall(levels
, allbones
);
624 /* Perhaps the person would like to play without a
627 /* Maybe not [Tom] */
630 /* PlaywoRAMdisk may not return, but if it does
631 * it is certain that ramdisk will be 0.
634 /* Rewind save file and try again */
635 (void) lseek(fd
, (off_t
)0, 0);
636 (void) uptodate(fd
, (char *)0); /* skip version */
637 return dorecover(fd
); /* 0 or 1 */
642 pline("Be seeing you...");
643 terminate(EXIT_SUCCESS
);
650 savelev(nfd
, ltmp
, WRITE_SAVE
| FREE_SAVE
);
659 unsigned int stuckid
= 0, steedid
= 0; /* not a register */
664 #ifdef STORE_PLNAME_IN_FILE
665 mread(fd
, (void *) plname
, PL_NSIZ
);
666 mread(fd
, (void *) plalias
, PL_NSIZ
);
670 getlev(fd
, 0, (xchar
)0, FALSE
);
671 if (!restgamestate(fd
, &stuckid
, &steedid
)) {
672 display_nhwindow(WIN_MESSAGE
, TRUE
);
673 savelev(-1, 0, FREE_SAVE
); /* discard current level */
675 (void) delete_savefile();
679 restlevelstate(stuckid
, steedid
);
684 flags
.missing_safety
= TRUE
; /* to prevent "segfault panics" from creating unrecoverable savegames --Amy */
686 rtmp
= restlevelfile(fd
, ledger_no(&u
.uz
));
687 if (rtmp
< 2) return(rtmp
); /* dorecover called recursively */
689 /* these pointers won't be valid while we're processing the
690 * other levels, but they'll be reset again by restlevelstate()
691 * afterwards, and in the meantime at least u.usteed may mislead
692 * place_monster() on other levels
694 setustuck((struct monst
*)0);
695 u
.usteed
= (struct monst
*)0;
698 # ifdef AMII_GRAPHICS
700 extern struct window_procs amii_procs
;
701 if(windowprocs
.win_init_nhwindows
== amii_procs
.win_init_nhwindows
){
702 extern winid WIN_BASE
;
703 clear_nhwindow(WIN_BASE
); /* hack until there's a hook for this */
707 clear_nhwindow(WIN_MAP
);
709 clear_nhwindow(WIN_MESSAGE
);
715 if (!strncmpi("tty", windowprocs
.name
, 3))
716 putstr(WIN_MAP
, 0, "Restoring:");
721 if(mread(fd
, (void *) <mp
, sizeof ltmp
) < 0)
723 if(read(fd
, (void *) <mp
, sizeof ltmp
) != sizeof ltmp
)
726 getlev(fd
, 0, ltmp
, FALSE
);
727 #if defined(MICRO) && defined(TTY_GRAPHICS)
728 if (!strncmpi("tty", windowprocs
.name
, 3)) {
729 curs(WIN_MAP
, 1+dotcnt
++, dotrow
);
730 if (dotcnt
>= (COLNO
- 1)) {
734 putstr(WIN_MAP
, 0, ".");
738 rtmp
= restlevelfile(fd
, ltmp
);
739 if (rtmp
< 2) return(rtmp
); /* dorecover called recursively */
743 (void) lseek(fd
, 0L, 0);
745 (void) lseek(fd
, 0L, 0);
746 /* (void) lseek(fd, (off_t)0, 0); */
748 (void) uptodate(fd
, (char *)0); /* skip version info */
749 #ifdef STORE_PLNAME_IN_FILE
750 mread(fd
, (void *) plname
, PL_NSIZ
);
751 mread(fd
, (void *) plalias
, PL_NSIZ
);
753 getlev(fd
, 0, (xchar
)0, FALSE
);
756 if (!wizard
&& !discover
)
757 (void) delete_savefile();
759 if (isrougelike
|| Is_rogue_level(&u
.uz
)) assign_rogue_graphics(TRUE
);
762 substitute_tiles(&u
.uz
);
764 restlevelstate(stuckid
, steedid
);
766 /* WAC -- This needs to be after the second restlevelstate
767 * You() writes to the message line, which also updates the
768 * status line. However, u.usteed needs to be corrected or else
769 * weight/carrying capacities will be calculated by dereferencing
771 * Side effect of this is that you don't see this message until after the
772 * all the levels are loaded
774 if (!DisplayDoesNotGoAtAll
) {You("return to level %d in %s%s.",
775 depth(&u
.uz
), dungeons
[u
.uz
.dnum
].dname
,
776 flags
.debug
? " while in debug mode" :
777 flags
.explore
? " while in explore mode" : "");
779 if (DisplayLoss
|| u
.uprops
[DISPLAY_LOST
].extrinsic
|| have_displaystone() ) pline("You return to the game with your underwear intact, but can't remember exactly where you are.");
780 if (uarmc
&& uarmc
->oartifact
== ART_CLOAK_OF_THE_CONSORT
) pline("The cloak of the consort obscures your actual location.");
785 max_rank_sz(); /* to recompute mrank_sz (botl.c) */
786 /* take care of iron ball & chain */
787 for(otmp
= fobj
; otmp
; otmp
= otmp
->nobj
)
789 setworn(otmp
, otmp
->owornmask
);
791 if ((uball
&& !uchain
) || (uchain
&& !uball
)) {
792 impossible("either ball or chain lost in restgamestate");
793 /* ugh, gotta fix it now to avoid further bugs... */
794 setworn((struct obj
*)0, W_CHAIN
);
795 setworn((struct obj
*)0, W_BALL
);
798 /* in_use processing must be after:
799 * + The inventory has been read so that freeinv() works.
800 * + The current level has been restored so billing information
805 load_qtlist(); /* re-load the quest text info */
806 reset_attribute_clock();
807 /* Set up the vision internals, after levl[] data is loaded */
808 /* but before docrt(). */
810 vision_full_recalc
= 1; /* recompute vision (not saved) */
812 run_timers(); /* expire all timers that have gone off while away */
815 clear_nhwindow(WIN_MESSAGE
);
816 program_state
.something_worth_saving
++; /* useful data now exists */
818 #if defined(RECORD_REALTIME) || defined(REALTIME_ON_BOTL)
820 /* Start the timer here (realtime has already been set) */
821 #if defined(BSD) && !defined(POSIX_TYPES)
822 (void) time((long *)&realtime_data
.restoretime
);
824 (void) time(&realtime_data
.restoretime
);
827 #endif /* RECORD_REALTIME || REALTIME_ON_BOTL */
838 pline("Strange, this map is not as I remember it.");
839 pline("Somebody is trying some trickery here...");
840 pline("This game is void.");
841 pline("Or it would have been, but apparently something else can cause this too,");
842 pline("so I'm letting it slide. --Amy");
848 getlev(fd
, pid
, lev
, ghostly
)
853 register struct trap
*trap
;
854 register struct monst
*mtmp
;
866 #if defined(MSDOS) || defined(OS2)
867 setmode(fd
, O_BINARY
);
869 /* Load the old fruit info. We have to do it first, so the
870 * information is available when restoring the objects.
872 if (ghostly
) oldfruit
= loadfruitchn(fd
);
874 /* First some sanity checks */
875 mread(fd
, (void *) &hpid
, sizeof(hpid
));
876 /* CHECK: This may prevent restoration */
878 mread(fd
, (void *) &tlev
, sizeof(tlev
));
881 mread(fd
, (void *) &dlvl
, sizeof(dlvl
));
883 if ((pid
&& pid
!= hpid
) || (lev
&& dlvl
!= lev
)) {
884 char trickbuf
[BUFSZ
];
886 if (pid
&& pid
!= hpid
)
887 sprintf(trickbuf
, "PID (%d) doesn't match saved PID (%d)!",
890 sprintf(trickbuf
, "This is level %d, not %d!", dlvl
, lev
);
892 if (wizard
) pline("%s", trickbuf
);
904 /* Suppress warning about used before set */
905 (void) memset((void *) &r
, 0, sizeof(r
));
907 i
= 0; j
= 0; len
= 0;
915 mread(fd
, (void *)&len
, sizeof(uchar
));
916 mread(fd
, (void *)&r
, sizeof(struct rm
));
924 mread(fd
, (void *) levl
, sizeof(levl
));
927 mread(fd
, (void *)&omoves
, sizeof(omoves
));
928 mread(fd
, (void *)&upstair
, sizeof(stairway
));
929 mread(fd
, (void *)&dnstair
, sizeof(stairway
));
930 mread(fd
, (void *)&upladder
, sizeof(stairway
));
931 mread(fd
, (void *)&dnladder
, sizeof(stairway
));
932 mread(fd
, (void *)&sstairs
, sizeof(stairway
));
933 mread(fd
, (void *)&updest
, sizeof(dest_area
));
934 mread(fd
, (void *)&dndest
, sizeof(dest_area
));
935 mread(fd
, (void *)&level
.flags
, sizeof(level
.flags
));
936 mread(fd
, (void *)doors
, sizeof(doors
));
937 rest_rooms(fd
); /* No joke :-) */
938 /* ALI - regenerate doorindex */
940 doorindex
= rooms
[nroom
- 1].fdoor
+ rooms
[nroom
- 1].doorct
;
943 for (y
= 0; y
< ROWNO
; y
++)
944 for (x
= 0; x
< COLNO
; x
++)
945 if (IS_DOOR(levl
[x
][y
].typ
))
949 restore_timers(fd
, RANGE_LEVEL
, ghostly
, monstermoves
- omoves
);
950 restore_light_sources(fd
);
951 fmon
= restmonchn(fd
, ghostly
);
953 /* regenerate animals while on another level */
955 register struct monst
*mtmp2
;
957 for(mtmp
= fmon
; mtmp
; mtmp
= mtmp2
) {
960 /* reset peaceful/malign relative to new character */
962 /* shopkeepers will reset based on name */
963 mtmp
->mpeaceful
= peace_minded(mtmp
->data
);
965 } else if (monstermoves
> omoves
)
966 mon_catchup_elapsed_time(mtmp
, monstermoves
- omoves
);
968 /* update shape-changers in case protection against
969 them is different now than when the level was saved */
974 rest_worm(fd
); /* restore worm information */
976 while (trap
= newtrap(),
977 mread(fd
, (void *)trap
, sizeof(struct trap
)),
978 trap
->tx
!= 0) { /* need "!= 0" to work around DICE 3.0 bug */
983 fobj
= restobjchn(fd
, ghostly
, FALSE
);
985 /* restobjchn()'s `frozen' argument probably ought to be a callback
986 routine so that we can check for objects being buried under ice */
987 level
.buriedobjlist
= restobjchn(fd
, ghostly
, FALSE
);
988 billobjs
= restobjchn(fd
, ghostly
, FALSE
);
991 /* reset level.monsters for new level */
992 for (x
= 0; x
< COLNO
; x
++)
993 for (y
= 0; y
< ROWNO
; y
++)
994 level
.monsters
[x
][y
] = (struct monst
*) 0;
995 for (mtmp
= level
.monlist
; mtmp
; mtmp
= mtmp
->nmon
) {
997 set_residency(mtmp
, FALSE
);
998 place_monster(mtmp
, mtmp
->mx
, mtmp
->my
);
999 if (mtmp
->wormno
) place_wsegs(mtmp
);
1001 restdamage(fd
, ghostly
);
1003 rest_regions(fd
, ghostly
);
1005 /* Now get rid of all the temp fruits... */
1006 freefruitchn(oldfruit
), oldfruit
= 0;
1008 if (lev
> ledger_no(&medusa_level
) &&
1009 lev
< ledger_no(&stronghold_level
) && xdnstair
== 0) {
1015 levl
[cc
.x
][cc
.y
].typ
= STAIRS
;
1018 br
= Is_branchlev(&u
.uz
);
1019 if (br
&& u
.uz
.dlevel
== 1) {
1022 if (on_level(&u
.uz
, &br
->end1
))
1023 assign_level(<mp
, &br
->end2
);
1025 assign_level(<mp
, &br
->end1
);
1030 case BR_NO_END2
: /* OK to assign to sstairs if it's not used */
1031 assign_level(&sstairs
.tolev
, <mp
);
1033 case BR_PORTAL
: /* max of 1 portal per level */
1035 register struct trap
*ttmp
;
1036 for(ttmp
= ftrap
; ttmp
; ttmp
= ttmp
->ntrap
)
1037 if (ttmp
->ttyp
== MAGIC_PORTAL
)
1039 if (!ttmp
) panic("getlev: need portal but none found");
1040 assign_level(&ttmp
->dst
, <mp
);
1045 /* Remove any dangling portals. */
1046 register struct trap
*ttmp
;
1047 for (ttmp
= ftrap
; ttmp
; ttmp
= ttmp
->ntrap
)
1048 if (ttmp
->ttyp
== MAGIC_PORTAL
) {
1050 break; /* max of 1 portal/level */
1055 /* must come after all mons & objs are restored */
1056 relink_timers(ghostly
);
1057 relink_light_sources(ghostly
);
1058 reset_oattached_mids(ghostly
);
1059 #ifdef DUNGEON_GROWTH
1062 /* Amy addition: a hacky variable that should be used to avoid goddamn savegame errors. Some things,
1063 * e.g. checking for the randomized appearance of your worn cloak, seem to have a chance of segfaulting
1064 * if we call them in this state, probably because the pertinent structures have already been discarded
1065 * during the saving routine, so checking for "uarmc" or its OBJ_DESCR leads to a garbage pointer which
1066 * then crashes the game. And the savegame error is NO fun, so we can now use this variable in all checks
1067 * that get called during saving to disable stuff that should not run during saving. mkobj.c in particular
1068 * is dangerous, because the tree fruit seeding is called during saving, but also doorlock stuff in lock.c
1069 * and various other functions. Too bad we can't just defer it until you return to the level in question! */
1070 u
.dungeongrowthhack
= TRUE
;
1071 /* catchup_dgn_growths((monstermoves - omoves) / 5); */
1072 /* Amy edit: disabled - it's stupid if that shit happens on all of the 200 levels that you're not on,
1073 * because monsters don't spawn on inactive levels either and so it makes more sense that stuff only
1074 * happens while you're really there. Yes, I know, pets on other levels go wild and corpses rot etc.,
1075 * but it's really stupid if walls grow super fast just because you saved while the nastytrap was active */
1076 u
.dungeongrowthhack
= FALSE
;
1085 /* Clear all structures for object and monster ID mapping. */
1089 struct bucket
*curr
;
1091 while ((curr
= id_map
) != 0) {
1092 id_map
= curr
->next
;
1093 free((void *) curr
);
1098 /* Add a mapping to the ID map. */
1100 add_id_mapping(gid
, nid
)
1105 idx
= n_ids_mapped
% N_PER_BUCKET
;
1106 /* idx is zero on first time through, as well as when a new bucket is */
1109 struct bucket
*gnu
= (struct bucket
*) alloc(sizeof(struct bucket
));
1114 id_map
->map
[idx
].gid
= gid
;
1115 id_map
->map
[idx
].nid
= nid
;
1120 * Global routine to look up a mapping. If found, return TRUE and fill
1121 * in the new ID value. Otherwise, return false and return -1 in the new
1125 lookup_id_mapping(gid
, nidp
)
1126 unsigned gid
, *nidp
;
1129 struct bucket
*curr
;
1132 for (curr
= id_map
; curr
; curr
= curr
->next
) {
1133 /* first bucket might not be totally full */
1134 if (curr
== id_map
) {
1135 i
= n_ids_mapped
% N_PER_BUCKET
;
1136 if (i
== 0) i
= N_PER_BUCKET
;
1141 if (gid
== curr
->map
[i
].gid
) {
1142 *nidp
= curr
->map
[i
].nid
;
1151 reset_oattached_mids(ghostly
)
1155 unsigned oldid
, nid
;
1156 for (otmp
= fobj
; otmp
; otmp
= otmp
->nobj
) {
1157 if (ghostly
&& otmp
->oattached
== OATTACHED_MONST
&& otmp
->oxlth
) {
1158 struct monst
*mtmp
= (struct monst
*)otmp
->oextra
;
1161 mtmp
->mpeaceful
= mtmp
->mtame
= 0; /* pet's owner died! */
1163 if (ghostly
&& otmp
->oattached
== OATTACHED_M_ID
) {
1164 (void) memcpy((void *)&oldid
, (void *)otmp
->oextra
,
1166 if (lookup_id_mapping(oldid
, &nid
))
1167 (void) memcpy((void *)otmp
->oextra
, (void *)&nid
,
1170 otmp
->oattached
= OATTACHED_NOTHING
;
1177 #define RLESC '\0' /* Leading character for run of RLESC's */
1179 #ifndef ZEROCOMP_BUFSIZ
1180 #define ZEROCOMP_BUFSIZ BUFSZ
1182 static NEARDATA
unsigned char inbuf
[ZEROCOMP_BUFSIZ
];
1183 static NEARDATA
unsigned short inbufp
= 0;
1184 static NEARDATA
unsigned short inbufsz
= 0;
1185 static NEARDATA
short inrunlength
= -1;
1186 static NEARDATA
int mreadfd
;
1191 if (inbufp
>= inbufsz
) {
1192 inbufsz
= read(mreadfd
, (void *)inbuf
, sizeof inbuf
);
1194 if (inbufp
> sizeof inbuf
)
1195 error("EOF on file #%d.\n", mreadfd
);
1196 inbufp
= 1 + sizeof inbuf
; /* exactly one warning :-) */
1201 return inbuf
[inbufp
++];
1216 register unsigned len
;
1218 /*register int readlen = 0;*/
1219 if (fd
< 0) error("Restore error; mread attempting to read file %d.", fd
);
1222 if (inrunlength
> 0) {
1224 *(*((char **)&buf
))++ = '\0';
1226 register short ch
= mgetc();
1227 if (ch
< 0) return -1; /*readlen;*/
1228 if ((*(*(char **)&buf
)++ = (char)ch
) == RLESC
) {
1229 inrunlength
= mgetc();
1234 return 0; /*readlen;*/
1237 #else /* ZEROCOMP */
1248 register void * buf
;
1249 register unsigned int len
;
1253 #if defined(BSD) || defined(ULTRIX)
1254 rlen
= read(fd
, buf
, (int) len
);
1256 #else /* e.g. SYSV, __TURBOC__ */
1257 rlen
= read(fd
, buf
, (unsigned) len
);
1258 if((unsigned)rlen
!= len
){
1260 pline("Read %d instead of %u bytes.", rlen
, len
);
1263 (void) delete_savefile();
1264 error("Error restoring old game.");
1266 panic("Error reading level file.");
1269 #endif /* ZEROCOMP */