aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--engines/prince/detection.cpp100
-rw-r--r--engines/prince/detection.h101
-rw-r--r--engines/prince/flags.h2
-rw-r--r--engines/prince/hero.cpp4
-rw-r--r--engines/prince/hero.h8
-rw-r--r--engines/prince/module.mk3
-rw-r--r--engines/prince/prince.cpp9
-rw-r--r--engines/prince/prince.h15
-rw-r--r--engines/prince/saveload.cpp508
-rw-r--r--engines/prince/script.cpp96
-rw-r--r--engines/prince/script.h31
11 files changed, 729 insertions, 148 deletions
diff --git a/engines/prince/detection.cpp b/engines/prince/detection.cpp
index fa9df38c90..285d7d1ce3 100644
--- a/engines/prince/detection.cpp
+++ b/engines/prince/detection.cpp
@@ -20,19 +20,10 @@
*
*/
-#include "base/plugins.h"
-#include "engines/advancedDetector.h"
-
-#include "prince/prince.h"
+#include "prince/detection.h"
namespace Prince {
-struct PrinceGameDescription {
- ADGameDescription desc;
-
- int gameType;
-};
-
int PrinceEngine::getGameType() const {
return _gameDescription->gameType;
}
@@ -49,78 +40,6 @@ Common::Language PrinceEngine::getLanguage() const {
return _gameDescription->desc.language;
}
-}
-
-static const PlainGameDescriptor princeGames[] = {
- {"prince", "Prince Game"},
- {0, 0}
-};
-
-namespace Prince {
-
-static const PrinceGameDescription gameDescriptions[] = {
-
- // German
- {
- {
- "prince",
- "Galador",
- AD_ENTRY1s("databank.ptc", "5fa03833177331214ec1354761b1d2ee", 3565031),
- Common::DE_DEU,
- Common::kPlatformWindows,
- ADGF_NO_FLAGS,
- GUIO1(GUIO_NONE)
- },
- 0
- },
- // Polish
- {
- {
- "prince",
- "Ksiaze i Tchorz",
- AD_ENTRY1s("databank.ptc", "48ec9806bda9d152acbea8ce31c93c49", 3435298),
- Common::PL_POL,
- Common::kPlatformWindows,
- ADGF_NO_FLAGS,
- GUIO1(GUIO_NONE)
- },
- 1
- },
-
-
- { AD_TABLE_END_MARKER, 0 }
-};
-
-} // End of namespace Prince
-
-using namespace Prince;
-
-// we match from data too, to stop detection from a non-top-level directory
-const static char *directoryGlobs[] = {
- "all",
- 0
-};
-
-class PrinceMetaEngine : public AdvancedMetaEngine {
-public:
- PrinceMetaEngine() : AdvancedMetaEngine(Prince::gameDescriptions, sizeof(Prince::PrinceGameDescription), princeGames) {
- _singleid = "prince";
- _maxScanDepth = 2;
- _directoryGlobs = directoryGlobs;
- }
-
- virtual const char *getName() const {
- return "Prince Engine";
- }
-
- virtual const char *getOriginalCopyright() const {
- return "Copyright (C)";
- }
-
- virtual bool createInstance(OSystem *syst, Engine **engine, const ADGameDescription *desc) const;
- virtual bool hasFeature(MetaEngineFeature f) const;
-};
-
bool PrinceMetaEngine::createInstance(OSystem *syst, Engine **engine, const ADGameDescription *desc) const {
using namespace Prince;
const PrinceGameDescription *gd = (const PrinceGameDescription *)desc;
@@ -131,17 +50,26 @@ bool PrinceMetaEngine::createInstance(OSystem *syst, Engine **engine, const ADGa
}
bool PrinceMetaEngine::hasFeature(MetaEngineFeature f) const {
- return false;
+ return
+ (f == kSupportsDeleteSave) ||
+ (f == kSavesSupportMetaInfo) ||
+ (f == kSavesSupportThumbnail) ||
+ (f == kSavesSupportCreationDate) ||
+ (f == kSupportsListSaves);
}
bool Prince::PrinceEngine::hasFeature(EngineFeature f) const {
- return false;//(f == kSupportsRTL);
+ return
+ (f == kSupportsLoadingDuringRuntime) ||
+ (f == kSupportsSavingDuringRuntime);
}
+} // End of namespace Prince
+
#if PLUGIN_ENABLED_DYNAMIC(PRINCE)
-REGISTER_PLUGIN_DYNAMIC(PRINCE, PLUGIN_TYPE_ENGINE, PrinceMetaEngine);
+REGISTER_PLUGIN_DYNAMIC(PRINCE, PLUGIN_TYPE_ENGINE, Prince::PrinceMetaEngine);
#else
-REGISTER_PLUGIN_STATIC(PRINCE, PLUGIN_TYPE_ENGINE, PrinceMetaEngine);
+REGISTER_PLUGIN_STATIC(PRINCE, PLUGIN_TYPE_ENGINE, Prince::PrinceMetaEngine);
#endif
/* vim: set tabstop=4 noexpandtab: */
diff --git a/engines/prince/detection.h b/engines/prince/detection.h
new file mode 100644
index 0000000000..6137730bd0
--- /dev/null
+++ b/engines/prince/detection.h
@@ -0,0 +1,101 @@
+/* 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.
+ *
+ */
+
+#ifndef PRINCE_DETECTION_H
+#define PRINCE_DETECTION_H
+
+#include "prince/prince.h"
+#include "engines/advancedDetector.h"
+
+namespace Prince {
+
+struct PrinceGameDescription {
+ ADGameDescription desc;
+ int gameType;
+};
+
+static const PlainGameDescriptor princeGames[] = {
+ {"prince", "Prince Game"},
+ {0, 0}
+};
+
+static const PrinceGameDescription gameDescriptions[] = {
+ {
+ {
+ "prince",
+ "Galador",
+ AD_ENTRY1s("databank.ptc", "5fa03833177331214ec1354761b1d2ee", 3565031),
+ Common::DE_DEU,
+ Common::kPlatformWindows,
+ ADGF_NO_FLAGS,
+ GUIO1(GUIO_NONE)
+ },
+ 0
+ },
+ {
+ {
+ "prince",
+ "Ksiaze i Tchorz",
+ AD_ENTRY1s("databank.ptc", "48ec9806bda9d152acbea8ce31c93c49", 3435298),
+ Common::PL_POL,
+ Common::kPlatformWindows,
+ ADGF_NO_FLAGS,
+ GUIO1(GUIO_NONE)
+ },
+ 1
+ },
+ { AD_TABLE_END_MARKER, 0 }
+};
+
+// we match from data too, to stop detection from a non-top-level directory
+const static char *directoryGlobs[] = {
+ "all",
+ 0
+};
+
+class PrinceMetaEngine : public AdvancedMetaEngine {
+public:
+ PrinceMetaEngine() : AdvancedMetaEngine(Prince::gameDescriptions, sizeof(Prince::PrinceGameDescription), princeGames) {
+ _singleid = "prince";
+ _maxScanDepth = 2;
+ _directoryGlobs = directoryGlobs;
+ }
+
+ virtual const char *getName() const {
+ return "Prince Engine";
+ }
+
+ virtual const char *getOriginalCopyright() const {
+ return "Copyright (C)";
+ }
+
+ virtual bool createInstance(OSystem *syst, Engine **engine, const ADGameDescription *desc) const;
+ virtual bool hasFeature(MetaEngineFeature f) const;
+ virtual int getMaximumSaveSlot() const;
+ virtual SaveStateList listSaves(const char *target) const;
+ SaveStateDescriptor querySaveMetaInfos(const char *target, int slot) const;
+ virtual void removeSaveState(const char *target, int slot) const;
+};
+
+} // End of namespace Prince
+
+#endif
diff --git a/engines/prince/flags.h b/engines/prince/flags.h
index aa607a01fe..5af6bffa00 100644
--- a/engines/prince/flags.h
+++ b/engines/prince/flags.h
@@ -31,7 +31,7 @@ struct Flags {
// TODO: Remove from release build
// useful just for debugging
- static const char * getFlagName(uint16 flagId);
+ static const char *getFlagName(uint16 flagId);
enum Id {
FLAGA1 = 0x8000,
diff --git a/engines/prince/hero.cpp b/engines/prince/hero.cpp
index 2cc5789781..6b4cafa968 100644
--- a/engines/prince/hero.cpp
+++ b/engines/prince/hero.cpp
@@ -41,7 +41,7 @@ Hero::Hero(PrinceEngine *vm, GraphicsMan *graph) : _vm(vm), _graph(graph)
, _shadZoomFactor(0), _shadScaleValue(0), _shadLineLen(0), _shadDrawX(0), _shadDrawY(0)
, _frameXSize(0), _frameYSize(0), _scaledFrameXSize(0), _scaledFrameYSize(0), _color(0)
, _coords(nullptr), _dirTab(nullptr), _currCoords(nullptr), _currDirTab(nullptr), _step(0)
- , _maxBoredom(200), _turnAnim(0), _leftRightMainDir(0), _upDownMainDir(0)
+ , _maxBoredom(200), _turnAnim(0), _leftRightMainDir(0), _upDownMainDir(0), _animSetNr(0)
{
_zoomBitmap = (byte *)malloc(kZoomBitmapLen);
_shadowBitmap = (byte *)malloc(2 * kShadowBitmapSize);
@@ -57,6 +57,8 @@ Hero::~Hero() {
}
bool Hero::loadAnimSet(uint32 animSetNr) {
+ _animSetNr = animSetNr;
+
if (animSetNr > sizeof(heroSetTable)) {
return false;
}
diff --git a/engines/prince/hero.h b/engines/prince/hero.h
index d2ad0d9c95..236818c3a1 100644
--- a/engines/prince/hero.h
+++ b/engines/prince/hero.h
@@ -182,11 +182,11 @@ public:
uint16 _currHeight; // height of current anim phase
- Common::Array<int> _inventory; // Inventory array of items
- Common::Array<int> _inventory2; // Inventory2 array of items
+ Common::Array<byte> _inventory; // Inventory array of items
+ Common::Array<byte> _inventory2; // Inventory2 array of items
// Font subtitiles font
- int _color; // Color Subtitles color
- // AnimSet number of animation set
+ int _color; // subtitles color
+ uint32 _animSetNr; // number of animation set
Common::Array<Animation *> _moveSet; // MoveAnims MoveSet
int16 _turnAnim;
byte *_zoomBitmap;
diff --git a/engines/prince/module.mk b/engines/prince/module.mk
index ad5b20aeb1..584fb99a97 100644
--- a/engines/prince/module.mk
+++ b/engines/prince/module.mk
@@ -19,7 +19,8 @@ MODULE_OBJS = \
hero.o \
hero_set.o \
cursor.o \
- pscr.o
+ pscr.o \
+ saveload.o
# This module can be built as a plugin
ifeq ($(ENABLE_PRINCE), DYNAMIC_PLUGIN)
diff --git a/engines/prince/prince.cpp b/engines/prince/prince.cpp
index 89fb9e334e..fe2f398b85 100644
--- a/engines/prince/prince.cpp
+++ b/engines/prince/prince.cpp
@@ -323,7 +323,7 @@ void PrinceEngine::init() {
_objSlot = new int[kMaxObjects];
for (int i = 0; i < kMaxObjects; i++) {
- _objSlot[i] = -1;
+ _objSlot[i] = 0xFF;
}
}
@@ -458,7 +458,7 @@ bool PrinceEngine::loadLocation(uint16 locationNr) {
_mainHero->setShadowScale(_script->getShadowScale(_locationNr));
for (uint i = 0; i < _mobList.size(); i++) {
- _mobList[i]._visible = _script->getMobVisible(i);
+ _mobList[i]._visible = _script->getMobVisible(_room->_mobs, i);
}
freeDrawNodes();
@@ -992,7 +992,7 @@ int PrinceEngine::checkMob(Graphics::Surface *screen, Common::Array<Mob> &mobLis
//mob_obj
if (mob->_mask < kMaxObjects) {
int nr = _objSlot[mob->_mask];
- if (nr != -1) {
+ if (nr != 0xFF) {
Object &obj = *_objList[nr];
Common::Rect objectRect(obj._x, obj._y, obj._x + obj._width, obj._y + obj._height);
if (objectRect.contains(mousePosCamera)) {
@@ -1682,7 +1682,7 @@ void PrinceEngine::freeZoomObject(int slot) {
void PrinceEngine::showObjects() {
for (int i = 0; i < kMaxObjects; i++) {
int nr = _objSlot[i];
- if (nr != -1) {
+ if (nr != 0xFF) {
Graphics::Surface *objSurface = nullptr;
if ((_objList[nr]->_flags & 0x8000)) {
_objList[nr]->_zoomTime--;
@@ -4508,7 +4508,6 @@ void PrinceEngine::mainLoop() {
}
}
}
-
if (_debugger->_locationNr != _locationNr)
loadLocation(_debugger->_locationNr);
if (_debugger->_cursorNr != _cursorNr)
diff --git a/engines/prince/prince.h b/engines/prince/prince.h
index fab49889bb..64f981cdb6 100644
--- a/engines/prince/prince.h
+++ b/engines/prince/prince.h
@@ -31,6 +31,8 @@
#include "common/rect.h"
#include "common/events.h"
#include "common/endian.h"
+#include "common/savefile.h"
+#include "common/serializer.h"
#include "image/bmp.h"
@@ -51,6 +53,7 @@
namespace Prince {
struct PrinceGameDescription;
+struct SavegameHeader;
class PrinceEngine;
class GraphicsMan;
@@ -252,6 +255,17 @@ public:
virtual ~PrinceEngine();
virtual bool hasFeature(EngineFeature f) const;
+ virtual bool canSaveGameStateCurrently();
+ virtual bool canLoadGameStateCurrently();
+ virtual Common::Error saveGameState(int slot, const Common::String &desc);
+ virtual Common::Error loadGameState(int slot);
+
+ static bool readSavegameHeader(Common::InSaveFile *in, SavegameHeader &header);
+ Common::String generateSaveName(int slot);
+ void writeSavegameHeader(Common::OutSaveFile *out, SavegameHeader &header);
+ void syncGame(Common::SeekableReadStream *readStream, Common::WriteStream *writeStream);
+ bool loadGame(int slotNumber);
+ void resetGame();
int getGameType() const;
const char *getGameId() const;
@@ -313,6 +327,7 @@ public:
static const int kMaxNormAnims = 64;
static const int kMaxBackAnims = 64;
static const int kMaxObjects = 64;
+ static const int kMaxMobs = 64;
Common::Array<AnimListItem> _animList;
Common::Array<BackgroundAnim> _backAnimList;
diff --git a/engines/prince/saveload.cpp b/engines/prince/saveload.cpp
new file mode 100644
index 0000000000..83d45a4bd7
--- /dev/null
+++ b/engines/prince/saveload.cpp
@@ -0,0 +1,508 @@
+/* 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.
+ *
+ */
+
+#include "prince/prince.h"
+#include "prince/graphics.h"
+#include "prince/detection.h"
+#include "prince/flags.h"
+#include "prince/script.h"
+#include "prince/hero.h"
+#include "common/savefile.h"
+#include "common/system.h"
+#include "common/config-manager.h"
+#include "common/memstream.h"
+#include "graphics/thumbnail.h"
+#include "graphics/surface.h"
+#include "graphics/palette.h"
+#include "graphics/scaler.h"
+
+namespace Prince {
+
+#define kBadSVG 99
+#define kSavegameVersion 1
+#define kSavegameStrSize 14
+#define kSavegameStr "SCUMMVM_PRINCE"
+
+class InterpreterFlags;
+class Interpreter;
+
+struct SavegameHeader {
+ uint8 version;
+ Common::String saveName;
+ Graphics::Surface *thumbnail;
+ int saveYear, saveMonth, saveDay;
+ int saveHour, saveMinutes;
+};
+
+int PrinceMetaEngine::getMaximumSaveSlot() const {
+ return 99;
+}
+
+SaveStateList PrinceMetaEngine::listSaves(const char *target) const {
+ Common::SaveFileManager *saveFileMan = g_system->getSavefileManager();
+ Common::StringArray filenames;
+ Common::String pattern = target;
+ pattern += ".???";
+
+ filenames = saveFileMan->listSavefiles(pattern);
+ sort(filenames.begin(), filenames.end()); // Sort (hopefully ensuring we are sorted numerically..)
+
+ SaveStateList saveList;
+ for (Common::StringArray::const_iterator filename = filenames.begin(); filename != filenames.end(); filename++) {
+ // Obtain the last 3 digits of the filename, since they correspond to the save slot
+ int slotNum = atoi(filename->c_str() + filename->size() - 3);
+
+ if (slotNum >= 0 && slotNum <= 99) {
+
+ Common::InSaveFile *file = saveFileMan->openForLoading(*filename);
+ if (file) {
+ Prince::SavegameHeader header;
+
+ // Check to see if it's a ScummVM savegame or not
+ char buffer[kSavegameStrSize + 1];
+ file->read(buffer, kSavegameStrSize + 1);
+
+ if (!strncmp(buffer, kSavegameStr, kSavegameStrSize + 1)) {
+ // Valid savegame
+ if (Prince::PrinceEngine::readSavegameHeader(file, header)) {
+ saveList.push_back(SaveStateDescriptor(slotNum, header.saveName));
+ if (header.thumbnail) {
+ header.thumbnail->free();
+ delete header.thumbnail;
+ }
+ }
+ } else {
+ // Must be an original format savegame
+ saveList.push_back(SaveStateDescriptor(slotNum, "Unknown"));
+ }
+
+ delete file;
+ }
+ }
+ }
+
+ return saveList;
+}
+
+SaveStateDescriptor PrinceMetaEngine::querySaveMetaInfos(const char *target, int slot) const {
+ Common::String fileName = Common::String::format("%s.%03d", target, slot);
+ Common::InSaveFile *f = g_system->getSavefileManager()->openForLoading(fileName);
+
+ if (f) {
+ Prince::SavegameHeader header;
+
+ // Check to see if it's a ScummVM savegame or not
+ char buffer[kSavegameStrSize + 1];
+ f->read(buffer, kSavegameStrSize + 1);
+
+ bool hasHeader = !strncmp(buffer, kSavegameStr, kSavegameStrSize + 1) &&
+ Prince::PrinceEngine::readSavegameHeader(f, header);
+ delete f;
+
+ if (!hasHeader) {
+ // Original savegame perhaps?
+ SaveStateDescriptor desc(slot, "Unknown");
+ return desc;
+ } else {
+ // Create the return descriptor
+ SaveStateDescriptor desc(slot, header.saveName);
+ desc.setThumbnail(header.thumbnail);
+ desc.setSaveDate(header.saveYear, header.saveMonth, header.saveDay);
+ desc.setSaveTime(header.saveHour, header.saveMinutes);
+
+ return desc;
+ }
+ }
+
+ return SaveStateDescriptor();
+}
+
+bool PrinceEngine::readSavegameHeader(Common::InSaveFile *in, SavegameHeader &header) {
+ header.thumbnail = nullptr;
+
+ // Get the savegame version
+ header.version = in->readByte();
+ if (header.version > kSavegameVersion)
+ return false;
+
+ // Read in the string
+ header.saveName.clear();
+ char ch;
+ while ((ch = (char)in->readByte()) != '\0')
+ header.saveName += ch;
+
+ // Get the thumbnail
+ header.thumbnail = Graphics::loadThumbnail(*in);
+ if (!header.thumbnail)
+ return false;
+
+ // Read in save date/time
+ header.saveYear = in->readSint16LE();
+ header.saveMonth = in->readSint16LE();
+ header.saveDay = in->readSint16LE();
+ header.saveHour = in->readSint16LE();
+ header.saveMinutes = in->readSint16LE();
+
+ return true;
+}
+
+void PrinceMetaEngine::removeSaveState(const char *target, int slot) const {
+ Common::String fileName = Common::String::format("%s.%03d", target, slot);
+ g_system->getSavefileManager()->removeSavefile(fileName);
+}
+
+// TODO
+bool PrinceEngine::canSaveGameStateCurrently() {
+ return true;
+}
+
+// TODO
+bool PrinceEngine::canLoadGameStateCurrently() {
+ return true;
+}
+
+Common::Error PrinceEngine::saveGameState(int slot, const Common::String &desc) {
+ // Set up the serializer
+ Common::String slotName = generateSaveName(slot);
+ Common::OutSaveFile *saveFile = g_system->getSavefileManager()->openForSaving(slotName);
+
+ // Write out the ScummVM savegame header
+ SavegameHeader header;
+ header.saveName = desc;
+ header.version = kSavegameVersion;
+ writeSavegameHeader(saveFile, header);
+
+ // Write out the data of the savegame
+ syncGame(nullptr, saveFile);
+
+ // Finish writing out game data
+ saveFile->finalize();
+ delete saveFile;
+
+ return Common::kNoError;
+}
+
+Common::String PrinceEngine::generateSaveName(int slot) {
+ return Common::String::format("%s.%03d", _targetName.c_str(), slot);
+}
+
+void PrinceEngine::writeSavegameHeader(Common::OutSaveFile *out, SavegameHeader &header) {
+ // Write out a savegame header
+ out->write(kSavegameStr, kSavegameStrSize + 1);
+
+ out->writeByte(kSavegameVersion);
+
+ // Write savegame name
+ out->write(header.saveName.c_str(), header.saveName.size() + 1);
+
+ // Get the active palette
+ uint8 thumbPalette[256 * 3];
+ _system->getPaletteManager()->grabPalette(thumbPalette, 0, 256);
+
+ // Create a thumbnail and save it
+ Graphics::Surface *thumb = new Graphics::Surface();
+ Graphics::Surface *s = _graph->_frontScreen; // check inventory / map etc..
+ ::createThumbnail(thumb, (const byte *)s->getPixels(), s->w, s->h, thumbPalette);
+ Graphics::saveThumbnail(*out, *thumb);
+ thumb->free();
+ delete thumb;
+
+ // Write out the save date/time
+ TimeDate td;
+ g_system->getTimeAndDate(td);
+ out->writeSint16LE(td.tm_year + 1900);
+ out->writeSint16LE(td.tm_mon + 1);
+ out->writeSint16LE(td.tm_mday);
+ out->writeSint16LE(td.tm_hour);
+ out->writeSint16LE(td.tm_min);
+}
+
+void PrinceEngine::syncGame(Common::SeekableReadStream *readStream, Common::WriteStream *writeStream) {
+ int emptyRoom = 0x00;
+ int normRoom = 0xFF;
+ byte endInv = 0xFF;
+
+ Common::Serializer s(readStream, writeStream);
+
+ if (s.isSaving()) {
+ // Flag values
+ for (int i = 0; i < _flags->kMaxFlags; i++) {
+ uint32 value = _flags->getFlagValue((Flags::Id)(_flags->kFlagMask + i));
+ s.syncAsUint32LE(value);
+ }
+
+ // Dialog data
+ for (uint32 i = 0; i < _dialogDatSize; i++) {
+ byte value = _dialogDat[i];
+ s.syncAsByte(value);
+ }
+
+ // Location number
+ s.syncAsUint16LE(_locationNr);
+
+ // Rooms
+ for (int roomId = 0; roomId < _script->kMaxRooms; roomId++) {
+ Room *room = new Room();
+ room->loadRoom(_script->getRoomOffset(roomId));
+
+ if (room->_mobs) {
+ s.syncAsByte(normRoom);
+ } else {
+ s.syncAsByte(emptyRoom);
+ delete room;
+ continue;
+ }
+
+ // Mobs
+ for (int mobId = 0; mobId < kMaxMobs; mobId++) {
+ byte value = _script->getMobVisible(room->_mobs, mobId);
+ s.syncAsByte(value);
+ }
+
+ // Background animations
+ for (int backAnimSlot = 0; backAnimSlot < kMaxBackAnims; backAnimSlot++) {
+ uint32 value = _script->getBackAnimId(_room->_backAnim, backAnimSlot);
+ s.syncAsUint32LE(value);
+ }
+
+ // Objects
+ for (int objectSlot = 0; objectSlot < kMaxObjects; objectSlot++) {
+ byte value = _script->getObjId(room->_obj, objectSlot);
+ s.syncAsByte(value);
+ }
+
+ delete room;
+ }
+
+ // Main hero
+ s.syncAsUint16LE(_mainHero->_visible);
+ s.syncAsUint16LE(_mainHero->_middleX);
+ s.syncAsUint16LE(_mainHero->_middleY);
+ s.syncAsUint16LE(_mainHero->_lastDirection);
+ s.syncAsUint32LE(_mainHero->_color);
+ s.syncAsUint16LE(_mainHero->_maxBoredom);
+ s.syncAsUint32LE(_mainHero->_animSetNr);
+
+ for (uint inv1Slot = 0; inv1Slot < _mainHero->_inventory.size(); inv1Slot++) {
+ s.syncAsByte(_mainHero->_inventory[inv1Slot]);
+ }
+ s.syncAsByte(endInv);
+
+ for (uint inv2Slot = 0; inv2Slot < _mainHero->_inventory2.size(); inv2Slot++) {
+ s.syncAsByte(_mainHero->_inventory2[inv2Slot]);
+ }
+ s.syncAsByte(endInv);
+
+ // Second hero
+ s.syncAsUint16LE(_secondHero->_visible);
+ s.syncAsUint16LE(_secondHero->_middleX);
+ s.syncAsUint16LE(_secondHero->_middleY);
+ s.syncAsUint16LE(_secondHero->_lastDirection);
+ s.syncAsUint32LE(_secondHero->_color);
+ s.syncAsUint16LE(_secondHero->_maxBoredom);
+ s.syncAsUint32LE(_secondHero->_animSetNr);
+
+ for (uint inv1Slot = 0; inv1Slot < _secondHero->_inventory.size(); inv1Slot++) {
+ s.syncAsByte(_secondHero->_inventory[inv1Slot]);
+ }
+ s.syncAsByte(endInv);
+
+ for (uint inv2Slot = 0; inv2Slot < _secondHero->_inventory2.size(); inv2Slot++) {
+ s.syncAsByte(_secondHero->_inventory2[inv2Slot]);
+ }
+ s.syncAsByte(endInv);
+
+ } else {
+ // Flag values
+ for (int i = 0; i < _flags->kMaxFlags; i++) {
+ uint32 value = 0;
+ s.syncAsUint32LE(value);
+ _flags->setFlagValue((Flags::Id)(_flags->kFlagMask + i), value);
+ }
+
+ // Dialog data
+ for (uint32 i = 0; i < _dialogDatSize; i++) {
+ byte value = 0;
+ s.syncAsByte(value);
+ _dialogDat[i] = value;
+ }
+
+ // Location number
+ int restoreRoom = 0;
+ s.syncAsUint16LE(restoreRoom);
+ _flags->setFlagValue(Flags::RESTOREROOM, restoreRoom);
+
+ // Rooms
+ for (int roomId = 0; roomId < _script->kMaxRooms; roomId++) {
+ Room *room = new Room();
+ room->loadRoom(_script->getRoomOffset(roomId));
+
+ byte roomType = emptyRoom;
+ s.syncAsByte(roomType);
+ if (roomType == emptyRoom) {
+ delete room;
+ continue;
+ }
+
+ // Mobs
+ for (int mobId = 0; mobId < kMaxMobs; mobId++) {
+ byte value = 0;
+ s.syncAsByte(value);
+ _script->setMobVisible(room->_mobs, mobId, value);
+ }
+
+ // Background animations
+ for (int backAnimSlot = 0; backAnimSlot < kMaxBackAnims; backAnimSlot++) {
+ uint32 value = 0;
+ s.syncAsUint32LE(value);
+ _script->setBackAnimId(_room->_backAnim, backAnimSlot, value);
+ }
+
+ // Objects
+ for (int objectSlot = 0; objectSlot < kMaxObjects; objectSlot++) {
+ byte value = 0;
+ s.syncAsByte(value);
+ _script->setObjId(room->_obj, objectSlot, value);
+ }
+
+ delete room;
+ }
+
+ // Main hero
+ s.syncAsUint16LE(_mainHero->_visible);
+ s.syncAsUint16LE(_mainHero->_middleX);
+ s.syncAsUint16LE(_mainHero->_middleY);
+ s.syncAsUint16LE(_mainHero->_lastDirection);
+ s.syncAsUint32LE(_mainHero->_color);
+ s.syncAsUint16LE(_mainHero->_maxBoredom);
+ s.syncAsUint32LE(_mainHero->_animSetNr);
+ _mainHero->loadAnimSet(_mainHero->_animSetNr);
+
+ _mainHero->_inventory.clear();
+ byte invId = endInv;
+ while (1) {
+ s.syncAsByte(invId);
+ if (invId == endInv) {
+ break;
+ }
+ _mainHero->_inventory.push_back(invId);
+ }
+
+ _mainHero->_inventory2.clear();
+ invId = endInv;
+ while (1) {
+ s.syncAsByte(invId);
+ if (invId == endInv) {
+ break;
+ }
+ _mainHero->_inventory.push_back(invId);
+ }
+
+ // Second hero
+ s.syncAsUint16LE(_secondHero->_visible);
+ s.syncAsUint16LE(_secondHero->_middleX);
+ s.syncAsUint16LE(_secondHero->_middleY);
+ s.syncAsUint16LE(_secondHero->_lastDirection);
+ s.syncAsUint32LE(_secondHero->_color);
+ s.syncAsUint16LE(_secondHero->_maxBoredom);
+ s.syncAsUint32LE(_secondHero->_animSetNr);
+ _secondHero->loadAnimSet(_secondHero->_animSetNr);
+
+ _secondHero->_inventory.clear();
+ invId = endInv;
+ while (1) {
+ s.syncAsByte(invId);
+ if (invId == endInv) {
+ break;
+ }
+ _secondHero->_inventory.push_back(invId);
+ }
+
+ _secondHero->_inventory2.clear();
+ invId = endInv;
+ while (1) {
+ s.syncAsByte(invId);
+ if (invId == endInv) {
+ break;
+ }
+ _secondHero->_inventory.push_back(invId);
+ }
+
+ // Script
+ _interpreter->setBgOpcodePC(0);
+ _interpreter->setFgOpcodePC(_script->_scriptInfo.restoreGame);
+
+ }
+}
+
+Common::Error PrinceEngine::loadGameState(int slot) {
+ if (!loadGame(slot)) {
+ return Common::kReadingFailed;
+ }
+ return Common::kNoError;
+}
+
+bool PrinceEngine::loadGame(int slotNumber) {
+ Common::MemoryReadStream *readStream;
+
+ // Open up the savegame file
+ Common::String slotName = generateSaveName(slotNumber);
+ Common::InSaveFile *saveFile = g_system->getSavefileManager()->openForLoading(slotName);
+
+ // Read the data into a data buffer
+ int size = saveFile->size();
+ byte *dataBuffer = (byte *)malloc(size);
+ saveFile->read(dataBuffer, size);
+ readStream = new Common::MemoryReadStream(dataBuffer, size, DisposeAfterUse::YES);
+ delete saveFile;
+
+ // Check to see if it's a ScummVM savegame or not
+ char buffer[kSavegameStrSize + 1];
+ readStream->read(buffer, kSavegameStrSize + 1);
+
+ if (strncmp(buffer, kSavegameStr, kSavegameStrSize + 1) != 0) {
+ delete readStream;
+ return false;
+ } else {
+ SavegameHeader saveHeader;
+
+ if (!readSavegameHeader(readStream, saveHeader)) {
+ delete readStream;
+ return false;
+ }
+
+ // Delete the thumbnail
+ saveHeader.thumbnail->free();
+ delete saveHeader.thumbnail;
+ }
+
+ // Get in the savegame
+ syncGame(readStream, nullptr);
+ delete readStream;
+
+ // TODO
+ //syncSpeechSettings();
+
+ return true;
+}
+
+} // End of namespace Prince
diff --git a/engines/prince/script.cpp b/engines/prince/script.cpp
index e2c323b415..57d0b8a770 100644
--- a/engines/prince/script.cpp
+++ b/engines/prince/script.cpp
@@ -148,12 +148,16 @@ uint32 Script::getStartGameOffset() {
return _scriptInfo.startGame;
}
-bool Script::getMobVisible(int mob) {
- return _data[_vm->_room->_mobs + mob];
+uint32 Script::getLocationInitScript(int initRoomTableOffset, int roomNr) {
+ return (uint32)READ_UINT32(&_data[initRoomTableOffset + roomNr * 4]);
}
-void Script::setMobVisible(int mob, int value) {
- _data[_vm->_room->_mobs + mob] = value;
+byte Script::getMobVisible(int roomMobOffset, uint16 mob) {
+ return _data[roomMobOffset + mob];
+}
+
+void Script::setMobVisible(int roomMobOffset, uint16 mob, byte value) {
+ _data[roomMobOffset + mob] = value;
}
uint8 *Script::getRoomOffset(int locationNr) {
@@ -185,12 +189,21 @@ uint8 *Script::getHeroAnimName(int offset) {
return &_data[offset];
}
-void Script::setBackAnimId(int offset, int animId) {
- WRITE_UINT32(&_data[offset], animId);
+uint32 Script::getBackAnimId(int roomBackAnimOffset, int slot) {
+ uint32 animId = READ_UINT32(&_data[roomBackAnimOffset + slot * 4]);
+ return animId;
+}
+
+void Script::setBackAnimId(int roomBackAnimOffset, int slot, int animId) {
+ WRITE_UINT32(&_data[roomBackAnimOffset + slot * 4], animId);
}
-void Script::setObjId(int offset, int objId) {
- _data[offset] = objId;
+byte Script::getObjId(int roomObjOffset, int slot) {
+ return _data[roomObjOffset + slot];
+}
+
+void Script::setObjId(int roomObjOffset, int slot, byte objectId) {
+ _data[roomObjOffset + slot] = objectId;
}
int Script::scanMobEvents(int mobMask, int dataEventOffset) {
@@ -232,7 +245,9 @@ int Script::scanMobEventsWithItem(int mobMask, int dataEventOffset, int itemMask
return -1;
}
-void Script::installSingleBackAnim(Common::Array<BackgroundAnim> &backAnimList, int slot, int offset) {
+void Script::installSingleBackAnim(Common::Array<BackgroundAnim> &backAnimList, int slot, int roomBackAnimOffset) {
+
+ int offset = roomBackAnimOffset + slot * 4;
BackgroundAnim newBackgroundAnim;
@@ -311,20 +326,15 @@ void Script::installSingleBackAnim(Common::Array<BackgroundAnim> &backAnimList,
}
}
-void Script::installBackAnims(Common::Array<BackgroundAnim> &backAnimList, int offset) {
+void Script::installBackAnims(Common::Array<BackgroundAnim> &backAnimList, int roomBackAnimOffset) {
for (int i = 0; i < _vm->kMaxBackAnims; i++) {
- installSingleBackAnim(backAnimList, i, offset);
- offset += 4;
+ installSingleBackAnim(backAnimList, i, roomBackAnimOffset);
}
}
void Script::installObjects(int offset) {
for (int i = 0; i < _vm->kMaxObjects; i++) {
- if (_data[offset] != 0xFF) {
- _vm->_objSlot[i] = i;
- } else {
- _vm->_objSlot[i] = -1;
- }
+ _vm->_objSlot[i] = _data[offset];
offset++;
}
}
@@ -382,11 +392,11 @@ void InterpreterFlags::resetAllFlags() {
}
void InterpreterFlags::setFlagValue(Flags::Id flagId, uint32 value) {
- _flags[(uint32)flagId - FLAG_MASK] = value;
+ _flags[(uint32)flagId - kFlagMask] = value;
}
uint32 InterpreterFlags::getFlagValue(Flags::Id flagId) {
- return _flags[(uint32)flagId - FLAG_MASK];
+ return _flags[(uint32)flagId - kFlagMask];
}
Interpreter::Interpreter(PrinceEngine *vm, Script *script, InterpreterFlags *flags) :
@@ -497,6 +507,14 @@ void Interpreter::setResult(byte value) {
_result = value;
}
+void Interpreter::setBgOpcodePC(uint32 value) {
+ _bgOpcodePC = value;
+}
+
+void Interpreter::setFgOpcodePC(uint32 value) {
+ _fgOpcodePC = value;
+}
+
template <typename T>
T Interpreter::readScript() {
T data = _script->read<T>(_currentInstruction);
@@ -506,7 +524,7 @@ T Interpreter::readScript() {
uint16 Interpreter::readScriptFlagValue() {
uint16 value = readScript<uint16>();
- if (value & InterpreterFlags::FLAG_MASK) {
+ if (value & InterpreterFlags::kFlagMask) {
return _flags->getFlagValue((Flags::Id)value);
}
return value;
@@ -567,8 +585,7 @@ void Interpreter::O_PUTOBJECT() {
uint16 objectId = readScriptFlagValue();
Room *room = new Room();
room->loadRoom(_script->getRoomOffset(roomId));
- int offset = room->_obj + slot;
- _vm->_script->setObjId(offset, objectId);
+ _vm->_script->setObjId(room->_obj, slot, objectId);
if (_vm->_locationNr == roomId) {
_vm->_objSlot[slot] = objectId;
}
@@ -581,10 +598,9 @@ void Interpreter::O_REMOBJECT() {
uint16 slot = readScriptFlagValue();
Room *room = new Room();
room->loadRoom(_script->getRoomOffset(roomId));
- int offset = room->_obj + slot;
- _vm->_script->setObjId(offset, 0xFF);
+ _vm->_script->setObjId(room->_obj, slot, 0xFF);
if (_vm->_locationNr == roomId) {
- _vm->_objSlot[slot] = -1;
+ _vm->_objSlot[slot] = 0xFF;
}
delete room;
debugInterpreter("O_REMOBJECT roomId %d slot %d", roomId, slot);
@@ -653,10 +669,9 @@ void Interpreter::O_PUTBACKANIM() {
int32 animId = readScript<uint32>();
Room *room = new Room();
room->loadRoom(_script->getRoomOffset(roomId));
- int offset = room->_backAnim + slot * 4;
- _vm->_script->setBackAnimId(offset, animId);
+ _vm->_script->setBackAnimId(room->_backAnim, slot, animId);
if (_vm->_locationNr == roomId) {
- _vm->_script->installSingleBackAnim(_vm->_backAnimList, slot, offset);
+ _vm->_script->installSingleBackAnim(_vm->_backAnimList, slot, room->_backAnim);
}
delete room;
debugInterpreter("O_PUTBACKANIM roomId %d, slot %d, animId %d", roomId, slot, animId);
@@ -670,8 +685,7 @@ void Interpreter::O_REMBACKANIM() {
}
Room *room = new Room();
room->loadRoom(_script->getRoomOffset(roomId));
- int offset = room->_backAnim + slot * 4;
- _vm->_script->setBackAnimId(offset, 0);
+ _vm->_script->setBackAnimId(room->_backAnim, slot, 0);
delete room;
debugInterpreter("O_REMBACKANIM roomId %d, slot %d", roomId, slot);
}
@@ -1019,22 +1033,24 @@ void Interpreter::O_CLSTEXT() {
debugInterpreter("O_CLSTEXT slot %d", slot);
}
-// TODO - check if need this for saving
void Interpreter::O_CALLTABLE() {
- uint16 flag = readScript<uint16>();
- int32 table = readScript<uint32>();
-
- debugInterpreter("O_CALLTABLE flag %d, table %d", flag, table);
- // makes a call from script function table
- // must read table pointer from _code and
- // use table entry as next opcode
+ Flags::Id flagId = readScriptFlagId();
+ int roomNr = _flags->getFlagValue(flagId);
+ int32 tableOffset = readScript<uint32>();
+ int initLocationScript = _script->getLocationInitScript(tableOffset, roomNr);
+ if (initLocationScript) {
+ _stack[_stacktop] = _currentInstruction;
+ _stacktop++;
+ _currentInstruction = initLocationScript;
+ }
+ debugInterpreter("O_CALLTABLE loc %d", roomNr);
}
void Interpreter::O_CHANGEMOB() {
uint16 mob = readScriptFlagValue();
uint16 value = readScriptFlagValue();
value ^= 1;
- _vm->_script->setMobVisible(mob, value);
+ _vm->_script->setMobVisible(_vm->_room->_mobs, mob, value);
_vm->_mobList[mob]._visible = value;
debugInterpreter("O_CHANGEMOB mob %d, value %d", mob, value);
}
@@ -1527,7 +1543,7 @@ void Interpreter::O_BACKANIMRANGE() {
uint16 low = readScriptFlagValue();
uint16 high = readScriptFlagValue();
if (animId != 0xFFFF) {
- if (animId & InterpreterFlags::FLAG_MASK) {
+ if (animId & InterpreterFlags::kFlagMask) {
animId = _flags->getFlagValue((Flags::Id)animId);
}
}
diff --git a/engines/prince/script.h b/engines/prince/script.h
index 04f125a8ea..6ebef3d94b 100644
--- a/engines/prince/script.h
+++ b/engines/prince/script.h
@@ -96,6 +96,8 @@ private:
class Script {
public:
+ static const int16 kMaxRooms = 60;
+
Script(PrinceEngine *vm);
~Script();
@@ -133,23 +135,30 @@ public:
}
uint32 getStartGameOffset();
+ uint32 getLocationInitScript(int initRoomTableOffset, int roomNr);
int16 getLightX(int locationNr);
int16 getLightY(int locationNr);
int32 getShadowScale(int locationNr);
uint8 *getRoomOffset(int locationNr);
int32 getOptionStandardOffset(int option);
uint8 *getHeroAnimName(int offset);
- void setBackAnimId(int offset, int animId);
- void setObjId(int offset, int objId);
- void installBackAnims(Common::Array<BackgroundAnim> &backAnimList, int offset);
- void installSingleBackAnim(Common::Array<BackgroundAnim> &backAnimList, int slot, int offset);
+
+ void installBackAnims(Common::Array<BackgroundAnim> &backAnimList, int roomBackAnimOffset);
+ void installSingleBackAnim(Common::Array<BackgroundAnim> &backAnimList, int slot, int roomBackAnimOffset);
void installObjects(int offset);
bool loadAllMasks(Common::Array<Mask> &maskList, int offset);
int scanMobEvents(int mobMask, int dataEventOffset);
int scanMobEventsWithItem(int mobMask, int dataEventOffset, int itemMask);
- bool getMobVisible(int mob);
- void setMobVisible(int mob, int value);
+
+ byte getMobVisible(int roomMobOffset, uint16 mob);
+ void setMobVisible(int roomMobOffset, uint16 mob, byte value);
+
+ uint32 getBackAnimId(int roomBackAnimOffset, int slot);
+ void setBackAnimId(int roomBackAnimOffset, int slot, int animId);
+
+ byte getObjId(int roomObjOffset, int slot);
+ void setObjId(int roomObjOffset, int slot, byte objectId);
const char *getString(uint32 offset) {
return (const char *)(&_data[offset]);
@@ -171,11 +180,10 @@ public:
void resetAllFlags();
- static const uint16 FLAG_MASK = 0x8000;
-
+ static const uint16 kFlagMask = 0x8000;
+ static const uint16 kMaxFlags = 2000;
private:
- static const uint16 MAX_FLAGS = 2000;
- int32 _flags[MAX_FLAGS];
+ int32 _flags[kMaxFlags];
};
class Interpreter {
@@ -189,6 +197,9 @@ public:
int getLastOPCode();
int getFgOpcodePC();
+ void setBgOpcodePC(uint32 value);
+ void setFgOpcodePC(uint32 value);
+
uint32 getCurrentString();
void setCurrentString(uint32 value);