// WIZARDRY ROUTINES (START, MAINT, WIZARD, HOURS(X), NEWHRS(X), MOTD, POOF)

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <ctype.h>

// all the data header includes needed are in the adv_magic.h file
//   but we still need headers for the other code modules
#include "adv_func.h"
#include "adv_io.h"
#include "adv_util.h"
#include "adv_magic.h"

// global variables for file names
//   some are extern'd in adv_magic.h to share with other routines
//     they are NOT in "common", they are needed to get "common" reloaded
//     from a restore file, and to load the saved "magic" file (hours, etc.)
//   some are just used several place in this module
char magicfyle[] = "advpoof.dat";
char savefyle[] = "advent.sav";
char nowrite[] = "UNABLE TO WRITE OUT \"MAGIC\" FILE.\n";
char writeok[] = 
       "YOUR \"MAGIC\" FILE HAS BEEN WRITTEN AND WILL BE AVAILABLE FOR FUTURE GAMES.\n";

BOOL start(void)
{
// CHECK TO SEE IF THIS IS "PRIME TIME".  IF SO, ONLY WIZARDS MAY PLAY, THOUGH
// OTHERS MAY BE ALLOWED A SHORT GAME FOR DEMONSTRATION PURPOSES.  IF SETUP<0,
// WE"RE CONTINUING FROM A SAVED GAME, SO CHECK FOR SUITABLE LATENCY.  RETURN
// TRUE IF THIS IS A DEMO GAME (VALUE IS IGNORED FOR RESTARTS).

#ifdef ORIGINAL
  BOOL ptime,soon,start,is_holiday = FALSE;           // needed for ORIGINAL only
  long t, d, h;
  time_t now;
  struct tm *pt;
  int primtm, delay;

// FIRST FIND OUT WHETHER IT IS PRIME TIME (SAVE IN PTIME) AND, IF RESTARTING,
// WHETHER IT"S TOO SOON (SAVE IN SOON).  PRIME-TIME SPECS ARE IN WKDAY, WKEND,
// AND HOLID; SEE MAINT ROUTINE FOR DETAILS.  LATNCY IS REQUIRED DELAY BEFORE
// RESTARTING.  WIZARDS MAY CUT THIS TO A THIRD.

  now = time(NULL);
  pt = localtime(&now);        // separate out various fields
  d = pt->tm_yday;             // days since Jan
  h = pt->tm_hour;
  t = 60*h + pt->tm_min;   // time in minutes since midnight

  // decide if we are doing a weekday, weekend, or holiday
  if (d >= wizcom.hbegin && d <= wizcom.hend)
  {
    primtm = wizcom.holid;
    is_holiday = TRUE;
  }
  else if (pt->tm_wday == 0 || pt->tm_wday == 6) primtm = wizcom.wkend;
  else primtm = wizcom.wkday;

  ptime = (primtm & (1 << h)) != 0;  // primetime if this hour is a 1-bit
  
  // printf("D = %li, wday = %s, T = %li, T2 = %li, primtm = %0x, primetime = %i\n",
  //        d,daynm[ptrtime->tm_wday],t,t2,primtm,ptime);

  soon = FALSE;
  if(gm.setup < 0)    // restoring a saved game
  {
    delay = difftime(now,gm.saved)/60;  // minutes since game was saved
    if(delay < wizcom.latncy)
    { 
      printf("THIS ADVENTURE WAS SUSPENDED A MERE %i MINUTES AGO.\n",delay);
      soon = TRUE;
      if(delay < wizcom.latncy/3)
      { 
         mspeak(2);
         exit (1);
      }
      else    // a wizard, but only a wizard, can resume now
      {
        // COME HERE IF RESTARTING TOO SOON.  IF HE"S A WIZARD, LET HIM GO (AND NOTE
        // THAT IT THEN DOESN"T MATTER WHETHER IT"S PRIME TIME).  ELSE, TOUGH BEANS.
        mspeak(8);
        if (is_a_wizard())
        {
          gm.saved = -1;
          return (FALSE);
        }
        else
        {
          mspeak(9);
          exit (1);
        }
      }  // end  else  a wizard, but only a wizard, can resume now
    }  // end  if(delay < wizcom.latncy)
  }  // end  if(gm.setup < 0)    // restoring a saved game

  // not restarting, or past latency delay period
  // if primetime, a wizard can play, others get a demo game
  // if NOT primetime, anyone can play a regular game
  if (ptime)
  {
    // COME HERE IF NOT RESTARTING TOO SOON (MAYBE NOT RESTARTING AT ALL), BUT IT"S
    // PRIME TIME.  GIVE OUR HOURS AND SEE IF HE"S A WIZARD.  IF NOT, THEN CAN"T
    // RESTART, BUT IF JUST BEGINNING THEN WE CAN OFFER A SHORT GAME.
    mspeak(3);
    hours();
    mspeak(4);
    if (is_a_wizard())
    {
      gm.saved = -1;
      return (FALSE);
    }
    // not a wizard - allow a demo, do not allow a "resume game"
    if (gm.setup >= 0)
    {
      start = yesm(5,7,7);
      if (start)
      {
        gm.saved = -1;
        return (FALSE);
      }
    }
    mspeak(9);     // a resumed game, or he just didn't want a demo
    exit (1);
  }  // end  if (ptime)
  gm.saved = -1;   // OK, not prime time, and not too soon, go for it!
  return (FALSE);
#else
  return FALSE;    // let's cut the "prime time" and "too soon" stuff for now
                   // allow play any time, and allow instant save-restart
                   // maybe we'll' fix this up later  
                   // Note - return of "TRUE" means a 30-move gm.demo game
                   //        FALSE is a "regular" game
#endif
}

