diff options
Diffstat (limited to 'engines/agos/saveload.cpp')
-rw-r--r-- | engines/agos/saveload.cpp | 821 |
1 files changed, 821 insertions, 0 deletions
diff --git a/engines/agos/saveload.cpp b/engines/agos/saveload.cpp new file mode 100644 index 0000000000..37907024b6 --- /dev/null +++ b/engines/agos/saveload.cpp @@ -0,0 +1,821 @@ +/* ScummVM - Scumm Interpreter + * Copyright (C) 2001 Ludvig Strigeus + * Copyright (C) 2001-2006 The ScummVM project + * + * 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$ + * $Id$ + * + */ + +#include "common/stdafx.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 Simon { + +int SimonEngine::countSaveGames() { + Common::InSaveFile *f; + uint i = 1; + bool marks[256]; + + char *prefix = genSaveName(999); + prefix[strlen(prefix)-3] = '\0'; + _saveFileMan->listSavefiles(prefix, marks, 256); + + while (i < 256) { + if (marks[i] && + (f = _saveFileMan->openForLoading(genSaveName(i)))) { + i++; + delete f; + } else + break; + } + return i; +} + +int SimonEngine::displaySaveGameList(int curpos, bool load, char *dst) { + int slot, last_slot; + Common::InSaveFile *in; + + showMessageFormat("\xC"); + + memset(dst, 0, 108); + + slot = curpos; + + while (curpos + 6 > slot) { + if (!(in = _saveFileMan->openForLoading(genSaveName(slot)))) + break; + + in->read(dst, 18); + delete in; + + last_slot = slot; + if (slot < 10) { + showMessageFormat(" "); + } else if (_language == Common::HB_ISR) { + last_slot = (slot % 10) * 10; + last_slot += slot / 10; + } + + if (_language == Common::HB_ISR && !(slot % 10)) + showMessageFormat("0"); + showMessageFormat("%d", last_slot); + showMessageFormat(".%s\n", dst); + dst += 18; + slot++; + } + // while_break + if (!load) { + if (curpos + 6 == slot) + slot++; + else { + if (slot < 10) + showMessageFormat(" "); + showMessageFormat("%d.\n", slot); + } + } else { + if (curpos + 6 == slot) { + if ((in = _saveFileMan->openForLoading(genSaveName(slot)))) { + slot++; + delete in; + } + } + } + + return slot - curpos; +} + +char *SimonEngine::genSaveName(int slot) { + static char buf[15]; + + if (getGameType() == GType_FF) { + if (slot == 999) { + // Restart state + if (getPlatform() == Common::kPlatformWindows) + sprintf(buf, "save.%.3d", slot); + else + sprintf(buf, "setup"); + } else { + sprintf(buf, "feeble.%.3d", slot); + } + } else if (getGameType() == GType_SIMON2) { + sprintf(buf, "simon2.%.3d", slot); + } else { + sprintf(buf, "simon1.%.3d", slot); + } + return buf; +} + +void SimonEngine::quickLoadOrSave() { + // The demo of Simon 1 (DOS Floppy) is missing too many segments + // and the Feeble Files doesn't always allow a load or save + if (getGameId() == GID_SIMON1DEMO || getGameType() == GType_FF) + return; + + bool success; + char buf[50]; + + char *filename = genSaveName(_saveLoadSlot); + if (_saveLoadType == 2) { + Subroutine *sub; + success = loadGame(_saveLoadSlot); + if (!success) { + sprintf(buf, "Failed to load game state to file:\n\n%s", filename); + } else { + // Redraw Inventory + mouseOff(); + drawIconArray(2, me(), 0, 0); + mouseOn(); + // Reset engine? + setBitFlag(97, true); + sub = getSubroutineByID(100); + 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; +} + +void SimonEngine::listSaveGames(char *buf) { + int i; + + disableFileBoxes(); + + i = displaySaveGameList(_saveLoadRowCurPos, _saveOrLoad, buf); + + _saveDialogFlag = true; + + 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 SimonEngine::userGame(bool load) { + time_t save_time; + int number_of_savegames; + int i, name_len, result; + WindowBlock *window; + char *name; + bool b; + char buf[108]; + int maxChar = (_language == Common::HB_ISR) ? 155: 128; + + _saveOrLoad = load; + + save_time = time(NULL); + + _copyPartialMode = 1; + + number_of_savegames = countSaveGames(); + if (!load) + number_of_savegames++; + number_of_savegames -= 6; + if (number_of_savegames < 0) + number_of_savegames = 0; + number_of_savegames++; + _numSaveGameRows = number_of_savegames; + + _saveLoadRowCurPos = 1; + if (!load) + _saveLoadRowCurPos = number_of_savegames; + + _saveLoadEdit = false; + +restart:; + do { + i = userGameGetKey(&b, buf); + } while (!b); + + 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; + window->textLength = 3; + } 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 + name_len = 0; + while (name[name_len]) { + if (_language == Common::HB_ISR) { + byte width = 6; + if (name[name_len] >= 64 && name[name_len] < 91) + width = _hebrewCharWidths [name[name_len] - 64]; + window->textLength++; + window->textColumnOffset -= width; + if (window->textColumnOffset < width) { + window->textColumnOffset += 8; + window->textColumn++; + } + } else { + window->textLength++; + window->textColumnOffset += 6; + if (name[name_len] == 'i' || name[name_len] == 'l') + window->textColumnOffset -= 2; + if (window->textColumnOffset >= 8) { + window->textColumnOffset -= 8; + window->textColumn++; + } + } + name_len++; + } + // while_1_end + + // do_3_start + for (;;) { + windowPutChar(window, 0x7f); + + _saveLoadEdit = true; + + // do_2 + do { + i = userGameGetKey(&b, buf); + + if (b) { + if (i == 205) + goto get_out; + enableBox(208 + result); + if (_saveLoadEdit) { + userGameBackSpace(_windowArray[5], 8); + } + goto if_1; + } + + // is_not_b + if (!_saveLoadEdit) { + enableBox(208 + result); + goto restart; + } + } while (i >= maxChar || i == 0); + + if (_language == Common::HB_ISR) { + if (i >= 128) + i -= 64; + else if (i >= 32) + i = hebrewKeyTable[i - 32]; + } + + // after_do_2 + userGameBackSpace(_windowArray[5], 8); + if (i == 10 || i == 13) + break; + if (i == 8) { + // do_backspace + if (name_len != 0) { + int x; + byte m; + + name_len--; + m = name[name_len]; + + if (_language == Common::HB_ISR) + x = 8; + else + x = (name[name_len] == 'i' || name[name_len] == 'l') ? 1 : 8; + + name[name_len] = 0; + + userGameBackSpace(_windowArray[5], x, m); + } + } else if (i >= 32 && name_len != 17) { + name[name_len++] = i; + + windowPutChar(_windowArray[5], i); + } + } + + // do_save + if (!saveGame(_saveLoadRowCurPos + result, buf + result * 18)) + fileError(_windowArray[5], true); + } else { + if (!loadGame(_saveLoadRowCurPos + i)) + fileError(_windowArray[5], false); + } + +get_out:; + disableFileBoxes(); + + _gameStoppedClock = time(NULL) - save_time + _gameStoppedClock; + _copyPartialMode = 0; + + restoreBlock(94, 208, 46, 80); + + i = _timer4; + do { + delay(10); + } while (i == _timer4); +} + +int SimonEngine::userGameGetKey(bool *b, char *buf) { + HitArea *ha; + *b = true; + + if (!_saveLoadEdit) { + listSaveGames(buf); + } + + _keyPressed = 0; + + for (;;) { + _lastHitArea = NULL; + _lastHitArea3 = NULL; + + do { + if (_saveLoadEdit && _keyPressed != 0) { + *b = false; + return _keyPressed; + } + delay(10); + } while (_lastHitArea3 == 0); + + 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; + } + } +} + +void SimonEngine::disableFileBoxes() { + for (int i = 208; i != 214; i++) + disableBox(i); +} + +void SimonEngine::userGameBackSpace(WindowBlock *window, int x, byte b) { + byte old_text; + + windowPutChar(window, x, b); + old_text = window->text_color; + window->text_color = window->fill_color; + + if (_language == Common::HB_ISR) { + x = 128; + } else { + x += 120; + if (x != 128) + x = 129; + } + + windowPutChar(window, x); + + window->text_color = old_text; + windowPutChar(window, 8); +} + +void SimonEngine::fileError(WindowBlock *window, bool save_error) { + HitArea *ha; + const char *string1, *string2; + + if (save_error) { + switch (_language) { + case Common::RU_RUS: + if (getGameType() == GType_SIMON2) { + string1 = "\r Mf sowrap+fts+."; + string2 = "\r Nzjb#a ejs#a."; + } else { + string1 = "\r Mf sowrap]fts]."; + string2 = "\r Nzjb_a ejs_a."; + } + break; + case Common::PL_POL: + string1 = "\r Blad zapisu. "; + string2 = "\rBlad dysku. "; + break; + case Common::ES_ESP: + string1 = "\r Error al salvar"; + string2 = "\r Intenta con otro disco"; + break; + case Common::IT_ITA: + string1 = "\r Salvataggio non riuscito"; + string2 = "\r Prova un""\x27""altro disco"; + break; + case Common::FR_FRA: + string1 = "\r Echec sauvegarde"; + string2 = "\rEssayez une autre disquette"; + break; + case Common::DE_DEU: + string1 = "\r Sicherung erfolglos."; + string2 = "\rVersuche eine andere Diskette."; + break; + default: + string1 = "\r Save failed."; + string2 = "\r Disk error."; + break; + } + } else { + switch (_language) { + case Common::RU_RUS: + if (getGameType() == GType_SIMON2) { + string1 = "\r Mf ^adruhafts+."; + string2 = "\r Takm pf pakefp."; + } else { + string1 = "\r Mf ^adruhafts]."; + string2 = "\r Takm pf pakefp."; + } + break; + case Common::PL_POL: + string1 = "\r Blad odczytu. "; + string2 = "\r Nie znaleziono pliku."; + break; + case Common::ES_ESP: + string1 = "\r Error al cargar"; + string2 = "\r Archivo no encontrado"; + break; + case Common::IT_ITA: + string1 = "\r Caricamento non riuscito"; + string2 = "\r File non trovato"; + break; + case Common::FR_FRA: + string1 = "\r Echec chargement"; + string2 = "\r Fichier introuvable"; + break; + case Common::DE_DEU: + string1 = "\r Laden erfolglos."; + string2 = "\r Datei nicht gefunden."; + break; + default: + string1 = "\r Load failed."; + string2 = "\r File not found."; + break; + } + } + + windowPutChar(window, 0xC); + for (; *string1; string1++) + windowPutChar(window, *string1); + for (; *string2; string2++) + windowPutChar(window, *string2); + + window->textColumn = (window->width / 2) - 3; + window->textRow = window->height - 1; + window->textLength = 0; + + string1 = "[ OK ]"; + for (; *string1; string1++) + windowPutChar(window, *string1); + + ha = findEmptyHitArea(); + ha->x = ((window->width / 2) + (window->x - 3)) * 8; + ha->y = (window->height * 8) + window->y - 8; + ha->width = 48; + ha->height = 8; + ha->flags = kBFBoxInUse; + ha->id = 0x7FFF; + ha->priority = 0x3EF; + +loop:; + _lastHitArea = _lastHitArea3 = 0; + + do { + delay(1); + } while (_lastHitArea3 == 0); + + ha = _lastHitArea; + if (ha == NULL || ha->id != 0x7FFF) + goto loop; + + // Return + undefineBox(0x7FFF); +} + +bool SimonEngine::saveGame(uint slot, char *caption) { + Common::WriteStream *f; + uint item_index, num_item, i, j; + TimeEvent *te; + uint32 curTime = 0; + uint32 gsc = _gameStoppedClock; + + _lockWord |= 0x100; + + f = _saveFileMan->openForSaving(genSaveName(slot)); + if (f == NULL) { + warning("saveGame: Failed to save slot %d", slot); + _lockWord &= ~0x100; + return false; + } + + if (getGameType() == GType_FF) { + f->write(caption, 100); + curTime = time(NULL); + } else { + f->write(caption, 18); + } + + f->writeUint32BE(_itemArrayInited - 1); + f->writeUint32BE(0xFFFFFFFF); + f->writeUint32BE(0); + f->writeUint32BE(0); + + i = 0; + for (te = _firstTimeStruct; te; te = te->next) + i++; + f->writeUint32BE(i); + + if (_clockStopped) + gsc += ((uint32)time(NULL) - _clockStopped); + 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++]; + + f->writeUint16BE(item->parent); + f->writeUint16BE(item->sibling); + f->writeUint16BE(item->state); + f->writeUint16BE(item->classFlags); + + SubRoom *subRoom = (SubRoom *)findChildOfType(item, 1); + if (subRoom) { + f->writeUint16BE(subRoom->roomExitStates); + } + + SubObject *subObject = (SubObject *)findChildOfType(item, 2); + if (subObject) { + f->writeUint32BE(subObject->objectFlags); + i = subObject->objectFlags & 1; + + for (j = 1; j < 16; j++) { + if (subObject->objectFlags & (1 << j)) { + f->writeUint16BE(subObject->objectFlagValue[i++]); + } + } + } + + SubUserFlag *subUserFlag = (SubUserFlag *)findChildOfType(item, 9); + if (subUserFlag) { + for (i = 0; i != 4; i++) { + f->writeUint16BE(subUserFlag->userFlags[i]); + } + } + } + + // write the 255 variables + for (i = 0; i != 255; i++) { + f->writeUint16BE(readVariable(i)); + } + + // write the items in array 6 + for (i = 0; i != 10; i++) { + f->writeUint16BE(itemPtrToID(_itemStore[i])); + } + + // Write the bits in array 1 + for (i = 0; i != 16; i++) + f->writeUint16BE(_bitArray[i]); + + // Write the bits in array 2 + for (i = 0; i != 16; i++) + f->writeUint16BE(_bitArrayTwo[i]); + + // Write the bits in array 3 + if (getGameType() == GType_FF) { + for (i = 0; i != 16; i++) + f->writeUint16BE(_bitArrayThree[i]); + } + + f->flush(); + bool result = !f->ioFailed(); + + delete f; + _lockWord &= ~0x100; + + return result; +} + +bool SimonEngine::loadGame(uint slot) { + char ident[100]; + Common::SeekableReadStream *f = NULL; + uint num, item_index, i, j; + + _lockWord |= 0x100; + + if (getGameType() == GType_FF && slot == 999) { + // Load restart state + Common::File *file = new Common::File(); + file->open(genSaveName(slot), Common::File::kFileReadMode); + if (!file->isOpen()) { + delete file; + } else { + f = file; + } + } else { + f = _saveFileMan->openForLoading(genSaveName(slot)); + } + + if (f == NULL) { + warning("loadGame: Failed to load slot %d", slot); + _lockWord &= ~0x100; + return false; + } + + if (getGameType() == GType_FF) { + f->read(ident, 100); + } else { + f->read(ident, 18); + } + + num = f->readUint32BE(); + + if (f->readUint32BE() != 0xFFFFFFFF || num != _itemArrayInited - 1) { + delete f; + _lockWord &= ~0x100; + return false; + } + + f->readUint32BE(); + f->readUint32BE(); + _noParentNotify = true; + + + // add all timers + killAllTimers(); + for (num = f->readUint32BE(); num; num--) { + uint32 timeout = f->readUint32BE(); + uint16 func_to_call = f->readUint16BE(); + addTimeEvent(timeout, func_to_call); + } + + item_index = 1; + for (num = _itemArrayInited - 1; num; num--) { + Item *item = _itemArrayPtr[item_index++], *parent_item; + + uint parent = f->readUint16BE(); + uint sibling = f->readUint16BE(); + + parent_item = derefItem(parent); + + setItemParent(item, parent_item); + + if (parent_item == NULL) { + item->parent = parent; + item->sibling = sibling; + } + + item->state = f->readUint16BE(); + item->classFlags = f->readUint16BE(); + + SubRoom *subRoom = (SubRoom *)findChildOfType(item, 1); + if (subRoom != NULL) { + subRoom->roomExitStates = f->readUint16BE(); + } + + SubObject *subObject = (SubObject *)findChildOfType(item, 2); + if (subObject != NULL) { + subObject->objectFlags = f->readUint32BE(); + i = subObject->objectFlags & 1; + + for (j = 1; j < 16; j++) { + if (subObject->objectFlags & (1 << j)) { + subObject->objectFlagValue[i++] = f->readUint16BE(); + } + } + } + + SubUserFlag *subUserFlag = (SubUserFlag *) findChildOfType(item, 9); + if (subUserFlag) { + for (i = 0; i != 4; i++) { + subUserFlag->userFlags[i] = f->readUint16BE(); + } + } + } + + + // read the 255 variables + for (i = 0; i != 255; i++) { + writeVariable(i, f->readUint16BE()); + } + + // read the items in array 6 + for (i = 0; i != 10; i++) { + _itemStore[i] = derefItem(f->readUint16BE()); + } + + // Read the bits in array 1 + for (i = 0; i != 16; i++) + _bitArray[i] = f->readUint16BE(); + + // Read the bits in array 2 + for (i = 0; i != 16; i++) + _bitArrayTwo[i] = f->readUint16BE(); + + // Read the bits in array 3 + if (getGameType() == GType_FF) { + for (i = 0; i != 16; i++) + _bitArrayThree[i] = f->readUint16BE(); + } + + if (f->ioFailed()) { + error("load failed"); + } + + delete f; + + _noParentNotify = false; + + _lockWord &= ~0x100; + + return true; +} + +} // End of namespace Simon |