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. */
4
5 #include "hack.h"
6 #include "lev.h"
7 #include "tcap.h" /* for TERMLIB and ASCIIGRAPH */
8
9 #if defined(MICRO)
10 extern int dotcnt; /* shared with save */
11 extern int dotrow; /* shared with save */
12 #endif
13
14 #ifdef USE_TILES
15 extern void FDECL(substitute_tiles, (d_level *)); /* from tile.c */
16 #endif
17
18 #ifdef ZEROCOMP
19 static int NDECL(mgetc);
20 #endif
21 STATIC_DCL void NDECL(find_lev_obj);
22 STATIC_DCL void FDECL(restlevchn, (int));
23 STATIC_DCL void FDECL(restdamage, (int,BOOLEAN_P));
24 STATIC_DCL struct obj *FDECL(restobjchn, (int,BOOLEAN_P,BOOLEAN_P));
25 STATIC_DCL struct monst *FDECL(restmonchn, (int,BOOLEAN_P));
26 STATIC_DCL struct fruit *FDECL(loadfruitchn, (int));
27 STATIC_DCL void FDECL(freefruitchn, (struct fruit *));
28 STATIC_DCL void FDECL(ghostfruit, (struct obj *));
29 STATIC_DCL boolean FDECL(restgamestate, (int, unsigned int *, unsigned int *));
30 STATIC_DCL void FDECL(restlevelstate, (unsigned int, unsigned int));
31 STATIC_DCL int FDECL(restlevelfile, (int,XCHAR_P));
32 STATIC_DCL void FDECL(reset_oattached_mids, (BOOLEAN_P));
33
34 /*
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.
37 */
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];
45 };
46
47 STATIC_DCL void NDECL(clear_id_mapping);
48 STATIC_DCL void FDECL(add_id_mapping, (unsigned, unsigned));
49
50 static int n_ids_mapped = 0;
51 static struct bucket *id_map = 0;
52
53
54 #ifdef AMII_GRAPHICS
55 void FDECL( amii_setpens, (int) ); /* use colors from save file */
56 extern int amii_numcolors;
57 #endif
58
59 #include "quest.h"
60
61 boolean restoring = FALSE;
62 static NEARDATA struct fruit *oldfruit;
63 static NEARDATA long omoves;
64
65 #define Is_IceBox(o) ((o)->otyp == ICE_BOX ? TRUE : FALSE)
66
67 /* Recalculate level.objects[x][y], since this info was not saved. */
68 STATIC_OVL void
find_lev_obj()69 find_lev_obj()
70 {
71 register struct obj *fobjtmp = (struct obj *)0;
72 register struct obj *otmp;
73 int x,y;
74
75 for(x=0; x<COLNO; x++) for(y=0; y<ROWNO; y++)
76 level.objects[x][y] = (struct obj *)0;
77
78 /*
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.
82 */
83 while ((otmp = fobj) != 0) {
84 fobj = otmp->nobj;
85 otmp->nobj = fobjtmp;
86 otmp->where = OBJ_FREE;
87 fobjtmp = otmp;
88 }
89 /* fobj should now be empty */
90
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);
95 }
96 }
97
98 /* Things that were marked "in_use" when the game was saved (ex. via the
99 * infamous "HUP" cheat) get used up here.
100 */
101 void
inven_inuse(quietly)102 inven_inuse(quietly)
103 boolean quietly;
104 {
105 register struct obj *otmp, *otmp2;
106
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");
114 }
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);
123 }
124 }
125 }
126
127 STATIC_OVL void
restlevchn(fd)128 restlevchn(fd)
129 register int fd;
130 {
131 int cnt;
132 s_level *tmplev, *x;
133
134 sp_levchn = (s_level *) 0;
135 mread(fd, (genericptr_t) &cnt, sizeof(int));
136 for(; cnt > 0; cnt--) {
137
138 tmplev = (s_level *)alloc(sizeof(s_level));
139 mread(fd, (genericptr_t) tmplev, sizeof(s_level));
140 if(!sp_levchn) sp_levchn = tmplev;
141 else {
142
143 for(x = sp_levchn; x->next; x = x->next);
144 x->next = tmplev;
145 }
146 tmplev->next = (s_level *)0;
147 }
148 }
149
150 STATIC_OVL void
restdamage(fd,ghostly)151 restdamage(fd, ghostly)
152 int fd;
153 boolean ghostly;
154 {
155 int counter;
156 struct damage *tmp_dam;
157
158 mread(fd, (genericptr_t) &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;
164
165 mread(fd, (genericptr_t) 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.
175 */
176 for (shp = damaged_shops; *shp; shp++) {
177 struct monst *shkp = shop_keeper(*shp);
178
179 if (shkp && inhishop(shkp) &&
180 repair_damage(shkp, tmp_dam, TRUE))
181 break;
182 }
183 }
184 if (!shp || !*shp) {
185 tmp_dam->next = level.damagelist;
186 level.damagelist = tmp_dam;
187 tmp_dam = (struct damage *)alloc(sizeof(*tmp_dam));
188 }
189 }
190 free((genericptr_t)tmp_dam);
191 }
192
193 struct lvl_sounds *
rest_lvl_sounds(fd)194 rest_lvl_sounds(fd)
195 register int fd;
196 {
197 int marker;
198 struct lvl_sounds *or = NULL;
199 mread(fd, (genericptr_t) &marker, sizeof(marker));
200 if (marker) {
201 or = (struct lvl_sounds *)alloc(sizeof(struct lvl_sounds));
202 mread(fd, (genericptr_t) or, sizeof(*or));
203 or->sounds = NULL;
204 if (or->n_sounds) {
205 int i;
206 int len;
207 or->sounds = (struct lvl_sound_bite *)alloc(sizeof(struct lvl_sound_bite)*or->n_sounds);
208 for (i = 0; i < or->n_sounds; i++) {
209 mread(fd, (genericptr_t)&(or->sounds[i].flags), sizeof(or->sounds[i].flags));
210 mread(fd, (genericptr_t)&len, sizeof(len));
211 or->sounds[i].msg = (char *)alloc(len);
212 mread(fd, (genericptr_t)or->sounds[i].msg, len);
213 }
214 }
215 }
216 return or;
217 }
218
219 struct mon_gen_override *
rest_mongen_override(fd)220 rest_mongen_override(fd)
221 register int fd;
222 {
223 int marker;
224 struct mon_gen_override *or = NULL;
225 struct mon_gen_tuple *mt = NULL;
226 int next;
227
228 mread(fd, (genericptr_t) &marker, sizeof(marker));
229 if (marker) {
230 or = (struct mon_gen_override *)alloc(sizeof(struct mon_gen_override));
231 mread(fd, (genericptr_t) or, sizeof(*or));
232 if (or->gen_chances) {
233 or->gen_chances = NULL;
234 do {
235 mt = (struct mon_gen_tuple *)alloc(sizeof(struct mon_gen_tuple));
236 mread(fd, (genericptr_t) mt, sizeof(*mt));
237 if (mt->next) {
238 next = 1;
239 } else {
240 next = 0;
241 }
242 mt->next = or->gen_chances;
243 or->gen_chances = mt;
244 } while (next);
245 }
246 }
247 return or;
248 }
249
250
251 STATIC_OVL struct obj *
restobjchn(fd,ghostly,frozen)252 restobjchn(fd, ghostly, frozen)
253 register int fd;
254 boolean ghostly, frozen;
255 {
256 register struct obj *otmp, *otmp2 = 0;
257 register struct obj *first = (struct obj *)0;
258 int xl;
259
260 while(1) {
261 mread(fd, (genericptr_t) &xl, sizeof(xl));
262 if(xl == -1) break;
263 otmp = newobj(xl);
264 if(!first) first = otmp;
265 else otmp2->nobj = otmp;
266 mread(fd, (genericptr_t) otmp,
267 (unsigned) xl + sizeof(struct obj));
268 if (ghostly) {
269 unsigned nid = flags.ident++;
270 add_id_mapping(otmp->o_id, nid);
271 otmp->o_id = nid;
272 }
273 if (ghostly && otmp->otyp == SLIME_MOLD) ghostfruit(otmp);
274 /* Ghost levels get object age shifted from old player's clock
275 * to new player's clock. Assumption: new player arrived
276 * immediately after old player died.
277 */
278 if (ghostly && !frozen && !age_is_relative(otmp))
279 otmp->age = monstermoves - omoves + otmp->age;
280
281 /* get contents of a container or statue */
282 if (Has_contents(otmp)) {
283 struct obj *otmp3;
284 otmp->cobj = restobjchn(fd, ghostly, Is_IceBox(otmp));
285 /* restore container back pointers */
286 for (otmp3 = otmp->cobj; otmp3; otmp3 = otmp3->nobj)
287 otmp3->ocontainer = otmp;
288 }
289 if (otmp->bypass) otmp->bypass = 0;
290
291 otmp2 = otmp;
292 }
293 if(first && otmp2->nobj){
294 impossible("Restobjchn: error reading objchn.");
295 otmp2->nobj = 0;
296 }
297
298 return(first);
299 }
300
301 STATIC_OVL struct monst *
restmonchn(fd,ghostly)302 restmonchn(fd, ghostly)
303 register int fd;
304 boolean ghostly;
305 {
306 register struct monst *mtmp, *mtmp2 = 0;
307 register struct monst *first = (struct monst *)0;
308 int xl;
309 struct permonst *monbegin;
310 boolean moved;
311
312 /* get the original base address */
313 mread(fd, (genericptr_t)&monbegin, sizeof(monbegin));
314 moved = (monbegin != mons);
315
316 while(1) {
317 mread(fd, (genericptr_t) &xl, sizeof(xl));
318 if(xl == -1) break;
319 mtmp = newmonst(xl);
320 if(!first) first = mtmp;
321 else mtmp2->nmon = mtmp;
322 mread(fd, (genericptr_t) mtmp, (unsigned) xl + sizeof(struct monst));
323 if (ghostly) {
324 unsigned nid = flags.ident++;
325 add_id_mapping(mtmp->m_id, nid);
326 mtmp->m_id = nid;
327 }
328 if (moved && mtmp->data) {
329 int offset = mtmp->data - monbegin; /*(ptrdiff_t)*/
330 mtmp->data = mons + offset; /* new permonst location */
331 }
332 if (ghostly) {
333 int mndx = monsndx(mtmp->data);
334 if (propagate(mndx, TRUE, ghostly) == 0) {
335 /* cookie to trigger purge in getbones() */
336 mtmp->mhpmax = DEFUNCT_MONSTER;
337 }
338 }
339 if(mtmp->minvent) {
340 struct obj *obj;
341 mtmp->minvent = restobjchn(fd, ghostly, FALSE);
342 /* restore monster back pointer */
343 for (obj = mtmp->minvent; obj; obj = obj->nobj)
344 obj->ocarry = mtmp;
345 }
346 if (mtmp->mw) {
347 struct obj *obj;
348
349 for(obj = mtmp->minvent; obj; obj = obj->nobj)
350 if (obj->owornmask & W_WEP) break;
351 if (obj) mtmp->mw = obj;
352 else {
353 MON_NOWEP(mtmp);
354 impossible("bad monster weapon restore");
355 }
356 }
357
358 if (mtmp->isshk) restshk(mtmp, ghostly);
359 if (mtmp->ispriest) restpriest(mtmp, ghostly);
360
361 mtmp2 = mtmp;
362 }
363 if(first && mtmp2->nmon){
364 impossible("Restmonchn: error reading monchn.");
365 mtmp2->nmon = 0;
366 }
367 return(first);
368 }
369
370 STATIC_OVL struct fruit *
loadfruitchn(fd)371 loadfruitchn(fd)
372 int fd;
373 {
374 register struct fruit *flist, *fnext;
375
376 flist = 0;
377 while (fnext = newfruit(),
378 mread(fd, (genericptr_t)fnext, sizeof *fnext),
379 fnext->fid != 0) {
380 fnext->nextf = flist;
381 flist = fnext;
382 }
383 dealloc_fruit(fnext);
384 return flist;
385 }
386
387 STATIC_OVL void
freefruitchn(flist)388 freefruitchn(flist)
389 register struct fruit *flist;
390 {
391 register struct fruit *fnext;
392
393 while (flist) {
394 fnext = flist->nextf;
395 dealloc_fruit(flist);
396 flist = fnext;
397 }
398 }
399
400 STATIC_OVL void
ghostfruit(otmp)401 ghostfruit(otmp)
402 register struct obj *otmp;
403 {
404 register struct fruit *oldf;
405
406 for (oldf = oldfruit; oldf; oldf = oldf->nextf)
407 if (oldf->fid == otmp->spe) break;
408
409 if (!oldf) impossible("no old fruit?");
410 else otmp->spe = fruitadd(oldf->fname);
411 }
412
413 STATIC_OVL
414 boolean
restgamestate(fd,stuckid,steedid)415 restgamestate(fd, stuckid, steedid)
416 register int fd;
417 unsigned int *stuckid, *steedid; /* STEED */
418 {
419 /* discover is actually flags.explore */
420 boolean remember_discover = discover;
421 struct obj *otmp;
422 int uid;
423
424 mread(fd, (genericptr_t) &uid, sizeof uid);
425 if (uid != getuid()) { /* strange ... */
426 /* for wizard mode, issue a reminder; for others, treat it
427 as an attempt to cheat and refuse to restore this file */
428 pline("Saved game was not yours.");
429 #ifdef WIZARD
430 if (!wizard)
431 #endif
432 return FALSE;
433 }
434
435 mread(fd, (genericptr_t) &flags, sizeof(struct flag));
436 flags.bypasses = 0; /* never use the saved value of bypasses */
437 if (remember_discover) discover = remember_discover;
438
439 role_init(); /* Reset the initial role, race, gender, and alignment */
440 #ifdef AMII_GRAPHICS
441 amii_setpens(amii_numcolors); /* use colors from save file */
442 #endif
443 mread(fd, (genericptr_t) &u, sizeof(struct you));
444 init_uasmon();
445 #ifdef CLIPPING
446 cliparound(u.ux, u.uy);
447 #endif
448 if(u.uhp <= 0 && (!Upolyd || u.mh <= 0)) {
449 u.ux = u.uy = 0; /* affects pline() [hence You()] */
450 You("were not healthy enough to survive restoration.");
451 /* wiz1_level.dlevel is used by mklev.c to see if lots of stuff is
452 * uninitialized, so we only have to set it and not the other stuff.
453 */
454 wiz1_level.dlevel = 0;
455 u.uz.dnum = 0;
456 u.uz.dlevel = 1;
457 return(FALSE);
458 }
459
460 /* this stuff comes after potential aborted restore attempts */
461 restore_timers(fd, RANGE_GLOBAL, FALSE, 0L);
462 restore_light_sources(fd);
463 invent = restobjchn(fd, FALSE, FALSE);
464 migrating_objs = restobjchn(fd, FALSE, FALSE);
465 migrating_mons = restmonchn(fd, FALSE);
466 mread(fd, (genericptr_t) mvitals, sizeof(mvitals));
467
468 restore_dungeon(fd);
469 restlevchn(fd);
470 mread(fd, (genericptr_t) &moves, sizeof moves);
471 mread(fd, (genericptr_t) &monstermoves, sizeof monstermoves);
472 mread(fd, (genericptr_t) &quest_status, sizeof(struct q_score));
473 mread(fd, (genericptr_t) spl_book,
474 sizeof(struct spell) * (MAXSPELL + 1));
475 restore_artifacts(fd);
476 restore_oracles(fd);
477 if (u.ustuck)
478 mread(fd, (genericptr_t) stuckid, sizeof (*stuckid));
479 #ifdef STEED
480 if (u.usteed)
481 mread(fd, (genericptr_t) steedid, sizeof (*steedid));
482 #endif
483 mread(fd, (genericptr_t) pl_tutorial, sizeof pl_tutorial);
484 mread(fd, (genericptr_t) pl_character, sizeof pl_character);
485
486 mread(fd, (genericptr_t) pl_fruit, sizeof pl_fruit);
487 mread(fd, (genericptr_t) ¤t_fruit, sizeof current_fruit);
488 freefruitchn(ffruit); /* clean up fruit(s) made by initoptions() */
489 ffruit = loadfruitchn(fd);
490
491 restnames(fd);
492 restore_waterlevel(fd);
493
494 #ifdef RECORD_ACHIEVE
495 mread(fd, (genericptr_t) &achieve, sizeof achieve);
496 #endif
497 #if defined(RECORD_REALTIME) || defined(REALTIME_ON_BOTL)
498 mread(fd, (genericptr_t) &realtime_data.realtime,
499 sizeof realtime_data.realtime);
500 #endif
501
502 /* must come after all mons & objs are restored */
503 relink_timers(FALSE);
504 relink_light_sources(FALSE);
505 #ifdef WHEREIS_FILE
506 touch_whereis();
507 #endif
508 return(TRUE);
509 }
510
511 /* update game state pointers to those valid for the current level (so we
512 * don't dereference a wild u.ustuck when saving the game state, for instance)
513 */
514 STATIC_OVL void
restlevelstate(stuckid,steedid)515 restlevelstate(stuckid, steedid)
516 unsigned int stuckid, steedid; /* STEED */
517 {
518 register struct monst *mtmp;
519
520 if (stuckid) {
521 for (mtmp = fmon; mtmp; mtmp = mtmp->nmon)
522 if (mtmp->m_id == stuckid) break;
523 if (!mtmp) panic("Cannot find the monster ustuck.");
524 u.ustuck = mtmp;
525 }
526 #ifdef STEED
527 if (steedid) {
528 for (mtmp = fmon; mtmp; mtmp = mtmp->nmon)
529 if (mtmp->m_id == steedid) break;
530 if (!mtmp) panic("Cannot find the monster usteed.");
531 u.usteed = mtmp;
532 remove_monster(mtmp->mx, mtmp->my);
533 }
534 #endif
535 }
536
537 /*ARGSUSED*/ /* fd used in MFLOPPY only */
538 STATIC_OVL int
restlevelfile(fd,ltmp)539 restlevelfile(fd, ltmp)
540 register int fd;
541 xchar ltmp;
542 #if defined(macintosh) && (defined(__SC__) || defined(__MRC__))
543 # pragma unused(fd)
544 #endif
545 {
546 register int nfd;
547 char whynot[BUFSZ];
548
549 nfd = create_levelfile(ltmp, whynot);
550 if (nfd < 0) {
551 /* BUG: should suppress any attempt to write a panic
552 save file if file creation is now failing... */
553 panic("restlevelfile: %s", whynot);
554 }
555 #ifdef MFLOPPY
556 if (!savelev(nfd, ltmp, COUNT_SAVE)) {
557
558 /* The savelev can't proceed because the size required
559 * is greater than the available disk space.
560 */
561 pline("Not enough space on `%s' to restore your game.",
562 levels);
563
564 /* Remove levels and bones that may have been created.
565 */
566 (void) close(nfd);
567 # ifdef AMIGA
568 clearlocks();
569 # else
570 eraseall(levels, alllevels);
571 eraseall(levels, allbones);
572
573 /* Perhaps the person would like to play without a
574 * RAMdisk.
575 */
576 if (ramdisk) {
577 /* PlaywoRAMdisk may not return, but if it does
578 * it is certain that ramdisk will be 0.
579 */
580 playwoRAMdisk();
581 /* Rewind save file and try again */
582 (void) lseek(fd, (off_t)0, 0);
583 (void) uptodate(fd, (char *)0); /* skip version */
584 return dorecover(fd); /* 0 or 1 */
585 } else {
586 # endif
587 pline("Be seeing you...");
588 terminate(EXIT_SUCCESS);
589 # ifndef AMIGA
590 }
591 # endif
592 }
593 #endif
594 bufon(nfd);
595 savelev(nfd, ltmp, WRITE_SAVE | FREE_SAVE);
596 bclose(nfd);
597 return(2);
598 }
599
600 int
dorecover(fd)601 dorecover(fd)
602 register int fd;
603 {
604 unsigned int stuckid = 0, steedid = 0; /* not a register */
605 xchar ltmp;
606 int rtmp;
607 struct obj *otmp;
608
609 #ifdef STORE_PLNAME_IN_FILE
610 mread(fd, (genericptr_t) plname, PL_NSIZ);
611 #endif
612
613 restoring = TRUE;
614 getlev(fd, 0, (xchar)0, FALSE);
615 if (!restgamestate(fd, &stuckid, &steedid)) {
616 display_nhwindow(WIN_MESSAGE, TRUE);
617 savelev(-1, 0, FREE_SAVE); /* discard current level */
618 (void) close(fd);
619 (void) delete_savefile();
620 restoring = FALSE;
621 return(0);
622 }
623 restlevelstate(stuckid, steedid);
624 #ifdef INSURANCE
625 savestateinlock();
626 #endif
627 rtmp = restlevelfile(fd, ledger_no(&u.uz));
628 if (rtmp < 2) return(rtmp); /* dorecover called recursively */
629
630 /* these pointers won't be valid while we're processing the
631 * other levels, but they'll be reset again by restlevelstate()
632 * afterwards, and in the meantime at least u.usteed may mislead
633 * place_monster() on other levels
634 */
635 u.ustuck = (struct monst *)0;
636 #ifdef STEED
637 u.usteed = (struct monst *)0;
638 #endif
639
640 #ifdef MICRO
641 # ifdef AMII_GRAPHICS
642 {
643 extern struct window_procs amii_procs;
644 if(windowprocs.win_init_nhwindows== amii_procs.win_init_nhwindows){
645 extern winid WIN_BASE;
646 clear_nhwindow(WIN_BASE); /* hack until there's a hook for this */
647 }
648 }
649 # else
650 clear_nhwindow(WIN_MAP);
651 # endif
652 clear_nhwindow(WIN_MESSAGE);
653 You("return to level %d in %s%s.",
654 depth(&u.uz), dungeons[u.uz.dnum].dname,
655 flags.debug ? " while in debug mode" :
656 flags.explore ? " while in explore mode" : "");
657 curs(WIN_MAP, 1, 1);
658 dotcnt = 0;
659 dotrow = 2;
660 if (strncmpi("X11", windowprocs.name, 3))
661 putstr(WIN_MAP, 0, "Restoring:");
662 #endif
663 while(1) {
664 #ifdef ZEROCOMP
665 if(mread(fd, (genericptr_t) <mp, sizeof ltmp) < 0)
666 #else
667 if(read(fd, (genericptr_t) <mp, sizeof ltmp) != sizeof ltmp)
668 #endif
669 break;
670 getlev(fd, 0, ltmp, FALSE);
671 #ifdef MICRO
672 curs(WIN_MAP, 1+dotcnt++, dotrow);
673 if (dotcnt >= (COLNO - 1)) {
674 dotrow++;
675 dotcnt = 0;
676 }
677 if (strncmpi("X11", windowprocs.name, 3)){
678 putstr(WIN_MAP, 0, ".");
679 }
680 mark_synch();
681 #endif
682 rtmp = restlevelfile(fd, ltmp);
683 if (rtmp < 2) return(rtmp); /* dorecover called recursively */
684 }
685
686 #ifdef BSD
687 (void) lseek(fd, 0L, 0);
688 #else
689 (void) lseek(fd, (off_t)0, 0);
690 #endif
691 (void) uptodate(fd, (char *)0); /* skip version info */
692 #ifdef STORE_PLNAME_IN_FILE
693 mread(fd, (genericptr_t) plname, PL_NSIZ);
694 #endif
695 getlev(fd, 0, (xchar)0, FALSE);
696 (void) close(fd);
697
698 if (!wizard && !discover)
699 (void) delete_savefile();
700 #ifdef REINCARNATION
701 if (Is_rogue_level(&u.uz)) assign_rogue_graphics(TRUE);
702 #endif
703 #ifdef USE_TILES
704 substitute_tiles(&u.uz);
705 #endif
706 restlevelstate(stuckid, steedid);
707 #ifdef MFLOPPY
708 gameDiskPrompt();
709 #endif
710 max_rank_sz(); /* to recompute mrank_sz (botl.c) */
711
712 /* this comes after inventory has been loaded */
713 for(otmp = invent; otmp; otmp = otmp->nobj)
714 if(otmp->owornmask)
715 setworn(otmp, otmp->owornmask);
716
717 /* reset weapon so that player will get a reminder about "bashing"
718 during next fight when bare-handed or wielding an unconventional
719 item; for pick-axe, we aren't able to distinguish between having
720 applied or wielded it, so be conservative and assume the former */
721 otmp = uwep; /* `uwep' usually init'd by setworn() in loop above */
722 uwep = 0; /* clear it and have setuwep() reinit */
723 setuwep(otmp); /* (don't need any null check here) */
724 if (!uwep || uwep->otyp == PICK_AXE || uwep->otyp == GRAPPLING_HOOK)
725 unweapon = TRUE;
726
727 /* take care of iron ball & chain */
728 for(otmp = fobj; otmp; otmp = otmp->nobj)
729 if(otmp->owornmask)
730 setworn(otmp, otmp->owornmask);
731
732 /* in_use processing must be after:
733 * + The inventory has been read so that freeinv() works.
734 * + The current level has been restored so billing information
735 * is available.
736 */
737 inven_inuse(FALSE);
738
739 load_qtlist(); /* re-load the quest text info */
740 reset_attribute_clock();
741 /* Set up the vision internals, after levl[] data is loaded */
742 /* but before docrt(). */
743 vision_reset();
744 vision_full_recalc = 1; /* recompute vision (not saved) */
745
746 run_timers(); /* expire all timers that have gone off while away */
747 docrt();
748 restoring = FALSE;
749 clear_nhwindow(WIN_MESSAGE);
750 program_state.something_worth_saving++; /* useful data now exists */
751
752 #if defined(RECORD_REALTIME) || defined(REALTIME_ON_BOTL)
753
754 /* Start the timer here (realtime has already been set) */
755 #if defined(BSD) && !defined(POSIX_TYPES)
756 (void) time((long *)&realtime_data.restoretime);
757 #else
758 (void) time(&realtime_data.restoretime);
759 #endif
760
761 #endif /* RECORD_REALTIME || REALTIME_ON_BOTL */
762
763 /* Success! */
764 welcome(FALSE);
765 return(1);
766 }
767
768 void
trickery(reason)769 trickery(reason)
770 char *reason;
771 {
772 pline("Strange, this map is not as I remember it.");
773 pline("Somebody is trying some trickery here...");
774 pline("This game is void.");
775 killer = reason;
776 done(TRICKED);
777 }
778
779 void
getlev(fd,pid,lev,ghostly)780 getlev(fd, pid, lev, ghostly)
781 int fd, pid;
782 xchar lev;
783 boolean ghostly;
784 {
785 register struct trap *trap;
786 register struct monst *mtmp;
787 branch *br;
788 int hpid;
789 xchar dlvl;
790 int x, y;
791 #ifdef TOS
792 short tlev;
793 #endif
794
795 if (ghostly)
796 clear_id_mapping();
797
798 #if defined(MSDOS) || defined(OS2)
799 setmode(fd, O_BINARY);
800 #endif
801 /* Load the old fruit info. We have to do it first, so the
802 * information is available when restoring the objects.
803 */
804 if (ghostly) oldfruit = loadfruitchn(fd);
805
806 /* First some sanity checks */
807 mread(fd, (genericptr_t) &hpid, sizeof(hpid));
808 /* CHECK: This may prevent restoration */
809 #ifdef TOS
810 mread(fd, (genericptr_t) &tlev, sizeof(tlev));
811 dlvl=tlev&0x00ff;
812 #else
813 mread(fd, (genericptr_t) &dlvl, sizeof(dlvl));
814 #endif
815 if ((pid && pid != hpid) || (lev && dlvl != lev)) {
816 char trickbuf[BUFSZ];
817
818 if (pid && pid != hpid)
819 Sprintf(trickbuf, "PID (%d) doesn't match saved PID (%d)!",
820 hpid, pid);
821 else
822 Sprintf(trickbuf, "This is level %d, not %d!", dlvl, lev);
823 #ifdef WIZARD
824 if (wizard) pline("%s", trickbuf);
825 #endif
826 trickery(trickbuf);
827 }
828
829 #ifdef RLECOMP
830 {
831 short i, j;
832 uchar len;
833 struct rm r;
834
835 #if defined(MAC)
836 /* Suppress warning about used before set */
837 (void) memset((genericptr_t) &r, 0, sizeof(r));
838 #endif
839 i = 0; j = 0; len = 0;
840 while(i < ROWNO) {
841 while(j < COLNO) {
842 if(len > 0) {
843 levl[j][i] = r;
844 len -= 1;
845 j += 1;
846 } else {
847 mread(fd, (genericptr_t)&len, sizeof(uchar));
848 mread(fd, (genericptr_t)&r, sizeof(struct rm));
849 }
850 }
851 j = 0;
852 i += 1;
853 }
854 }
855 #else
856 mread(fd, (genericptr_t) levl, sizeof(levl));
857 #endif /* RLECOMP */
858
859 mread(fd, (genericptr_t)&omoves, sizeof(omoves));
860 mread(fd, (genericptr_t)&upstair, sizeof(stairway));
861 mread(fd, (genericptr_t)&dnstair, sizeof(stairway));
862 mread(fd, (genericptr_t)&upladder, sizeof(stairway));
863 mread(fd, (genericptr_t)&dnladder, sizeof(stairway));
864 mread(fd, (genericptr_t)&sstairs, sizeof(stairway));
865 mread(fd, (genericptr_t)&updest, sizeof(dest_area));
866 mread(fd, (genericptr_t)&dndest, sizeof(dest_area));
867 mread(fd, (genericptr_t)&level.flags, sizeof(level.flags));
868 mread(fd, (genericptr_t)doors, sizeof(doors));
869 rest_rooms(fd); /* No joke :-) */
870 if (nroom)
871 doorindex = rooms[nroom - 1].fdoor + rooms[nroom - 1].doorct;
872 else
873 doorindex = 0;
874
875 restore_timers(fd, RANGE_LEVEL, ghostly, monstermoves - omoves);
876 restore_light_sources(fd);
877 fmon = restmonchn(fd, ghostly);
878
879 /* regenerate animals while on another level */
880 if (u.uz.dlevel) {
881 register struct monst *mtmp2;
882
883 for (mtmp = fmon; mtmp; mtmp = mtmp2) {
884 mtmp2 = mtmp->nmon;
885 if (ghostly) {
886 /* reset peaceful/malign relative to new character */
887 if(!mtmp->isshk)
888 /* shopkeepers will reset based on name */
889 mtmp->mpeaceful = peace_minded(mtmp->data);
890 set_malign(mtmp);
891 } else if (monstermoves > omoves)
892 mon_catchup_elapsed_time(mtmp, monstermoves - omoves);
893
894 /* update shape-changers in case protection against
895 them is different now than when the level was saved */
896 restore_cham(mtmp);
897 }
898 }
899
900 rest_worm(fd); /* restore worm information */
901 ftrap = 0;
902 while (trap = newtrap(),
903 mread(fd, (genericptr_t)trap, sizeof(struct trap)),
904 trap->tx != 0) { /* need "!= 0" to work around DICE 3.0 bug */
905 trap->ntrap = ftrap;
906 ftrap = trap;
907 }
908 dealloc_trap(trap);
909 fobj = restobjchn(fd, ghostly, FALSE);
910 find_lev_obj();
911 /* restobjchn()'s `frozen' argument probably ought to be a callback
912 routine so that we can check for objects being buried under ice */
913 level.buriedobjlist = restobjchn(fd, ghostly, FALSE);
914 billobjs = restobjchn(fd, ghostly, FALSE);
915 level.mon_gen = rest_mongen_override(fd);
916 level.sounds = rest_lvl_sounds(fd);
917 rest_engravings(fd);
918
919 /* reset level.monsters for new level */
920 for (x = 0; x < COLNO; x++)
921 for (y = 0; y < ROWNO; y++)
922 level.monsters[x][y] = (struct monst *) 0;
923 for (mtmp = level.monlist; mtmp; mtmp = mtmp->nmon) {
924 if (mtmp->isshk)
925 set_residency(mtmp, FALSE);
926 place_monster(mtmp, mtmp->mx, mtmp->my);
927 if (mtmp->wormno) place_wsegs(mtmp);
928 }
929 restdamage(fd, ghostly);
930
931 rest_regions(fd, ghostly);
932 if (ghostly) {
933 /* Now get rid of all the temp fruits... */
934 freefruitchn(oldfruit), oldfruit = 0;
935
936 if (lev > ledger_no(&medusa_level) &&
937 lev < ledger_no(&stronghold_level) && xdnstair == 0) {
938 coord cc;
939
940 mazexy(&cc);
941 xdnstair = cc.x;
942 ydnstair = cc.y;
943 levl[cc.x][cc.y].typ = STAIRS;
944 }
945
946 br = Is_branchlev(&u.uz);
947 if (br && u.uz.dlevel == 1) {
948 d_level ltmp;
949
950 if (on_level(&u.uz, &br->end1))
951 assign_level(<mp, &br->end2);
952 else
953 assign_level(<mp, &br->end1);
954
955 switch(br->type) {
956 case BR_STAIR:
957 case BR_NO_END1:
958 case BR_NO_END2: /* OK to assign to sstairs if it's not used */
959 assign_level(&sstairs.tolev, <mp);
960 break;
961 case BR_PORTAL: /* max of 1 portal per level */
962 {
963 register struct trap *ttmp;
964 for(ttmp = ftrap; ttmp; ttmp = ttmp->ntrap)
965 if (ttmp->ttyp == MAGIC_PORTAL)
966 break;
967 if (!ttmp) panic("getlev: need portal but none found");
968 assign_level(&ttmp->dst, <mp);
969 }
970 break;
971 }
972 } else if (!br) {
973 /* Remove any dangling portals. */
974 register struct trap *ttmp;
975 for (ttmp = ftrap; ttmp; ttmp = ttmp->ntrap)
976 if (ttmp->ttyp == MAGIC_PORTAL) {
977 deltrap(ttmp);
978 break; /* max of 1 portal/level */
979 }
980 }
981 }
982
983 /* must come after all mons & objs are restored */
984 relink_timers(ghostly);
985 relink_light_sources(ghostly);
986 reset_oattached_mids(ghostly);
987 #ifdef DUNGEON_GROWTH
988 if (!ghostly) catchup_dgn_growths((monstermoves - omoves) / 5);
989 #endif
990 if (ghostly)
991 clear_id_mapping();
992 }
993
994
995 /* Clear all structures for object and monster ID mapping. */
996 STATIC_OVL void
clear_id_mapping()997 clear_id_mapping()
998 {
999 struct bucket *curr;
1000
1001 while ((curr = id_map) != 0) {
1002 id_map = curr->next;
1003 free((genericptr_t) curr);
1004 }
1005 n_ids_mapped = 0;
1006 }
1007
1008 /* Add a mapping to the ID map. */
1009 STATIC_OVL void
add_id_mapping(gid,nid)1010 add_id_mapping(gid, nid)
1011 unsigned gid, nid;
1012 {
1013 int idx;
1014
1015 idx = n_ids_mapped % N_PER_BUCKET;
1016 /* idx is zero on first time through, as well as when a new bucket is */
1017 /* needed */
1018 if (idx == 0) {
1019 struct bucket *gnu = (struct bucket *) alloc(sizeof(struct bucket));
1020 gnu->next = id_map;
1021 id_map = gnu;
1022 }
1023
1024 id_map->map[idx].gid = gid;
1025 id_map->map[idx].nid = nid;
1026 n_ids_mapped++;
1027 }
1028
1029 /*
1030 * Global routine to look up a mapping. If found, return TRUE and fill
1031 * in the new ID value. Otherwise, return false and return -1 in the new
1032 * ID.
1033 */
1034 boolean
lookup_id_mapping(gid,nidp)1035 lookup_id_mapping(gid, nidp)
1036 unsigned gid, *nidp;
1037 {
1038 int i;
1039 struct bucket *curr;
1040
1041 if (n_ids_mapped)
1042 for (curr = id_map; curr; curr = curr->next) {
1043 /* first bucket might not be totally full */
1044 if (curr == id_map) {
1045 i = n_ids_mapped % N_PER_BUCKET;
1046 if (i == 0) i = N_PER_BUCKET;
1047 } else
1048 i = N_PER_BUCKET;
1049
1050 while (--i >= 0)
1051 if (gid == curr->map[i].gid) {
1052 *nidp = curr->map[i].nid;
1053 return TRUE;
1054 }
1055 }
1056
1057 return FALSE;
1058 }
1059
1060 STATIC_OVL void
reset_oattached_mids(ghostly)1061 reset_oattached_mids(ghostly)
1062 boolean ghostly;
1063 {
1064 struct obj *otmp;
1065 unsigned oldid, nid;
1066 for (otmp = fobj; otmp; otmp = otmp->nobj) {
1067 if (ghostly && otmp->oattached == OATTACHED_MONST && otmp->oxlth) {
1068 struct monst *mtmp = (struct monst *)otmp->oextra;
1069
1070 mtmp->m_id = 0;
1071 mtmp->mpeaceful = mtmp->mtame = 0; /* pet's owner died! */
1072 }
1073 if (ghostly && otmp->oattached == OATTACHED_M_ID) {
1074 (void) memcpy((genericptr_t)&oldid, (genericptr_t)otmp->oextra,
1075 sizeof(oldid));
1076 if (lookup_id_mapping(oldid, &nid))
1077 (void) memcpy((genericptr_t)otmp->oextra, (genericptr_t)&nid,
1078 sizeof(nid));
1079 else
1080 otmp->oattached = OATTACHED_NOTHING;
1081 }
1082 }
1083 }
1084
1085
1086 #ifdef ZEROCOMP
1087 #define RLESC '\0' /* Leading character for run of RLESC's */
1088
1089 #ifndef ZEROCOMP_BUFSIZ
1090 #define ZEROCOMP_BUFSIZ BUFSZ
1091 #endif
1092 static NEARDATA unsigned char inbuf[ZEROCOMP_BUFSIZ];
1093 static NEARDATA unsigned short inbufp = 0;
1094 static NEARDATA unsigned short inbufsz = 0;
1095 static NEARDATA short inrunlength = -1;
1096 static NEARDATA int mreadfd;
1097
1098 static int
mgetc()1099 mgetc()
1100 {
1101 if (inbufp >= inbufsz) {
1102 inbufsz = read(mreadfd, (genericptr_t)inbuf, sizeof inbuf);
1103 if (!inbufsz) {
1104 if (inbufp > sizeof inbuf)
1105 error("EOF on file #%d.\n", mreadfd);
1106 inbufp = 1 + sizeof inbuf; /* exactly one warning :-) */
1107 return -1;
1108 }
1109 inbufp = 0;
1110 }
1111 return inbuf[inbufp++];
1112 }
1113
1114 void
minit()1115 minit()
1116 {
1117 inbufsz = 0;
1118 inbufp = 0;
1119 inrunlength = -1;
1120 }
1121
1122 int
mread(fd,buf,len)1123 mread(fd, buf, len)
1124 int fd;
1125 genericptr_t buf;
1126 register unsigned len;
1127 {
1128 /*register int readlen = 0;*/
1129 if (fd < 0) error("Restore error; mread attempting to read file %d.", fd);
1130 mreadfd = fd;
1131 while (len--) {
1132 if (inrunlength > 0) {
1133 inrunlength--;
1134 *(*((char **)&buf))++ = '\0';
1135 } else {
1136 register short ch = mgetc();
1137 if (ch < 0) return -1; /*readlen;*/
1138 if ((*(*(char **)&buf)++ = (char)ch) == RLESC) {
1139 inrunlength = mgetc();
1140 }
1141 }
1142 /*readlen++;*/
1143 }
1144 return 0; /*readlen;*/
1145 }
1146
1147 #else /* ZEROCOMP */
1148
1149 void
minit()1150 minit()
1151 {
1152 return;
1153 }
1154
1155 void
mread(fd,buf,len)1156 mread(fd, buf, len)
1157 register int fd;
1158 register genericptr_t buf;
1159 register unsigned int len;
1160 {
1161 register int rlen;
1162
1163 #if defined(BSD) || defined(ULTRIX)
1164 rlen = read(fd, buf, (int) len);
1165 if(rlen != len){
1166 #else /* e.g. SYSV, __TURBOC__ */
1167 rlen = read(fd, buf, (unsigned) len);
1168 if((unsigned)rlen != len){
1169 #endif
1170 pline("Read %d instead of %u bytes.", rlen, len);
1171 if(restoring) {
1172 (void) close(fd);
1173 (void) delete_savefile();
1174 error("Error restoring old game.");
1175 }
1176 panic("Error reading level file.");
1177 }
1178 }
1179 #endif /* ZEROCOMP */
1180
1181 /*restore.c*/
1182