// SOMEONE SAID THE MAGIC WORD TO INVOKE MAINTENANCE MODE.  MAKE SURE HE"S A
// WIZARD.  IF SO, LET HIM TWEAK ALL SORTS OF RANDOM THINGS, THEN EXIT SO CAN
// SAVE TWEAKED VERSION.  SINCE MAGIC WORD MUST BE FIRST COMMAND GIVEN, ONLY
// THING WHICH NEEDS TO BE FIXED UP IS ABB(1).
// note that the "magic data" has either been read in, or a default configuration
//   set up, by the normal initialization process (function "poof")
void maint(void)
{
  int rcode;
  BOOL changed_something = FALSE;
  FILE *poof_fyl;
  char onewd[6], junkwd[6];       // handy storage to read in junk
#ifdef ORIGINAL
  int x;
  long d, t;                                // date and time
  char lyn[80];
#endif

  printf("YOU NEED TO BE AN MCSE (MAGICALLY CERTIFIED SORCERY ENCHANTER) TO DO THIS!\n");
  if(is_a_wizard()) 
  {
#ifdef ORIGINAL
#else
    printf("SORRY, THE MAINTENANCE HELP DESK IS CLOSED RIGHT NOW.\n");
    printf("YOU'LL HAVE TO SETTLE FOR THE WAY THINGS ARE SET UP.\n");
    printf("\nWELL, WE MIGHT BE ABLE TO MAKE A SMALL EXCEPTION ...\n\n");
#endif

#ifdef ORIGINAL
    if (yesm(10,0,0)) hours();
    if (yesm(11,0,0))
    {
      newhrs();
      changed_something = TRUE;
    }
    if (yesm(26,0,0))
    {
      mspeak(27);
      fscanf(stdin,"%i",&wizcom.hbegin);    // read number, then ...
      fgets(lyn,80,stdin);      //   swallow rest of line (AT LEAST the newline)
      mspeak(28);
      fscanf(stdin,"%i",&wizcom.hend);    // read number, then ...
      fgets(lyn,80,stdin);      //   swallow rest of line (AT LEAST the newline)
      datime(&d,&t);
      wizcom.hbegin = wizcom.hbegin + d;
      wizcom.hend = wizcom.hbegin + wizcom.hend - 1;
      mspeak(29);
      fgets(wizcom.hname,80,stdin); //   swallow entire line
      if (wizcom.hname[strlen(wizcom.hname)-1] == '\n')
        wizcom.hname[strlen(wizcom.hname)-1] = '\0';     // but discard the newline
      changed_something = TRUE;
      printf("New holiday \"%s\" will be saved ... well, maybe not\n",wizcom.hname);
    } 
    printf("LENGTH OF SHORT GAME (NULL TO LEAVE AT %i): ",wizcom.shortgm);
    fgets(lyn,80,stdin);    
    if (lyn[0] != '\0' && lyn[0] != '\n')
    {
      wizcom.shortgm = atoi(lyn);
      changed_something = TRUE;
      printf("Setting short game to %i turns\n",wizcom.shortgm);
    }
    else printf("Leaving short game unchanged at %i turns\n",wizcom.shortgm);
    mspeak(12);
    getin(onewd,junkwd,junkwd,junkwd);
    if (onewd[0] != '\0')
    {
      strcpy(wizcom.magic,onewd);
      changed_something = TRUE;
      printf("Setting magic word to \"%s\"\n",onewd);
    }
    else printf("Leaving magic word unchanged as \"%s\"\n",wizcom.magic);
    mspeak(13);
    fgets(lyn,80,stdin);     
    if (lyn[0] != '\0' && lyn[0] != '\n')
    {
      wizcom.magnm = atoi(lyn);
      changed_something = TRUE;
      printf("Setting magic number to %i\n",wizcom.magnm);
    }
    else printf("Leaving magic number unchanged at %i\n",wizcom.magnm);
    printf("LATENCY FOR RESTART (NULL TO LEAVE AT %i): ",wizcom.latncy);
    fgets(lyn,80,stdin);   
    if (lyn[0] != '\0' && lyn[0] != '\n')
    {
      x = atoi(lyn);
      if (x < 45)
      {
         mspeak(30);
         x = 45;
      }  
      wizcom.latncy = x;
      changed_something = TRUE;
      printf("Setting latency to %i minutes\n",x);
    }
    else printf("Leaving latency unchanged at %i minutes\n",wizcom.latncy);
#endif
    // allow even simplified rules to change the MOTD
    if (yesm(14,0,0))
    {
      show_motd(TRUE);
      changed_something = TRUE;
    }

    // and since we allowed even one change, allow it to be written out ... 
    if (changed_something)  // **IF** there were changes
    {
      mspeak(15);
      printf("ARE YOU SURE YOU WANT TO SAVE IT?>");
      getin(onewd,junkwd,junkwd,junkwd);
      if (strequ(onewd,"YES") || strequ(onewd,"Y"))
      {
        if ((poof_fyl = fopen(magicfyle,"wb")) == NULL) printf("%s",nowrite);
        else
        {
          rcode = fwrite(&wizcom,sizeof(struct t_wizcom),1,poof_fyl);
          if (rcode != 1) printf("%s",nowrite);
          else printf("%s",writeok);
        }
      }
      else printf("OK, NEW VALUES ENTERED WILL BE DISCARDED\n");
    }
    else printf("NOTHING WAS CHANGED, NO POINT IN SAVING THIS\n");
  }
  else printf("ONLY WIZARDS CAN PERFORM MAGIC! BEGONE, CHARLATAN!\n");
  return;
}  // end maint() ------------------------------------------------------------------

