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