diff options
Diffstat (limited to 'engines/wage')
-rw-r--r-- | engines/wage/design.cpp | 95 | ||||
-rw-r--r-- | engines/wage/design.h | 15 | ||||
-rw-r--r-- | engines/wage/detection.cpp | 6 | ||||
-rw-r--r-- | engines/wage/dialog.cpp | 2 | ||||
-rw-r--r-- | engines/wage/entities.cpp | 10 | ||||
-rw-r--r-- | engines/wage/entities.h | 6 | ||||
-rw-r--r-- | engines/wage/gui.cpp | 19 | ||||
-rw-r--r-- | engines/wage/macmenu.cpp | 5 | ||||
-rw-r--r-- | engines/wage/macwindow.cpp | 8 | ||||
-rw-r--r-- | engines/wage/macwindowmanager.cpp | 85 | ||||
-rw-r--r-- | engines/wage/module.mk | 1 | ||||
-rw-r--r-- | engines/wage/saveload.cpp | 770 | ||||
-rw-r--r-- | engines/wage/wage.cpp | 12 | ||||
-rw-r--r-- | engines/wage/wage.h | 17 | ||||
-rw-r--r-- | engines/wage/world.cpp | 16 | ||||
-rw-r--r-- | engines/wage/world.h | 3 |
16 files changed, 920 insertions, 150 deletions
diff --git a/engines/wage/design.cpp b/engines/wage/design.cpp index eda28df159..2bfea9df7d 100644 --- a/engines/wage/design.cpp +++ b/engines/wage/design.cpp @@ -422,7 +422,7 @@ void Design::drawBitmap(Graphics::ManagedSurface *surface, Common::SeekableReadS int x2 = in.readSint16BE(); int w = x2 - x1; int h = y2 - y1; - Graphics::ManagedSurface tmp; + Graphics::Surface tmp; tmp.create(w, h, Graphics::PixelFormat::createFormatCLUT8()); @@ -474,28 +474,27 @@ void Design::drawBitmap(Graphics::ManagedSurface *surface, Common::SeekableReadS in.skip(numBytes); - if (_boundsCalculationMode) - return; - - FloodFill ff(&tmp, kColorWhite, kColorGreen); - for (int yy = 0; yy < h; yy++) { - ff.addSeed(0, yy); - ff.addSeed(w - 1, yy); - } - for (int xx = 0; xx < w; xx++) { - ff.addSeed(xx, 0); - ff.addSeed(xx, h - 1); - } - ff.fill(); - - for (y = 0; y < h && y1 + y < surface->h; y++) { - byte *src = (byte *)tmp.getBasePtr(0, y); - byte *dst = (byte *)surface->getBasePtr(x1, y1 + y); - for (x = 0; x < w; x++) { - if (*src != kColorGreen) - *dst = *src; - src++; - dst++; + if (!_boundsCalculationMode) { + Graphics::FloodFill ff(&tmp, kColorWhite, kColorGreen); + for (int yy = 0; yy < h; yy++) { + ff.addSeed(0, yy); + ff.addSeed(w - 1, yy); + } + for (int xx = 0; xx < w; xx++) { + ff.addSeed(xx, 0); + ff.addSeed(xx, h - 1); + } + ff.fill(); + + for (y = 0; y < h && y1 + y < surface->h; y++) { + byte *src = (byte *)tmp.getBasePtr(0, y); + byte *dst = (byte *)surface->getBasePtr(x1, y1 + y); + for (x = 0; x < w; x++) { + if (*src != kColorGreen) + *dst = *src; + src++; + dst++; + } } } @@ -541,54 +540,4 @@ void Design::drawVLine(Graphics::ManagedSurface *surface, int x, int y1, int y2, Graphics::drawVLine(x, y1, y2, color, drawPixel, &pd); } -FloodFill::FloodFill(Graphics::ManagedSurface *surface, byte color1, byte color2) { - _surface = surface; - _color1 = color1; - _color2 = color2; - _w = surface->w; - _h = surface->h; - - _visited = (byte *)calloc(_w * _h, 1); -} - -FloodFill::~FloodFill() { - while(!_queue.empty()) { - Common::Point *p = _queue.front(); - - delete p; - _queue.pop_front(); - } - - free(_visited); -} - -void FloodFill::addSeed(int x, int y) { - byte *p; - - if (x >= 0 && x < _w && y >= 0 && y < _h) { - if (!_visited[y * _w + x] && *(p = (byte *)_surface->getBasePtr(x, y)) == _color1) { - _visited[y * _w + x] = 1; - *p = _color2; - - Common::Point *pt = new Common::Point(x, y); - - _queue.push_back(pt); - } - } -} - -void FloodFill::fill() { - while (!_queue.empty()) { - Common::Point *p = _queue.front(); - _queue.pop_front(); - addSeed(p->x , p->y - 1); - addSeed(p->x - 1, p->y ); - addSeed(p->x , p->y + 1); - addSeed(p->x + 1, p->y ); - - delete p; - } -} - - } // End of namespace Wage diff --git a/engines/wage/design.h b/engines/wage/design.h index 9b0231ca96..86225c9224 100644 --- a/engines/wage/design.h +++ b/engines/wage/design.h @@ -100,21 +100,6 @@ private: void drawBitmap(Graphics::ManagedSurface *surface, Common::SeekableReadStream &in); }; -class FloodFill { -public: - FloodFill(Graphics::ManagedSurface *surface, byte color1, byte color2); - ~FloodFill(); - void addSeed(int x, int y); - void fill(); - -private: - Common::List<Common::Point *> _queue; - Graphics::ManagedSurface *_surface; - byte _color1, _color2; - byte *_visited; - int _w, _h; -}; - } // End of namespace Wage #endif diff --git a/engines/wage/detection.cpp b/engines/wage/detection.cpp index 1b418b5aa8..e14a952588 100644 --- a/engines/wage/detection.cpp +++ b/engines/wage/detection.cpp @@ -101,7 +101,7 @@ SaveStateList WageMetaEngine::listSaves(const char *target) const { Common::StringArray filenames; char saveDesc[31]; Common::String pattern = target; - pattern += ".???"; + pattern += ".###"; filenames = saveFileMan->listSavefiles(pattern); @@ -142,11 +142,11 @@ void WageMetaEngine::removeSaveState(const char *target, int slot) const { namespace Wage { bool WageEngine::canLoadGameStateCurrently() { - return false; + return true; } bool WageEngine::canSaveGameStateCurrently() { - return false; + return true; } } // End of namespace Wage diff --git a/engines/wage/dialog.cpp b/engines/wage/dialog.cpp index d9bb3e6a61..86080c9a6f 100644 --- a/engines/wage/dialog.cpp +++ b/engines/wage/dialog.cpp @@ -86,6 +86,8 @@ Dialog::Dialog(Gui *gui, int width, const char *text, DialogButtonArray *buttons } Dialog::~Dialog() { + for (uint i = 0; i < _buttons->size(); i++) + delete _buttons->operator[](i); } const Graphics::Font *Dialog::getDialogFont() { diff --git a/engines/wage/entities.cpp b/engines/wage/entities.cpp index 43ac6c8cc7..b2babbab4d 100644 --- a/engines/wage/entities.cpp +++ b/engines/wage/entities.cpp @@ -80,6 +80,8 @@ Context::Context() { } Scene::Scene() { + _resourceId = 0; + _script = NULL; _design = NULL; _textBounds = NULL; @@ -104,6 +106,8 @@ Scene::Scene(Common::String name, Common::SeekableReadStream *data) { _classType = SCENE; _design = new Design(data); + _resourceId = 0; + _script = NULL; _textBounds = NULL; _fontSize = 0; @@ -221,6 +225,7 @@ Designed *Scene::lookUpEntity(int x, int y) { Obj::Obj() : _currentOwner(NULL), _currentScene(NULL) { _index = 0; + _resourceId = 0; _namePlural = false; _value = 0; _attackType = 0; @@ -231,7 +236,9 @@ Obj::Obj() : _currentOwner(NULL), _currentScene(NULL) { _damage = 0; } -Obj::Obj(Common::String name, Common::SeekableReadStream *data) { +Obj::Obj(Common::String name, Common::SeekableReadStream *data, int resourceId) { + _resourceId = resourceId; + _name = name; _classType = OBJ; _currentOwner = NULL; @@ -322,6 +329,7 @@ Chr::Chr(Common::String name, Common::SeekableReadStream *data) { _design = new Design(data); _index = 0; + _resourceId = 0; _currentScene = NULL; setDesignBounds(readRect(data)); diff --git a/engines/wage/entities.h b/engines/wage/entities.h index 9e706f0d58..f327270254 100644 --- a/engines/wage/entities.h +++ b/engines/wage/entities.h @@ -152,6 +152,7 @@ public: Chr(Common::String name, Common::SeekableReadStream *data); int _index; + int _resourceId; Common::String _initialScene; int _gender; bool _nameProperNoun; @@ -229,7 +230,7 @@ public: class Obj : public Designed { public: Obj(); - Obj(Common::String name, Common::SeekableReadStream *data); + Obj(Common::String name, Common::SeekableReadStream *data, int resourceId); ~Obj(); enum ObjectType { @@ -256,6 +257,7 @@ public: public: int _index; + int _resourceId; bool _namePlural; uint _value; int _attackType; @@ -301,6 +303,8 @@ public: RANDOM = 1 }; + int _resourceId; + Script *_script; Common::String _text; Common::Rect *_textBounds; diff --git a/engines/wage/gui.cpp b/engines/wage/gui.cpp index 310e5734b7..cdc646f649 100644 --- a/engines/wage/gui.cpp +++ b/engines/wage/gui.cpp @@ -65,9 +65,9 @@ static const MenuData menuSubItems[] = { { kMenuHighLevel, "File", 0, 0, false }, { kMenuHighLevel, "Edit", 0, 0, false }, { kMenuFile, "New", kMenuActionNew, 0, false }, - { kMenuFile, "Open...", kMenuActionOpen, 0, false }, + { kMenuFile, "Open...", kMenuActionOpen, 0, true }, { kMenuFile, "Close", kMenuActionClose, 0, true }, - { kMenuFile, "Save", kMenuActionSave, 0, false }, + { kMenuFile, "Save", kMenuActionSave, 0, true }, { kMenuFile, "Save as...", kMenuActionSaveAs, 0, true }, { kMenuFile, "Revert", kMenuActionRevert, 0, false }, { kMenuFile, "Quit", kMenuActionQuit, 0, true }, @@ -83,7 +83,7 @@ static const MenuData menuSubItems[] = { }; static void cursorTimerHandler(void *refCon) { - Gui *gui = (Gui *)refCon; + Gui *gui = (Gui *)refCon; int x = gui->_cursorX; int y = gui->_cursorY; @@ -323,12 +323,19 @@ void Gui::executeMenuCommand(int action, Common::String &text) { switch(action) { case kMenuActionAbout: case kMenuActionNew: - case kMenuActionOpen: case kMenuActionClose: - case kMenuActionSave: - case kMenuActionSaveAs: case kMenuActionRevert: case kMenuActionQuit: + break; + + case kMenuActionOpen: + _engine->scummVMSaveLoadDialog(false); + break; + + case kMenuActionSave: + case kMenuActionSaveAs: + _engine->scummVMSaveLoadDialog(true); + break; case kMenuActionUndo: actionUndo(); diff --git a/engines/wage/macmenu.cpp b/engines/wage/macmenu.cpp index a97e442c83..b29903c674 100644 --- a/engines/wage/macmenu.cpp +++ b/engines/wage/macmenu.cpp @@ -104,6 +104,9 @@ Menu::Menu(int id, const Common::Rect &bounds, MacWindowManager *wm) _activeItem = -1; _activeSubItem = -1; + _ccallback = NULL; + _cdata = NULL; + _tempSurface.create(_screen.w, _font->getFontHeight(), Graphics::PixelFormat::createFormatCLUT8()); } @@ -142,6 +145,8 @@ int Menu::addMenuItem(const char *name) { void Menu::addMenuSubItem(int id, const char *text, int action, int style, char shortcut, bool enabled) { _items[id]->subitems.push_back(new MenuSubItem(text, action, style, shortcut, enabled)); + + calcMenuBounds(_items[id]); } void Menu::calcDimensions() { diff --git a/engines/wage/macwindow.cpp b/engines/wage/macwindow.cpp index 7ff0f57ccb..db8ef38c39 100644 --- a/engines/wage/macwindow.cpp +++ b/engines/wage/macwindow.cpp @@ -76,6 +76,8 @@ MacWindow::MacWindow(int id, bool scrollable, bool resizable, bool editable, Mac _beingDragged = false; _beingResized = false; + _draggedX = _draggedY = 0; + _type = kWindowWindow; } @@ -262,16 +264,16 @@ void MacWindow::setHighlight(WindowClick highlightedPart) { _highlightedPart = highlightedPart; _borderIsDirty = true; - } +} - void MacWindow::setScroll(float scrollPos, float scrollSize) { +void MacWindow::setScroll(float scrollPos, float scrollSize) { if (_scrollPos == scrollPos && _scrollSize == scrollSize) return; _scrollPos = scrollPos; _scrollSize = scrollSize; _borderIsDirty = true; - } +} void MacWindow::drawBox(Graphics::ManagedSurface *g, int x, int y, int w, int h) { diff --git a/engines/wage/macwindowmanager.cpp b/engines/wage/macwindowmanager.cpp index 5cc54d648a..6ca2efd7c9 100644 --- a/engines/wage/macwindowmanager.cpp +++ b/engines/wage/macwindowmanager.cpp @@ -117,9 +117,9 @@ static const byte macCursorBeam[] = { }; MacWindowManager::MacWindowManager() { - _screen = 0; - _lastId = 0; - _activeWindow = -1; + _screen = 0; + _lastId = 0; + _activeWindow = -1; _menu = 0; @@ -141,21 +141,21 @@ MacWindowManager::MacWindowManager() { } MacWindowManager::~MacWindowManager() { - for (int i = 0; i < _lastId; i++) - delete _windows[i]; + for (int i = 0; i < _lastId; i++) + delete _windows[i]; } MacWindow *MacWindowManager::addWindow(bool scrollable, bool resizable, bool editable) { - MacWindow *w = new MacWindow(_lastId, scrollable, resizable, editable, this); + MacWindow *w = new MacWindow(_lastId, scrollable, resizable, editable, this); - _windows.push_back(w); - _windowStack.push_back(w); + _windows.push_back(w); + _windowStack.push_back(w); - setActive(_lastId); + setActive(_lastId); - _lastId++; + _lastId++; - return w; + return w; } Menu *MacWindowManager::addMenu() { @@ -169,20 +169,20 @@ Menu *MacWindowManager::addMenu() { } void MacWindowManager::setActive(int id) { - if (_activeWindow == id) - return; + if (_activeWindow == id) + return; - if (_activeWindow != -1) - _windows[_activeWindow]->setActive(false); + if (_activeWindow != -1) + _windows[_activeWindow]->setActive(false); - _activeWindow = id; + _activeWindow = id; - _windows[id]->setActive(true); + _windows[id]->setActive(true); - _windowStack.remove(_windows[id]); - _windowStack.push_back(_windows[id]); + _windowStack.remove(_windows[id]); + _windowStack.push_back(_windows[id]); - _fullRefresh = true; + _fullRefresh = true; } struct PlotData { @@ -241,28 +241,28 @@ void MacWindowManager::drawDesktop() { } void MacWindowManager::draw() { - assert(_screen); + assert(_screen); if (_fullRefresh) drawDesktop(); - for (Common::List<BaseMacWindow *>::const_iterator it = _windowStack.begin(); it != _windowStack.end(); it++) { - BaseMacWindow *w = *it; - if (w->draw(_screen, _fullRefresh)) { - w->setDirty(false); + for (Common::List<BaseMacWindow *>::const_iterator it = _windowStack.begin(); it != _windowStack.end(); it++) { + BaseMacWindow *w = *it; + if (w->draw(_screen, _fullRefresh)) { + w->setDirty(false); Common::Rect clip(w->getDimensions().left - 2, w->getDimensions().top - 2, w->getDimensions().right - 2, w->getDimensions().bottom - 2); clip.clip(_screen->getBounds()); - g_system->copyRectToScreen(_screen->getBasePtr(clip.left, clip.top), _screen->pitch, clip.left, clip.top, clip.width(), clip.height()); - } - } + g_system->copyRectToScreen(_screen->getBasePtr(clip.left, clip.top), _screen->pitch, clip.left, clip.top, clip.width(), clip.height()); + } + } // Menu is drawn on top of everything and always if (_menu) _menu->draw(_screen, _fullRefresh); - _fullRefresh = false; + _fullRefresh = false; } bool MacWindowManager::processEvent(Common::Event &event) { @@ -270,9 +270,9 @@ bool MacWindowManager::processEvent(Common::Event &event) { if (_menu && _menu->processEvent(event)) return true; - if (event.type != Common::EVENT_MOUSEMOVE && event.type != Common::EVENT_LBUTTONDOWN && - event.type != Common::EVENT_LBUTTONUP) - return false; + if (event.type != Common::EVENT_MOUSEMOVE && event.type != Common::EVENT_LBUTTONDOWN && + event.type != Common::EVENT_LBUTTONUP) + return false; if (_windows[_activeWindow]->isEditable() && _windows[_activeWindow]->getType() == kWindowWindow && ((MacWindow *)_windows[_activeWindow])->getInnerDimensions().contains(event.mouse.x, event.mouse.y)) { @@ -287,19 +287,19 @@ bool MacWindowManager::processEvent(Common::Event &event) { } } - for (Common::List<BaseMacWindow *>::const_iterator it = _windowStack.end(); it != _windowStack.begin();) { - it--; - BaseMacWindow *w = *it; + for (Common::List<BaseMacWindow *>::const_iterator it = _windowStack.end(); it != _windowStack.begin();) { + it--; + BaseMacWindow *w = *it; - if (w->hasAllFocus() || w->getDimensions().contains(event.mouse.x, event.mouse.y)) { - if (event.type == Common::EVENT_LBUTTONDOWN || event.type == Common::EVENT_LBUTTONUP) - setActive(w->getId()); + if (w->hasAllFocus() || w->getDimensions().contains(event.mouse.x, event.mouse.y)) { + if (event.type == Common::EVENT_LBUTTONDOWN || event.type == Common::EVENT_LBUTTONUP) + setActive(w->getId()); - return w->processEvent(event); - } - } + return w->processEvent(event); + } + } - return false; + return false; } ////////////////////// @@ -376,5 +376,4 @@ void MacWindowManager::popCursor() { CursorMan.popCursor(); } - } // End of namespace Wage diff --git a/engines/wage/module.mk b/engines/wage/module.mk index e150d5f27e..1f397b5a71 100644 --- a/engines/wage/module.mk +++ b/engines/wage/module.mk @@ -13,6 +13,7 @@ MODULE_OBJS := \ macwindow.o \ macwindowmanager.o \ randomhat.o \ + saveload.o \ script.o \ sound.o \ util.o \ diff --git a/engines/wage/saveload.cpp b/engines/wage/saveload.cpp new file mode 100644 index 0000000000..78e8d389d3 --- /dev/null +++ b/engines/wage/saveload.cpp @@ -0,0 +1,770 @@ +/* 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. + * + * MIT License: + * + * Copyright (c) 2009 Alexei Svitkine, Eugene Sandulenko + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + */ + +#include "common/file.h" +#include "common/debug.h" +#include "common/debug-channels.h" +#include "common/config-manager.h" +#include "common/savefile.h" +#include "common/system.h" +#include "common/textconsole.h" +#include "common/translation.h" + +#include "gui/saveload.h" + +#include "graphics/thumbnail.h" +#include "graphics/surface.h" + +#include "wage/wage.h" +#include "wage/world.h" +#include "wage/entities.h" + +#define SAVEGAME_CURRENT_VERSION 1 + +// +// Original saves format is supported. +// ScummVM adds flags, description and thumbnail +// in the end of the file (shouldn't make saves incompatible). +// +// Version 0 (original/ScummVM): first ScummVM version +// + +namespace Wage { + +static const uint32 WAGEflag = MKTAG('W', 'A', 'G', 'E'); + +//TODO: make sure these are calculated right: (we add flag, description, etc) +#define VARS_INDEX 0x005E +#define SCENES_INDEX 0x0232 + +#define SCENE_SIZE 0x0010 +#define CHR_SIZE 0x0016 +#define OBJ_SIZE 0x0010 + +#define GET_HEX_OFFSET(ptr, baseOffset, entrySize) ((ptr) == nullptr ? -1 : ((baseOffset) + (entrySize) * (ptr)->_index)) +#define GET_HEX_CHR_OFFSET(ptr) GET_HEX_OFFSET((ptr), chrsHexOffset, CHR_SIZE) +#define GET_HEX_OBJ_OFFSET(ptr) GET_HEX_OFFSET((ptr), objsHexOffset, OBJ_SIZE) +#define GET_HEX_SCENE_OFFSET(ptr) ((ptr) == nullptr ? -1 : \ + ((ptr) == _world->_storageScene ? 0 : (SCENES_INDEX + getSceneIndex(_world->_player->_currentScene) * SCENE_SIZE))) + +int WageEngine::getSceneIndex(Scene *scene) const { + assert(scene); + Common::Array<Scene *> &orderedScenes = _world->_orderedScenes; + for (uint32 i = 0; i < orderedScenes.size(); ++i) { + if (orderedScenes[i] == scene) return i-1; + } + + warning("Scene's index not found"); + return -1; +} + +Obj *WageEngine::getObjByOffset(int offset, int objBaseOffset) const { + int objIndex = -1; + + if (offset != 0xFFFF) { + objIndex = (offset - objBaseOffset) / CHR_SIZE; + } + + if (objIndex >= 0 && objIndex < _world->_orderedObjs.size()) { + return _world->_orderedObjs[objIndex]; + } + + return nullptr; +} + +Chr *WageEngine::getChrById(int resId) const { + Common::Array<Chr *> &orderedChrs = _world->_orderedChrs; + for (uint32 i = 0; i < orderedChrs.size(); ++i) { + if (orderedChrs[i]->_resourceId == resId) + return orderedChrs[i]; + } + + return nullptr; +} + +Chr *WageEngine::getChrByOffset(int offset, int chrBaseOffset) const { + int chrIndex = -1; + + if (offset != 0xFFFF) { + chrIndex = (offset - chrBaseOffset) / CHR_SIZE; + } + + if (chrIndex >= 0 && chrIndex < _world->_orderedChrs.size()) { + return _world->_orderedChrs[chrIndex]; + } + + return nullptr; +} + +Scene *WageEngine::getSceneById(int resId) const { + Common::Array<Scene *> &orderedScenes = _world->_orderedScenes; + for (uint32 i = 0; i < orderedScenes.size(); ++i) { + if (orderedScenes[i]->_resourceId == resId) + return orderedScenes[i]; + } + + return nullptr; +} + +Scene *WageEngine::getSceneByOffset(int offset) const { + int sceneIndex = -1; + + if (offset != 0xFFFF) { + if (offset == 0) + sceneIndex = 0; + else + sceneIndex = 1 + (offset - SCENES_INDEX) / SCENE_SIZE; + } + + if (sceneIndex >= 0 && sceneIndex < _world->_orderedScenes.size()) { + if (sceneIndex == 0) return _world->_storageScene; + return _world->_orderedScenes[sceneIndex]; + } + + return nullptr; +} + +int WageEngine::saveGame(const Common::String &fileName, const Common::String &descriptionString) { + Common::OutSaveFile *out; + int result = 0; + + debug(9, "WageEngine::saveGame(%s, %s)", fileName.c_str(), descriptionString.c_str()); + if (!(out = _saveFileMan->openForSaving(fileName))) { + warning("Can't create file '%s', game not saved", fileName.c_str()); + return -1; + } else { + debug(9, "Successfully opened %s for writing", fileName.c_str()); + } + + // Counters + out->writeSint16LE(_world->_scenes.size()); //numScenes + out->writeSint16LE(_world->_chrs.size()); //numChars + out->writeSint16LE(_world->_objs.size()); //numObjs + + // Hex Offsets + int chrsHexOffset = SCENES_INDEX + _world->_scenes.size() * SCENE_SIZE; //chrs start after scenes + int objsHexOffset = chrsHexOffset + _world->_chrs.size() * CHR_SIZE; //objs start after chrs + out->writeSint32LE(chrsHexOffset); + out->writeSint32LE(objsHexOffset); + + // Unique 8-byte World Signature + out->writeSint32LE(_world->_signature); //8-byte ints? seriously? (uses 4 bytes in java code too) + + Chr *player = _world->_player; + Context &playerContext = player->_context; + + // More Counters + out->writeSint32LE(playerContext._visits); //visitNum + out->writeSint32LE(_loopCount); //loopNum + out->writeSint32LE(playerContext._kills); //killNum + + // Hex offset to player character + out->writeSint32LE(GET_HEX_CHR_OFFSET(player)); //getPlayerHexOffset() == getHexOffsetForChr(player) + + // character in this scene? + out->writeSint32LE(GET_HEX_CHR_OFFSET(_monster)); //getPresCharHexOffset() == getHexOffsetForChr(monster) + + // Hex offset to current scene + out->writeSint32LE(GET_HEX_SCENE_OFFSET(player->_currentScene)); //getCurSceneHexOffset() + + // wearing a helmet? + out->writeSint32LE(GET_HEX_OBJ_OFFSET(player->_armor[Chr::HEAD_ARMOR])); //helmetIndex + + // holding a shield? + out->writeSint32LE(GET_HEX_OBJ_OFFSET(player->_armor[Chr::SHIELD_ARMOR])); //shieldIndex + + // wearing chest armor? + out->writeSint32LE(GET_HEX_OBJ_OFFSET(player->_armor[Chr::BODY_ARMOR])); //chestArmIndex + + // wearing spiritual armor? + out->writeSint32LE(GET_HEX_OBJ_OFFSET(player->_armor[Chr::MAGIC_ARMOR])); //sprtArmIndex + + // TODO: + out->writeSint16LE(0xffff); // ???? - always FFFF + out->writeSint16LE(0xffff); // ???? - always FFFF + out->writeSint16LE(0xffff); // ???? - always FFFF + out->writeSint16LE(0xffff); // ???? - always FFFF + + // did a character just escape? + out->writeSint32LE(GET_HEX_CHR_OFFSET(_running)); //getRunCharHexOffset() == getHexOffsetForChr(running) + + // players experience points + out->writeSint32LE(playerContext._experience); + + out->writeSint16LE(_aim); //aim + out->writeSint16LE(_opponentAim); //opponentAim + + // TODO: + out->writeSint16LE(0x0000); // always 0 + out->writeSint16LE(0x0000); // always 0 + out->writeSint16LE(0x0000); // always 0 + + // Base character stats + out->writeByte(playerContext._statVariables[PHYS_STR_BAS]); //state.getBasePhysStr() + out->writeByte(playerContext._statVariables[PHYS_HIT_BAS]); //state.getBasePhysHp() + out->writeByte(playerContext._statVariables[PHYS_ARM_BAS]); //state.getBasePhysArm() + out->writeByte(playerContext._statVariables[PHYS_ACC_BAS]); //state.getBasePhysAcc() + out->writeByte(playerContext._statVariables[SPIR_STR_BAS]); //state.getBaseSprtStr() + out->writeByte(playerContext._statVariables[SPIR_HIT_BAS]); //state.getBaseSprtHp() + out->writeByte(playerContext._statVariables[SPIR_ARM_BAS]); //state.getBaseSprtArm() + out->writeByte(playerContext._statVariables[SPIR_ACC_BAS]); //state.getBaseSprtAcc() + out->writeByte(playerContext._statVariables[PHYS_SPE_BAS]); //state.getBaseRunSpeed() + + // TODO: + out->writeByte(0x0A); // ???? - always seems to be 0x0A + + // write user vars + for (uint32 i = 0; i < 26 * 9; ++i) + out->writeSint16LE(playerContext._userVariables[i]); + + // write updated info for all scenes + Common::Array<Scene *> &orderedScenes = _world->_orderedScenes; + for (uint32 i = 0; i < orderedScenes.size(); ++i) { + Scene *scene = orderedScenes[i]; + if (scene != _world->_storageScene) { + out->writeSint16LE(scene->_resourceId); + out->writeSint16LE(scene->_worldY); + out->writeSint16LE(scene->_worldX); + out->writeByte(scene->_blocked[NORTH] ? 0x01 : 0x00); + out->writeByte(scene->_blocked[SOUTH] ? 0x01 : 0x00); + out->writeByte(scene->_blocked[EAST] ? 0x01 : 0x00); + out->writeByte(scene->_blocked[WEST] ? 0x01 : 0x00); + out->writeSint16LE(scene->_soundFrequency); + out->writeByte(scene->_soundType); + // the following two bytes are currently unknown + out->writeByte(0); + out->writeByte(0); + out->writeByte(scene->_visited ? 0x01 : 0x00); + } + } + + // write updated info for all characters + Common::Array<Chr *> &orderedChrs = _world->_orderedChrs; + for (uint32 i = 0; i < orderedChrs.size(); ++i) { + Chr *chr = orderedChrs[i]; + out->writeSint16LE(chr->_resourceId); + out->writeSint16LE(chr->_currentScene->_resourceId); + Context &chrContext = chr->_context; + out->writeByte(chrContext._statVariables[PHYS_STR_CUR]); + out->writeByte(chrContext._statVariables[PHYS_HIT_CUR]); + out->writeByte(chrContext._statVariables[PHYS_ARM_CUR]); + out->writeByte(chrContext._statVariables[PHYS_ACC_CUR]); + out->writeByte(chrContext._statVariables[SPIR_STR_CUR]); + out->writeByte(chrContext._statVariables[SPIR_HIT_CUR]); + out->writeByte(chrContext._statVariables[SPIR_ARM_CUR]); + out->writeByte(chrContext._statVariables[SPIR_ACC_CUR]); + out->writeByte(chrContext._statVariables[PHYS_SPE_CUR]); + out->writeByte(chr->_rejectsOffers); + out->writeByte(chr->_followsOpponent); + // bytes 16-20 are unknown + out->writeByte(0); + out->writeByte(0); + out->writeByte(0); + out->writeByte(0); + out->writeByte(0); + out->writeByte(chr->_weaponDamage1); + out->writeByte(chr->_weaponDamage2); + } + + // write updated info for all objects + Common::Array<Obj *> &orderedObjs = _world->_orderedObjs; + for (uint32 i = 0; i < orderedObjs.size(); ++i) { + Obj *obj = orderedObjs[i]; + Scene *location = obj->_currentScene; + Chr *owner = obj->_currentOwner; + + out->writeSint16LE(obj->_resourceId); + out->writeSint16LE(location == nullptr ? 0 : location->_resourceId); + out->writeSint16LE(owner == nullptr ? 0 : owner->_resourceId); + + // bytes 7-9 are unknown (always = 0) + out->writeByte(0); + out->writeByte(0); + out->writeByte(0); + + out->writeByte(obj->_accuracy); + out->writeByte(obj->_value); + out->writeByte(obj->_type); + out->writeByte(obj->_damage); + out->writeByte(obj->_attackType); + out->writeSint16LE(obj->_numberOfUses); + } + + // the following is appended by ScummVM + out->writeUint32BE(WAGEflag); + + // Write description of saved game, limited to WAGE_SAVEDGAME_DESCRIPTION_LEN characters + terminating NUL + const int WAGE_SAVEDGAME_DESCRIPTION_LEN = 127; + char description[WAGE_SAVEDGAME_DESCRIPTION_LEN + 1]; + + memset(description, 0, sizeof(description)); + strncpy(description, descriptionString.c_str(), WAGE_SAVEDGAME_DESCRIPTION_LEN); + assert(WAGE_SAVEDGAME_DESCRIPTION_LEN + 1 == 128); // safety + out->write(description, 128); + + out->writeByte(SAVEGAME_CURRENT_VERSION); + debug(9, "Writing save game version (%d)", SAVEGAME_CURRENT_VERSION); + + // Thumbnail + Graphics::saveThumbnail(*out); + + // this one to make checking easier: + // it couldn't be added to the beginning + // and we won't be able to find it in the middle, + // so these would be the last 4 bytes of the file + out->writeUint32BE(WAGEflag); + + out->finalize(); + if (out->err()) { + warning("Can't write file '%s'. (Disk full?)", fileName.c_str()); + result = -1; + } else + debug(9, "Saved game %s in file %s", descriptionString.c_str(), fileName.c_str()); + + delete out; + return result; +} + +int WageEngine::loadGame(int slotId) { + Common::InSaveFile *data; + Common::String fileName = getSavegameFilename(slotId); + + debug(9, "WageEngine::loadGame(%d)", slotId); + if (!(data = _saveFileMan->openForLoading(fileName))) { + warning("Can't open file '%s', game not loaded", fileName.c_str()); + return -1; + } else { + debug(9, "Successfully opened %s for reading", fileName.c_str()); + } + + // Counters + int numScenes = data->readSint16LE(); + int numChars = data->readSint16LE(); + int numObjs = data->readSint16LE(); + + // Hex Offsets + int chrsHexOffset = data->readSint32LE(); + int objsHexOffset = data->readSint32LE(); + + // Unique 8-byte World Signature + int signature = data->readSint32LE(); + if (_world->_signature != signature) { + warning("This saved game is for a different world, please select another one"); + warning("World signature = %d, save signature = %d", _world->_signature, signature); + delete data; + return -1; + } + + // More Counters + int visitNum = data->readSint32LE(); //visitNum + int loopNum = data->readSint32LE(); //loopNum + int killNum = data->readSint32LE(); //killNum + + // Hex offset to player character + int playerOffset = data->readSint32LE(); + + // character in this scene? + int presCharOffset = data->readSint32LE(); + + // Hex offset to current scene + int currentSceneOffset = data->readSint32LE(); + + // find player and current scene + Chr *player = getChrByOffset(playerOffset, chrsHexOffset); + if (player == nullptr) { + warning("Invalid Character! Aborting load."); + delete data; + return -1; + } + + Scene *currentScene = getSceneByOffset(currentSceneOffset); + if (currentScene == nullptr) { + warning("Invalid Scene! Aborting load."); + delete data; + return -1; + } + + // set player character + _world->_player = player; + + // set current scene + player->_currentScene = currentScene; + + // clear the players inventory list + player->_inventory.clear(); + + // wearing a helmet? + int helmetOffset = data->readSint32LE(); //helmetIndex + + // holding a shield? + int shieldOffset = data->readSint32LE(); //shieldIndex + + // wearing chest armor? + int armorOffset = data->readSint32LE(); //chestArmIndex + + // wearing spiritual armor? + int spiritualArmorOffset = data->readSint32LE(); //sprtArmIndex + + data->readSint16LE(); // FFFF + data->readSint16LE(); // FFFF + data->readSint16LE(); // FFFF + data->readSint16LE(); // FFFF + + int runCharOffset = data->readSint32LE(); + + // players experience points + int exp = data->readSint32LE(); // @ playerContext._experience + + int aim = data->readSint16LE(); //aim + int opponentAim = data->readSint16LE(); //opponentAim + + data->readSint16LE(); // 0000 + data->readSint16LE(); // 0000 + data->readSint16LE(); // 0000 + + // Base character stats + int basePhysStr = data->readByte(); + int basePhysHp = data->readByte(); + int basePhysArm = data->readByte(); + int basePhysAcc = data->readByte(); + int baseSprtStr = data->readByte(); + int baseSprtHp = data->readByte(); + int baseSprtArm = data->readByte(); + int baseSprtAcc = data->readByte(); + int baseRunSpeed = data->readByte(); + + // set player stats + Context &playerContext = player->_context; + // I'm setting player fields also, because those are used as base values in Chr::resetState() + playerContext._statVariables[PHYS_STR_BAS] = player->_physicalStrength = basePhysStr; + playerContext._statVariables[PHYS_HIT_BAS] = player->_physicalHp = basePhysHp; + playerContext._statVariables[PHYS_ARM_BAS] = player->_naturalArmor = basePhysArm; + playerContext._statVariables[PHYS_ACC_BAS] = player->_physicalAccuracy = basePhysAcc; + playerContext._statVariables[SPIR_STR_BAS] = player->_spiritualStength = baseSprtStr; + playerContext._statVariables[SPIR_HIT_BAS] = player->_spiritialHp = baseSprtHp; + playerContext._statVariables[SPIR_ARM_BAS] = player->_resistanceToMagic = baseSprtArm; + playerContext._statVariables[SPIR_ACC_BAS] = player->_spiritualAccuracy = baseSprtAcc; + playerContext._statVariables[PHYS_SPE_BAS] = player->_runningSpeed = baseRunSpeed; + + // set visit# + playerContext._visits = visitNum; + + // set monsters killed + playerContext._kills = killNum; + + // set experience + playerContext._experience = exp; + + // if a character is present, move it to this scene + // TODO: This is done in the engine object, would it be cleaner + // to move it here? + // well, it's actually down there now, now sure if that's "cleaner" + // when it's up there or down there + + // if a character just ran away, let our engine know + // TODO: The current engine doesn't have a case for this, we + // should update it + // yep, I don't see such code anywhere in java, so not added it here + + data->readByte(); // 0x0A? + + // set all user variables + for (uint32 i = 0; i < 26 * 9; ++i) { + playerContext._userVariables[i] = data->readSint16LE(); + } + + // update all scene stats + Common::Array<Scene *> &orderedScenes = _world->_orderedScenes; + if (numScenes != orderedScenes.size()) { + warning("scenes number in file (%d) differs from the one in world (%d)", numScenes, orderedScenes.size()); + } + for (uint32 i = 0; i < orderedScenes.size(); ++i) { + Scene *scene = orderedScenes[i]; + if (scene == _world->_storageScene) { + scene->_chrs.clear(); + scene->_objs.clear(); + } else { + int id = data->readSint16LE(); + + if (scene->_resourceId != id) { + warning("loadGame(): updating scenes: expected %d but got %d", scene->_resourceId, id); + data->skip(14); //2,2,1,1,1,1,2,1,1,1,1 down there + continue; + } + + scene->_worldY = data->readSint16LE(); + scene->_worldX = data->readSint16LE(); + scene->_blocked[NORTH] = data->readByte() != 0; + scene->_blocked[SOUTH] = data->readByte() != 0; + scene->_blocked[EAST] = data->readByte() != 0; + scene->_blocked[WEST] = data->readByte() != 0; + scene->_soundFrequency = data->readSint16LE(); + scene->_soundType = data->readByte(); + // the following two bytes are currently unknown + data->readByte(); + data->readByte(); + scene->_visited = data->readByte() != 0; + } + } + + // update all char locations and stats + Common::Array<Chr *> &orderedChrs = _world->_orderedChrs; + if (numChars != orderedChrs.size()) { + warning("characters number in file (%d) differs from the one in world (%d)", numChars, orderedChrs.size()); + } + for (uint32 i = 0; i < orderedChrs.size(); ++i) { + int resourceId = data->readSint16LE(); + int sceneResourceId = data->readSint16LE(); + + int strength = data->readByte(); + int hp = data->readByte(); + int armor = data->readByte(); + int accuracy = data->readByte(); + int spirStrength = data->readByte(); + int spirHp = data->readByte(); + int spirArmor = data->readByte(); + int spirAccuracy = data->readByte(); + int speed = data->readByte(); + int rejectsOffers = data->readByte(); + int followsOpponent = data->readByte(); + + // bytes 16-20 are unknown + data->readByte(); + data->readByte(); + data->readByte(); + data->readByte(); + data->readByte(); + + int weaponDamage1 = data->readByte(); + int weaponDamage2 = data->readByte(); + + Chr *chr = orderedChrs[i]; + if (chr->_resourceId != resourceId) { + warning("loadGame(): updating chrs: expected %d but got %d", chr->_resourceId, resourceId); + continue; + } + + chr->_currentScene = getSceneById(sceneResourceId); + Context &chrContext = chr->_context; + chrContext._statVariables[PHYS_STR_CUR] = strength; + chrContext._statVariables[PHYS_HIT_CUR] = hp; + chrContext._statVariables[PHYS_ARM_CUR] = armor; + chrContext._statVariables[PHYS_ACC_CUR] = accuracy; + chrContext._statVariables[SPIR_STR_CUR] = spirStrength; + chrContext._statVariables[SPIR_HIT_CUR] = spirHp; + chrContext._statVariables[SPIR_ARM_CUR] = spirArmor; + chrContext._statVariables[SPIR_ACC_CUR] = spirAccuracy; + chrContext._statVariables[PHYS_SPE_CUR] = speed; + chr->_rejectsOffers = rejectsOffers; + chr->_followsOpponent = followsOpponent; + chr->_weaponDamage1 = weaponDamage1; + chr->_weaponDamage2 = weaponDamage2; + } + + // update all object locations and stats + Common::Array<Obj *> &orderedObjs = _world->_orderedObjs; + if (numObjs != orderedObjs.size()) { + warning("objects number in file (%d) differs from the one in world (%d)", numObjs, orderedObjs.size()); + } + for (uint32 i = 0; i < orderedObjs.size(); ++i) { + int resourceId = data->readSint16LE(); + int locationResourceId = data->readSint16LE(); + int ownerResourceId = data->readSint16LE(); + + // bytes 7-9 are unknown (always = 0) + data->readByte(); + data->readByte(); + data->readByte(); + + int accuracy = data->readByte(); + int value = data->readByte(); + int type = data->readByte(); + int damage = data->readByte(); + int attackType= data->readByte(); + int numberOfUses = data->readSint16LE(); + + Obj *obj = orderedObjs[i]; + if (obj->_resourceId != resourceId) { + warning("loadGame(): updating objs: expected %d but got %d", obj->_resourceId, resourceId); + continue; + } + + if (ownerResourceId != 0) { + obj->setCurrentOwner(getChrById(ownerResourceId)); + if (obj->_currentOwner == nullptr) + warning("loadGame(): updating objs: owner not found - char with id %d", ownerResourceId); + } else { + obj->setCurrentScene(getSceneById(locationResourceId)); + if (obj->_currentScene == nullptr) + warning("loadGame(): updating objs: scene with id %d not found", ownerResourceId); + } + + obj->_accuracy = accuracy; + obj->_value = value; + obj->_type = type; + obj->_damage = damage; + obj->_attackType = attackType; + obj->_numberOfUses = numberOfUses; + } + + // update inventories and scene contents + for (uint32 i = 0; i < orderedObjs.size(); ++i) { + Obj *obj = orderedObjs[i]; + Chr *chr = obj->_currentOwner; + if (chr != nullptr) { + chr->_inventory.push_back(obj); + } else { + Scene *scene = obj->_currentScene; + scene->_objs.push_back(obj); + } + } + + // update scene chrs + for (uint32 i = 0; i < orderedChrs.size(); ++i) { + Chr *chr = orderedChrs[i]; + Scene *scene = chr->_currentScene; + scene->_chrs.push_back(chr); + if (chr != player) { + wearObjs(chr); + } + } + + // move all worn helmets, shields, chest armors and spiritual + // armors to player + for (int type = 0; type < Chr::NUMBER_OF_ARMOR_TYPES; ++type) { + Obj *armor; + + if (type == Chr::HEAD_ARMOR) + armor = getObjByOffset(helmetOffset, objsHexOffset); + else if (type == Chr::SHIELD_ARMOR) + armor = getObjByOffset(shieldOffset, objsHexOffset); + else if (type == Chr::BODY_ARMOR) + armor = getObjByOffset(armorOffset, objsHexOffset); + else + armor = getObjByOffset(spiritualArmorOffset, objsHexOffset); + + if (armor != nullptr) { + _world->move(armor, player); + player->_armor[type] = armor; + } + } + + //TODO: make sure that armor in the inventory gets put on if we are wearing it + + _loopCount = loopNum; + + // let the engine know if there is a npc in the current scene + if (presCharOffset != 0xffff) { + _monster = getChrByOffset(presCharOffset, chrsHexOffset); + } + + // java engine calls clearOutput(); here + // processTurn("look", NULL); called in Wage right after this loadGame() + + // TODO: as you may see, aim, opponentAim or runCharOffset are not used anywhere + // I'm fixing the first two, as those are clearly not even mentioned anywhere + // the runCharOffset is mentioned up there as "not implemented case" + _aim = aim; + _opponentAim = opponentAim; + + delete data; + return 0; +} + +Common::String WageEngine::getSavegameFilename(int16 slotId) const { + Common::String saveLoadSlot = _targetName; + saveLoadSlot += Common::String::format(".%.3d", slotId); + return saveLoadSlot; +} + +Common::Error WageEngine::loadGameState(int slot) { + if (loadGame(slot) == 0) + return Common::kNoError; + else + return Common::kUnknownError; +} + +Common::Error WageEngine::saveGameState(int slot, const Common::String &description) { + Common::String saveLoadSlot = getSavegameFilename(slot); + if (saveGame(saveLoadSlot, description) == 0) + return Common::kNoError; + else + return Common::kUnknownError; +} + +bool WageEngine::scummVMSaveLoadDialog(bool isSave) { + if (!isSave) { + // do loading + GUI::SaveLoadChooser dialog = GUI::SaveLoadChooser(_("Load game:"), _("Load"), false); + int slot = dialog.runModalWithCurrentTarget(); + + if (slot < 0) + return true; + + return loadGameState(slot).getCode() == Common::kNoError; + } + + // do saving + GUI::SaveLoadChooser dialog = GUI::SaveLoadChooser(_("Save game:"), _("Save"), true); + int slot = dialog.runModalWithCurrentTarget(); + Common::String desc = dialog.getResultString(); + + if (desc.empty()) { + // create our own description for the saved game, the user didnt enter it + desc = dialog.createDefaultSaveDescription(slot); + } + + if (desc.size() > 28) + desc = Common::String(desc.c_str(), 28); + + if (slot < 0) + return true; + + return saveGameState(slot, desc).getCode() == Common::kNoError; +} + +} // End of namespace Agi diff --git a/engines/wage/wage.cpp b/engines/wage/wage.cpp index 567e2768d8..6a33efa02a 100644 --- a/engines/wage/wage.cpp +++ b/engines/wage/wage.cpp @@ -45,6 +45,7 @@ * */ +#include "common/config-manager.h" #include "common/debug-channels.h" #include "common/error.h" #include "common/events.h" @@ -126,6 +127,12 @@ Common::Error WageEngine::run() { _temporarilyHidden = true; performInitialSetup(); + if (ConfMan.hasKey("save_slot")) { + int saveSlot = ConfMan.getInt("save_slot"); + loadGame(saveSlot); + _gui->regenCommandsMenu(); + _gui->regenWeaponsMenu(); + } Common::String input("look"); processTurn(&input, NULL); _temporarilyHidden = false; @@ -307,6 +314,11 @@ void WageEngine::performInitialSetup() { } } +void WageEngine::wearObjs(Chr* chr) { + if (chr != nullptr) + chr->wearObjs(); +} + void WageEngine::doClose() { warning("STUB: doClose()"); } diff --git a/engines/wage/wage.h b/engines/wage/wage.h index eb50a2e3dd..511a2d9e26 100644 --- a/engines/wage/wage.h +++ b/engines/wage/wage.h @@ -208,6 +208,23 @@ public: void redrawScene(); void saveGame(); + virtual Common::Error loadGameState(int slot); + virtual Common::Error saveGameState(int slot, const Common::String &description); + bool scummVMSaveLoadDialog(bool isSave); + +private: + int getSceneIndex(Scene *scene) const; + Obj *getObjByOffset(int offset, int objBaseOffset) const; + Chr *getChrById(int resId) const; + Chr *getChrByOffset(int offset, int chrBaseOffset) const; + Scene *getSceneById(int id) const; + Scene *getSceneByOffset(int offset) const; + int saveGame(const Common::String &fileName, const Common::String &descriptionString); + int loadGame(int slotId); + Common::String getSavegameFilename(int16 slotId) const; + +public: + virtual GUI::Debugger *getDebugger() { return _debugger; } private: diff --git a/engines/wage/world.cpp b/engines/wage/world.cpp index 53fc1b4742..286ecddf4d 100644 --- a/engines/wage/world.cpp +++ b/engines/wage/world.cpp @@ -69,6 +69,7 @@ World::World(WageEngine *engine) { _globalScript = nullptr; _player = nullptr; + _signature = 0; _weaponMenuDisabled = true; @@ -119,6 +120,8 @@ bool World::loadWorld(Common::MacResManager *resMan) { out.open("code.bin"); out.write(buf, res->size()); out.close(); + free(buf); + delete res; #endif if ((resArray = resMan->getResIDArray(MKTAG('G','C','O','D'))).size() == 0) @@ -144,7 +147,8 @@ bool World::loadWorld(Common::MacResManager *resMan) { res = resMan->getResource(MKTAG('V','E','R','S'), resArray[0]); - res->skip(10); + _signature = res->readSint32LE(); + res->skip(6); byte b = res->readByte(); _weaponMenuDisabled = (b != 0); if (b != 0 && b != 1) @@ -213,6 +217,8 @@ bool World::loadWorld(Common::MacResManager *resMan) { delete res; } + + scene->_resourceId = *iter; addScene(scene); } @@ -222,7 +228,7 @@ bool World::loadWorld(Common::MacResManager *resMan) { for (iter = resArray.begin(); iter != resArray.end(); ++iter) { res = resMan->getResource(MKTAG('A','O','B','J'), *iter); - addObj(new Obj(resMan->getResName(MKTAG('A','O','B','J'), *iter), res)); + addObj(new Obj(resMan->getResName(MKTAG('A','O','B','J'), *iter), res, *iter)); } // Load Characters @@ -232,7 +238,7 @@ bool World::loadWorld(Common::MacResManager *resMan) { for (iter = resArray.begin(); iter != resArray.end(); ++iter) { res = resMan->getResource(MKTAG('A','C','H','R'), *iter); Chr *chr = new Chr(resMan->getResName(MKTAG('A','C','H','R'), *iter), res); - + chr->_resourceId = *iter; addChr(chr); // TODO: What if there's more than one player character? if (chr->_playerCharacter) @@ -415,7 +421,7 @@ Common::String *World::loadStringFromDITL(Common::MacResManager *resMan, int res } static bool invComparator(const Obj *l, const Obj *r) { - return l->_index < r->_index; + return l->_index < r->_index; } void World::move(Obj *obj, Chr *chr) { @@ -455,7 +461,7 @@ void World::move(Obj *obj, Scene *scene, bool skipSort) { } static bool chrComparator(const Chr *l, const Chr *r) { - return l->_index < r->_index; + return l->_index < r->_index; } void World::move(Chr *chr, Scene *scene, bool skipSort) { diff --git a/engines/wage/world.h b/engines/wage/world.h index 468bedbc59..918616c9c1 100644 --- a/engines/wage/world.h +++ b/engines/wage/world.h @@ -48,10 +48,12 @@ #ifndef WAGE_WORLD_H #define WAGE_WORLD_H +#include "wage/entities.h" #include "wage/macwindowmanager.h" namespace Wage { +class Script; class Sound; class World { @@ -90,6 +92,7 @@ public: Patterns *_patterns; Scene *_storageScene; Chr *_player; + int _signature; //List<MoveListener> moveListeners; Common::String *_gameOverMessage; |