// ASK IF HE"S A WIZARD.  IF HE SAYS YES, MAKE HIM PROVE IT.  RETURN TRUE IF HE
// REALLY IS A WIZARD.
BOOL is_a_wizard(void)
{
  BOOL isWizard;
  char lyn[80];
#ifdef ORIGINAL
  char word[6], word2[6];
  long t, d, h;
  time_t now;
  struct tm *pt;
  int val[6];         // need index values 1..5
  int ix, iy, iz;     // loops and such
#endif

  isWizard = yesm(16,0,7);   // he must answer "yes" here
  if (!isWizard) 
    return isWizard;

  // HE SAYS HE IS.  FIRST STEP: DOES HE KNOW ANYTHING MAGICAL?
  mspeak(17);
  fgets(lyn,80,stdin);   
  if (lyn[strlen(lyn)-1] == '\n')
    lyn[strlen(lyn)-1] = '\0';     // but discard the newline
  if(!strequ(lyn,wizcom.magic))    // he must know the magic word ("linux")
  {
    // AHA!  AN IMPOSTOR!
    mspeak(20);
    isWizard= FALSE;
    return isWizard;
  }
  // if we are running simplified rules, the "else" for this is further down,
  //   AFTER the code for ORIGINAL
  // if running ORIGINAL, the else serves as the else for the last test of that sequence
#ifdef ORIGINAL
  now = time(NULL);
  pt = localtime(&now);        // separate out various fields
  d = pt->tm_yday;             // days since Jan
  h = pt->tm_hour;
  t = 60*h + pt->tm_min;   // time in minutes since midnight
  t = t*2+1;
  strcpy(word,"@@@@@");    // on original PDP, 5 chars packed in a word
  for (iy=1;iy<=5;iy++)
  {
    ix = 79+(d%5);          // 79 + 0..4  ->  79..83
    d = d/5;                // could be, like, 0 to 73 (74 leap year?)
    for (iz=1;iz<=ix;iz++)
      t = (t*1027) % 1048576;
    val[iy] = (t*26)/1048576+1;
    // based on the next line, it looks like we had 5 7-bit characters, located
    //   in the high-order (well, leftmost) 35 bits of a 36-bit word. Sheeesh!
    // word = word + (val[iy] << (36-7*iy));
    word[iy-1] += val[iy];  // this SHOULD be a replacement for the above  
  }
  // something missing here - we need to print this, then get a reply
  if (yesm(18,0,0))         // "do you know what I thought it was?", must reply NO
  {
    // AHA!  AN IMPOSTOR!
    mspeak(20);
    isWizard= FALSE;
    return isWizard;
  }

  // debug
  strcpy(word2,word);          // save it for debugging

  printf("%s\n",word);
  fgets(lyn,80,stdin);         // get in whatever he typed
  // take exactly FIVE chars (we know word[5] == '\0'), make sure it's upper case
  for (ix=0;ix<5;ix++) word[ix] = toupper(lyn[ix]);
  // datime(&d,&t);
  now = time(NULL);            // YES, get the time AGAIN
  pt = localtime(&now);        // separate out various fields
  d = pt->tm_yday;             // days since Jan
  h = pt->tm_hour;
  t = 60*h + pt->tm_min;   // time in minutes since midnight

  t = (t/60)*40+(t/10)*10;
  d = wizcom.magnm;
 
  // debug
  printf("seed is %i %i %i %i %i\n",'@','@','@','@','@');
  printf("orig word: \"%s\", reply: \"%s\", t = %li, d = %li\n",word2,word,t,d); 
  printf("orig word numeric: %i %i %i %i %i\n",word2[0],word2[1],word2[2],word2[3],word2[4]); 
  printf("    reply numeric: %i %i %i %i %i\n",word[0],word[1],word[2],word[3],word[4]); 

  for (iy=1;iy<=5;iy++)
  {
    iz = (iy%5)+1;
    ix = ((abs(iy-iz)*(d%10)+(t%10))%26)+1;

    // debug
    printf("iy=%i, iz=%i, abs(iy-iz)=%i, d=%li, dmod10=%li, t=%li, tmod10=%li, ix=%i\n",
           iy,iz,abs(iy-iz),d,d%10,t,t%10,ix);

    t = t/10;
    d = d/10;
    // word = word-(ix<<(36-7*iy));
    word[iy-1] -= ix;       // again, this SHOULD be a replacement

    // debug 
    printf("End loop, reply: \"%s\", iy = %i, ix = %i, iz = %i, t = %li, d = %li\n",
           word,iy,ix,iz,t,d);
 
  } 
  printf("final reply numeric: %i %i %i %i %i\n",word[0],word[1],word[2],word[3],word[4]); 
  if (!strequ(word,"@@@@@"))       // he's a charlatan
  {
    // AHA!  AN IMPOSTOR!
    mspeak(20);
    isWizard= FALSE;
    return isWizard;
  }
#endif
  else  // this else is for the simplified magic-word test, or for ORIGINAL test
  {
    // BY GEORGE, HE REALLY *IS* A WIZARD!
    mspeak(19);
    isWizard = TRUE;
    return isWizard;
  }
}  // end is_a_wizard() --------------------------------------------------------

