Blindfold removal fix
[slashemextended.git] / src / restore.c
blob44ed7165cdaee225452eb62888bbdce1fb930f93
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. */
5 #include "hack.h"
6 #include "lev.h"
7 #include "tcap.h" /* for TERMLIB and ASCIIGRAPH */
9 #if defined(MICRO)
10 extern int dotcnt; /* shared with save */
11 extern int dotrow; /* shared with save */
12 #endif
14 #ifdef USE_TILES
15 extern void substitute_tiles(d_level *); /* from tile.c */
16 #endif
18 #ifdef ZEROCOMP
19 static int mgetc(void);
20 #endif
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
39 struct bucket {
40 struct bucket *next;
41 struct {
42 unsigned gid; /* ghost ID */
43 unsigned nid; /* new ID */
44 } map[N_PER_BUCKET];
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;
54 #ifdef AMII_GRAPHICS
55 void amii_setpens(int); /* use colors from save file */
56 extern int amii_numcolors;
57 #endif
59 #include "quest.h"
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. */
68 STATIC_OVL void
69 find_lev_obj()
71 register struct obj *fobjtmp = (struct obj *)0;
72 register struct obj *otmp;
73 int x,y;
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) {
84 fobj = otmp->nobj;
85 otmp->nobj = fobjtmp;
86 otmp->where = OBJ_FREE;
87 fobjtmp = otmp;
89 /* fobj should now be empty */
91 /* Set level.objects (as well as reversing the chain back again) */
92 while ((otmp = fobjtmp) != 0) {
93 fobjtmp = otmp->nobj;
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.
101 void
102 inven_inuse(quietly)
103 boolean quietly;
105 register struct obj *otmp, *otmp2;
107 for (otmp = invent; otmp; otmp = otmp2) {
108 otmp2 = otmp->nobj;
109 #ifndef GOLDOBJ
110 if (otmp->oclass == COIN_CLASS) {
111 /* in_use gold is created by some menu operations */
112 if (!otmp->in_use) {
113 impossible("inven_inuse: !in_use gold in inventory");
115 extract_nobj(otmp, &invent);
116 otmp->in_use = FALSE;
117 dealloc_obj(otmp);
118 } else
119 #endif /* GOLDOBJ */
120 if (otmp->in_use) {
121 if (!quietly) pline("Finishing off %s...", xname(otmp));
122 useup(otmp);
127 STATIC_OVL void
128 restlevchn(fd)
129 register int fd;
131 int cnt;
132 s_level *tmplev, *x;
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;
141 else {
143 for(x = sp_levchn; x->next; x = x->next);
144 x->next = tmplev;
146 tmplev->next = (s_level *)0;
150 STATIC_OVL void
151 restdamage(fd, ghostly)
152 int fd;
153 boolean ghostly;
155 int counter;
156 struct damage *tmp_dam;
158 mread(fd, (void *) &counter, sizeof(counter));
159 if (!counter)
160 return;
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));
166 if (ghostly)
167 tmp_dam->when += (monstermoves - omoves);
168 strcpy(damaged_shops,
169 in_rooms(tmp_dam->place.x, tmp_dam->place.y, SHOPBASE));
170 if (u.uz.dlevel) {
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
174 * the second pass.
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))
181 break;
184 if (!shp || !*shp) {
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)
195 register int fd;
196 boolean ghostly, frozen;
198 register struct obj *otmp, *otmp2 = 0;
199 register struct obj *first = (struct obj *)0;
200 int xl;
202 while(1) {
203 mread(fd, (void *) &xl, sizeof(xl));
204 if(xl == -1) break;
205 otmp = newobj(xl);
206 if(!first) first = otmp;
207 else otmp2->nobj = otmp;
208 mread(fd, (void *) otmp,
209 (unsigned) xl + sizeof(struct obj));
210 if (ghostly) {
211 unsigned nid = flags.ident++;
212 add_id_mapping(otmp->o_id, nid);
213 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)) {
226 struct obj *otmp3;
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;
234 otmp2 = otmp;
236 if(first && otmp2->nobj){
237 impossible("Restobjchn: error reading objchn.");
238 otmp2->nobj = 0;
241 return(first);
244 STATIC_OVL struct monst *
245 restmonchn(fd, ghostly)
246 register int fd;
247 boolean ghostly;
249 register struct monst *mtmp, *mtmp2 = 0;
250 register struct monst *first = (struct monst *)0;
251 int xl;
252 struct permonst *monbegin;
253 boolean moved;
255 /* get the original base address */
256 mread(fd, (void *)&monbegin, sizeof(monbegin));
257 moved = (monbegin != mons);
259 while(1) {
260 mread(fd, (void *) &xl, sizeof(xl));
261 if(xl == -1) break;
262 mtmp = newmonst(xl);
263 if(!first) first = mtmp;
264 else mtmp2->nmon = mtmp;
265 mread(fd, (void *) mtmp, (unsigned) xl + sizeof(struct monst));
266 if (ghostly) {
267 unsigned nid = flags.ident++;
268 add_id_mapping(mtmp->m_id, nid);
269 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 */
275 if (ghostly) {
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;
282 if(mtmp->minvent) {
283 struct obj *obj;
284 mtmp->minvent = restobjchn(fd, ghostly, FALSE);
285 /* restore monster back pointer */
286 for (obj = mtmp->minvent; obj; obj = obj->nobj)
287 obj->ocarry = mtmp;
289 if (mtmp->mw) {
290 struct obj *obj;
292 for(obj = mtmp->minvent; obj; obj = obj->nobj)
293 if (obj->owornmask & W_WEP) break;
294 if (obj) mtmp->mw = obj;
295 else {
296 MON_NOWEP(mtmp);
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);
306 mtmp2 = mtmp;
308 if(first && mtmp2->nmon){
309 impossible("Restmonchn: error reading monchn.");
310 mtmp2->nmon = 0;
312 return(first);
315 STATIC_OVL struct fruit *
316 loadfruitchn(fd)
317 int fd;
319 register struct fruit *flist, *fnext;
321 flist = 0;
322 while (fnext = newfruit(),
323 mread(fd, (void *)fnext, sizeof *fnext),
324 fnext->fid != 0) {
325 fnext->nextf = flist;
326 flist = fnext;
328 dealloc_fruit(fnext);
329 return flist;
332 STATIC_OVL void
333 freefruitchn(flist)
334 register struct fruit *flist;
336 register struct fruit *fnext;
338 while (flist) {
339 fnext = flist->nextf;
340 dealloc_fruit(flist);
341 flist = fnext;
345 STATIC_OVL void
346 ghostfruit(otmp)
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);
358 STATIC_OVL
359 boolean
360 restgamestate(fd, stuckid, steedid)
361 register int fd;
362 unsigned int *stuckid, *steedid; /* STEED */
364 /* discover is actually flags.explore */
365 boolean remember_discover = discover;
366 struct obj *otmp;
367 struct obj *bc_obj;
368 int uid;
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.");
376 #ifdef WIZARD
377 if(!wizard)
378 #endif
379 /*return FALSE*/;
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 */
390 #ifdef AMII_GRAPHICS
391 amii_setpens(amii_numcolors); /* use colors from save file */
392 #endif
393 mread(fd, (void *) &u, sizeof(struct you));
394 init_uasmon();
395 #ifdef CLIPPING
396 cliparound(u.ux, u.uy);
397 #endif
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;
408 monstcursor++;
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 */
444 #if 0
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;
452 u.uz.dnum = 0;
453 u.uz.dlevel = 1;
454 return(FALSE);
456 #endif
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);
463 while (bc_obj) {
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;
467 bc_obj = nobj;
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)
482 if(otmp->owornmask)
483 #ifdef DEBUG
485 pline ("obj(%s),", xname(otmp));
486 #endif
487 setworn(otmp, otmp->owornmask);
488 #ifdef DEBUG
490 #endif
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)
502 unweapon = TRUE;
504 restore_dungeon(fd);
506 restlevchn(fd);
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));
514 restore_oracles(fd);
515 if (u.ustuck)
516 mread(fd, (void *) stuckid, sizeof (*stuckid));
517 if (u.usteed)
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 *) &current_fruit, sizeof current_fruit);
523 freefruitchn(ffruit); /* clean up fruit(s) made by initoptions() */
524 ffruit = loadfruitchn(fd);
526 restnames(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);
533 #endif
534 #if defined(RECORD_REALTIME) || defined(REALTIME_ON_BOTL)
535 mread(fd, (void *) &realtime_data.realtime,
536 sizeof realtime_data.realtime);
537 #endif
539 /* must come after all mons & objs are restored */
540 relink_timers(FALSE);
541 relink_light_sources(FALSE);
542 #ifdef WHEREIS_FILE
543 touch_whereis();
544 #endif
545 return(TRUE);
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)
551 STATIC_OVL void
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... */
565 if (stuckid) {
566 for (mtmp = fmon; mtmp; mtmp = mtmp->nmon)
567 if (mtmp->m_id == stuckid) break;
568 if (!mtmp) {
569 setustuck((struct monst *)0);
570 impossible("Cannot find the monster ustuck.");
571 } else {
572 setustuck(mtmp);
575 if (steedid) {
576 for (mtmp = fmon; mtmp; mtmp = mtmp->nmon)
577 if (mtmp->m_id == steedid) break;
578 if (!mtmp) {
579 u.usteed = (struct monst *)0;
580 impossible("Cannot find the monster usteed.");
581 } else {
582 u.usteed = mtmp;
583 remove_monster(mtmp->mx, mtmp->my);
588 /*ARGSUSED*/ /* fd used in MFLOPPY only */
589 STATIC_OVL int
590 restlevelfile(fd, ltmp)
591 register int fd;
592 xchar ltmp;
594 #ifdef MAC_MPW
595 # pragma unused(fd)
596 #endif
597 register int nfd;
598 char whynot[BUFSZ];
600 nfd = create_levelfile(ltmp, whynot);
601 if (nfd < 0) {
602 /* BUG: should suppress any attempt to write a panic
603 save file if file creation is now failing... */
604 panic("restlevelfile: %s", whynot);
606 #ifdef MFLOPPY
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.",
613 levels);
615 /* Remove levels and bones that may have been created.
617 (void) close(nfd);
618 # ifdef AMIGA
619 clearlocks();
620 # else
621 eraseall(levels, alllevels);
622 eraseall(levels, allbones);
624 /* Perhaps the person would like to play without a
625 * RAMdisk.
627 /* Maybe not [Tom] */
628 #if 0
629 if (ramdisk) {
630 /* PlaywoRAMdisk may not return, but if it does
631 * it is certain that ramdisk will be 0.
633 playwoRAMdisk();
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 */
638 } else
639 #endif
641 # endif
642 pline("Be seeing you...");
643 terminate(EXIT_SUCCESS);
644 # ifndef AMIGA
646 # endif
648 #endif
649 bufon(nfd);
650 savelev(nfd, ltmp, WRITE_SAVE | FREE_SAVE);
651 bclose(nfd);
652 return(2);
656 dorecover(fd)
657 register int fd;
659 unsigned int stuckid = 0, steedid = 0; /* not a register */
660 xchar ltmp;
661 int rtmp;
662 struct obj *otmp;
664 #ifdef STORE_PLNAME_IN_FILE
665 mread(fd, (void *) plname, PL_NSIZ);
666 mread(fd, (void *) plalias, PL_NSIZ);
667 #endif
669 restoring = TRUE;
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 */
674 (void) close(fd);
675 (void) delete_savefile();
676 restoring = FALSE;
677 return(0);
679 restlevelstate(stuckid, steedid);
680 #ifdef INSURANCE
681 savestateinlock();
682 #endif
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;
697 #ifdef MICRO
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 */
706 # else
707 clear_nhwindow(WIN_MAP);
708 # endif
709 clear_nhwindow(WIN_MESSAGE);
710 /* moved lower */
711 curs(WIN_MAP, 1, 1);
712 dotcnt = 0;
713 dotrow = 2;
714 # ifdef TTY_GRAPHICS
715 if (!strncmpi("tty", windowprocs.name, 3))
716 putstr(WIN_MAP, 0, "Restoring:");
717 # endif
718 #endif
719 while(1) {
720 #ifdef ZEROCOMP
721 if(mread(fd, (void *) &ltmp, sizeof ltmp) < 0)
722 #else
723 if(read(fd, (void *) &ltmp, sizeof ltmp) != sizeof ltmp)
724 #endif
725 break;
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)) {
731 dotrow++;
732 dotcnt = 0;
734 putstr(WIN_MAP, 0, ".");
735 mark_synch();
737 #endif
738 rtmp = restlevelfile(fd, ltmp);
739 if (rtmp < 2) return(rtmp); /* dorecover called recursively */
742 #ifdef BSD
743 (void) lseek(fd, 0L, 0);
744 #else
745 (void) lseek(fd, 0L, 0);
746 /* (void) lseek(fd, (off_t)0, 0); */
747 #endif
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);
752 #endif
753 getlev(fd, 0, (xchar)0, FALSE);
754 (void) close(fd);
756 if (!wizard && !discover)
757 (void) delete_savefile();
758 #ifdef REINCARNATION
759 if (isrougelike || Is_rogue_level(&u.uz)) assign_rogue_graphics(TRUE);
760 #endif
761 #ifdef USE_TILES
762 substitute_tiles(&u.uz);
763 #endif
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
770 * garbage pointers.
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.");
782 #ifdef MFLOPPY
783 gameDiskPrompt();
784 #endif
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)
788 if(otmp->owornmask)
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
801 * is available.
803 inven_inuse(FALSE);
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(). */
809 vision_reset();
810 vision_full_recalc = 1; /* recompute vision (not saved) */
812 run_timers(); /* expire all timers that have gone off while away */
813 docrt();
814 restoring = FALSE;
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);
823 #else
824 (void) time(&realtime_data.restoretime);
825 #endif
827 #endif /* RECORD_REALTIME || REALTIME_ON_BOTL */
829 /* Success! */
830 welcome(FALSE);
831 return(1);
834 void
835 trickery(reason)
836 char *reason;
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");
843 /*killer = reason;
844 done(TRICKED);*/
847 void
848 getlev(fd, pid, lev, ghostly)
849 int fd, pid;
850 xchar lev;
851 boolean ghostly;
853 register struct trap *trap;
854 register struct monst *mtmp;
855 branch *br;
856 int hpid;
857 xchar dlvl;
858 int x, y;
859 #ifdef TOS
860 short tlev;
861 #endif
863 if (ghostly)
864 clear_id_mapping();
866 #if defined(MSDOS) || defined(OS2)
867 setmode(fd, O_BINARY);
868 #endif
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 */
877 #ifdef TOS
878 mread(fd, (void *) &tlev, sizeof(tlev));
879 dlvl=tlev&0x00ff;
880 #else
881 mread(fd, (void *) &dlvl, sizeof(dlvl));
882 #endif
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)!",
888 hpid, pid);
889 else
890 sprintf(trickbuf, "This is level %d, not %d!", dlvl, lev);
891 #ifdef WIZARD
892 if (wizard) pline("%s", trickbuf);
893 #endif
894 trickery(trickbuf);
897 #ifdef RLECOMP
899 short i, j;
900 uchar len;
901 struct rm r;
903 #if defined(MAC)
904 /* Suppress warning about used before set */
905 (void) memset((void *) &r, 0, sizeof(r));
906 #endif
907 i = 0; j = 0; len = 0;
908 while(i < ROWNO) {
909 while(j < COLNO) {
910 if(len > 0) {
911 levl[j][i] = r;
912 len -= 1;
913 j += 1;
914 } else {
915 mread(fd, (void *)&len, sizeof(uchar));
916 mread(fd, (void *)&r, sizeof(struct rm));
919 j = 0;
920 i += 1;
923 #else
924 mread(fd, (void *) levl, sizeof(levl));
925 #endif /* RLECOMP */
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 */
939 if (nroom)
940 doorindex = rooms[nroom - 1].fdoor + rooms[nroom - 1].doorct;
941 else {
942 doorindex = 0;
943 for (y = 0; y < ROWNO; y++)
944 for (x = 0; x < COLNO; x++)
945 if (IS_DOOR(levl[x][y].typ))
946 doorindex++;
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 */
954 if (u.uz.dlevel) {
955 register struct monst *mtmp2;
957 for(mtmp = fmon; mtmp; mtmp = mtmp2) {
958 mtmp2 = mtmp->nmon;
959 if (ghostly) {
960 /* reset peaceful/malign relative to new character */
961 if(!mtmp->isshk)
962 /* shopkeepers will reset based on name */
963 mtmp->mpeaceful = peace_minded(mtmp->data);
964 set_malign(mtmp);
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 */
970 restore_cham(mtmp);
974 rest_worm(fd); /* restore worm information */
975 ftrap = 0;
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 */
979 trap->ntrap = ftrap;
980 ftrap = trap;
982 dealloc_trap(trap);
983 fobj = restobjchn(fd, ghostly, FALSE);
984 find_lev_obj();
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);
989 rest_engravings(fd);
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) {
996 if (mtmp->isshk)
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);
1004 if (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) {
1010 coord cc;
1012 mazexy_all(&cc);
1013 xdnstair = cc.x;
1014 ydnstair = cc.y;
1015 levl[cc.x][cc.y].typ = STAIRS;
1018 br = Is_branchlev(&u.uz);
1019 if (br && u.uz.dlevel == 1) {
1020 d_level ltmp;
1022 if (on_level(&u.uz, &br->end1))
1023 assign_level(&ltmp, &br->end2);
1024 else
1025 assign_level(&ltmp, &br->end1);
1027 switch(br->type) {
1028 case BR_STAIR:
1029 case BR_NO_END1:
1030 case BR_NO_END2: /* OK to assign to sstairs if it's not used */
1031 assign_level(&sstairs.tolev, &ltmp);
1032 break;
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)
1038 break;
1039 if (!ttmp) panic("getlev: need portal but none found");
1040 assign_level(&ttmp->dst, &ltmp);
1042 break;
1044 } else if (!br) {
1045 /* Remove any dangling portals. */
1046 register struct trap *ttmp;
1047 for (ttmp = ftrap; ttmp; ttmp = ttmp->ntrap)
1048 if (ttmp->ttyp == MAGIC_PORTAL) {
1049 deltrap(ttmp);
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
1060 if (!ghostly) {
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;
1079 #endif
1080 if (ghostly)
1081 clear_id_mapping();
1085 /* Clear all structures for object and monster ID mapping. */
1086 STATIC_OVL void
1087 clear_id_mapping()
1089 struct bucket *curr;
1091 while ((curr = id_map) != 0) {
1092 id_map = curr->next;
1093 free((void *) curr);
1095 n_ids_mapped = 0;
1098 /* Add a mapping to the ID map. */
1099 STATIC_OVL void
1100 add_id_mapping(gid, nid)
1101 unsigned gid, nid;
1103 int idx;
1105 idx = n_ids_mapped % N_PER_BUCKET;
1106 /* idx is zero on first time through, as well as when a new bucket is */
1107 /* needed */
1108 if (idx == 0) {
1109 struct bucket *gnu = (struct bucket *) alloc(sizeof(struct bucket));
1110 gnu->next = id_map;
1111 id_map = gnu;
1114 id_map->map[idx].gid = gid;
1115 id_map->map[idx].nid = nid;
1116 n_ids_mapped++;
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
1122 * ID.
1124 boolean
1125 lookup_id_mapping(gid, nidp)
1126 unsigned gid, *nidp;
1128 int i;
1129 struct bucket *curr;
1131 if (n_ids_mapped)
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;
1137 } else
1138 i = N_PER_BUCKET;
1140 while (--i >= 0)
1141 if (gid == curr->map[i].gid) {
1142 *nidp = curr->map[i].nid;
1143 return TRUE;
1147 return FALSE;
1150 STATIC_OVL void
1151 reset_oattached_mids(ghostly)
1152 boolean ghostly;
1154 struct obj *otmp;
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;
1160 mtmp->m_id = 0;
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,
1165 sizeof(oldid));
1166 if (lookup_id_mapping(oldid, &nid))
1167 (void) memcpy((void *)otmp->oextra, (void *)&nid,
1168 sizeof(nid));
1169 else
1170 otmp->oattached = OATTACHED_NOTHING;
1176 #ifdef ZEROCOMP
1177 #define RLESC '\0' /* Leading character for run of RLESC's */
1179 #ifndef ZEROCOMP_BUFSIZ
1180 #define ZEROCOMP_BUFSIZ BUFSZ
1181 #endif
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;
1188 static int
1189 mgetc()
1191 if (inbufp >= inbufsz) {
1192 inbufsz = read(mreadfd, (void *)inbuf, sizeof inbuf);
1193 if (!inbufsz) {
1194 if (inbufp > sizeof inbuf)
1195 error("EOF on file #%d.\n", mreadfd);
1196 inbufp = 1 + sizeof inbuf; /* exactly one warning :-) */
1197 return -1;
1199 inbufp = 0;
1201 return inbuf[inbufp++];
1204 void
1205 minit()
1207 inbufsz = 0;
1208 inbufp = 0;
1209 inrunlength = -1;
1213 mread(fd, buf, len)
1214 int fd;
1215 void * buf;
1216 register unsigned len;
1218 /*register int readlen = 0;*/
1219 if (fd < 0) error("Restore error; mread attempting to read file %d.", fd);
1220 mreadfd = fd;
1221 while (len--) {
1222 if (inrunlength > 0) {
1223 inrunlength--;
1224 *(*((char **)&buf))++ = '\0';
1225 } else {
1226 register short ch = mgetc();
1227 if (ch < 0) return -1; /*readlen;*/
1228 if ((*(*(char **)&buf)++ = (char)ch) == RLESC) {
1229 inrunlength = mgetc();
1232 /*readlen++;*/
1234 return 0; /*readlen;*/
1237 #else /* ZEROCOMP */
1239 void
1240 minit()
1242 return;
1245 void
1246 mread(fd, buf, len)
1247 register int fd;
1248 register void * buf;
1249 register unsigned int len;
1251 register int rlen;
1253 #if defined(BSD) || defined(ULTRIX)
1254 rlen = read(fd, buf, (int) len);
1255 if(rlen != len){
1256 #else /* e.g. SYSV, __TURBOC__ */
1257 rlen = read(fd, buf, (unsigned) len);
1258 if((unsigned)rlen != len){
1259 #endif
1260 pline("Read %d instead of %u bytes.", rlen, len);
1261 if(restoring) {
1262 (void) close(fd);
1263 (void) delete_savefile();
1264 error("Error restoring old game.");
1266 panic("Error reading level file.");
1269 #endif /* ZEROCOMP */
1271 /*restore.c*/