Logo Search packages:      
Sourcecode: scummvm version File versions  Download package

saveload.cpp

/* ScummVM - Graphic Adventure Engine
 *
 * ScummVM is the legal property of its developers, whose names
 * are too numerous to list here. Please refer to the COPYRIGHT
 * file distributed with this source distribution.
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License
 * as published by the Free Software Foundation; either version 2
 * of the License, or (at your option) any later version.

 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.

 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
 *
 * $URL: https://scummvm.svn.sourceforge.net/svnroot/scummvm/scummvm/tags/release-1-1-0/engines/agos/saveload.cpp $
 * $Id: saveload.cpp 46941 2010-01-03 19:37:43Z eriktorbjorn $
 *
 */

#include "common/file.h"
#include "common/savefile.h"
#include "common/system.h"

#include "gui/about.h"
#include "gui/message.h"

#include "agos/agos.h"
#include "agos/intern.h"

namespace AGOS {

int AGOSEngine::countSaveGames() {
      Common::InSaveFile *f;
      Common::StringList filenames;
      uint i = 1;
      char slot[4];
      int slotNum;
      bool marks[256];

      char *prefix = genSaveName(998);
      prefix[strlen(prefix)-3] = '*';
      prefix[strlen(prefix)-2] = '\0';
      memset(marks, false, 256 * sizeof(bool)); //assume no savegames for this title
      filenames = _saveFileMan->listSavefiles(prefix);

      for (Common::StringList::const_iterator file = filenames.begin(); file != filenames.end(); ++file){
            //Obtain the last 3 digits of the filename, since they correspond to the save slot
            slot[0] = file->c_str()[file->size()-3];
            slot[1] = file->c_str()[file->size()-2];
            slot[2] = file->c_str()[file->size()-1];
            slot[3] = '\0';

            slotNum = atoi(slot);
            if (slotNum >= 0 && slotNum < 256)
                  marks[slotNum] = true;  //mark this slot as valid
      }

      while (i < 256) {
            if (marks[i] &&
                (f = _saveFileMan->openForLoading(genSaveName(i)))) {
                  i++;
                  delete f;
            } else
                  break;
      }

      return i;
}

#ifdef ENABLE_AGOS2
char *AGOSEngine_PuzzlePack::genSaveName(int slot) {
      static char buf[20];

      if (getGameId() == GID_DIMP)
            sprintf(buf, "dimp.sav");
      else
            sprintf(buf, "swampy.sav");

      return buf;
}

char *AGOSEngine_Feeble::genSaveName(int slot) {
      static char buf[20];
      sprintf(buf, "feeble.%.3d", slot);
      return buf;
}
#endif

char *AGOSEngine_Simon2::genSaveName(int slot) {
      static char buf[20];
      sprintf(buf, "simon2.%.3d", slot);
      return buf;
}

char *AGOSEngine_Simon1::genSaveName(int slot) {
      static char buf[20];
      sprintf(buf, "simon1.%.3d", slot);
      return buf;
}

char *AGOSEngine_Waxworks::genSaveName(int slot) {
      static char buf[20];

      if (getPlatform() == Common::kPlatformPC)
            sprintf(buf, "waxworks-pc.%.3d", slot);
      else
            sprintf(buf, "waxworks.%.3d", slot);

      return buf;
}

char *AGOSEngine_Elvira2::genSaveName(int slot) {
      static char buf[20];

      if (getPlatform() == Common::kPlatformPC)
            sprintf(buf, "elvira2-pc.%.3d", slot);
      else
            sprintf(buf, "elvira2.%.3d", slot);

      return buf;
}

char *AGOSEngine_Elvira1::genSaveName(int slot) {
      static char buf[20];
      sprintf(buf, "elvira1.%.3d", slot);
      return buf;
}

char *AGOSEngine::genSaveName(int slot) {
      static char buf[20];
      sprintf(buf, "pn.%.3d", slot);
      return buf;
}

void AGOSEngine::quickLoadOrSave() {
      // Quick load & save is only supported complete version of Simon the Sorcerer 1/2
      if (getGameType() == GType_PP || getGameType() == GType_FF ||
            (getFeatures() & GF_DEMO)) {
            return;
      }

      bool success;
      char buf[60];

      char *filename = genSaveName(_saveLoadSlot);
      if (_saveLoadType == 2) {
            Subroutine *sub;
            success = loadGame(genSaveName(_saveLoadSlot));
            if (!success) {
                  sprintf(buf, "Failed to load game state to file:\n\n%s", filename);
            } else if (getGameType() == GType_SIMON1 || getGameType() == GType_SIMON2) {
                  drawIconArray(2, me(), 0, 0);
                  setBitFlag(97, true);
                  sub = getSubroutineByID(100);
                  startSubroutine(sub);
            } else if (getGameType() == GType_WW) {
                  sub = getSubroutineByID(66);
                  startSubroutine(sub);
            } else if (getGameType() == GType_ELVIRA2) {
                  sub = getSubroutineByID(87);
                  startSubroutine(sub);
                  setBitFlag(7, false);
                  sub = getSubroutineByID(19);
                  startSubroutine(sub);
                  printStats();
                  sub = getSubroutineByID(28);
                  startSubroutine(sub);
                  setBitFlag(17, false);
                  sub = getSubroutineByID(207);
                  startSubroutine(sub);
                  sub = getSubroutineByID(71);
                  startSubroutine(sub);
            } else if (getGameType() == GType_ELVIRA1) {
                  drawIconArray(2, me(), 0, 0);
                  sub = getSubroutineByID(265);
                  startSubroutine(sub);
                  sub = getSubroutineByID(129);
                  startSubroutine(sub);
                  sub = getSubroutineByID(131);
                  startSubroutine(sub);
            }
      } else {
            success = saveGame(_saveLoadSlot, _saveLoadName);
            if (!success)
                  sprintf(buf, "Failed to save game state to file:\n\n%s", filename);
      }

      if (!success) {
            GUI::MessageDialog dialog(buf, "OK");
            dialog.runModal();

      } else if (_saveLoadType == 1) {
            sprintf(buf, "Successfully saved game state in file:\n\n%s", filename);
            GUI::TimedMessageDialog dialog(buf, 1500);
            dialog.runModal();

      }

      _saveLoadType = 0;
}

bool AGOSEngine_Waxworks::confirmOverWrite(WindowBlock *window) {
      Subroutine *sub = getSubroutineByID(80);
      if (sub != NULL)
            startSubroutineEx(sub);

      if (_variableArray[253] == 0)
            return true;

      return false;
}

bool AGOSEngine_Elvira2::confirmOverWrite(WindowBlock *window) {
      // Original verison never confirmed
      return true;
}

bool AGOSEngine::confirmOverWrite(WindowBlock *window) {
      const char *message1, *message2, *message3;

      switch (_language) {
      case Common::FR_FRA:
            message1 = "\rFichier d/j; existant.\r\r";
            message2 = "  Ecrire pardessus ?\r\r";
            message3 = "     Oui      Non";
            break;
      case Common::DE_DEU:
            message1 = "\rDatei existiert bereits.\r\r";
            message2 = "   Ueberschreiben ?\r\r";
            message3 = "     Ja        Nein";
            break;
      default:
            message1 = "\r File already exists.\r\r";
            message2 = "    Overwrite it ?\r\r";
            message3 = "     Yes       No";
            break;
      }

      printScroll();
      window->textColumn = 0;
      window->textRow = 0;
      window->textColumnOffset = 0;
      window->textLength = 0;       // Difference

      for (; *message1; message1++)
            windowPutChar(window, *message1);
      for (; *message2; message2++)
            windowPutChar(window, *message2);
      for (; *message3; message3++)
            windowPutChar(window, *message3);

      if (confirmYesOrNo(120, 78) == 0x7FFF)
            return true;

      return false;
}

int16 AGOSEngine::matchSaveGame(const char *name, uint16 max) {
      Common::InSaveFile *in;
      char dst[10];
      uint16 slot;

      memset(dst, 0, sizeof(dst));
      for (slot = 0; slot < max; slot++) {
            if ((in = _saveFileMan->openForLoading(genSaveName(slot)))) {
                  in->read(dst, 8);
                  delete in;

                  if (!scumm_stricmp(name, dst)) {
                        return slot;
                  }
            }
      }

      return -1;
}

void AGOSEngine::userGame(bool load) {
      WindowBlock *window = _windowArray[4];
      const char *message1;
      int i = 0, numSaveGames;
      char *name;
      char buf[10];

      numSaveGames = countSaveGames();

      uint32 saveTime = getTime();
      haltAnimation();

restart:
      printScroll();
      window->textColumn = 0;
      window->textRow = 0;
      window->textColumnOffset = 0;
      window->textLength = 0;       // Difference

      switch (_language) {
      case Common::FR_FRA:
            message1 = "\rIns/rez disquette de\rsauvegarde de jeux &\rentrez nom de fichier:\r\r   ";
            break;
      case Common::DE_DEU:
            message1 = "\rLege Spielstandsdiskette ein. Dateinamen eingeben:\r\r   ";
            break;
      default:
            message1 = "\r Insert savegame data disk & enter filename:\r\r   ";
            break;
      }

      for (; *message1; message1++)
            windowPutChar(window, *message1);

      memset(buf, 0, 10);
      name = buf;
      _saveGameNameLen = 0;

      while (!shouldQuit()) {
            windowPutChar(window, 128);
            _keyPressed.reset();

            while (!shouldQuit()) {
                  delay(10);
                  if (_keyPressed.ascii && _keyPressed.ascii < 128) {
                        i = _keyPressed.ascii;
                        break;
                  }
            }

            userGameBackSpace(_windowArray[4], 8);
            if (i == 10 || i == 13) {
                  break;
            } else if (i == 8) {
                  // do_backspace
                  if (_saveGameNameLen) {
                        _saveGameNameLen--;
                        name[_saveGameNameLen] = 0;
                        userGameBackSpace(_windowArray[4], 8);
                  }
            } else if (i >= 32 && _saveGameNameLen != 8) {
                  name[_saveGameNameLen++] = i;
                  windowPutChar(_windowArray[4], i);
            }
      }

      if (_saveGameNameLen != 0) {
            int16 slot = matchSaveGame(name, numSaveGames);
            if (!load) {
                  if (slot >= 0 && !confirmOverWrite(window))
                        goto restart;

                  if (slot < 0)
                        slot = numSaveGames;

                  if (!saveGame(slot, name))
                        fileError(_windowArray[4], true);
            } else {
                  if (slot < 0) {
                        fileError(_windowArray[4], false);
                  } else {
                        if (!loadGame(genSaveName(slot)))
                              fileError(_windowArray[4], false);
                  }
            }

            printStats();
      }

      restartAnimation();
      _gameStoppedClock = getTime() - saveTime + _gameStoppedClock;
}

void AGOSEngine_Elvira2::listSaveGames(char *dst) {
      Common::InSaveFile *in;
      uint y, slot;

      const uint8 num = (getGameType() == GType_WW) ? 3 : 4;

      disableFileBoxes();

      WindowBlock *window = _windowArray[num];
      window->textRow = 0;
      window->textColumn = 0;
      window->textColumnOffset = 4;

      windowPutChar(window, 12);

      memset(dst, 0, 200);

      slot = _saveLoadRowCurPos;
      for (y = 0; y < 8; y++) {
            window->textColumn = 0;
            window->textColumnOffset = (getGameType() == GType_ELVIRA2) ? 4 : 0;
            window->textLength = 0;
            if ((in = _saveFileMan->openForLoading(genSaveName(slot++)))) {
                  in->read(dst, 8);
                  delete in;

                  const char *name = dst;
                  for (; *name; name++)
                        windowPutChar(window, *name);

                  enableBox(200 + y * 3 + 0);
            }
            dst+= 8;

            if (getGameType() == GType_WW) {
                  window->textColumn = 7;
                  window->textColumnOffset = 4;
            } else if (getGameType() == GType_ELVIRA2) {
                  window->textColumn = 8;
                  window->textColumnOffset = 0;
            }
            window->textLength = 0;
            if ((in = _saveFileMan->openForLoading(genSaveName(slot++)))) {
                  in->read(dst, 8);
                  delete in;

                  const char *name = dst;
                  for (; *name; name++)
                        windowPutChar(window, *name);

                  enableBox(200 + y * 3 + 1);
            }
            dst+= 8;

            window->textColumn = 15;
            window->textColumnOffset = (getGameType() == GType_ELVIRA2) ? 4 : 0;
            window->textLength = 0;
            if ((in = _saveFileMan->openForLoading(genSaveName(slot++)))) {
                  in->read(dst, 8);
                  delete in;

                  const char *name = dst;
                  for (; *name; name++)
                        windowPutChar(window, *name);

                  enableBox(200 + y * 3 + 2);
            }
            dst+= 8;

            windowPutChar(window, 13);
      }

      window->textRow = 9;
      window->textColumn = 0;
      window->textColumnOffset = 4;
      window->textLength = 0;

      _saveGameNameLen = 0;
}

void AGOSEngine_Elvira2::userGame(bool load) {
      uint32 saveTime;
      int i, numSaveGames;
      char *name;
      bool b;
      char buf[200];

      _saveOrLoad = load;

      saveTime = getTime();

      if (getGameType() == GType_ELVIRA2)
            haltAnimation();

      numSaveGames = countSaveGames();
      _numSaveGameRows = numSaveGames;
      _saveLoadRowCurPos = 1;
      _saveLoadEdit = false;

      const uint8 num = (getGameType() == GType_WW) ? 3 : 4;

      listSaveGames(buf);

      if (!load) {
            WindowBlock *window = _windowArray[num];
            int16 slot = -1;

            name = buf + 192;

            while (!shouldQuit()) {
                  windowPutChar(window, 128);

                  _saveLoadEdit = true;

                  i = userGameGetKey(&b, buf, 128);
                  if (b) {
                        if (i <= 223) {
                              if (!confirmOverWrite(window)) {
                                    listSaveGames(buf);
                                    continue;
                              }

                              if (!saveGame(_saveLoadRowCurPos + i, buf + i * 8))
                                    fileError(_windowArray[num], true);
                        }

                        goto get_out;
                  }

                  userGameBackSpace(_windowArray[num], 8);
                  if (i == 10 || i == 13) {
                        slot = matchSaveGame(name, numSaveGames);
                        if (slot >= 0) {
                              if (!confirmOverWrite(window)) {
                                    listSaveGames(buf);
                                    continue;
                              }
                        }
                        break;
                  } else if (i == 8) {
                        // do_backspace
                        if (_saveGameNameLen) {
                              _saveGameNameLen--;
                              name[_saveGameNameLen] = 0;
                              userGameBackSpace(_windowArray[num], 8);
                        }
                  } else if (i >= 32 && _saveGameNameLen != 8) {
                        name[_saveGameNameLen++] = i;
                        windowPutChar(_windowArray[num], i);
                  }
            }

            if (_saveGameNameLen != 0) {
                  if (slot < 0)
                        slot = numSaveGames;

                  if (!saveGame(slot, buf + 192))
                        fileError(_windowArray[num], true);
            }
      } else {
            i = userGameGetKey(&b, buf, 128);
            if (i != 225) {
                  if (!loadGame(genSaveName(_saveLoadRowCurPos + i)))
                        fileError(_windowArray[num], false);
            }
      }

get_out:;
      disableFileBoxes();

      _gameStoppedClock = getTime() - saveTime + _gameStoppedClock;

      if (getGameType() == GType_ELVIRA2)
            restartAnimation();
}

int AGOSEngine_Elvira2::userGameGetKey(bool *b, char *buf, uint maxChar) {
      HitArea *ha;
      *b = true;

      _keyPressed.reset();

      while (!shouldQuit()) {
            _lastHitArea = NULL;
            _lastHitArea3 = NULL;

            do {
                  if (_saveLoadEdit && _keyPressed.ascii && _keyPressed.ascii < maxChar) {
                        *b = false;
                        return _keyPressed.ascii;
                  }
                  delay(10);
            } while (_lastHitArea3 == 0 && !shouldQuit());

            ha = _lastHitArea;
            if (ha == NULL || ha->id < 200) {
            } else if (ha->id == 225) {
                  return ha->id;
            } else if (ha->id == 224) {
                  _saveGameNameLen = 0;
                  _saveLoadRowCurPos += 24;
                  if (_saveLoadRowCurPos >= _numSaveGameRows)
                        _saveLoadRowCurPos = 1;

                  listSaveGames(buf);
            } else if (ha->id < 224) {
                  return ha->id - 200;
            }
      }

      return 225;
}

void AGOSEngine_Simon1::listSaveGames(char *dst) {
      Common::InSaveFile *in;
      uint16 i, slot, lastSlot;

      disableFileBoxes();

      showMessageFormat("\xC");

      memset(dst, 0, 108);

      slot = _saveLoadRowCurPos;
      while (_saveLoadRowCurPos + 6 > slot) {
            if (!(in = _saveFileMan->openForLoading(genSaveName(slot))))
                  break;

            in->read(dst, 18);
            delete in;

            lastSlot = slot;
            if (slot < 10) {
                  showMessageFormat(" ");
            } else if (_language == Common::HB_ISR) {
                  lastSlot = (slot % 10) * 10;
                  lastSlot += slot / 10;
            }

            showMessageFormat("%d", lastSlot);
            if (_language == Common::HB_ISR && !(slot % 10))
                  showMessageFormat("0");
            showMessageFormat(".%s\n", dst);
            dst += 18;
            slot++;
      }

      if (!_saveOrLoad) {
            if (_saveLoadRowCurPos + 6 == slot) {
                  slot++;
            } else {
                  if (slot < 10)
                        showMessageFormat(" ");
                  showMessageFormat("%d.\n", slot);
            }
      } else {
            if (_saveLoadRowCurPos + 6 == slot) {
                  if ((in = _saveFileMan->openForLoading(genSaveName(slot)))) {
                        slot++;
                        delete in;
                  }
            }
      }

      _saveDialogFlag = true;

      i = slot - _saveLoadRowCurPos;
      if (i != 7) {
            i++;
            if (!_saveOrLoad)
                  i++;
            _saveDialogFlag = false;
      }

      if (!--i)
            return;

      do {
            enableBox(208 + i - 1);
      } while (--i);
}

const byte hebrewKeyTable[96] = {
      32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 90, 45, 85, 47, 48, 49, 50,
      51, 52, 53, 54, 55, 56, 57, 83, 83, 90, 61, 85, 63, 35, 89, 80, 65, 66, 87,
      75, 82, 73, 79, 71, 76, 74, 86, 78, 77, 84, 47, 88, 67, 64, 69, 68, 44, 81,
      72, 70, 91, 92, 93, 94, 95, 96, 89, 80, 65, 66, 87, 75, 82, 73, 79, 71, 76,
      74, 86, 78, 77, 84, 47, 88, 67, 64, 69, 68, 44, 81, 72, 70,
      123, 124, 125, 126, 127,
};

void AGOSEngine_Simon1::userGame(bool load) {
      uint32 saveTime;
      int i, numSaveGames, result;
      WindowBlock *window;
      char *name;
      bool b;
      char buf[108];
      int maxChar = (_language == Common::HB_ISR) ? 155: 128;

      _saveOrLoad = load;

      saveTime = getTime();

      numSaveGames = countSaveGames();
      if (!load)
            numSaveGames++;
      numSaveGames -= 6;
      if (numSaveGames < 0)
            numSaveGames = 0;
      numSaveGames++;
      _numSaveGameRows = numSaveGames;

      _saveLoadRowCurPos = 1;
      if (!load)
            _saveLoadRowCurPos = numSaveGames;

      _saveLoadEdit = false;

restart:;
      i = userGameGetKey(&b, buf, maxChar);

      if (i == 205)
            goto get_out;
      if (!load) {
            // if_1
      if_1:;
            result = i;

            disableBox(208 + i);
            leaveHitAreaById(208 + i);

            window = _windowArray[5];

            window->textRow = result;

            // init x offset with a 2 character savegame number + a period (18 pix)
            if (_language == Common::HB_ISR) {
                  window->textColumn = 3;
                  window->textColumnOffset = 6;
            } else {
                  window->textColumn = 2;
                  window->textColumnOffset = 2;
            }
            window->textLength = 3;

            name = buf + i * 18;

            // now process entire savegame name to get correct x offset for cursor
            _saveGameNameLen = 0;
            while (name[_saveGameNameLen]) {
                  if (_language == Common::HB_ISR) {
                        byte width = 6;
                        if (name[_saveGameNameLen] >= 64 && name[_saveGameNameLen] < 91)
                              width = _hebrewCharWidths [name[_saveGameNameLen] - 64];
                        window->textLength++;
                        window->textColumnOffset -= width;
                        if (window->textColumnOffset < width) {
                              window->textColumnOffset += 8;
                              window->textColumn++;
                        }
                  } else {
                        window->textLength++;
                        window->textColumnOffset += 6;
                        if (name[_saveGameNameLen] == 'i' || name[_saveGameNameLen] == 'l')
                              window->textColumnOffset -= 2;
                        if (window->textColumnOffset >= 8) {
                              window->textColumnOffset -= 8;
                              window->textColumn++;
                        }
                  }
                  _saveGameNameLen++;
            }

            while (!shouldQuit()) {
                  windowPutChar(window, 127);

                  _saveLoadEdit = true;

                  i = userGameGetKey(&b, buf, maxChar);

                  if (b) {
                        if (i == 205)
                              goto get_out;
                        enableBox(208 + result);
                        if (_saveLoadEdit) {
                              userGameBackSpace(_windowArray[5], 8);
                        }
                        goto if_1;
                  }

                  if (!_saveLoadEdit) {
                        enableBox(208 + result);
                        goto restart;
                  }

                  if (_language == Common::HB_ISR) {
                        if (i >= 128)
                              i -= 64;
                        else if (i >= 32)
                              i = hebrewKeyTable[i - 32];
                  }

                  userGameBackSpace(_windowArray[5], 8);
                  if (i == 10 || i == 13) {
                        break;
                  } else if (i == 8) {
                        // do_backspace
                        if (_saveGameNameLen) {
                              byte m, x;

                              _saveGameNameLen--;
                              m = name[_saveGameNameLen];

                              if (_language == Common::HB_ISR)
                                    x = 8;
                              else
                                    x = (name[_saveGameNameLen] == 'i' || name[_saveGameNameLen] == 'l') ? 1 : 8;

                              name[_saveGameNameLen] = 0;

                              userGameBackSpace(_windowArray[5], x, m);
                        }
                  } else if (i >= 32 && _saveGameNameLen != 17) {
                        name[_saveGameNameLen++] = i;

                        windowPutChar(_windowArray[5], i);
                  }
            }

            if (!saveGame(_saveLoadRowCurPos + result, buf + result * 18))
                  fileError(_windowArray[5], true);
      } else {
            if (!loadGame(genSaveName(_saveLoadRowCurPos + i)))
                  fileError(_windowArray[5], false);
      }

get_out:;
      disableFileBoxes();

      _gameStoppedClock = getTime() - saveTime + _gameStoppedClock;
}

int AGOSEngine_Simon1::userGameGetKey(bool *b, char *buf, uint maxChar) {
      HitArea *ha;
      *b = true;

      if (!_saveLoadEdit) {
            listSaveGames(buf);
      }

      _keyPressed.reset();

      while (!shouldQuit()) {
            _lastHitArea = NULL;
            _lastHitArea3 = NULL;

            do {
                  if (_saveLoadEdit && _keyPressed.ascii && _keyPressed.ascii < maxChar) {
                        *b = false;
                        return _keyPressed.ascii;
                  }
                  delay(10);
            } while (_lastHitArea3 == 0 && !shouldQuit());

            ha = _lastHitArea;
            if (ha == NULL || ha->id < 205) {
            } else if (ha->id == 205) {
                  return ha->id;
            } else if (ha->id == 206) {
                  if (_saveLoadRowCurPos != 1) {
                        if (_saveLoadRowCurPos < 7)
                              _saveLoadRowCurPos = 1;
                        else
                              _saveLoadRowCurPos -= 6;

                        _saveLoadEdit = false;
                        listSaveGames(buf);
                  }
            } else if (ha->id == 207) {
                  if (_saveDialogFlag) {
                        _saveLoadRowCurPos += 6;
                        if (_saveLoadRowCurPos >= _numSaveGameRows)
                              _saveLoadRowCurPos = _numSaveGameRows;

                        _saveLoadEdit = false;
                        listSaveGames(buf);
                  }
            } else if (ha->id < 214) {
                  return ha->id - 208;
            }
      }

      return 205;
}

void AGOSEngine::disableFileBoxes() {
      int i;

      if (getGameType() == GType_SIMON1 || getGameType() == GType_SIMON2) {
            for (i = 208; i != 214; i++)
                  disableBox(i);
      } else {
            for (i = 200; i != 224; i++)
                  disableBox(i);
      }
}

void AGOSEngine::userGameBackSpace(WindowBlock *window, int x, byte b) {
      byte oldTextColor;

      windowPutChar(window, x, b);
      oldTextColor = window->textColor;
      window->textColor = window->fillColor;

      if (_language == Common::HB_ISR) {
            x = 128;
      } else {
            x += 120;
            if (x != 128)
                  x = 129;
      }

      windowPutChar(window, x);

      window->textColor = oldTextColor;
      windowPutChar(window, 8);
}

void AGOSEngine::fileError(WindowBlock *window, bool saveError) {
      const char *message1, *message2;

      if (saveError) {
            switch (_language) {
            case Common::RU_RUS:
                  if (getGameType() == GType_SIMON2) {
                        message1 = "\r   Mf sowrap+fts+.";
                        message2 = "\r  Nzjb#a ejs#a.";
                  } else {
                        message1 = "\r   Mf sowrap]fts].";
                        message2 = "\r   Nzjb_a ejs_a.";
                  }
                  break;
            case Common::PL_POL:
                  message1 = "\r      Blad zapisu.    ";
                  message2 = "\rBlad dysku.                       ";
                  break;
            case Common::ES_ESP:
                  message1 = "\r     Error al salvar";
                  message2 = "\r  Intenta con otro disco";
                  break;
            case Common::IT_ITA:
                  message1 = "\r  Salvataggio non riuscito";
                  message2 = "\r    Prova un""\x27""altro disco";
                  break;
            case Common::FR_FRA:
                  message1 = "\r    Echec sauvegarde";
                  message2 = "\rEssayez une autre disquette";
                  break;
            case Common::DE_DEU:
                  message1 = "\r  Sicherung erfolglos.";
                  message2 = "\rVersuche eine andere     Diskette.";
                  break;
            default:
                  message1 = "\r       Save failed.";
                  message2 = "\r       Disk error.";
                  break;
            }
      } else {
            switch (_language) {
            case Common::RU_RUS:
                  if (getGameType() == GType_SIMON2) {
                        message1 = "\r  Mf ^adruhafts+.";
                        message2 = "\r   Takm pf pakefp.";
                  } else {
                        message1 = "\r   Mf ^adruhafts].";
                        message2 = "\r   Takm pf pakefp.";
                  }
                  break;
            case Common::PL_POL:
                  message1 = "\r   Blad odczytu.    ";
                  message2 = "\r  Nie znaleziono pliku.";
                  break;
            case Common::ES_ESP:
                  message1 = "\r     Error al cargar";
                  message2 = "\r  Archivo no encontrado";
                  break;
            case Common::IT_ITA:
                  message1 = "\r  Caricamento non riuscito";
                  message2 = "\r      File non trovato";
                  break;
            case Common::FR_FRA:
                  message1 = "\r    Echec chargement";
                  message2 = "\r  Fichier introuvable";
                  break;
            case Common::DE_DEU:
                  message1 = "\r    Laden erfolglos.";
                  message2 = "\r  Datei nicht gefunden.";
                  break;
            default:
                  message1 = "\r       Load failed.";
                  message2 = "\r     File not found.";
                  break;
            }
      }

      if (getGameType() == GType_ELVIRA1) {
            printScroll();
            window->textColumn = 0;
            window->textRow = 0;
            window->textColumnOffset = 0;
            window->textLength = 0;       // Difference
      } else {
            windowPutChar(window, 12);
      }

      for (; *message1; message1++)
            windowPutChar(window, *message1);
      for (; *message2; message2++)
            windowPutChar(window, *message2);

      waitWindow(window);
}

uint16 readItemID(Common::SeekableReadStream *f) {
      uint32 val = f->readUint32BE();
      if (val == 0xFFFFFFFF)
            return 0;
      return val + 1;
}

void writeItemID(Common::WriteStream *f, uint16 val) {
      if (val == 0)
            f->writeUint32BE(0xFFFFFFFF);
      else
            f->writeUint32BE(val - 1);
}

bool AGOSEngine::loadGame(const char *filename, bool restartMode) {
      char ident[100];
      Common::SeekableReadStream *f = NULL;
      uint num, item_index, i;

      _videoLockOut |= 0x100;

      if (restartMode) {
            // Load restart state
            Common::File *file = new Common::File();
            file->open(filename);
            f = file;
      } else {
            f = _saveFileMan->openForLoading(filename);
      }

      if (f == NULL) {
            _videoLockOut &= ~0x100;
            return false;
      }

      if (!restartMode) {
            f->read(ident, 8);
      }

      num = f->readUint32BE();

      if (f->readUint32BE() != 0xFFFFFFFF || num != _itemArrayInited - 1) {
            delete f;
            _videoLockOut &= ~0x100;
            return false;
      }

      f->readUint32BE();
      f->readUint32BE();
      _noParentNotify = true;

      // add all timers
      killAllTimers();
      for (num = f->readUint32BE(); num; num--) {
            uint32 timeout = f->readUint32BE();
            uint16 subroutine_id = f->readUint16BE();
            addTimeEvent(timeout, subroutine_id);
      }

      item_index = 1;
      for (num = _itemArrayInited - 1; num; num--) {
            Item *item = _itemArrayPtr[item_index++], *parent_item;

            parent_item = derefItem(readItemID(f));
            setItemParent(item, parent_item);

            item->state = f->readUint16BE();
            item->classFlags = f->readUint16BE();

            SubObject *o = (SubObject *)findChildOfType(item, kObjectType);
            if (o) {
                  o->objectSize = f->readUint16BE();
                  o->objectWeight = f->readUint16BE();
            }

            SubPlayer *p = (SubPlayer *)findChildOfType(item, kPlayerType);
            if (p) {
                  p->score = f->readUint32BE();
                  p->level = f->readUint16BE();
                  p->size = f->readUint16BE();
                  p->weight = f->readUint16BE();
                  p->strength = f->readUint16BE();
            }

            SubUserFlag *u = (SubUserFlag *)findChildOfType(item, kUserFlagType);
            if (u) {
                  for (i = 0; i != 8; i++) {
                        u->userFlags[i] = f->readUint16BE();
                  }
                  u->userItems[0] = readItemID(f);
            }
      }

      // read the variables
      for (i = 0; i != _numVars; i++) {
            writeVariable(i, f->readUint16BE());
      }

      if (f->err()) {
            error("load failed");
      }

      delete f;

      _noParentNotify = false;

      _videoLockOut &= ~0x100;

      return true;
}

bool AGOSEngine::saveGame(uint slot, const char *caption) {
      Common::OutSaveFile *f;
      uint item_index, num_item, i;
      TimeEvent *te;
      uint32 curTime = getTime();
      uint32 gsc = _gameStoppedClock;

      _videoLockOut |= 0x100;

      f = _saveFileMan->openForSaving(genSaveName(slot));
      if (f == NULL) {
            _videoLockOut &= ~0x100;
            return false;
      }

      f->write(caption, 8);

      f->writeUint32BE(_itemArrayInited - 1);
      f->writeUint32BE(0xFFFFFFFF);
      f->writeUint32BE(curTime);
      f->writeUint32BE(0);

      i = 0;
      for (te = _firstTimeStruct; te; te = te->next)
            i++;
      f->writeUint32BE(i);

      for (te = _firstTimeStruct; te; te = te->next) {
            f->writeUint32BE(te->time - curTime + gsc);
            f->writeUint16BE(te->subroutine_id);
      }

      item_index = 1;
      for (num_item = _itemArrayInited - 1; num_item; num_item--) {
            Item *item = _itemArrayPtr[item_index++];

            writeItemID(f, item->parent);

            f->writeUint16BE(item->state);
            f->writeUint16BE(item->classFlags);

            SubObject *o = (SubObject *)findChildOfType(item, kObjectType);
            if (o) {
                  f->writeUint16BE(o->objectSize);
                  f->writeUint16BE(o->objectWeight);
            }

            SubPlayer *p = (SubPlayer *)findChildOfType(item, kPlayerType);
            if (p) {
                  f->writeUint32BE(p->score);
                  f->writeUint16BE(p->level);
                  f->writeUint16BE(p->size);
                  f->writeUint16BE(p->weight);
                  f->writeUint16BE(p->strength);
            }

            SubUserFlag *u = (SubUserFlag *)findChildOfType(item, kUserFlagType);
            if (u) {
                  for (i = 0; i != 8; i++) {
                        f->writeUint16BE(u->userFlags[i]);
                  }
                  writeItemID(f, u->userItems[0]);
            }
      }

      // write the variables
      for (i = 0; i != _numVars; i++) {
            f->writeUint16BE(readVariable(i));
      }

      f->finalize();
      bool result = !f->err();

      delete f;
      _videoLockOut &= ~0x100;

      return result;
}

bool AGOSEngine_Elvira2::loadGame(const char *filename, bool restartMode) {
      char ident[100];
      Common::SeekableReadStream *f = NULL;
      uint num, item_index, i, j;

      _videoLockOut |= 0x100;

      if (restartMode) {
            // Load restart state
            Common::File *file = new Common::File();
            file->open(filename);
            f = file;
      } else {
            f = _saveFileMan->openForLoading(filename);
      }

      if (f == NULL) {
            _videoLockOut &= ~0x100;
            return false;
      }

      if (getGameType() == GType_PP) {
            // No caption
      } else if (getGameType() == GType_FF) {
            f->read(ident, 100);
      } else if (getGameType() == GType_SIMON1 || getGameType() == GType_SIMON2) {
            f->read(ident, 18);
      } else if (!restartMode) {
            f->read(ident, 8);
      }

      num = f->readUint32BE();

      if (f->readUint32BE() != 0xFFFFFFFF || num != _itemArrayInited - 1) {
            delete f;
            _videoLockOut &= ~0x100;
            return false;
      }

      f->readUint32BE();
      f->readUint32BE();
      _noParentNotify = true;

      // add all timers
      killAllTimers();
      for (num = f->readUint32BE(); num; num--) {
            uint32 timeout = f->readUint32BE();
            uint16 subroutine_id = f->readUint16BE();
            addTimeEvent(timeout, subroutine_id);
      }

      if (getGameType() == GType_WW && getPlatform() == Common::kPlatformPC) {
            for (uint s = 0; s < _numRoomStates; s++) {
                  _roomStates[s].state = f->readUint16BE();
                  _roomStates[s].classFlags = f->readUint16BE();
                  _roomStates[s].roomExitStates = f->readUint16BE();
            }
            f->readUint16BE();

            uint16 room = _currentRoom;
            _currentRoom = f->readUint16BE();

            if (_roomsListPtr) {
                  byte *p = _roomsListPtr;
                  if (room == _currentRoom) {
                        for (;;) {
                              uint16 minNum = READ_BE_UINT16(p); p += 2;
                              if (minNum == 0)
                                    break;

                              uint16 maxNum = READ_BE_UINT16(p); p += 2;

                               for (uint16 z = minNum; z <= maxNum; z++) {
                                    uint16 itemNum = z + 2;
                                    Item *item = derefItem(itemNum);

                                    num = (itemNum - _itemArrayInited);
                                    item->state = _roomStates[num].state;
                                    item->classFlags = _roomStates[num].classFlags;
                                    SubRoom *subRoom = (SubRoom *)findChildOfType(item, kRoomType);
                                    subRoom->roomExitStates = _roomStates[num].roomExitStates;
                              }
                        }
                  } else {
                        for (;;) {
                              uint16 minNum = READ_BE_UINT16(p); p += 2;
                              if (minNum == 0)
                                    break;

                              uint16 maxNum = READ_BE_UINT16(p); p += 2;

                               for (uint16 z = minNum; z <= maxNum; z++) {
                                    uint16 itemNum = z + 2;
                                    Item *item = derefItem(itemNum);
                                    item->parent = 0;
                              }
                        }
                  }
            }

            if (room != _currentRoom) {
                  _roomsListPtr = 0;
                  loadRoomItems(_currentRoom);
            }
      }

      item_index = 1;
      for (num = _itemArrayInited - 1; num; num--) {
            Item *item = _itemArrayPtr[item_index++], *parent_item;

            if ((getGameType() == GType_WW && getPlatform() == Common::kPlatformAmiga) ||
                  getGameType() == GType_ELVIRA2) {
                  parent_item = derefItem(readItemID(f));
                  setItemParent(item, parent_item);
            } else {
                  uint parent = f->readUint16BE();
                  uint next = f->readUint16BE();

                  parent_item = derefItem(parent);
                  setItemParent(item, parent_item);

                  if (parent_item == NULL) {
                        item->parent = parent;
                        item->next = next;
                  }
            }

            item->state = f->readUint16BE();
            item->classFlags = f->readUint16BE();

            SubRoom *r = (SubRoom *)findChildOfType(item, kRoomType);
            if (r) {
                  r->roomExitStates = f->readUint16BE();
            }

            SubSuperRoom *sr = (SubSuperRoom *)findChildOfType(item, kSuperRoomType);
            if (sr) {
                  uint16 n = sr->roomX * sr->roomY * sr->roomZ;
                  for (i = j = 0; i != n; i++)
                        sr->roomExitStates[j++] = f->readUint16BE();
            }

            SubObject *o = (SubObject *)findChildOfType(item, kObjectType);
            if (o) {
                  o->objectFlags = f->readUint32BE();
                  i = o->objectFlags & 1;

                  for (j = 1; j < 16; j++) {
                        if (o->objectFlags & (1 << j)) {
                              o->objectFlagValue[i++] = f->readUint16BE();
                        }
                  }
            }

            SubUserFlag *u = (SubUserFlag *)findChildOfType(item, kUserFlagType);
            if (u) {
                  for (i = 0; i != 4; i++) {
                        u->userFlags[i] = f->readUint16BE();
                  }
            }
      }

      // read the variables
      for (i = 0; i != _numVars; i++) {
            writeVariable(i, f->readUint16BE());
      }

      // read the items in item store
      for (i = 0; i != _numItemStore; i++) {
            if (getGameType() == GType_WW && getPlatform() == Common::kPlatformAmiga) {
                  _itemStore[i] = derefItem(f->readUint16BE() / 16);
            } else if (getGameType() == GType_ELVIRA2) {
                  if (getPlatform() == Common::kPlatformPC) {
                        _itemStore[i] = derefItem(readItemID(f));
                  } else {
                        _itemStore[i] = derefItem(f->readUint16BE() / 18);
                  }
            } else {
                  _itemStore[i] = derefItem(f->readUint16BE());
            }
      }

      // Read the bits in array 1
      for (i = 0; i != _numBitArray1; i++)
            _bitArray[i] = f->readUint16BE();

      // Read the bits in array 2
      for (i = 0; i != _numBitArray2; i++)
            _bitArrayTwo[i] = f->readUint16BE();

      // Read the bits in array 3
      for (i = 0; i != _numBitArray3; i++)
            _bitArrayThree[i] = f->readUint16BE();

      if (getGameType() == GType_ELVIRA2 || getGameType() == GType_WW) {
            _superRoomNumber = f->readUint16BE();
      }

      if (f->err()) {
            error("load failed");
      }

      delete f;

      _noParentNotify = false;

      _videoLockOut &= ~0x100;

      return true;
}

bool AGOSEngine_Elvira2::saveGame(uint slot, const char *caption) {
      Common::OutSaveFile *f;
      uint item_index, num_item, i, j;
      TimeEvent *te;
      uint32 curTime = getTime();
      uint32 gsc = _gameStoppedClock;

      _videoLockOut |= 0x100;

      f = _saveFileMan->openForSaving(genSaveName(slot));
      if (f == NULL) {
            _videoLockOut &= ~0x100;
            return false;
      }

      if (getGameType() == GType_PP) {
            // No caption
      } else if (getGameType() == GType_FF) {
            f->write(caption, 100);
      } else if (getGameType() == GType_SIMON1 || getGameType() == GType_SIMON2) {
            f->write(caption, 18);
      } else {
            f->write(caption, 8);
      }

      f->writeUint32BE(_itemArrayInited - 1);
      f->writeUint32BE(0xFFFFFFFF);
      f->writeUint32BE(curTime);
      f->writeUint32BE(0);

      i = 0;
      for (te = _firstTimeStruct; te; te = te->next)
            i++;
      f->writeUint32BE(i);

      if (getGameType() == GType_FF && _clockStopped)
            gsc += (getTime() - _clockStopped);
      for (te = _firstTimeStruct; te; te = te->next) {
            f->writeUint32BE(te->time - curTime + gsc);
            f->writeUint16BE(te->subroutine_id);
      }

      if (getGameType() == GType_WW && getPlatform() == Common::kPlatformPC) {
            if (_roomsListPtr) {
                  byte *p = _roomsListPtr;
                  for (;;) {
                        uint16 minNum = READ_BE_UINT16(p); p += 2;
                        if (minNum == 0)
                              break;

                        uint16 maxNum = READ_BE_UINT16(p); p += 2;

                         for (uint16 z = minNum; z <= maxNum; z++) {
                              uint16 itemNum = z + 2;
                              Item *item = derefItem(itemNum);

                              uint16 num = (itemNum - _itemArrayInited);
                              _roomStates[num].state = item->state;
                              _roomStates[num].classFlags = item->classFlags;
                              SubRoom *subRoom = (SubRoom *)findChildOfType(item, kRoomType);
                              _roomStates[num].roomExitStates = subRoom->roomExitStates;
                        }
                  }
            }

            for (uint s = 0; s < _numRoomStates; s++) {
                  f->writeUint16BE(_roomStates[s].state);
                  f->writeUint16BE(_roomStates[s].classFlags);
                  f->writeUint16BE(_roomStates[s].roomExitStates);
            }
            f->writeUint16BE(0);
            f->writeUint16BE(_currentRoom);
      }

      item_index = 1;
      for (num_item = _itemArrayInited - 1; num_item; num_item--) {
            Item *item = _itemArrayPtr[item_index++];

            if ((getGameType() == GType_WW && getPlatform() == Common::kPlatformAmiga) ||
                  getGameType() == GType_ELVIRA2) {
                  writeItemID(f, item->parent);
            } else {
                  f->writeUint16BE(item->parent);
                  f->writeUint16BE(item->next);
            }

            f->writeUint16BE(item->state);
            f->writeUint16BE(item->classFlags);

            SubRoom *r = (SubRoom *)findChildOfType(item, kRoomType);
            if (r) {
                  f->writeUint16BE(r->roomExitStates);
            }

            SubSuperRoom *sr = (SubSuperRoom *)findChildOfType(item, kSuperRoomType);
            if (sr) {
                  uint16 n = sr->roomX * sr->roomY * sr->roomZ;
                  for (i = j = 0; i != n; i++)
                        f->writeUint16BE(sr->roomExitStates[j++]);
            }

            SubObject *o = (SubObject *)findChildOfType(item, kObjectType);
            if (o) {
                  f->writeUint32BE(o->objectFlags);
                  i = o->objectFlags & 1;

                  for (j = 1; j < 16; j++) {
                        if (o->objectFlags & (1 << j)) {
                              f->writeUint16BE(o->objectFlagValue[i++]);
                        }
                  }
            }

            SubUserFlag *u = (SubUserFlag *)findChildOfType(item, kUserFlagType);
            if (u) {
                  for (i = 0; i != 4; i++) {
                        f->writeUint16BE(u->userFlags[i]);
                  }
            }
      }

      // write the variables
      for (i = 0; i != _numVars; i++) {
            f->writeUint16BE(readVariable(i));
      }

      // write the items in item store
      for (i = 0; i != _numItemStore; i++) {
            if (getGameType() == GType_WW && getPlatform() == Common::kPlatformAmiga) {
                  f->writeUint16BE(itemPtrToID(_itemStore[i]) * 16);
            } else if (getGameType() == GType_ELVIRA2) {
                  if (getPlatform() == Common::kPlatformPC) {
                        writeItemID(f, itemPtrToID(_itemStore[i]));
                  } else {
                        f->writeUint16BE(itemPtrToID(_itemStore[i]) * 18);
                  }
            } else {
                  f->writeUint16BE(itemPtrToID(_itemStore[i]));
            }
      }

      // Write the bits in array 1
      for (i = 0; i != _numBitArray1; i++)
            f->writeUint16BE(_bitArray[i]);

      // Write the bits in array 2
      for (i = 0; i != _numBitArray2; i++)
            f->writeUint16BE(_bitArrayTwo[i]);

      // Write the bits in array 3
      for (i = 0; i != _numBitArray3; i++)
            f->writeUint16BE(_bitArrayThree[i]);

      if (getGameType() == GType_ELVIRA2 || getGameType() == GType_WW) {
            f->writeUint16BE(_superRoomNumber);
      }

      f->finalize();
      bool result = !f->err();

      delete f;
      _videoLockOut &= ~0x100;

      return result;
}

// Personal Nightmare specific
bool AGOSEngine_PN::badload(int8 errorNum) {
      if (errorNum == -2)
            return 0;
      // Load error recovery routine

      // Clear any stack
      while (_stackbase != NULL) {
            dumpstack();
      }

      // Restart from process 1
      _tagOfActiveDoline = 1;
      _dolineReturnVal = 3;
      return 1;
}

void AGOSEngine_PN::getFilename() {
      _noScanFlag = 1;
      clearInputLine();

      memset(_saveFile, 0, sizeof(_saveFile));
      while (!shouldQuit() && !strlen(_saveFile)) {
            const char *msg = "File name : ";
            pcf((unsigned char)'\n');
            while (*msg)
                  pcf((unsigned char)*msg++);

            interact(_saveFile, 8);
            pcf((unsigned char)'\n');
            _noScanFlag = 0;
      }
}

int AGOSEngine_PN::loadFile(char *name) {
      Common::InSaveFile *f;
      haltAnimation();

      f = _saveFileMan->openForLoading(name);
      if (f == NULL) {
            restartAnimation();
            return -2;
      }
      f->read(_saveFile, 8);

      if (f->readByte() != 41) {
            restartAnimation();
            delete f;
            return -2;
      }
      if (f->readByte() != 33) {
            restartAnimation();
            delete f;
            return -2;
      }
      // TODO: Make endian safe
      if (!f->read(_dataBase + _quickptr[2], (int)(_quickptr[6] - _quickptr[2]))) {
            restartAnimation();
            delete f;
            return -1;
      }
      delete f;
      restartAnimation();
      dbtosysf();
      return 0;
}

int AGOSEngine_PN::saveFile(char *name) {
      Common::OutSaveFile *f;
      sysftodb();
      haltAnimation();

      f = _saveFileMan->openForSaving(name);
      if (f == NULL) {
            restartAnimation();

            const char *msg = "Couldn't save. ";
            pcf((unsigned char)'\n');
            while (*msg)
                  pcf((unsigned char)*msg++);

            return 0;
      }
      f->write(_saveFile, 8);

      f->writeByte(41);
      f->writeByte(33);
      // TODO: Make endian safe
      if (!f->write(_dataBase + _quickptr[2], (int)(_quickptr[6] - _quickptr[2]))) {
            delete f;
            restartAnimation();
            error("Couldn't save ");
            return 0;   // for compilers that don't support NORETURN
      }
      f->finalize();
      delete f;

      restartAnimation();
      return 1;
}

void AGOSEngine_PN::sysftodb() {
      uint32 pos = _quickptr[2];
      int ct = 0;

      while (ct < (getptr(49L) / 2)) {
            _dataBase[pos] = (uint8)(_variableArray[ct] % 256);
            _dataBase[pos + 1] = (uint8)(_variableArray[ct] / 256);
            pos+=2;
            ct++;
      }
}

void AGOSEngine_PN::dbtosysf() {
      uint32 pos = _quickptr[2];
      int ct = 0;

      while (ct < (getptr(49L) / 2)) {
            _variableArray[ct] = _dataBase[pos] + 256 * _dataBase[pos + 1];
            pos += 2;
            ct++;
      }
}

} // End of namespace AGOS

Generated by  Doxygen 1.6.0   Back to index