// ANNOUNCE THE CURRENT HOURS WHEN THE CAVE IS OPEN FOR ADVENTURING.  THIS INFO
// IS STORED IN WKDAY, WKEND, AND HOLID, WHERE BIT SHIFT(1,N) IS ON IFF THE
// HOUR FROM N:00 TO N:59 IS "PRIME TIME" (CAVE CLOSED).  WKDAY IS FOR
// WEEKDAYS, WKEND FOR WEEKENDS, HOLID FOR HOLIDAYS.  NEXT HOLIDAY IS FROM
// HBEGIN TO HEND.
void hours(void)
{
#ifdef ORIGINAL
  int d, t, h;
  time_t now;
  struct tm *pt;
  int hominy;   // hominy days till the holiday??
  char tdays[6];
  char daynm[7][10] = {"SUNDAY","MONDAY","TUESDAY",
                       "WEDNESDAY","THURSDAY","FRIDAY","SATURDAY"};

  hoursx(wizcom.wkday,"mon - fri:");
  hoursx(wizcom.wkend,"sat - sun:");
  hoursx(wizcom.holid,"holidays: ");

  now = time(NULL);
  pt = localtime(&now);   // separate out various fields
  d = pt->tm_yday;             // days since Jan
  h = pt->tm_hour;
  t = 60*h + pt->tm_min;   // time in minutes since midnight
  printf("IT IS NOW %i:00 ON %s\n",t/60,daynm[pt->tm_wday]);

  if(wizcom.hend >= d && wizcom.hend >= wizcom.hbegin)  // holidays
  {
    if(wizcom.hbegin == d)
      printf("TODAY IS A HOLIDAY, NAMELY %s\n",wizcom.hname);
    else
    {
      hominy = wizcom.hbegin - d;
      if (hominy == 1) strcpy(tdays,"day,");
      else strcpy(tdays,"days,");
      printf("THE NEXT HOLIDAY WILL BE IN %i %s NAMELY %s\n", hominy, tdays, wizcom.hname);
    }
  }
#else
  printf("\nACTUALLY, ...\n");
  printf("    FOR THE NONCE, THE CAVE IS OPEN ALL THE TIME. ENJOY!\n");
#endif
}  // end hours() -----------------------------------------------------------------

