diff options
Diffstat (limited to 'engines/simon/saveload.cpp')
-rw-r--r-- | engines/simon/saveload.cpp | 634 |
1 files changed, 634 insertions, 0 deletions
diff --git a/engines/simon/saveload.cpp b/engines/simon/saveload.cpp new file mode 100644 index 0000000000..9314a4bfca --- /dev/null +++ b/engines/simon/saveload.cpp @@ -0,0 +1,634 @@ +/* ScummVM - Scumm Interpreter + * 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 "gui/about.h" +#include "gui/message.h" + +#include "simon/simon.h" +#include "simon/intern.h" + +#include "common/savefile.h" +#include "common/system.h" + +namespace Simon { + +void SimonEngine::o_saveGame() { + saveOrLoadDialog(false); +} + +void SimonEngine::o_loadGame() { + saveOrLoadDialog(true); +} + +int SimonEngine::countSaveGames() { + Common::InSaveFile *f; + uint i = 1; + bool marks[256]; + + char *prefix = gen_savename(999); + prefix[strlen(prefix)-3] = '\0'; + _saveFileMan->listSavefiles(prefix, marks, 256); + + while (i < 256) { + if (marks[i] && + (f = _saveFileMan->openForLoading(gen_savename(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, 18 * 6); + + slot = curpos; + + while (curpos + 6 > slot) { + if (!(in = _saveFileMan->openForLoading(gen_savename(slot)))) + break; + + in->read(dst, 18); + delete in; + last_slot = slot; + if (slot < 10) + showMessageFormat(" "); + showMessageFormat("%d", 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(gen_savename(slot)))) { + slot++; + delete in; + } + } + } + + return slot - curpos; +} + +void SimonEngine::quickLoadOrSave() { + // simon1demo subroutines are missing too many segments + // original demo didn't allow load or save either. + if (getGameId() == GID_SIMON1DEMO) + return; + + bool success; + char buf[50]; + + char *filename = gen_savename(_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, getItem1Ptr(), 0, 0); + mouseOn(); + // Reset engine? + vcSetBitTo(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::saveGameDialog(char *buf) { + int i; + + o_unk_132_helper_3(); + + i = displaySaveGameList(_saveLoadRowCurPos, _saveOrLoad, buf); + + _saveDialogFlag = true; + + if (i != 7) { + i++; + if (!_saveOrLoad) + i++; + _saveDialogFlag = false; + } + + if (!--i) + return; + + do { + clear_hitarea_bit_0x40(0xd0 + i - 1); + } while (--i); +} + +void SimonEngine::saveOrLoadDialog(bool load) { + time_t save_time; + int number_of_savegames; + int i; + int unk132_result; + FillOrCopyStruct *fcs; + char *name; + int name_len; + bool b; + char buf[108]; + + _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; + + _saveLoadFlag = false; + +restart:; + do { + i = o_unk_132_helper(&b, buf); + } while (!b); + + if (i == 205) + goto get_out; + if (!load) { + // if_1 + if_1:; + unk132_result = i; + + set_hitarea_bit_0x40(0xd0 + i); + leaveHitAreaById(0xd0 + i); + + // some code here + + fcs = _windowArray[5]; + + fcs->textRow = unk132_result; + + if (_language == Common::HB_ISR) { //Hebrew + // init x offset with a 2 character savegame number + a period (18 pix) + fcs->textColumn = 3; + fcs->textColumnOffset = 6; + fcs->textLength = 3; + } else { + // init x offset with a 2 character savegame number + a period (18 pix) + fcs->textColumn = 2; + fcs->textColumnOffset = 2; + fcs->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) { //Hebrew + byte width = 6; + if (name[name_len] >= 64 && name[name_len] < 91) + width = _hebrew_char_widths [name[name_len] - 64]; + fcs->textLength++; + fcs->textColumnOffset -= width; + if (fcs->textColumnOffset < width) { + fcs->textColumnOffset += 8; + fcs->textColumn++; + } + } else { + fcs->textLength++; + fcs->textColumnOffset += 6; + if (name[name_len] == 'i' || name[name_len] == 'l') + fcs->textColumnOffset -= 2; + if (fcs->textColumnOffset >= 8) { + fcs->textColumnOffset -= 8; + fcs->textColumn++; + } + } + name_len++; + } + // while_1_end + + // do_3_start + for (;;) { + video_putchar(fcs, 0x7f); + + _saveLoadFlag = true; + + // do_2 + do { + i = o_unk_132_helper(&b, buf); + + if (b) { + if (i == 205) + goto get_out; + clear_hitarea_bit_0x40(0xd0 + unk132_result); + if (_saveLoadFlag) { + o_clearCharacter(_windowArray[5], 8); + // move code + } + goto if_1; + } + + // is_not_b + if (!_saveLoadFlag) { + clear_hitarea_bit_0x40(0xd0 + unk132_result); + goto restart; + } + } while (i >= 0x80 || i == 0); + + // after_do_2 + o_clearCharacter(_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) //Hebrew + x = 8; + else + x = (name[name_len] == 'i' || name[name_len] == 'l') ? 1 : 8; + + name[name_len] = 0; + + o_clearCharacter(_windowArray[5], x, m); + } + } else if (i >= 32 && name_len != 17) { + name[name_len++] = i; + + video_putchar(_windowArray[5], i); + } + } + + // do_save + if (!saveGame(_saveLoadRowCurPos + unk132_result, buf + unk132_result * 18)) + o_fileError(_windowArray[5], true); + } else { + if (!loadGame(_saveLoadRowCurPos + i)) + o_fileError(_windowArray[5], false); + } + +get_out:; + o_unk_132_helper_3(); + + _base_time = time(NULL) - save_time + _base_time; + _copyPartialMode = 0; + + dx_copy_rgn_from_3_to_2(94, 208, 46, 80); + + i = _timer4; + do { + delay(10); + } while (i == _timer4); + + g_system->setFeatureState(OSystem::kFeatureVirtualKeyboard, false); +} + +void SimonEngine::o_fileError(FillOrCopyStruct *fcs, bool save_error) { + HitArea *ha; + const char *string, *string2; + + if (save_error) { + string = "\r Save failed."; + string2 = "\r Disk error."; + } else { + string = "\r Load failed."; + string2 = "\r File not found."; + } + + video_putchar(fcs, 0xC); + for (; *string; string++) + video_putchar(fcs, *string); + for (; *string2; string2++) + video_putchar(fcs, *string2); + + fcs->textColumn = (fcs->width >> 1) - 3; + fcs->textRow = fcs->height - 1; + fcs->textLength = 0; + + string = "[ OK ]"; + for (; *string; string++) + video_putchar(fcs, *string); + + ha = findEmptyHitArea(); + ha->x = ((fcs->width >> 1) + (fcs->x - 3)) << 3; + ha->y = (fcs->height << 3) + fcs->y - 8; + ha->width = 48; + ha->height = 8; + ha->flags = 0x20; + ha->id = 0x7FFF; + ha->layer = 0x3EF; + +loop:; + _lastHitArea = _lastHitArea3 = 0; + + do { + delay(1); + } while (_lastHitArea3 == 0); + + ha = _lastHitArea; + if (ha == NULL || ha->id != 0x7FFF) + goto loop; + + // Return + delete_hitarea(0x7FFF); +} + +bool SimonEngine::saveGame(uint slot, char *caption) { + Common::OutSaveFile *f; + uint item_index, num_item, i, j; + TimeEvent *te; + + _lockWord |= 0x100; + + f = _saveFileMan->openForSaving(gen_savename(slot)); + if (f == NULL) { + _lockWord &= ~0x100; + return false; + } + + if (getGameType() == GType_FF) { + f->write(caption, 100); + } 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); + + for (te = _firstTimeStruct; te; te = te->next) { + f->writeUint32BE(te->time + _base_time); + 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); + + Child1 *child1 = (Child1 *)findChildOfType(item, 1); + if (child1) { + f->writeUint16BE(child1->fr2); + } + + Child2 *child2 = (Child2 *)findChildOfType(item, 2); + if (child2) { + f->writeUint32BE(child2->avail_props); + i = child2->avail_props & 1; + + for (j = 1; j < 16; j++) { + if ((1 << j) & child2->avail_props) { + f->writeUint16BE(child2->array[i++]); + } + } + } + + Child9 *child9 = (Child9 *)findChildOfType(item, 9); + if (child9) { + for (i = 0; i != 4; i++) { + f->writeUint16BE(child9->array[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(_itemArray6[i])); + } + + // Write the bits in array 1 & 2 + for (i = 0; i != 32; i++) + f->writeUint16BE(_bitArray[i]); + + // Write the bits in array 3 + if (getGameType() == GType_FF) { + for (i = 33; i != 48; i++) + f->writeUint16BE(_bitArray[i]); + } + + f->flush(); + bool result = !f->ioFailed(); + + delete f; + _lockWord &= ~0x100; + + return result; +} + +char *SimonEngine::gen_savename(int slot) { + static char buf[15]; + + if (getGameType() == GType_FF) { + if (slot == 999) + sprintf(buf, "save.%.3d", slot); + else + sprintf(buf, "feeble.%.3d", slot); + } else if (getGameType() == GType_SIMON2) { + sprintf(buf, "simon2.%.3d", slot); + } else { + sprintf(buf, "simon1.%.3d", slot); + } + return buf; +} + +bool SimonEngine::loadGame(uint slot) { + char ident[100]; + Common::InSaveFile *f; + uint num, item_index, i, j; + + _lockWord |= 0x100; + + f = _saveFileMan->openForLoading(gen_savename(slot)); + if (f == NULL) { + _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(); + + Child1 *child1 = (Child1 *)findChildOfType(item, 1); + if (child1 != NULL) { + child1->fr2 = f->readUint16BE(); + } + + Child2 *child2 = (Child2 *)findChildOfType(item, 2); + if (child2 != NULL) { + child2->avail_props = f->readUint32BE(); + i = child2->avail_props & 1; + + for (j = 1; j < 16; j++) { + if ((1 << j) & child2->avail_props) { + child2->array[i++] = f->readUint16BE(); + } + } + } + + Child9 *child9 = (Child9 *) findChildOfType(item, 9); + if (child9) { + for (i = 0; i != 4; i++) { + child9->array[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++) { + _itemArray6[i] = derefItem(f->readUint16BE()); + } + + // Read the bits in array 1 & 2 + for (i = 0; i != 32; i++) + _bitArray[i] = f->readUint16BE(); + + // Read the bits in array 3 + if (getGameType() == GType_FF) { + for (i = 33; i != 48; i++) + _bitArray[i] = f->readUint16BE(); + } + + if (f->ioFailed()) { + error("load failed"); + } + + delete f; + + _noParentNotify = false; + + _lockWord &= ~0x100; + + return true; +} + +} // End of namespace Simon |