home *** CD-ROM | disk | FTP | other *** search
/ Assassins - Ultimate CD Games Collection 4 / Assassins 4 (1999)(Weird Science).iso / misc / omega / source / save.c < prev    next >
Encoding:
C/C++ Source or Header  |  1997-05-02  |  26.2 KB  |  926 lines

  1. /* omega copyright (c) 1987,1988,1989 by Laurence Raphael Brothers */
  2. /* save.c */
  3.  
  4. #ifndef MSDOS
  5. #include <unistd.h>
  6. #include <stdlib.h>
  7. #endif
  8.  
  9. #include "glob.h"
  10.  
  11. /*Various functions for doing game saves and restores */
  12. /*The game remembers various player information, the city level,
  13. the country level, and the last or current dungeon level */
  14.  
  15. #if defined(MSDOS) || defined(AMIGA)
  16. void do_compression(int, char *);
  17. #endif
  18.  
  19. /**************** SAVE FUNCTIONS */
  20.  
  21. /* Checks to see if save file already exists.
  22.    Checks to see if save file can be opened for write.
  23.    The player, the city level, and the current dungeon level are saved.
  24. */
  25.  
  26. int save_game(compress,savestr)
  27. int compress;
  28. char *savestr;
  29. {
  30.   FILE *fd;
  31.   int slashpos;
  32. #ifdef SAVE_LEVELS
  33.   int tmpdepth;
  34. #endif
  35.   int i,writeok=TRUE;
  36.   plv current, save;
  37.   char temp[200];
  38.  
  39. #ifndef MSDOS
  40. #ifndef AMIGA
  41.   if (access(savestr, R_OK) == 0)
  42.     if (access(savestr, W_OK) == 0)
  43.     {
  44.     mprint(" Overwrite old file?");
  45.     writeok = (ynq() == 'y');
  46.     }
  47.     else
  48.     {
  49.     mprint(" File already exists.");
  50.     writeok = FALSE;
  51.     }
  52.   else
  53.   {
  54.     for (slashpos = strlen(savestr); slashpos > 0 && savestr[slashpos] != '/';
  55.     slashpos--)
  56.     ;
  57.     if (slashpos > 0)
  58.     {
  59.     savestr[slashpos] = '\0';
  60.     if (access(savestr, W_OK) == -1)
  61.     {
  62.         mprint(" Unable to save to that directory.");
  63.         writeok = FALSE;
  64.     }
  65.     savestr[slashpos] = '/';
  66.     }
  67.   }
  68. #endif
  69. #endif
  70.   change_to_user_perms();
  71.   if (writeok) {
  72.     fd = fopen(savestr,"wb");
  73.     if (fd == NULL) {
  74.       writeok = FALSE;
  75.       mprint(" Error opening file.");
  76.     }
  77.   }
  78.   if (! writeok)
  79.   {
  80.     morewait();
  81.     print2("Save aborted.");
  82.   }
  83.   else {
  84.  
  85.     print1("Saving Game....");
  86.  
  87.     /* write the version number */
  88.     i = VERSION;
  89.     fwrite((char *)&i,sizeof(int),1,fd);
  90.     /* write game id to save file */
  91.  
  92.     writeok &= save_player(fd);
  93.     writeok &= save_country(fd);
  94. #ifdef SAVE_LEVELS
  95.     tmpdepth = Level->depth;
  96.     City = msdos_changelevel(Level,E_CITY,0);
  97. #endif
  98.     writeok &= save_level(fd,City);
  99.     
  100.     if (Current_Environment == E_CITY || Current_Environment == E_COUNTRYSIDE)
  101.       save = Dungeon;
  102.     else if (Current_Environment == Current_Dungeon)
  103.       save = Dungeon;
  104.     else
  105.       save = Level;
  106.     for (i = 0, current = save; current; current = current->next, i++)
  107.       ;
  108.     if (!fwrite((char *)&i,sizeof(int),1,fd))
  109.       writeok = FALSE;
  110. #ifdef SAVE_LEVELS
  111.     Level = msdos_changelevel(NULL,Current_Environment,tmpdepth);
  112. #endif
  113.     for (current = save; current; current = current->next)
  114.       if (current != Level)
  115.     writeok &= save_level(fd,current);
  116.     if (save)
  117.       writeok &= save_level(fd,Level);    /* put current level last */
  118.     fclose(fd);
  119.     if (writeok)
  120.     print1("Game Saved.");
  121.     else
  122.     print1("Something didn't work... save aborted.");
  123. #ifdef COMPRESS_SAVE_FILES
  124.     if (writeok && compress) {
  125.       print2("Compressing Save File....");
  126. # if defined(MSDOS) || defined(AMIGA)
  127.       do_compression(0, savestr);
  128.       strcpy(temp, savestr);
  129.       strcat(temp, "Z");
  130.       rename(temp, savestr);
  131. # else
  132.       strcpy(temp,COMPRESSOR);
  133.       strcat(temp," ");
  134.       strcat(temp,savestr);
  135.       system(temp);
  136.       sprintf(temp, "%s.%s", savestr, COMPRESS_EXT);
  137.       unlink(savestr);
  138.       link(temp, savestr);
  139.       unlink(temp);    /* renames, but sys-V doesn't have rename()... */
  140. # endif
  141.     }
  142. #endif
  143.     morewait();
  144.     clearmsg();
  145.   }
  146.   change_to_game_perms();
  147.   return(writeok);
  148. }
  149.  
  150.  
  151.  
  152.  
  153. /* saves game on SIGHUP */
  154. /* no longer tries to compress, which hangs */
  155. void signalsave()
  156. {
  157.   change_to_user_perms();
  158.   save_game(FALSE, "Omega.Sav");
  159. #ifdef COMPRESS_SAVE_FILES
  160.   print1("Signal - Saving uncompressed file 'Omega.Sav'.");
  161.   print2("You can compress it yourself, if you like.");
  162. #else
  163.   print1("Signal - Saving file 'Omega.Sav'.");
  164. #endif
  165.   morewait();
  166.   endgraf();
  167.   exit(0);
  168. }
  169.  
  170.  
  171. /* also saves some globals like Level->depth... */
  172.  
  173. int save_player(fd)
  174. FILE *fd;
  175. {
  176.   int i;
  177.   int ok = 1;
  178.  
  179.   /* Save random global state information */
  180.  
  181.   Player.click = (Tick + 1)%60;
  182.   ok &= (fwrite((char *)&Player,sizeof(Player),1,fd) > 0);
  183.   ok &= (fprintf(fd,"%s\n",Password) >= 0);
  184.   ok &= (fprintf(fd,"%s\n",Player.name) >= 0);
  185.   ok &= (fwrite((char *)CitySiteList,sizeof(CitySiteList),1,fd) > 0);
  186.   ok &= (fwrite((char *)&GameStatus,sizeof(long),1,fd) > 0);
  187.   ok &= (fwrite((char *)&Current_Environment,sizeof(int),1,fd) > 0);
  188.   ok &= (fwrite((char *)&Last_Environment,sizeof(int),1,fd) > 0);
  189.   ok &= (fwrite((char *)&Current_Dungeon,sizeof(int),1,fd) > 0);
  190.   ok &= (fwrite((char *)&Villagenum,sizeof(int),1,fd) > 0);
  191.   ok &= (fwrite((char *)&Verbosity,sizeof(char),1,fd) > 0);
  192.   ok &= (fwrite((char *)&Time,sizeof(long),1,fd) > 0);
  193.   ok &= (fwrite((char *)&Tick,sizeof(int),1,fd) > 0);
  194.   ok &= (fwrite((char *)&Searchnum,sizeof(int),1,fd) > 0);
  195.   ok &= (fwrite((char *)&Behavior,sizeof(int),1,fd) > 0);
  196.   ok &= (fwrite((char *)&Phase,sizeof(int),1,fd) > 0);
  197.   ok &= (fwrite((char *)&Date,sizeof(int),1,fd) > 0);
  198.   ok &= (fwrite((char *)&Spellsleft,sizeof(int),1,fd) > 0);
  199.   ok &= (fwrite((char *)&SymbolUseHour,sizeof(int),1,fd) > 0);
  200.   ok &= (fwrite((char *)&ViewHour,sizeof(int),1,fd) > 0);
  201.   ok &= (fwrite((char *)&HelmHour,sizeof(int),1,fd) > 0);
  202.   ok &= (fwrite((char *)&Constriction,sizeof(int),1,fd) > 0);
  203.   ok &= (fwrite((char *)&Blessing,sizeof(int),1,fd) > 0);
  204.   ok &= (fwrite((char *)&LastDay,sizeof(int),1,fd) > 0);
  205.   ok &= (fwrite((char *)&RitualHour,sizeof(int),1,fd) > 0);
  206.   ok &= (fwrite((char *)&Lawstone,sizeof(int),1,fd) > 0);
  207.   ok &= (fwrite((char *)&Chaostone,sizeof(int),1,fd) > 0);
  208.   ok &= (fwrite((char *)&Mindstone,sizeof(int),1,fd) > 0);
  209.   ok &= (fwrite((char *)&Arena_Opponent,sizeof(int),1,fd) > 0);
  210.   ok &= (fwrite((char *)&Imprisonment,sizeof(int),1,fd) > 0);
  211.   ok &= (fwrite((char *)&Gymcredit,sizeof(long),1,fd) > 0);
  212.   ok &= (fwrite((char *)&Balance,sizeof(long),1,fd) > 0);
  213.   ok &= (fwrite((char *)&StarGemUse,sizeof(int),1,fd) > 0);
  214.   ok &= (fwrite((char *)&HiMagicUse,sizeof(int),1,fd) > 0);
  215.   ok &= (fwrite((char *)&HiMagic,sizeof(int),1,fd) > 0);
  216.   ok &= (fwrite((char *)&FixedPoints,sizeof(long),1,fd) > 0);
  217.   ok &= (fwrite((char *)&LastCountryLocX,sizeof(int),1,fd) > 0);
  218.   ok &= (fwrite((char *)&LastCountryLocY,sizeof(int),1,fd) > 0);
  219.   ok &= (fwrite((char *)&LastTownLocX,sizeof(int),1,fd) > 0);
  220.   ok &= (fwrite((char *)&LastTownLocY,sizeof(int),1,fd) > 0);
  221.   ok &= (fwrite((char *)&Pawndate,sizeof(int),1,fd) > 0);
  222.  
  223.   ok &= (fwrite((char *)Spells,sizeof(Spells),1,fd) > 0);
  224.  
  225.   ok &= (fwrite((char *)&Command_Duration,sizeof(Command_Duration),1,fd) > 0);
  226.   ok &= (fwrite((char *)&Precipitation,sizeof(Precipitation),1,fd) > 0);
  227.   ok &= (fwrite((char *)&Lunarity,sizeof(Lunarity),1,fd) > 0);
  228.   ok &= (fwrite((char *)&ZapHour,sizeof(ZapHour),1,fd) > 0);
  229.   ok &= (fwrite((char *)&RitualRoom,sizeof(RitualRoom),1,fd) > 0);
  230.  
  231.   /* stuff which used to be statics */
  232.   ok &= (fwrite((char *)&twiddle,sizeof(twiddle),1,fd) > 0);
  233.   ok &= (fwrite((char *)&saved,sizeof(saved),1,fd) > 0);
  234.   ok &= (fwrite((char *)&onewithchaos,sizeof(onewithchaos),1,fd) > 0);
  235.   ok &= (fwrite((char *)&club_hinthour,sizeof(club_hinthour),1,fd) > 0);
  236.   ok &= (fwrite((char *)&winnings,sizeof(winnings),1,fd) > 0);
  237.   ok &= (fwrite((char *)&tavern_hinthour,sizeof(tavern_hinthour),1,fd) > 0);
  238.   ok &= (fwrite((char *)scroll_ids,sizeof(scroll_ids),1,fd) > 0);
  239.   ok &= (fwrite((char *)potion_ids,sizeof(potion_ids),1,fd) > 0);
  240.   ok &= (fwrite((char *)stick_ids,sizeof(stick_ids),1,fd) > 0);
  241.   ok &= (fwrite((char *)ring_ids,sizeof(ring_ids),1,fd) > 0);
  242.   ok &= (fwrite((char *)cloak_ids,sizeof(cloak_ids),1,fd) > 0);
  243.   ok &= (fwrite((char *)boot_ids,sizeof(boot_ids),1,fd) > 0);
  244.   ok &= (fwrite((char *)deepest,sizeof(int),E_MAX + 1,fd) > 0);
  245.   ok &= (fwrite((char *)level_seed,sizeof(int),E_MAX + 1,fd) > 0);
  246.  
  247.   /* Save player possessions */
  248.  
  249.   if (Player.possessions[O_READY_HAND] == Player.possessions[O_WEAPON_HAND])
  250.     Player.possessions[O_READY_HAND] = NULL;
  251.   for(i=0;i<MAXITEMS;i++) ok &= save_item(fd,Player.possessions[i]);
  252.   for(i=0;i<MAXPACK;i++) ok &= save_item(fd,Player.pack[i]);
  253.   for(i=0;i<PAWNITEMS;i++) ok &= save_item(fd,Pawnitems[i]);
  254.  
  255.   /* Save items in condo vault */
  256.   ok &= save_itemlist(fd,Condoitems);
  257.  
  258.   /* Save player item knowledge */
  259.   for (i=0;i<TOTALITEMS;i++)
  260.     ok &= (fwrite((char *)&(Objects[i].known),sizeof(Objects[i].known),1,fd) > 0);
  261.   return ok;
  262. }
  263.  
  264.  
  265. /* Save whatever is pointed to by level */
  266. int save_level(fd,level)
  267. FILE *fd;
  268. plv level;
  269. {
  270.   int i, j, run;
  271.   unsigned long int mask;
  272.   int ok = 1;
  273.  
  274.   ok &= (fwrite((char *)&level->depth,sizeof(char),1,fd) > 0);
  275.   ok &= (fwrite((char *)&level->numrooms,sizeof(char),1,fd) > 0);
  276.   ok &= (fwrite((char *)&level->tunnelled,sizeof(char),1,fd) > 0);
  277.   ok &= (fwrite((char *)&level->environment,sizeof(int),1,fd) > 0);
  278.   for (j = 0; j < MAXLENGTH; j++)
  279.     for (i = 0; i < MAXWIDTH; i++)
  280.       if (level->site[i][j].lstatus&CHANGED) {    /* this loc has been changed */
  281.     for (run = i + 1; run < MAXWIDTH &&    /* find how many in a row */
  282.       level->site[run][j].lstatus&CHANGED; run++)
  283.       ;
  284.     ok &= (fwrite((char *)&i,sizeof(int),1,fd) > 0);
  285.     ok &= (fwrite((char *)&j,sizeof(int),1,fd) > 0);
  286.     ok &= (fwrite((char *)&run,sizeof(int),1,fd) > 0);
  287.     for (; i < run; i++)
  288.       ok &= (fwrite((char *)&level->site[i][j],sizeof(struct location),1,fd) > 0);
  289.       }
  290.   ok &= (fwrite((char *)&i,sizeof(int),1,fd) > 0);
  291.   ok &= (fwrite((char *)&j,sizeof(int),1,fd) > 0);    /* signify end */
  292.   /* since we don't mark the 'seen' bits as CHANGED, need to save a bitmask */
  293.   run = 8*sizeof(long int);
  294.   mask = 0;
  295.   for (j = 0; j < MAXLENGTH; j++)
  296.     for (i = 0; i < MAXWIDTH; i++) {
  297.       if (run == 0) {
  298.     run = 8*sizeof(long int);
  299.     ok &= (fwrite((char *)&mask,sizeof(long int),1,fd) > 0);
  300.     mask = 0;
  301.       }
  302.       mask >>= 1;
  303.       if (level->site[i][j].lstatus&SEEN)
  304.     mask |= (1<<(sizeof(long int)*8 - 1));
  305.       run--;
  306.     }
  307.   if (run < 8*sizeof(long int))
  308.     ok &= (fwrite((char *)&mask,sizeof(long int),1,fd) > 0);
  309.   ok &= save_monsters(fd,level->mlist);
  310.   for(i=0;i<MAXWIDTH;i++)
  311.     for(j=0;j<MAXLENGTH;j++)
  312.       if (level->site[i][j].things) {
  313.     ok &= (fwrite((char *)&i,sizeof(int),1,fd) > 0);
  314.     ok &= (fwrite((char *)&j,sizeof(int),1,fd) > 0);
  315.     ok &= save_itemlist(fd,level->site[i][j].things);
  316.       }
  317.   ok &= (fwrite((char *)&i,sizeof(int),1,fd) > 0);
  318.   ok &= (fwrite((char *)&j,sizeof(int),1,fd) > 0);    /* signify end */
  319.   return ok;
  320. }
  321.  
  322.  
  323. int save_monsters(fd,ml)
  324. FILE *fd;
  325. pml ml;
  326. {
  327.   pml tml;
  328.   int nummonsters=0;
  329.   int ok = 1;
  330.   unsigned char type;
  331.  
  332.   /* First count monsters */
  333.   for(tml=ml;tml!=NULL;tml=tml->next) 
  334.     if (tml->m->hp > 0) nummonsters++;
  335.  
  336.   ok &= (fwrite((char *)&nummonsters,sizeof(int),1,fd) > 0);
  337.  
  338.   /* Now save monsters */
  339.   for(tml=ml;tml!=NULL;tml=tml->next) {
  340.     if (tml->m->hp > 0) {
  341.       ok &= (fwrite((char *)tml->m,sizeof(montype),1,fd) > 0);
  342.       if (tml->m->id != HISCORE_NPC) {
  343.     type = 0x0;
  344.     if (strcmp(tml->m->monstring, Monsters[tml->m->id].monstring))
  345.       type |= 0x1;
  346.     if (strcmp(tml->m->corpsestr, Monsters[tml->m->id].corpsestr))
  347.       type |= 0x2;
  348.     ok &= (fwrite((char *)&type,sizeof(unsigned char),1,fd) > 0);
  349.     if (type&1)
  350.       ok &= (fprintf(fd,"%s\n",tml->m->monstring) >= 0);
  351.     if (type&2)
  352.       ok &= (fprintf(fd,"%s\n",tml->m->corpsestr) >= 0);
  353.     ok &= save_itemlist(fd,tml->m->possessions);
  354.       }    /* else it'll be reloaded from the hiscore file on restore */
  355.     }
  356.   }
  357.   return ok;
  358. }
  359.  
  360.  
  361. /* Save o unless it's null, then save a special flag byte instead */
  362. /* Use other values of flag byte to indicate what strings are saved */
  363. int save_item(fd,o)
  364. FILE *fd;
  365. pob o;
  366. {
  367.   int ok = 1;
  368.   unsigned char type;
  369.  
  370.   if (o == NULL) {
  371.     type = 0xff;
  372.     ok &= (fwrite((char *)&type,sizeof(type),1,fd) > 0);
  373.   }
  374.   else {
  375.     type = 0;
  376.     if (strcmp(o->objstr, Objects[o->id].objstr))
  377.       type |= 1;
  378.     if (strcmp(o->truename, Objects[o->id].truename))
  379.       type |= 2;
  380.     if (strcmp(o->cursestr, Objects[o->id].cursestr))
  381.       type |= 4;
  382.     ok &= (fwrite((char *)&type,sizeof(type),1,fd) > 0);
  383.     ok &= (fwrite((char *)o,sizeof(objtype),1,fd) > 0);
  384.     if (type&1)
  385.       ok &= (fprintf(fd,"%s\n",o->objstr) >= 0);
  386.     if (type&2)
  387.       ok &= (fprintf(fd,"%s\n",o->truename) >= 0);
  388.     if (type&4)
  389.       ok &= (fprintf(fd,"%s\n",o->cursestr) >= 0);
  390.   }
  391.   return ok;
  392. }
  393.  
  394. int save_itemlist(fd,ol)
  395. FILE *fd;
  396. pol ol;
  397. {
  398.   int numitems = 0;
  399.   pol tol;
  400.   int ok = 1;
  401.  
  402.   for(tol=ol;tol!=NULL;tol=tol->next) numitems++;
  403.   ok &= (fwrite((char *)&numitems,sizeof(int),1,fd) > 0);
  404.   for(tol=ol;tol!=NULL;tol=tol->next)
  405.     ok &= save_item(fd,tol->thing);
  406.   return ok;
  407. }
  408.  
  409.  
  410. int save_country(fd)
  411. FILE *fd;
  412. {
  413.   int i, j;
  414.   int ok = 1;
  415.   int run;
  416.   unsigned long int mask;
  417.  
  418.   for (i = 0; i < MAXWIDTH; i++)
  419.     for (j = 0; j < MAXLENGTH; j++)
  420.       if (c_statusp(i, j, CHANGED)) {
  421.     ok &= (fwrite((char *)&i,sizeof(int),1,fd) > 0);
  422.     ok &= (fwrite((char *)&j,sizeof(int),1,fd) > 0);
  423.     ok &= (fwrite((char *)&Country[i][j],sizeof(struct terrain),1,fd) > 0);
  424.       }
  425.   ok &= (fwrite((char *)&i,sizeof(int),1,fd) > 0);
  426.   ok &= (fwrite((char *)&j,sizeof(int),1,fd) > 0);
  427.   /* since we don't mark the 'seen' bits as CHANGED, need to save a bitmask */
  428.   run = 8*sizeof(long int);
  429.   mask = 0;
  430.   for (i = 0; i < MAXWIDTH; i++)
  431.     for (j = 0; j < MAXLENGTH; j++) {
  432.       if (run == 0) {
  433.     run = 8*sizeof(long int);
  434.     ok &= (fwrite((char *)&mask,sizeof(long int),1,fd) > 0);
  435.     mask = 0;
  436.       }
  437.       mask >>= 1;
  438.       if (c_statusp(i, j, SEEN))
  439.     mask |= (1<<(sizeof(long int)*8 - 1));
  440.       run--;
  441.     }
  442.   if (run < 8*sizeof(long int))
  443.     ok &= (fwrite((char *)&mask,sizeof(long int),1,fd) > 0);
  444.   return ok;
  445. }
  446.  
  447.  
  448.  
  449.  
  450. /* read player data, city level, dungeon level,
  451.    check on validity of save file, etc.
  452.    return TRUE if game restored, FALSE otherwise */
  453.  
  454. int restore_game(savestr)
  455. char *savestr;
  456. {
  457.   int i,version; 
  458.   char temp[200];
  459.   FILE *fd;
  460.  
  461. #ifndef MSDOS
  462. #ifndef AMIGA
  463.   if (access(savestr, F_OK|R_OK|W_OK) == -1) /* access uses real uid */
  464.   {
  465.     print1("Unable to access save file: ");
  466.     nprint1(savestr);
  467.     morewait();
  468.     return FALSE;
  469.   }
  470. #endif
  471. #endif
  472.   change_to_user_perms();
  473. #ifdef COMPRESS_SAVE_FILES
  474.   fd = fopen(savestr,"rb");
  475.   if (fd == NULL) {
  476.     print1("Error restoring game -- aborted.");
  477.     print2("File name was: ");
  478.     nprint2(savestr);
  479.     morewait();
  480.     change_to_game_perms();
  481.     return(FALSE);
  482.   }
  483.   fread((char *)&version,sizeof(int),1,fd);
  484.   fclose(fd);
  485.   if (VERSION != version) {
  486.     print1("Uncompressing Save File....");
  487. #if defined(MSDOS) || defined(AMIGA)
  488.     strcpy(temp, savestr);
  489.     strcat(temp, "Z");
  490.     rename(savestr, temp);
  491.     do_compression(1, savestr);
  492. #else
  493.     sprintf(temp, "%s.%s", savestr, COMPRESS_EXT);
  494.     unlink(temp);
  495.     link(savestr, temp);
  496.     unlink(savestr);    /* renames, but sys-V doesn't have rename()... */
  497.     strcpy(temp,UNCOMPRESSOR);
  498.     strcat(temp," ");
  499.     strcat(temp,savestr);
  500.     system(temp);
  501. #endif
  502.     print2("Save file uncompressed.");
  503.     morewait();
  504.   }
  505. #endif
  506.   
  507.   fd = fopen(savestr,"rb");
  508.  
  509.   if (fd == NULL) {
  510.     print1("Error restoring game -- aborted.");
  511.     print2("File name was: ");
  512.     nprint2(savestr);
  513.     morewait();
  514.     change_to_game_perms();
  515.     return(FALSE);
  516.   }
  517.   else {
  518.     print1("Restoring...");
  519.  
  520.     fread((char *)&version,sizeof(int),1,fd);
  521.  
  522.     if (VERSION != version) {
  523.       print2(" Sorry, I can't restore an outdated save file!");
  524.       morewait();
  525.       change_to_game_perms();
  526.       return(FALSE);
  527.     }
  528.     restore_player(fd);
  529.     restore_country(fd);
  530.     restore_level(fd); /* the city level */
  531.     fread((char *)&i,sizeof(int),1,fd);
  532.     for (; i > 0; i--) {
  533. #ifdef SAVE_LEVELS
  534.       msdos_changelevel(Level,0,-1);
  535. #endif
  536.       restore_level(fd);
  537.       if (Level->environment == Current_Dungeon) {
  538.     Level->next = Dungeon;
  539.     Dungeon = Level;
  540.       }
  541.       if (Current_Environment == E_CITY)
  542.     Level = City;
  543.     }
  544.     /* this disgusting kludge because LENGTH and WIDTH are globals... */
  545.     WIDTH = 64;
  546.     switch (Current_Environment) {
  547.       case E_COURT:
  548.     LENGTH = 24; break;
  549.       case E_ARENA: case E_ABYSS: case E_CIRCLE: case E_MANSION:
  550.       case E_HOUSE: case E_HOVEL: case E_DLAIR: case E_STARPEAK:
  551.       case E_MAGIC_ISLE: case E_TEMPLE: case E_VILLAGE:
  552.     LENGTH = 16; break;
  553.       default:
  554.     LENGTH = 64; break;
  555.     }
  556.     fclose(fd);
  557.     print3("Restoration complete.");
  558.     ScreenOffset = -1000;    /* to force a redraw */
  559.     setgamestatus(SKIP_MONSTERS);
  560.     change_to_game_perms();
  561.     return(TRUE);
  562.   }
  563. }
  564.  
  565. void restore_player(fd)
  566. FILE *fd;
  567. {
  568.   int i;
  569.   fread((char *)&Player,sizeof(Player),1,fd);
  570.   filescanstring(fd,Password);
  571.   filescanstring(fd,Player.name);
  572.   fread((char *)CitySiteList,sizeof(CitySiteList),1,fd);
  573.   fread((char *)&GameStatus,sizeof(long),1,fd);
  574.   fread((char *)&Current_Environment,sizeof(int),1,fd);
  575.   fread((char *)&Last_Environment,sizeof(int),1,fd);
  576.   fread((char *)&Current_Dungeon,sizeof(int),1,fd);
  577.   fread((char *)&Villagenum,sizeof(int),1,fd);
  578.   switch(Current_Dungeon) {
  579.     case E_ASTRAL: MaxDungeonLevels = ASTRALLEVELS; break;
  580.     case E_SEWERS: MaxDungeonLevels = SEWERLEVELS; break;
  581.     case E_CASTLE: MaxDungeonLevels = CASTLELEVELS; break;
  582.     case E_CAVES: MaxDungeonLevels = CAVELEVELS; break;
  583.     case E_VOLCANO: MaxDungeonLevels = VOLCANOLEVELS; break;
  584.   }
  585.   fread((char *)&Verbosity,sizeof(char),1,fd);
  586.   fread((char *)&Time,sizeof(long),1,fd);
  587.   fread((char *)&Tick,sizeof(int),1,fd);
  588.   fread((char *)&Searchnum,sizeof(int),1,fd);
  589.   fread((char *)&Behavior,sizeof(int),1,fd);
  590.   fread((char *)&Phase,sizeof(int),1,fd);
  591.   fread((char *)&Date,sizeof(int),1,fd);
  592.   fread((char *)&Spellsleft,sizeof(int),1,fd);
  593.   fread((char *)&SymbolUseHour,sizeof(int),1,fd);
  594.   fread((char *)&ViewHour,sizeof(int),1,fd);
  595.   fread((char *)&HelmHour,sizeof(int),1,fd);
  596.   fread((char *)&Constriction,sizeof(int),1,fd);
  597.   fread((char *)&Blessing,sizeof(int),1,fd);
  598.   fread((char *)&LastDay,sizeof(int),1,fd);
  599.   fread((char *)&RitualHour,sizeof(int),1,fd);
  600.   fread((char *)&Lawstone,sizeof(int),1,fd);
  601.   fread((char *)&Chaostone,sizeof(int),1,fd);
  602.   fread((char *)&Mindstone,sizeof(int),1,fd);
  603.   fread((char *)&Arena_Opponent,sizeof(int),1,fd);
  604.   fread((char *)&Imprisonment,sizeof(int),1,fd);
  605.   fread((char *)&Gymcredit,sizeof(long),1,fd);
  606.   fread((char *)&Balance,sizeof(long),1,fd);
  607.   fread((char *)&StarGemUse,sizeof(int),1,fd);
  608.   fread((char *)&HiMagicUse,sizeof(int),1,fd);
  609.   fread((char *)&HiMagic,sizeof(int),1,fd);
  610.   fread((char *)&FixedPoints,sizeof(long),1,fd);
  611.   fread((char *)&LastCountryLocX,sizeof(int),1,fd);
  612.   fread((char *)&LastCountryLocY,sizeof(int),1,fd);
  613.   fread((char *)&LastTownLocX,sizeof(int),1,fd);
  614.   fread((char *)&LastTownLocY,sizeof(int),1,fd);
  615.   fread((char *)&Pawndate,sizeof(int),1,fd);
  616.  
  617.   fread((char *)Spells,sizeof(Spells),1,fd);
  618.  
  619.   fread((char *)&Command_Duration,sizeof(Command_Duration),1,fd);
  620.   fread((char *)&Precipitation,sizeof(Precipitation),1,fd);
  621.   fread((char *)&Lunarity,sizeof(Lunarity),1,fd);
  622.   fread((char *)&ZapHour,sizeof(ZapHour),1,fd);
  623.   fread((char *)&RitualRoom,sizeof(RitualRoom),1,fd);
  624.  
  625.   /* stuff which used to be statics */
  626.   fread((char *)&twiddle,sizeof(twiddle),1,fd);
  627.   fread((char *)&saved,sizeof(saved),1,fd);
  628.   fread((char *)&onewithchaos,sizeof(onewithchaos),1,fd);
  629.   fread((char *)&club_hinthour,sizeof(club_hinthour),1,fd);
  630.   fread((char *)&winnings,sizeof(winnings),1,fd);
  631.   fread((char *)&tavern_hinthour,sizeof(tavern_hinthour),1,fd);
  632.   fread((char *)scroll_ids,sizeof(scroll_ids),1,fd);
  633.   fread((char *)potion_ids,sizeof(potion_ids),1,fd);
  634.   fread((char *)stick_ids,sizeof(stick_ids),1,fd);
  635.   fread((char *)ring_ids,sizeof(ring_ids),1,fd);
  636.   fread((char *)cloak_ids,sizeof(cloak_ids),1,fd);
  637.   fread((char *)boot_ids,sizeof(boot_ids),1,fd);
  638.   fread((char *)deepest,sizeof(int),E_MAX + 1,fd);
  639.   fread((char *)level_seed,sizeof(int),E_MAX + 1,fd);
  640.  
  641.   /* Set up the strings for the id's */
  642.   inititem(FALSE);
  643.  
  644.   for(i=0;i<MAXITEMS;i++) 
  645.     Player.possessions[i] = restore_item(fd);
  646.  
  647.   if (!Player.possessions[O_READY_HAND] && Player.possessions[O_WEAPON_HAND] &&
  648.     twohandedp(Player.possessions[O_WEAPON_HAND]->id))
  649.     Player.possessions[O_READY_HAND] = Player.possessions[O_WEAPON_HAND];
  650.  
  651.   for(i=0;i<MAXPACK;i++) 
  652.     Player.pack[i] = restore_item(fd);
  653.   for(i=0;i<PAWNITEMS;i++) 
  654.     Pawnitems[i] = restore_item(fd);
  655.   Condoitems = restore_itemlist(fd);
  656.   for (i=0;i<TOTALITEMS;i++) 
  657.     fread((char *)&(Objects[i].known),sizeof(Objects[i].known),1,fd);
  658. }
  659.  
  660.  
  661.  
  662. /* Restore an item, the first byte tells us if it's NULL, and what strings */
  663. /* have been saved as different from the typical */
  664. pob restore_item(fd)
  665. FILE *fd;
  666. {
  667.   char tempstr[80];
  668.   unsigned char type;
  669.   pob obj = NULL;
  670.  
  671.   fread((char *)&type,sizeof(type),1,fd);
  672.   if (type != 0xff) {
  673.     obj = ((pob) checkmalloc(sizeof(objtype)));
  674.     fread((char *)obj,sizeof(objtype),1,fd);
  675.     if (type&1) {
  676.       filescanstring(fd,tempstr);
  677.       obj->objstr = salloc(tempstr);
  678.     }
  679.     else
  680.       obj->objstr = Objects[obj->id].objstr;
  681.     if (type&2) {
  682.       filescanstring(fd,tempstr);
  683.       obj->truename = salloc(tempstr);
  684.     }
  685.     else
  686.       obj->truename = Objects[obj->id].truename;
  687.     if (type&4) {
  688.       filescanstring(fd,tempstr);
  689.       obj->cursestr = salloc(tempstr);
  690.     }
  691.     else
  692.       obj->cursestr = Objects[obj->id].cursestr;
  693.   }
  694.   return obj;
  695. }
  696.  
  697. pol restore_itemlist(fd)
  698. FILE *fd;
  699. {
  700.   pol ol=NULL,cur=NULL,new=NULL;
  701.   int i,numitems,firsttime=TRUE;
  702.   fread((char *)&numitems,sizeof(int),1,fd);
  703.   for(i=0;i<numitems;i++) {
  704.     new = ((pol) checkmalloc(sizeof(oltype)));
  705.     new->thing = restore_item(fd);
  706.     new->next = NULL;
  707.     if (firsttime==TRUE) {
  708.       ol = cur = new;
  709.       firsttime = FALSE;
  710.     }
  711.     else {
  712.       cur->next = new;
  713.       cur = new;
  714.     }
  715.   }
  716.   return(ol);
  717. }
  718.  
  719.  
  720.  
  721.  
  722.  
  723.  
  724. void restore_level(fd)
  725. FILE *fd;
  726. {
  727.   int i, j, run;
  728.   unsigned long int mask;
  729.   int temp_env;
  730.  
  731.   Level = (plv) checkmalloc(sizeof(levtype));
  732.   clear_level(Level);
  733.   fread((char *)&Level->depth,sizeof(char),1,fd);
  734.   fread((char *)&Level->numrooms,sizeof(char),1,fd);
  735.   fread((char *)&Level->tunnelled,sizeof(char),1,fd);
  736.   fread((char *)&Level->environment,sizeof(int),1,fd);
  737.   Level->generated = TRUE;
  738.   temp_env = Current_Environment;
  739.   Current_Environment = Level->environment;
  740.   switch(Level->environment) {
  741.     case E_COUNTRYSIDE:
  742.       load_country();
  743.       break;
  744.     case E_CITY:
  745.       load_city(FALSE);
  746.       break;
  747.     case E_VILLAGE:
  748.       load_village(Country[LastCountryLocX][LastCountryLocY].aux, FALSE);
  749.       break;
  750.     case E_CAVES: 
  751.       initrand(Current_Environment, Level->depth);
  752.       if ((random_range(4)==0) && (Level->depth < MaxDungeonLevels))
  753.     room_level();
  754.       else cavern_level();
  755.       break;
  756.     case E_SEWERS: 
  757.       initrand(Current_Environment, Level->depth);
  758.       if ((random_range(4)==0) && (Level->depth < MaxDungeonLevels))
  759.     room_level();
  760.       else sewer_level(); 
  761.       break;
  762.     case E_CASTLE:
  763.       initrand(Current_Environment, Level->depth);
  764.       room_level();
  765.       break;
  766.     case E_ASTRAL:
  767.       initrand(Current_Environment, Level->depth);
  768.       maze_level();
  769.       break;
  770.     case E_VOLCANO:
  771.       initrand(Current_Environment, Level->depth);
  772.       switch(random_range(3)) {
  773.       case 0: cavern_level(); break;
  774.       case 1: room_level(); break;
  775.       case 2: maze_level(); break;
  776.       }
  777.       break;
  778.     case E_HOVEL:
  779.     case E_MANSION:
  780.     case E_HOUSE:
  781.       load_house(Level->environment, FALSE);
  782.       break;
  783.     case E_DLAIR:
  784.       load_dlair(gamestatusp(KILLED_DRAGONLORD), FALSE);
  785.       break;
  786.     case E_STARPEAK:
  787.       load_speak(gamestatusp(KILLED_LAWBRINGER), FALSE);
  788.       break;
  789.     case E_MAGIC_ISLE:
  790.       load_misle(gamestatusp(KILLED_EATER), FALSE);
  791.       break;
  792.     case E_TEMPLE:
  793.       load_temple(Country[LastCountryLocX][LastCountryLocY].aux, FALSE);
  794.       break;
  795.     case E_CIRCLE:
  796.       load_circle(FALSE);
  797.       break;
  798.     case E_COURT:
  799.       load_court(FALSE);
  800.       break;
  801.     default: print3("This dungeon not implemented!"); break;
  802.   }
  803.   if (Level->depth > 0) {    /* dungeon... */
  804.     install_traps();
  805.     install_specials();
  806.     make_stairs(-1);
  807.     make_stairs(-1);
  808.     initrand(-2, 0);
  809.   }
  810.   Current_Environment = temp_env;
  811.   fread((char *)&i,sizeof(int),1,fd);
  812.   fread((char *)&j,sizeof(int),1,fd);
  813.   while (j < MAXLENGTH && i < MAXWIDTH) {
  814.     fread((char *)&run,sizeof(int),1,fd);
  815.     for (; i < run; i++) {
  816.       fread((char *)&Level->site[i][j],sizeof(struct location),1,fd);
  817.       Level->site[i][j].creature = NULL;
  818.       Level->site[i][j].things = NULL;
  819.     }
  820.     fread((char *)&i,sizeof(int),1,fd);
  821.     fread((char *)&j,sizeof(int),1,fd);
  822.   }
  823.   run = 0;
  824.   for (j = 0; j < MAXLENGTH; j++)
  825.     for (i = 0; i < MAXWIDTH; i++) {
  826.       if (run == 0) {
  827.     run = 8*sizeof(long int);
  828.     fread((char *)&mask,sizeof(long int),1,fd);
  829.       }
  830.       if (mask&1)
  831.     lset(i, j, SEEN);
  832.       mask >>= 1;
  833.       run--;
  834.     }
  835.   restore_monsters(fd,Level);
  836.   fread((char *)&i,sizeof(int),1,fd);
  837.   fread((char *)&j,sizeof(int),1,fd);
  838.   while (j < MAXLENGTH && i < MAXWIDTH) {
  839.     Level->site[i][j].things = restore_itemlist(fd);
  840.     fread((char *)&i,sizeof(int),1,fd);
  841.     fread((char *)&j,sizeof(int),1,fd);
  842.   }
  843. }
  844.  
  845.  
  846.  
  847. void restore_monsters(fd,level)
  848. FILE *fd;
  849. plv level;
  850. {
  851.   pml ml=NULL;
  852.   int i,nummonsters;
  853.   char tempstr[80];
  854.   int temp_x, temp_y;
  855.   unsigned char type;
  856.  
  857.   level->mlist = NULL;
  858.  
  859.   fread((char *)&nummonsters,sizeof(int),1,fd);
  860.   
  861.   for(i=0;i<nummonsters;i++) {
  862.     ml = ((pml) checkmalloc(sizeof(mltype)));
  863.     ml->m = ((pmt) checkmalloc(sizeof(montype)));
  864.     ml->next = NULL;
  865.     fread((char *)ml->m,sizeof(montype),1,fd);
  866.     if (ml->m->id == HISCORE_NPC) {
  867.       temp_x = ml->m->x;
  868.       temp_y = ml->m->y;
  869.       make_hiscore_npc(ml->m, ml->m->aux2);
  870.       ml->m->x = temp_x;
  871.       ml->m->y = temp_y;
  872.     }
  873.     else {
  874.       fread((char *)&type,sizeof(unsigned char),1,fd);
  875.       if (type&1) {
  876.     filescanstring(fd,tempstr);
  877.     ml->m->monstring = salloc(tempstr);
  878.       }
  879.       else
  880.     ml->m->monstring = Monsters[ml->m->id].monstring;
  881.       if (type&2) {
  882.     filescanstring(fd,tempstr);
  883.     ml->m->corpsestr = salloc(tempstr);
  884.       }
  885.       else
  886.     ml->m->corpsestr = Monsters[ml->m->id].corpsestr;
  887.       ml->m->possessions = restore_itemlist(fd);
  888.       ml->m->meleestr = Monsters[ml->m->id].meleestr;
  889.     }
  890.     level->site[ml->m->x][ml->m->y].creature = ml->m;
  891.     ml->next = level->mlist;
  892.     level->mlist = ml;
  893.   }
  894. }
  895.  
  896.  
  897.  
  898. void restore_country(fd)
  899. FILE *fd;
  900. {
  901.   int i, j;
  902.   int run;
  903.   unsigned long int mask;
  904.  
  905.   load_country();
  906.   fread((char *)&i,sizeof(int),1,fd);
  907.   fread((char *)&j,sizeof(int),1,fd);
  908.   while (i < MAXWIDTH && j < MAXLENGTH) {
  909.     fread((char *)&Country[i][j],sizeof(struct terrain),1,fd);
  910.     fread((char *)&i,sizeof(int),1,fd);
  911.     fread((char *)&j,sizeof(int),1,fd);
  912.   }
  913.   run = 0;
  914.   for (i = 0; i < MAXWIDTH; i++)
  915.     for (j = 0; j < MAXLENGTH; j++) {
  916.       if (run == 0) {
  917.     run = 8*sizeof(long int);
  918.     fread((char *)&mask,sizeof(long int),1,fd);
  919.       }
  920.       if (mask&1)
  921.     c_set(i, j, SEEN);
  922.       mask >>= 1;
  923.       run--;
  924.     }
  925. }
  926.