#ifdef ORIGINAL
// USED BY HOURS (ABOVE) TO PRINT HOURS FOR EITHER WEEKDAYS OR WEEKENDS.
//   but never used outside of ORIGINAL
void hoursx(int h, char *days)
{
  BOOL first;
  int from,till;

  first = TRUE;
  from = -1;
  if (h == 0) 
    printf("          %s open all day\n",days);
  else
  {
    while (FOREVER)
    {
      do from++; while ( (h & (1 << from)) != 0);  // find a zero bit 
      if (from >= 24) break;    // end of day - we're done
      till = from;
      do till++; while ( (h & (1 << till)) == 0 && till < 24); // find a one bit
      if (first) 
        printf("          %s %2i:00 to %2i:00\n",days,from,till);
      else 
        printf("                     %2i:00 to %2i:00\n",from,till);
      first = FALSE;
      from = till;
    } // end while (FOREVER)

    if (first) 
      printf("        %s closed all day\n",days);
  }  // end else h != 0
}  // end hoursx() --------------------------------------------------------------
#endif

#ifdef ORIGINAL
// SET UP NEW HOURS FOR THE CAVE.  SPECIFIED AS INVERSE--I.E., WHEN IS IT
// CLOSED DUE TO PRIME TIME?  SEE HOURS (ABOVE) FOR DESC OF VARIABLES.
//   but never used outside of ORIGINAL
void newhrs(void)
{
  mspeak(21);
  // printf("Ooops! We're not quite set up to change the hours ... yet ... Sir!\n");
  // printf("Perhaps you could drop by later in the week ... ???\n");
  wizcom.wkday = newhrx("weekdays:");
  wizcom.wkend = newhrx("weekends:");
  wizcom.holid = newhrx("holidays:");
  mspeak(22);
  hours();
}  // end newhrs() -----------------------------------------------------------------
#endif

#ifdef ORIGINAL
// INPUT PRIME TIME SPECS AND SET UP A WORD OF INTERNAL FORMAT.
//   but never used outside of ORIGINAL
int newhrx(char *days)
{
  int from, till, mask, i;
  char lyn[80];

  // return 0;
  mask = 0;
  printf("PRIME TIME ON %s\n",days);
  while (FOREVER)
  {      
    printf(" FROM:");
    fscanf(stdin,"%i",&from);    // read number, then ...
    fgets(lyn,80,stdin);      //   swallow rest of line (AT LEAST the newline)
    if (from < 0 || from >= 24) return (mask);  // return what we got
    printf(" TILL:");
    fscanf(stdin,"%i",&till);    // read number, then ...
    fgets(lyn,80,stdin);      //   swallow rest of line (AT LEAST the newline)
    till--;
    if (till < from || till >= 24) return (0);  // return what we got
    // ok, we have something, set some mask bits
    for (i=from;i<=till;i++)
      mask |= (1 << i);
  } 
}  // end newhrx(char *days) ----------------------------------------------------------
#endif

// HANDLES MESSAGE OF THE DAY.  IF ALTER IS TRUE, READ A NEW MESSAGE FROM THE
// WIZARD.  ELSE PRINT THE CURRENT ONE.  MESSAGE IS INITIALLY NULL.
void show_motd(BOOL alter)
{
  char msg[100];

  if (alter)
  {
    mspeak(23);
    wizcom.motd[0] = '\0';      // clear previous message
    while (FOREVER)
    {
      fgets(msg,99,stdin);
      if (strlen(msg) > 70)
      {
        mspeak(24);
        continue;
      }
      else if (msg[0] == '\n')
        break;                  // null line - user is finished
      strcat(wizcom.motd,msg); 
      if (strlen(wizcom.motd)+72 > 1024)
      {
        mspeak(25);
        break;
      }
    };
  }
  else
    printf("%s",wizcom.motd);  
  return;
}  // end show_motd() ------------------------------------------------------------

// AS PART OF DATABASE INITIALISATION, WE CALL POOF TO SET UP SOME DUMMY
// PRIME-TIME SPECS, MAGIC WORDS, ETC.
void poof(void)
{
  int rcode;
  BOOL write_it = TRUE;
  FILE *poof_fyl;

  if ((poof_fyl = fopen(magicfyle,"rb")) == NULL)
    printf("NO \"MAGIC\" FILE FOUND, USING DEFAULTS.\n");
  else
  {
    // if we find a file, then have trouble reading it, don't try to write
    write_it = FALSE;
    // read in existing file
    rcode = fread(&wizcom,sizeof(struct t_wizcom),1,poof_fyl);
    if (rcode != 1) printf("TROUBLE READING \"MAGIC\" FOLE, USING DEFAULTS.\n");
    else return;               // file read OK, skip defaults
  } 

  // could not find file, or could not read it. set defaults
  wizcom.wkday = 0x03FF00;     // was octal 00777400;
  wizcom.wkend = 0;
  wizcom.holid = 0;
  wizcom.hbegin = 0;
  wizcom.hend = -1;
  wizcom.shortgm = 30;
  strcpy(wizcom.magic,"linux");
  wizcom.magnm = 11111;
  wizcom.latncy = 3;              // was 90; - better shorter for debugging
  strcpy(wizcom.motd,
  "*****************************************************************************\n"
  "**                                                                         **\n"
  "**                        HAVE A NICE DAY!                                 **\n"
  "**                                                                         **\n"
  "*****************************************************************************\n");

  // now, if the file just didn't exist, write it out (if we can)
  if ((poof_fyl = fopen(magicfyle,"wb")) == NULL) printf("%s",nowrite);
  else
  {
    rcode = fwrite(&wizcom,sizeof(struct t_wizcom),1,poof_fyl);
    if (rcode != 1) printf("%s",nowrite);
    else printf("%s",writeok);
  }
}  // end poof ------------------------------------------------------------------------

// restore_game
// reads in a saved game, does a fixup on all the pointers, and sets things up to continue
// later, we need to add the prime-time and latency checks from routine "start()" above
// return a code of -1 if the restore was OK, 0 if we couldn't do it (to start a new game)
int restore_game(void)
{
  FILE *savp;
  int rcode, ix, iy;
  char *tmem;       // pointer for allocating string storage
  long delta;       // pointer adjustment routine

  // open the save file for output (overwrite anything previously there)
  savp = fopen(savefyle,"rb");
  if (savp != NULL) 
  {
    rcode = (NULL != (tmem = malloc(5*LINSIZ)));
    if (rcode == 1)
      rcode = fread(&gm,sizeof(struct game_data),1,savp);
    if (rcode == 1)
      rcode = fread(tmem,5*LINSIZ,1,savp);
    if (rcode == 1)
      rcode = fread(&wizcom,sizeof(struct t_wizcom),1,savp);
    fclose(savp);  // ignore condx code here
  }
  // now, if savp is not NULL, and rcode == 1, everything worked
  //   if savp is NULL, we didn't even try to write
  //   if rcode != 1, some write failed, and the rest were skipped
  if (savp == NULL || rcode != 1)
  {
    printf("UH, OH! CAN'T RESTORE YOUR GAME RIGHT NOW.\n");
    printf("THE FILE IS MISSING, OR YOUR HARD DRIVE IS CURSED, OR SOMETHING.\n");
    printf("WELL, I'LL JUST LET YOU START A NEW GAME, IF YOU WANT. SORRY!\n");
    return 0;
  }
  else
  {
    // everything read in OK. now we have to fixup all the pointers.
    //  except, of course, the NULL pointers ... they remain NULL
    delta = tmem - gm.bblock;  // how far the block moved (plus or minus)
    for (ix=1;ix<=LOCSIZ;ix++)  
      {
        if (gm.stext[ix] != NULL) gm.stext[ix] += delta; 
        if (gm.ltext[ix] != NULL) gm.ltext[ix] += delta;
      }
    for (ix=1;ix<=OBJSIZ;ix++)
    {
        if (gm.ptext[ix] != NULL) gm.ptext[ix] += delta;    
        for (iy=0;iy<OBJALTMAX;iy++) 
          if (gm.ptexta[ix][iy] != NULL) gm.ptexta[ix][iy] += delta;    
    }
    for (ix=1;ix<=RTXSIZ;ix++) 
      if (gm.rtext[ix] != NULL) gm.rtext[ix] += delta;       
    for (ix=1;ix<=CLSMAX;ix++) 
      if (gm.ctext[ix] != NULL) gm.ctext[ix] += delta;      
    for (ix=1;ix<=MAGSIZ;ix++) 
      if (gm.mtext[ix] != NULL) gm.mtext[ix] += delta;      
    gm.nblock += delta;
    gm.eblock += delta;
    gm.bblock = tmem;
  }

  // here we may want to check primetime, latency, etc., and refuse to allow him
  //   to resume some games ... or maybe not
  // for the moment, just let it go
  printf("YOUR GAME HAS BEEN RESTORED.\n");
  return -1;
}  // end restore_game ----------------------------------------------------------------

