aboutsummaryrefslogtreecommitdiff
path: root/engines/toltecs
diff options
context:
space:
mode:
authorEugene Sandulenko2008-08-04 11:28:57 +0000
committerWillem Jan Palenstijn2011-11-20 22:43:05 +0100
commit7c2835313ee3c68e6ac753782b63a9dd485b0a60 (patch)
tree86049438fa48c2a9fee1c40e0eacb2cfb0bb9962 /engines/toltecs
parent528c1173d7b9d15d9b7e36f25a876c8952357f26 (diff)
downloadscummvm-rg350-7c2835313ee3c68e6ac753782b63a9dd485b0a60.tar.gz
scummvm-rg350-7c2835313ee3c68e6ac753782b63a9dd485b0a60.tar.bz2
scummvm-rg350-7c2835313ee3c68e6ac753782b63a9dd485b0a60.zip
TOLTECS: Initial checkin
Diffstat (limited to 'engines/toltecs')
-rw-r--r--engines/toltecs/animation.cpp139
-rw-r--r--engines/toltecs/animation.h85
-rw-r--r--engines/toltecs/detection.cpp121
-rw-r--r--engines/toltecs/input.cpp133
-rw-r--r--engines/toltecs/input.h76
-rw-r--r--engines/toltecs/module.mk21
-rw-r--r--engines/toltecs/palette.cpp157
-rw-r--r--engines/toltecs/palette.h87
-rw-r--r--engines/toltecs/resource.cpp161
-rw-r--r--engines/toltecs/resource.h115
-rw-r--r--engines/toltecs/screen.cpp971
-rw-r--r--engines/toltecs/screen.h378
-rw-r--r--engines/toltecs/script.cpp1219
-rw-r--r--engines/toltecs/script.h132
-rw-r--r--engines/toltecs/segmap.cpp535
-rw-r--r--engines/toltecs/segmap.h134
-rw-r--r--engines/toltecs/toltecs.cpp483
-rw-r--r--engines/toltecs/toltecs.h130
18 files changed, 5077 insertions, 0 deletions
diff --git a/engines/toltecs/animation.cpp b/engines/toltecs/animation.cpp
new file mode 100644
index 0000000000..2dbffbd763
--- /dev/null
+++ b/engines/toltecs/animation.cpp
@@ -0,0 +1,139 @@
+/* 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 "common/events.h"
+#include "common/keyboard.h"
+#include "common/file.h"
+#include "common/savefile.h"
+#include "common/config-manager.h"
+
+#include "base/plugins.h"
+#include "base/version.h"
+
+#include "sound/mixer.h"
+
+#include "toltecs/toltecs.h"
+#include "toltecs/animation.h"
+#include "toltecs/screen.h"
+
+namespace Toltecs {
+
+AnimationPlayer::AnimationPlayer(ToltecsEngine *vm) : _vm(vm) {
+ _animBuffer = new byte[262144];
+}
+
+AnimationPlayer::~AnimationPlayer() {
+ delete[] _animBuffer;
+}
+
+void AnimationPlayer::start(uint resIndex) {
+ debug(1, "AnimationPlayer::start(%d)", resIndex);
+
+ _resIndex = resIndex;
+
+ _vm->_arc->openResource(_resIndex);
+ _height = _vm->_arc->readUint16LE();
+ _width = _vm->_arc->readUint16LE();
+ _frameCount = _vm->_arc->readUint16LE();
+ _vm->_arc->read(_palette, 768);
+ _curFrameSize = _vm->_arc->readUint32LE();
+ _nextFrameOffset = _curFrameSize + 782;
+ _vm->_arc->read(_animBuffer, _curFrameSize);
+ _nextFrameSize = _vm->_arc->readUint32LE();
+ _vm->_arc->closeResource();
+
+ debug(1, "AnimationPlayer::start() width = %d; height = %d; frameCount = %d", _width, _height, _frameCount);
+
+ unpackFrame();
+
+ _keepFrameCounter = 0;
+ _frameNumber = 0;
+ // TODO mov screenFlag01, 0FFFFh
+ // TODO mov animDrawFrameFlag, 0FFFFh
+
+ _firstNextFrameOffset = _nextFrameOffset;
+ _firstCurFrameSize = _curFrameSize;
+ _firstNextFrameSize = _nextFrameSize;
+
+}
+
+void AnimationPlayer::nextFrame() {
+ debug(1, "AnimationPlayer::nextFrame()");
+
+ if (_frameNumber == _frameCount) {
+ _nextFrameOffset = _firstNextFrameOffset;
+ _curFrameSize = _firstCurFrameSize;
+ _nextFrameSize = _firstNextFrameSize;
+ _frameNumber = 1;
+ } else {
+ _frameNumber++;
+ }
+
+ debug(1, "AnimationPlayer::nextFrame() frameNumber = %d", _frameNumber);
+
+ if (_keepFrameCounter > 0) {
+ _keepFrameCounter--;
+ return;
+ }
+
+ _vm->_arc->openResource(_resIndex);
+ _vm->_arc->seek(_nextFrameOffset, SEEK_CUR);
+ _curFrameSize = _nextFrameSize;
+
+ if (_curFrameSize == 0)
+ _curFrameSize = 1;
+
+ _vm->_arc->read(_animBuffer, _curFrameSize);
+ _nextFrameSize = _vm->_arc->readUint32LE();
+ _nextFrameOffset += _curFrameSize + 4;
+
+ if (_curFrameSize > 1) {
+ unpackFrame();
+ // TODO mov animDrawFrameFlag, 0FFFFh
+ } else {
+ _keepFrameCounter = _animBuffer[0] - 1;
+ // TODO mov animDrawFrameFlag, 0
+ }
+
+ _vm->_arc->closeResource();
+
+
+}
+
+int16 AnimationPlayer::getStatus() {
+ debug(1, "AnimationPlayer::getStatus()");
+ int16 status = -1;
+ if (_frameNumber == _frameCount)
+ status = 0;
+ else if (_frameNumber == _frameCount - 1)
+ status = 1;
+ debug(1, "AnimationPlayer::getStatus() status = %d", status);
+ return status;
+}
+
+void AnimationPlayer::unpackFrame() {
+ _vm->_screen->unpackRle(_animBuffer, _vm->_screen->_frontScreen, _width, _height);
+ _vm->_screen->unpackRle(_animBuffer, _vm->_screen->_backScreen, _width, _height);
+}
+
+} // End of namespace Toltecs
diff --git a/engines/toltecs/animation.h b/engines/toltecs/animation.h
new file mode 100644
index 0000000000..dc484215f9
--- /dev/null
+++ b/engines/toltecs/animation.h
@@ -0,0 +1,85 @@
+/* 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 TOLTECS_ANIMATION_H
+#define TOLTECS_ANIMATION_H
+
+#include "common/scummsys.h"
+#include "common/endian.h"
+#include "common/util.h"
+#include "common/file.h"
+#include "common/savefile.h"
+#include "common/system.h"
+#include "common/hash-str.h"
+#include "common/events.h"
+#include "common/keyboard.h"
+#include "common/array.h"
+
+#include "sound/audiostream.h"
+#include "sound/mixer.h"
+#include "sound/voc.h"
+#include "sound/audiocd.h"
+
+#include "engines/engine.h"
+
+#include "toltecs/toltecs.h"
+#include "toltecs/resource.h"
+
+namespace Toltecs {
+
+class AnimationPlayer {
+public:
+ AnimationPlayer(ToltecsEngine *vm);
+ ~AnimationPlayer();
+
+ void start(uint resIndex);
+ void nextFrame();
+ int16 getStatus();
+ uint16 getFrameNumber() const { return _frameNumber; }
+
+//protected:
+public:
+ ToltecsEngine *_vm;
+
+ // 262144
+ byte *_animBuffer;
+
+ uint _resIndex;
+ byte _palette[768];
+
+ uint16 _width, _height;
+ uint16 _frameNumber, _frameCount;
+ uint32 _keepFrameCounter;
+
+ uint32 _curFrameSize;
+ uint32 _nextFrameSize, _nextFrameOffset;
+
+ uint32 _firstNextFrameOffset, _firstCurFrameSize, _firstNextFrameSize;
+
+ void unpackFrame();
+
+};
+
+} // End of namespace Toltecs
+
+#endif /* TOLTECS_ANIMATION_H */
diff --git a/engines/toltecs/detection.cpp b/engines/toltecs/detection.cpp
new file mode 100644
index 0000000000..37c1ec4296
--- /dev/null
+++ b/engines/toltecs/detection.cpp
@@ -0,0 +1,121 @@
+/* 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 "base/plugins.h"
+
+#include "common/advancedDetector.h"
+#include "common/file.h"
+
+#include "toltecs/toltecs.h"
+
+
+namespace Toltecs {
+
+struct ToltecsGameDescription {
+ Common::ADGameDescription desc;
+};
+
+uint32 ToltecsEngine::getFeatures() const {
+ return _gameDescription->desc.flags;
+}
+
+Common::Language ToltecsEngine::getLanguage() const {
+ return _gameDescription->desc.language;
+}
+
+}
+
+static const PlainGameDescriptor toltecsGames[] = {
+ {"toltecs", "3 Skulls of the Toltecs"},
+ {0, 0}
+};
+
+
+namespace Toltecs {
+
+static const ToltecsGameDescription gameDescriptions[] = {
+
+ {
+ // Toltecs English version
+ {
+ "toltecs",
+ 0,
+ AD_ENTRY1s("WESTERN", "05472037e9cfde146e953c434e74f0f4", 337643527),
+ Common::EN_ANY,
+ Common::kPlatformPC,
+ Common::ADGF_NO_FLAGS
+ },
+ },
+
+ { AD_TABLE_END_MARKER }
+};
+
+} // End of namespace Toltecs
+
+static const Common::ADParams detectionParams = {
+ // Pointer to ADGameDescription or its superset structure
+ (const byte *)Toltecs::gameDescriptions,
+ // Size of that superset structure
+ sizeof(Toltecs::ToltecsGameDescription),
+ // Number of bytes to compute MD5 sum for
+ 5000,
+ // List of all engine targets
+ toltecsGames,
+ // Structure for autoupgrading obsolete targets
+ 0,
+ // Name of single gameid (optional)
+ "toltecs",
+ // List of files for file-based fallback detection (optional)
+ 0,
+ // Flags
+ 0
+};
+
+class ToltecsMetaEngine : public Common::AdvancedMetaEngine {
+public:
+ ToltecsMetaEngine() : Common::AdvancedMetaEngine(detectionParams) {}
+
+ virtual const char *getName() const {
+ return "Toltecs Engine";
+ }
+
+ virtual const char *getCopyright() const {
+ return "Toltecs Engine (C) 1996";
+ }
+
+ virtual bool createInstance(OSystem *syst, Engine **engine, const Common::ADGameDescription *desc) const;
+};
+
+bool ToltecsMetaEngine::createInstance(OSystem *syst, Engine **engine, const Common::ADGameDescription *desc) const {
+ const Toltecs::ToltecsGameDescription *gd = (const Toltecs::ToltecsGameDescription *)desc;
+ if (gd) {
+ *engine = new Toltecs::ToltecsEngine(syst, gd);
+ }
+ return gd != 0;
+}
+
+#if PLUGIN_ENABLED_DYNAMIC(TOLTECS)
+ REGISTER_PLUGIN_DYNAMIC(TOLTECS, PLUGIN_TYPE_ENGINE, ToltecsMetaEngine);
+#else
+ REGISTER_PLUGIN_STATIC(TOLTECS, PLUGIN_TYPE_ENGINE, ToltecsMetaEngine);
+#endif
diff --git a/engines/toltecs/input.cpp b/engines/toltecs/input.cpp
new file mode 100644
index 0000000000..50e9129412
--- /dev/null
+++ b/engines/toltecs/input.cpp
@@ -0,0 +1,133 @@
+/* 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 "common/events.h"
+#include "common/keyboard.h"
+#include "common/file.h"
+#include "common/savefile.h"
+#include "common/config-manager.h"
+
+#include "base/plugins.h"
+#include "base/version.h"
+
+#include "sound/mixer.h"
+
+#include "toltecs/toltecs.h"
+#include "toltecs/input.h"
+#include "toltecs/palette.h"
+#include "toltecs/resource.h"
+
+namespace Toltecs {
+
+Input::Input(ToltecsEngine *vm) : _vm(vm) {
+
+ _mouseX = 0;
+ _mouseY = 0;
+ _mousePosDelta = 0;
+ _mouseCounter = 0;
+ _mouseButtonPressedFlag = false;
+ _mouseButton = 0;
+ _mouseDisabled = 0;
+
+ _leftButtonDown = false;
+ _rightButtonDown = false;
+
+}
+
+Input::~Input() {
+}
+
+void Input::update() {
+
+ Common::Event event;
+ Common::EventManager *eventMan = _vm->_system->getEventManager();
+ while (eventMan->pollEvent(event)) {
+ switch (event.type) {
+ case Common::EVENT_KEYDOWN:
+ case Common::EVENT_QUIT:
+ break;
+ case Common::EVENT_MOUSEMOVE:
+ _mouseX = event.mouse.x;
+ _mouseY = event.mouse.y;
+ break;
+ case Common::EVENT_LBUTTONDOWN:
+ _mouseX = event.mouse.x;
+ _mouseY = event.mouse.y;
+ _leftButtonDown = true;
+ break;
+ case Common::EVENT_LBUTTONUP:
+ _mouseX = event.mouse.x;
+ _mouseY = event.mouse.y;
+ _leftButtonDown = false;
+ break;
+ case Common::EVENT_RBUTTONDOWN:
+ _mouseX = event.mouse.x;
+ _mouseY = event.mouse.y;
+ _rightButtonDown = true;
+ break;
+ case Common::EVENT_RBUTTONUP:
+ _mouseX = event.mouse.x;
+ _mouseY = event.mouse.y;
+ _rightButtonDown = false;
+ break;
+ default:
+ break;
+ }
+ }
+
+ if (_mouseDisabled == 0) {
+ _mousePosDelta = _mousePosDelta + _mouseY - _mouseX;
+
+ if (_mouseCounter > 0)
+ _mouseCounter--;
+
+ byte mouseButtons = 0;
+ if (_leftButtonDown)
+ mouseButtons |= 1;
+ if (_rightButtonDown)
+ mouseButtons |= 2;
+
+ if (mouseButtons != 0) {
+ if (!_mouseButtonPressedFlag) {
+ _mouseButton = mouseButtons;
+ if (_mouseCounter != 0)
+ _mouseButton |= 0x80;
+ _mouseCounter = 30; // maybe TODO
+ _mouseButtonPressedFlag = true;
+ } else {
+ _mouseButton = 0;
+ }
+ } else {
+ _mouseButtonPressedFlag = false;
+ _mouseButton = 0;
+ }
+
+ }
+
+}
+
+int16 Input::getMouseDeltaStuff(int16 divisor) {
+ return ABS(_mousePosDelta % divisor);
+}
+
+} // End of namespace Toltecs
diff --git a/engines/toltecs/input.h b/engines/toltecs/input.h
new file mode 100644
index 0000000000..c82dd783b9
--- /dev/null
+++ b/engines/toltecs/input.h
@@ -0,0 +1,76 @@
+/* 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 TOLTECS_INPUT_H
+#define TOLTECS_INPUT_H
+
+#include "common/scummsys.h"
+#include "common/endian.h"
+#include "common/util.h"
+#include "common/file.h"
+#include "common/savefile.h"
+#include "common/system.h"
+#include "common/hash-str.h"
+#include "common/events.h"
+#include "common/keyboard.h"
+#include "common/array.h"
+
+#include "sound/audiostream.h"
+#include "sound/mixer.h"
+#include "sound/voc.h"
+#include "sound/audiocd.h"
+
+#include "engines/engine.h"
+
+namespace Toltecs {
+
+class Input {
+public:
+ Input(ToltecsEngine *vm);
+ ~Input();
+
+ void update();
+
+ void enableMouse();
+ void disableMouse();
+
+ int16 getMouseDeltaStuff(int16 divisor);
+
+//protected:
+public:
+ ToltecsEngine *_vm;
+
+ int16 _mouseX, _mouseY;
+ int16 _mousePosDelta;
+ int16 _mouseCounter;
+ bool _mouseButtonPressedFlag;
+ byte _mouseButton;
+ int16 _mouseDisabled;
+
+ bool _leftButtonDown, _rightButtonDown;
+
+};
+
+} // End of namespace Toltecs
+
+#endif /* TOLTECS_INPUT_H */
diff --git a/engines/toltecs/module.mk b/engines/toltecs/module.mk
new file mode 100644
index 0000000000..63a804307d
--- /dev/null
+++ b/engines/toltecs/module.mk
@@ -0,0 +1,21 @@
+MODULE := engines/toltecs
+
+MODULE_OBJS = \
+ animation.o \
+ detection.o \
+ input.o \
+ palette.o \
+ toltecs.o \
+ resource.o \
+ screen.o \
+ script.o \
+ segmap.o
+
+
+# This module can be built as a plugin
+ifeq ($(ENABLE_TOLTECS), DYNAMIC_PLUGIN)
+PLUGIN := 1
+endif
+
+# Include common rules
+include $(srcdir)/rules.mk
diff --git a/engines/toltecs/palette.cpp b/engines/toltecs/palette.cpp
new file mode 100644
index 0000000000..6ff20ff3d7
--- /dev/null
+++ b/engines/toltecs/palette.cpp
@@ -0,0 +1,157 @@
+/* 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 "common/events.h"
+#include "common/keyboard.h"
+#include "common/file.h"
+#include "common/savefile.h"
+#include "common/config-manager.h"
+
+#include "base/plugins.h"
+#include "base/version.h"
+
+#include "sound/mixer.h"
+
+#include "toltecs/toltecs.h"
+#include "toltecs/palette.h"
+#include "toltecs/resource.h"
+
+namespace Toltecs {
+
+Palette::Palette(ToltecsEngine *vm) : _vm(vm) {
+
+ clearFragments();
+
+}
+
+Palette::~Palette() {
+}
+
+void Palette::setFullPalette(byte *palette) {
+ byte colors[1024];
+ for (int i = 0; i < 256; i++) {
+ colors[i * 4 + 0] = palette[i * 3 + 0] << 2;
+ colors[i * 4 + 1] = palette[i * 3 + 1] << 2;
+ colors[i * 4 + 2] = palette[i * 3 + 2] << 2;
+ colors[i * 4 + 3] = 255;
+ }
+ _vm->_system->setPalette((const byte *)colors, 0, 256);
+ _vm->_system->updateScreen();
+}
+
+void Palette::setDeltaPalette(byte *palette, byte mask, char deltaValue, int16 count, int16 startIndex) {
+
+ byte colors[1024];
+
+ byte *palPtr = palette + startIndex * 3;
+ int16 index = startIndex, colorCount = count;
+ byte rgb;
+
+ count++;
+
+ mask &= 7;
+
+ _vm->_system->grabPalette(colors, 0, 256);
+
+ if (deltaValue < 0) {
+ deltaValue = -deltaValue;
+ while (count--) {
+ rgb = *palPtr++;
+ if (mask & 1) colors[index * 4 + 0] = CLIP<int>(rgb + deltaValue, 0, 63) << 2;
+ rgb = *palPtr++;
+ if (mask & 2) colors[index * 4 + 1] = CLIP<int>(rgb + deltaValue, 0, 63) << 2;
+ rgb = *palPtr++;
+ if (mask & 4) colors[index * 4 + 2] = CLIP<int>(rgb + deltaValue, 0, 63) << 2;
+ index++;
+ }
+ } else {
+ while (count--) {
+ rgb = *palPtr++;
+ if (mask & 1) colors[index * 4 + 0] = CLIP<int>(rgb - deltaValue, deltaValue, 255) << 2;
+ rgb = *palPtr++;
+ if (mask & 2) colors[index * 4 + 1] = CLIP<int>(rgb - deltaValue, deltaValue, 255) << 2;
+ rgb = *palPtr++;
+ if (mask & 4) colors[index * 4 + 2] = CLIP<int>(rgb - deltaValue, deltaValue, 255) << 2;
+ index++;
+ }
+ }
+
+ debug(0, "startIndex = %d; colorCount = %d", startIndex, colorCount);
+
+ _vm->_system->setPalette((const byte *)colors, 0, 256);
+
+}
+
+void Palette::loadAddPalette(uint resIndex, byte startIndex) {
+ byte *data = _vm->_res->load(resIndex);
+ memcpy(&_mainPalette[startIndex * 3], data, _vm->_res->getCurItemSize());
+}
+
+void Palette::loadAddPaletteFrom(byte *source, byte startIndex, byte count) {
+ memcpy(&_mainPalette[startIndex * 3], source, count * 3);
+}
+
+void Palette::addFragment(uint resIndex, int16 id) {
+ debug(0, "Palette::addFragment(%d, %d)", resIndex, id);
+
+ byte *fragmentData = _vm->_res->load(resIndex);
+ byte count = _vm->_res->getCurItemSize() / 3;
+
+ memcpy(&_mainPalette[_fragmentIndex * 3], fragmentData, count * 3);
+
+ PaletteFragment fragment;
+ fragment.id = id;
+ fragment.index = _fragmentIndex;
+ fragment.count = count;
+ _fragments.push_back(fragment);
+
+ debug(0, "Palette::addFragment() index = %02X; count = %02X", fragment.index, fragment.count);
+
+ _fragmentIndex += count;
+
+}
+
+uint16 Palette::findFragment(int16 id) {
+ debug(0, "Palette::findFragment(%d)", id);
+
+ uint16 result = 0;
+ for (PaletteFragmentArray::iterator iter = _fragments.begin(); iter != _fragments.end(); iter++) {
+ PaletteFragment fragment = *iter;
+ if (fragment.id == id) {
+ result = (fragment.count << 8) | fragment.index;
+ break;
+ }
+ }
+
+ debug(0, "Palette::findFragment() result = %04X", result);
+
+ return result;
+}
+
+void Palette::clearFragments() {
+ debug(0, "Palette::clearFragments()");
+ _fragmentIndex = 128;
+ _fragments.clear();
+}
+
+} // End of namespace Toltecs
diff --git a/engines/toltecs/palette.h b/engines/toltecs/palette.h
new file mode 100644
index 0000000000..b550b80e70
--- /dev/null
+++ b/engines/toltecs/palette.h
@@ -0,0 +1,87 @@
+/* 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 TOLTECS_PALETTE_H
+#define TOLTECS_PALETTE_H
+
+#include "common/scummsys.h"
+#include "common/endian.h"
+#include "common/util.h"
+#include "common/file.h"
+#include "common/savefile.h"
+#include "common/system.h"
+#include "common/hash-str.h"
+#include "common/events.h"
+#include "common/keyboard.h"
+#include "common/array.h"
+
+#include "sound/audiostream.h"
+#include "sound/mixer.h"
+#include "sound/voc.h"
+#include "sound/audiocd.h"
+
+#include "engines/engine.h"
+
+namespace Toltecs {
+
+//#define ROT(index) (((index << 4) & 0xF0) | ((index >> 4) & 0x0F))
+//#define ROT(index) (index)
+
+class Palette {
+public:
+ Palette(ToltecsEngine *vm);
+ ~Palette();
+
+ void setFullPalette(byte *palette);
+ void setDeltaPalette(byte *palette, byte mask, char deltaValue, int16 count, int16 startIndex);
+
+ void loadAddPalette(uint resIndex, byte startIndex);
+ void loadAddPaletteFrom(byte *source, byte startIndex, byte count);
+
+ void addFragment(uint resIndex, int16 id);
+ uint16 findFragment(int16 id);
+ void clearFragments();
+
+ byte *getMainPalette() { return _mainPalette; }
+
+protected:
+
+ struct PaletteFragment {
+ int16 id;
+ byte index, count;
+ };
+
+ typedef Common::Array<PaletteFragment> PaletteFragmentArray;
+
+ ToltecsEngine *_vm;
+
+ byte _mainPalette[768];
+
+ PaletteFragmentArray _fragments;
+ byte _fragmentIndex;
+
+};
+
+} // End of namespace Toltecs
+
+#endif /* TOLTECS_PALETTE_H */
diff --git a/engines/toltecs/resource.cpp b/engines/toltecs/resource.cpp
new file mode 100644
index 0000000000..0280467fe3
--- /dev/null
+++ b/engines/toltecs/resource.cpp
@@ -0,0 +1,161 @@
+/* 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 "common/events.h"
+#include "common/keyboard.h"
+#include "common/file.h"
+#include "common/savefile.h"
+#include "common/config-manager.h"
+
+#include "base/plugins.h"
+#include "base/version.h"
+
+#include "sound/mixer.h"
+
+#include "toltecs/toltecs.h"
+#include "toltecs/resource.h"
+
+namespace Toltecs {
+
+
+/* ArchiveReader */
+
+ArchiveReader::ArchiveReader() {
+}
+
+ArchiveReader::~ArchiveReader() {
+}
+
+void ArchiveReader::openArchive(const char *filename) {
+ open(filename);
+ for (uint i = 0; i < 10000; i++)
+ _offsets[i] = readUint32LE();
+}
+
+uint32 ArchiveReader::openResource(uint resIndex) {
+ uint32 resourceSize = getResourceSize(resIndex);
+ seek(_offsets[resIndex]);
+ return resourceSize;
+}
+
+void ArchiveReader::closeResource() {
+}
+
+
+uint32 ArchiveReader::getResourceSize(uint resIndex) {
+ return _offsets[resIndex + 1] - _offsets[resIndex];
+}
+
+void ArchiveReader::dump(uint resIndex, const char *prefix) {
+ int32 resourceSize = getResourceSize(resIndex);
+ byte *data = new byte[resourceSize];
+
+ char fn[256];
+
+ if (prefix)
+ snprintf(fn, 256, "%s_%04X.0", prefix, resIndex);
+ else
+ snprintf(fn, 256, "%04X.0", resIndex);
+
+ openResource(resIndex);
+ read(data, resourceSize);
+ closeResource();
+
+ FILE *o = fopen(fn, "wb");
+ fwrite(data, resourceSize, 1, o);
+ fclose(o);
+
+ delete[] data;
+}
+
+/* ResourceCache */
+
+ResourceCache::ResourceCache(ToltecsEngine *vm) : _vm(vm) {
+
+ _base = new byte[kMaxCacheSize];
+ _bytesUsed = 0;
+
+ memset(_cache, 0, sizeof(_cache));
+ _cacheCount = 0;
+
+ _curItemOffset = 0;
+ _curItemSize = 0;
+
+}
+
+ResourceCache::~ResourceCache() {
+ delete[] _base;
+}
+
+byte *ResourceCache::load(uint resIndex) {
+ byte *data = NULL;
+ if (existsItem(resIndex)) {
+ debug(1, "ResourceCache::load(%d) From cache", resIndex);
+ data = _base + _curItemOffset;
+ } else {
+ debug(1, "ResourceCache::load(%d) From disk", resIndex);
+ uint32 size = _vm->_arc->openResource(resIndex);
+ data = addItem(resIndex, size);
+ _vm->_arc->read(data, size);
+ _vm->_arc->closeResource();
+ }
+ return data;
+}
+
+bool ResourceCache::existsItem(uint resIndex) {
+ for (uint i = 0; i < _cacheCount; i++) {
+ if (_cache[i].resIndex == resIndex) {
+ _curItemOffset = _cache[i].offset;
+ _curItemSize = _cache[i].size;
+ return true;
+ }
+ }
+ return false;
+}
+
+byte *ResourceCache::addItem(uint resIndex, uint32 size) {
+
+ checkCapacity(size);
+
+ _curItemOffset = _bytesUsed;
+ _curItemSize = size;
+
+ _cache[_cacheCount].resIndex = resIndex;
+ _cache[_cacheCount].offset = _curItemOffset;
+ _cache[_cacheCount].size = _curItemSize;
+ _cacheCount++;
+
+ _bytesUsed += size;
+
+ return _base + _curItemOffset;
+
+}
+
+void ResourceCache::checkCapacity(uint32 size) {
+ if (_cacheCount > kMaxCacheItems || _bytesUsed + size > kMaxCacheSize) {
+ _cacheCount = 0;
+ _bytesUsed = 0;
+ }
+}
+
+} // End of namespace Toltecs
diff --git a/engines/toltecs/resource.h b/engines/toltecs/resource.h
new file mode 100644
index 0000000000..c15918be25
--- /dev/null
+++ b/engines/toltecs/resource.h
@@ -0,0 +1,115 @@
+/* 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 TOLTECS_RESOURCE_H
+#define TOLTECS_RESOURCE_H
+
+#include "common/scummsys.h"
+#include "common/endian.h"
+#include "common/util.h"
+#include "common/file.h"
+#include "common/savefile.h"
+#include "common/system.h"
+#include "common/hash-str.h"
+#include "common/events.h"
+#include "common/keyboard.h"
+#include "common/array.h"
+
+#include "sound/audiostream.h"
+#include "sound/mixer.h"
+#include "sound/voc.h"
+#include "sound/audiocd.h"
+
+#include "engines/engine.h"
+
+namespace Toltecs {
+
+/*
+ TODO:
+
+ ArchiveReader:
+ - Add support for external resources; and check if they're used
+
+*/
+
+const uint kMaxCacheItems = 1024;
+const uint kMaxCacheSize = 8 * 1024 * 1024; // 8 MB
+
+
+class ArchiveReader : public Common::File {
+public:
+ ArchiveReader();
+ ~ArchiveReader();
+
+ void openArchive(const char *filename);
+
+ // Returns the size of the opened resource
+ uint32 openResource(uint resIndex);
+ // Closes the resource
+ void closeResource();
+ // Returns the size of the resource
+ uint32 getResourceSize(uint resIndex);
+
+ void dump(uint resIndex, const char *prefix = NULL);
+
+protected:
+ uint32 _offsets[10000];
+
+};
+
+class ResourceCache {
+public:
+ ResourceCache(ToltecsEngine *vm);
+ ~ResourceCache();
+
+ byte *load(uint resIndex);
+ uint32 getCurItemSize() const { return _curItemSize; }
+
+protected:
+
+ struct CacheItem {
+ uint resIndex;
+ //int value; // what is this?
+ int32 offset; // offset into _base
+ uint32 size; // size of the item
+ };
+
+ ToltecsEngine *_vm;
+
+ byte *_base;
+ uint32 _bytesUsed;
+ uint32 _curItemOffset, _curItemSize;
+
+ CacheItem _cache[kMaxCacheItems];
+ uint _cacheCount;
+
+ bool existsItem(uint resIndex);
+ byte *addItem(uint resIndex, uint32 size);
+ void checkCapacity(uint32 size);
+
+};
+
+
+} // End of namespace Toltecs
+
+#endif /* TOLTECS_H */
diff --git a/engines/toltecs/screen.cpp b/engines/toltecs/screen.cpp
new file mode 100644
index 0000000000..69d2966ef6
--- /dev/null
+++ b/engines/toltecs/screen.cpp
@@ -0,0 +1,971 @@
+/* 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 "common/events.h"
+#include "common/keyboard.h"
+#include "common/file.h"
+#include "common/savefile.h"
+#include "common/config-manager.h"
+
+#include "base/plugins.h"
+#include "base/version.h"
+
+#include "graphics/cursorman.h"
+
+#include "sound/mixer.h"
+
+#include "toltecs/toltecs.h"
+#include "toltecs/palette.h"
+#include "toltecs/resource.h"
+#include "toltecs/screen.h"
+#include "toltecs/script.h"
+#include "toltecs/segmap.h"
+
+namespace Toltecs {
+
+Screen::Screen(ToltecsEngine *vm) : _vm(vm) {
+
+ _frontScreen = new byte[268800];
+ _backScreen = new byte[870400];
+
+ memset(_fontResIndexArray, 0, sizeof(_fontResIndexArray));
+ _fontColor1 = 0;
+ _fontColor2 = 0;
+
+ // Screen shaking
+ _shakeActive = false;
+ _shakeCounterInit = 0;
+ _shakeCounter = 0;
+ _shakePos = 0;
+
+ // Verb line
+ _verbLineNum = 0;
+ memset(_verbLineItems, 0, sizeof(_verbLineItems));
+ _verbLineX = 160;
+ _verbLineY = 2;
+ _verbLineWidth = 20;
+ _verbLineCount = 0;
+
+ // Talk text
+ _talkTextItemNum = 0;
+ memset(_talkTextItems, 0, sizeof(_talkTextItems));
+ _talkTextX = 0;//TODO correct init values
+ _talkTextY = 0;
+ _talkTextFontColor = 0;
+ _talkTextMaxWidth = 520;
+
+}
+
+Screen::~Screen() {
+
+ delete[] _frontScreen;
+ delete[] _backScreen;
+
+}
+
+void Screen::unpackRle(byte *source, byte *dest, uint16 width, uint16 height) {
+ int32 size = width * height;
+ while (size > 0) {
+ byte a = *source++;
+ byte b = *source++;
+ if (a == 0) {
+ dest += b;
+ size -= b;
+ } else {
+ b = ((b << 4) & 0xF0) | ((b >> 4) & 0x0F);
+ memset(dest, b, a);
+ dest += a;
+ size -= a;
+ }
+ }
+}
+
+void Screen::loadMouseCursor(uint resIndex) {
+ byte mouseCursor[16 * 16], *mouseCursorP = mouseCursor;
+ byte *cursorData = _vm->_res->load(resIndex);
+ for (int i = 0; i < 32; i++) {
+ byte pixel;
+ byte mask1 = *cursorData++;
+ byte mask2 = *cursorData++;
+ for (int j = 0; j < 8; j++) {
+ pixel = 0xE5;
+ if ((mask2 & 0x80) == 0)
+ pixel = 0xE0;
+ mask2 <<= 1;
+ if ((mask1 & 0x80) == 0)
+ pixel = 0;
+ mask1 <<= 1;
+ *mouseCursorP++ = pixel;
+ }
+ }
+ //CursorMan.replaceCursor((const byte*)mouseCursor, 16, 16, 0, 0, 0);
+ // FIXME: Where's the cursor hotspot? Using 8, 8 seems good enough for now.
+ CursorMan.replaceCursor((const byte*)mouseCursor, 16, 16, 8, 8, 0);
+}
+
+void Screen::drawGuiImage(int16 x, int16 y, uint resIndex) {
+
+ byte *imageData = _vm->_res->load(resIndex);
+ int16 headerSize = READ_LE_UINT16(imageData);
+ int16 width = imageData[2];
+ int16 height = imageData[3];
+ int16 workWidth = width, workHeight = height;
+ imageData += headerSize;
+
+ byte *dest = _frontScreen + x + (y + _vm->_cameraHeight) * 640;
+
+ debug(0, "Screen::drawGuiImage() x = %d; y = %d; w = %d; h = %d; resIndex = %d", x, y, width, height, resIndex);
+
+ //_vm->_arc->dump(resIndex, "gui");
+
+ while (workHeight > 0) {
+ int count = 1;
+ byte pixel = *imageData++;
+ if (pixel & 0x80) {
+ pixel &= 0x7F;
+ count = *imageData++;
+ count += 2;
+ }
+ pixel = pixel + 0xE0;
+ while (count-- && workHeight > 0) {
+ *dest++ = pixel;
+ workWidth--;
+ if (workWidth == 0) {
+ workHeight--;
+ dest += 640 - width;
+ workWidth = width;
+ }
+ }
+ }
+
+}
+
+void Screen::startShakeScreen(int16 shakeCounter) {
+ _shakeActive = true;
+ _shakeCounterInit = shakeCounter;
+ _shakeCounter = shakeCounter;
+ _shakePos = 0;
+}
+
+void Screen::stopShakeScreen() {
+ _shakeActive = false;
+ _vm->_system->setShakePos(0);
+}
+
+void Screen::updateShakeScreen() {
+ if (_shakeActive) {
+ _shakeCounter--;
+ if (_shakeCounter == 0) {
+ _shakeCounter = _shakeCounterInit;
+ _shakePos ^= 8;
+ _vm->_system->setShakePos(_shakePos);
+ }
+ }
+}
+
+void Screen::addStaticSprite(byte *spriteItem) {
+
+ DrawRequest drawRequest;
+ memset(&drawRequest, 0, sizeof(drawRequest));
+
+ drawRequest.y = READ_LE_UINT16(spriteItem + 0);
+ drawRequest.x = READ_LE_UINT16(spriteItem + 2);
+ int16 fragmentId = READ_LE_UINT16(spriteItem + 4);
+ drawRequest.baseColor = _vm->_palette->findFragment(fragmentId) & 0xFF;
+ drawRequest.resIndex = READ_LE_UINT16(spriteItem + 6);
+ drawRequest.flags = READ_LE_UINT16(spriteItem + 8);
+ drawRequest.scaling = 0;
+
+ debug(0, "Screen::addStaticSprite() x = %d; y = %d; baseColor = %d; resIndex = %d; flags = %04X", drawRequest.x, drawRequest.y, drawRequest.baseColor, drawRequest.resIndex, drawRequest.flags);
+
+ addDrawRequest(drawRequest);
+
+}
+
+void Screen::addAnimatedSprite(int16 x, int16 y, int16 fragmentId, byte *data, int16 *spriteArray, bool loop, int mode) {
+
+ debug(0, "Screen::addAnimatedSprite(%d, %d, %d)", x, y, fragmentId);
+
+ DrawRequest drawRequest;
+ memset(&drawRequest, 0, sizeof(drawRequest));
+
+ drawRequest.x = x;
+ drawRequest.y = y;
+ drawRequest.baseColor = _vm->_palette->findFragment(fragmentId) & 0xFF;
+
+ if (mode == 1) {
+ drawRequest.scaling = _vm->_segmap->getScalingAtPoint(drawRequest.x, drawRequest.y);
+ } else if (mode == 2) {
+ drawRequest.scaling = 0;
+ }
+
+ int16 count = spriteArray[0];
+
+ debug(0, "count = %d", count);
+
+ for (int16 index = 1; index <= count; index++) {
+
+ byte *spriteItem = data + spriteArray[index];
+
+ uint16 loopNum = READ_LE_UINT16(spriteItem + 0) & 0x7FFF;
+ uint16 loopCount = READ_LE_UINT16(spriteItem + 2);
+ uint16 frameNum = READ_LE_UINT16(spriteItem + 4);
+ uint16 frameCount = READ_LE_UINT16(spriteItem + 6);
+ drawRequest.resIndex = READ_LE_UINT16(spriteItem + 8);
+ drawRequest.flags = READ_LE_UINT16(spriteItem + 10 + loopNum * 2);
+
+ debug(0, "Screen::addAnimatedSprite(%d of %d) loopNum = %d; loopCount = %d; frameNum = %d; frameCount = %d; resIndex = %d; flags = %04X, mode = %d",
+ index, count, loopNum, loopCount, frameNum, frameCount, drawRequest.resIndex, drawRequest.flags, mode);
+
+ addDrawRequest(drawRequest);
+
+ frameNum++;
+ if (frameNum == frameCount) {
+ frameNum = 0;
+ loopNum++;
+ if (loopNum == loopCount) {
+ if (loop) {
+ loopNum = 0;
+ } else {
+ loopNum--;
+ }
+ }
+ } else {
+ loopNum |= 0x8000;
+ }
+
+ WRITE_LE_UINT16(spriteItem + 0, loopNum);
+ WRITE_LE_UINT16(spriteItem + 4, frameNum);
+
+ }
+
+}
+
+void Screen::clearSprites() {
+
+ _spriteDrawList.clear();
+ // TODO
+
+}
+
+void Screen::addDrawRequest(const DrawRequest &drawRequest) {
+
+ int16 scaleValueX, scaleValueY;
+ int16 spriteDraw_X, spriteDraw_Y;
+ byte *spriteData;
+ int16 frameNum;
+
+ SpriteDrawItem sprite;
+ memset(&sprite, 0, sizeof(SpriteDrawItem));
+
+ if (drawRequest.flags == 0xFFFF)
+ return;
+
+ sprite.flags = 0;
+ sprite.baseColor = drawRequest.baseColor;
+ sprite.x = drawRequest.x;
+ sprite.y = drawRequest.y;
+ sprite.ybottom = drawRequest.y;
+ sprite.resIndex = drawRequest.resIndex;
+
+ spriteData = _vm->_res->load(drawRequest.resIndex);
+
+ if (drawRequest.flags & 0x2000) {
+ sprite.flags |= 0x10;
+ }
+
+ if (drawRequest.flags & 0x4000) {
+ sprite.flags |= 0x40;
+ }
+
+ frameNum = drawRequest.flags & 0x0FFF;
+
+ // First initialize the sprite item with the values from the sprite resource
+
+ SpriteFrameEntry spriteFrameEntry(spriteData + frameNum * 12);
+
+ if (spriteFrameEntry.w == 0 || spriteFrameEntry.h == 0)
+ return;
+
+ sprite.offset = spriteFrameEntry.offset;
+
+ sprite.width = spriteFrameEntry.w;
+ sprite.height = spriteFrameEntry.h;
+
+ sprite.origWidth = spriteFrameEntry.w;
+ sprite.origHeight = spriteFrameEntry.h;
+
+ if (drawRequest.flags & 0x1000) {
+ spriteDraw_X = spriteFrameEntry.w - spriteFrameEntry.x;
+ } else {
+ spriteDraw_X = spriteFrameEntry.x;
+ }
+
+ spriteDraw_Y = spriteFrameEntry.y;
+
+ // If the sprite should be scaled we need to initialize some values now
+
+ if (drawRequest.scaling != 0) {
+
+ byte scaleValue = ABS(drawRequest.scaling);
+
+ scaleValueX = scaleValue * sprite.origWidth;
+ sprite.xdelta = (10000 * sprite.origWidth) / scaleValueX;
+ scaleValueX /= 100;
+
+ scaleValueY = scaleValue * sprite.origHeight;
+ sprite.ydelta = (10000 * sprite.origHeight) / scaleValueY;
+ scaleValueY /= 100;
+
+ if (drawRequest.scaling > 0) {
+ sprite.flags |= 2;
+ sprite.width = sprite.origWidth + scaleValueX;
+ sprite.height = sprite.origHeight + scaleValueY;
+ spriteDraw_X += (spriteDraw_X * scaleValue) / 100;
+ spriteDraw_Y += (spriteDraw_Y * scaleValue) / 100;
+ } else {
+ sprite.flags |= 1;
+ sprite.width = sprite.origWidth - scaleValueX;
+ sprite.height = sprite.origHeight - 1 - scaleValueY;
+ if (sprite.width <= 0 || sprite.height <= 0)
+ return;
+ spriteDraw_X -= (spriteDraw_X * scaleValue) / 100;
+ spriteDraw_Y -= (spriteDraw_Y * scaleValue) / 100;
+ }
+
+ }
+
+ sprite.x -= spriteDraw_X;
+ sprite.y -= spriteDraw_Y;
+
+ sprite.yerror = sprite.ydelta;
+
+ // Now we check if the sprite needs to be clipped
+
+ // Clip Y
+ if (sprite.y - _vm->_cameraY < 0) {
+
+ int16 clipHeight = ABS(sprite.y - _vm->_cameraY);
+ int16 chopHeight, skipHeight, lineWidth;
+ byte *spriteFrameData;
+
+ sprite.height -= clipHeight;
+ if (sprite.height <= 0)
+ return;
+
+ sprite.y = _vm->_cameraY;
+
+ // If the sprite is scaled
+ if (sprite.flags & 3) {
+ chopHeight = sprite.ydelta;
+ skipHeight = clipHeight;
+ if ((sprite.flags & 2) == 0) {
+ do {
+ chopHeight -= 100;
+ if (chopHeight <= 0) {
+ skipHeight++;
+ chopHeight += sprite.ydelta;
+ } else {
+ clipHeight--;
+ }
+ } while (clipHeight > 0);
+ } else {
+ do {
+ chopHeight -= 100;
+ if (chopHeight < 0) {
+ skipHeight--;
+ chopHeight += sprite.ydelta + 100;
+ }
+ clipHeight--;
+ } while (clipHeight > 0);
+ }
+ sprite.yerror = chopHeight;
+ }
+
+ spriteFrameData = spriteData + sprite.offset;
+
+ // Now the sprite's offset is adjusted to point to the starting line
+ if ((sprite.flags & 0x10) == 0) {
+ while (clipHeight--) {
+ lineWidth = 0;
+ while (lineWidth </*CHECKME was != */ sprite.origWidth) {
+ sprite.offset++;
+ lineWidth += (*spriteFrameData++) & 0x0F;
+ }
+ }
+ } else {
+ lineWidth = 0;
+ while (clipHeight--) {
+ while (lineWidth < sprite.origWidth) {
+ sprite.offset += 2;
+ spriteFrameData++;
+ lineWidth += *spriteFrameData++;
+ }
+ }
+ }
+
+ }
+
+ if (sprite.y + sprite.height - _vm->_cameraY - _vm->_cameraHeight > 0)
+ sprite.height -= sprite.y + sprite.height - _vm->_cameraY - _vm->_cameraHeight;
+ if (sprite.height <= 0)
+ return;
+
+ sprite.value1 = 0;
+
+ if (drawRequest.flags & 0x1000) {
+ // Left border
+ sprite.flags |= 4;
+ if (sprite.x - _vm->_cameraX < 0) {
+ sprite.width -= ABS(sprite.x - _vm->_cameraX);
+ if (sprite.width <= 0)
+ return;
+ sprite.x = _vm->_cameraX;
+ }
+ // Right border
+ if (sprite.x + sprite.width - _vm->_cameraX - 640 > 0) {
+ sprite.flags |= 8;
+ sprite.width -= sprite.x + sprite.width - _vm->_cameraX - 640;
+ if (sprite.width <= 0)
+ return;
+ sprite.value1 = sprite.x + sprite.width - _vm->_cameraX - 640;
+ }
+ } else {
+ // Left border
+ if (sprite.x - _vm->_cameraX < 0) {
+ sprite.flags |= 8;
+ sprite.width -= ABS(sprite.x - _vm->_cameraX);
+ if (sprite.width <= 0)
+ return;
+ sprite.value1 = ABS(sprite.x - _vm->_cameraX);
+ sprite.x = _vm->_cameraX;
+ }
+ // Right border
+ if (sprite.x + sprite.width - _vm->_cameraX - 640 > 0) {
+ sprite.flags |= 8;
+ sprite.width -= sprite.x + sprite.width - _vm->_cameraX - 640;
+ if (sprite.width <= 0)
+ return;
+ }
+ }
+
+ // Add sprite sorted by priority
+ Common::List<SpriteDrawItem>::iterator iter = _spriteDrawList.begin();
+ while (iter != _spriteDrawList.end() && (*iter).ybottom <= sprite.ybottom) {
+ iter++;
+ }
+ _spriteDrawList.insert(iter, sprite);
+
+}
+
+void Screen::drawSprite(SpriteDrawItem *sprite) {
+
+ debug(0, "Screen::drawSprite() x = %d; y = %d; flags = %04X; resIndex = %d; offset = %08X; drawX = %d; drawY = %d",
+ sprite->x, sprite->y, sprite->flags, sprite->resIndex, sprite->offset,
+ sprite->x - _vm->_cameraX, sprite->y - _vm->_cameraY);
+ debug(0, "Screen::drawSprite() width = %d; height = %d; origWidth = %d; origHeight = %d",
+ sprite->width, sprite->height, sprite->origWidth, sprite->origHeight);
+
+ byte *source = _vm->_res->load(sprite->resIndex) + sprite->offset;
+ byte *dest = _frontScreen + (sprite->x - _vm->_cameraX) + (sprite->y - _vm->_cameraY) * 640;
+
+ // FIXME: Temporary hack until proper clipping is implemented
+ /*
+ int16 dx = sprite->x - _vm->_cameraX, dy = sprite->y - _vm->_cameraY;
+ if (dx < 0 || dy < 0 || dx + sprite->width >= 640 || dy + sprite->height >= 400)
+ return;
+ */
+
+ SpriteReader spriteReader(source, sprite);
+
+ if (sprite->flags & 0x40) {
+ // TODO: Shadow sprites
+ } else if (sprite->flags & 0x10) {
+ // 256 color sprite
+ drawSpriteCore(dest, spriteReader, sprite);
+ } else {
+ // 16 color sprite
+ if (sprite->flags & 1) {
+ SpriteFilterScaleDown spriteScaler(sprite, &spriteReader);
+ drawSpriteCore(dest, spriteScaler, sprite);
+ } else if (sprite->flags & 2) {
+ SpriteFilterScaleUp spriteScaler(sprite, &spriteReader);
+ drawSpriteCore(dest, spriteScaler, sprite);
+ } else {
+ drawSpriteCore(dest, spriteReader, sprite);
+ }
+ }
+
+ debug(0, "Screen::drawSprite() ok");
+
+}
+
+void Screen::drawSpriteCore(byte *dest, SpriteFilter &reader, SpriteDrawItem *sprite) {
+
+ int16 destInc;
+
+ /*
+ if ((sprite->flags & 8))
+ return;
+ */
+
+ if (sprite->flags & 4) {
+ destInc = -1;
+ dest += sprite->width;
+ } else {
+ destInc = 1;
+ }
+
+ SpriteReaderStatus status;
+ PixelPacket packet;
+
+ byte *destp = dest;
+ int16 skipX = sprite->value1;
+
+ do {
+ status = reader.readPacket(packet);
+
+ if (skipX > 0) {
+ while (skipX > 0) {
+ skipX -= packet.count;
+ if (skipX < 0) {
+ packet.count = ABS(skipX);
+ break;
+ }
+ status = reader.readPacket(packet);
+ }
+ }
+
+ if (((sprite->flags & 0x10) && (packet.pixel != 0xFF)) || !(sprite->flags & 0x10) && (packet.pixel != 0)) {
+ if (sprite->flags & 0x40) {
+ } else if (sprite->flags & 0x10) {
+ packet.pixel = ((packet.pixel << 4) & 0xF0) | ((packet.pixel >> 4) & 0x0F);
+ } else {
+ packet.pixel += sprite->baseColor - 1;
+ }
+ while (packet.count--) {
+ *dest = packet.pixel;
+ dest += destInc;
+ }
+ } else {
+ dest += packet.count * destInc;
+ }
+
+ if (status == kSrsEndOfLine) {
+ dest = destp + 640;
+ destp = dest;
+ skipX = sprite->value1;
+ }
+
+ } while (status != kSrsEndOfSprite);
+
+}
+
+void Screen::drawSprites() {
+ for (Common::List<SpriteDrawItem>::iterator iter = _spriteDrawList.begin(); iter != _spriteDrawList.end(); iter++) {
+ SpriteDrawItem *sprite = &(*iter);
+ drawSprite(sprite);
+ _vm->_segmap->restoreMasksBySprite(sprite);
+ }
+}
+
+void Screen::updateVerbLine(int16 slotIndex, int16 slotOffset) {
+
+ debug(0, "Screen::updateVerbLine() _verbLineNum = %d; _verbLineX = %d; _verbLineY = %d; _verbLineWidth = %d; _verbLineCount = %d",
+ _verbLineNum, _verbLineX, _verbLineY, _verbLineWidth, _verbLineCount);
+
+ Font font(_vm->_res->load(_fontResIndexArray[0]));
+
+ _verbLineItems[_verbLineNum].slotIndex = slotIndex;
+ _verbLineItems[_verbLineNum].slotOffset = slotOffset;
+
+ // First clear the line
+ int16 y = _verbLineY;
+ for (int16 i = 0; i < _verbLineCount; i++) {
+ byte *dest = _frontScreen + _verbLineX - _verbLineWidth / 2 + (y - 1 + _vm->_cameraHeight) * 640;
+ for (int16 j = 0; j < 20; j++) {
+ memset(dest, 0xE0, _verbLineWidth);
+ dest += 640;
+ }
+ y += 18;
+ }
+
+ int width = 0;
+ byte *sourceString;
+ byte *destString;
+ byte len;
+
+ _tempStringLen1 = 0;
+ destString = _tempString;
+ y = _verbLineY;
+
+ memset(_tempString, 0, sizeof(_tempString));
+
+ for (int16 i = 0; i <= _verbLineNum; i++) {
+ sourceString = _vm->_script->getSlotData(_verbLineItems[i].slotIndex) + _verbLineItems[i].slotOffset;
+ preprocessText(_fontResIndexArray[0], _verbLineWidth, width, sourceString, destString, len);
+ _tempStringLen1 += len;
+ }
+
+ if (_verbLineCount != 1) {
+ int16 charWidth;
+ if (*sourceString < 0xF0) {
+ while (*sourceString > 0x20 && *sourceString < 0xF0 && len > 0/*CHECKME, len check added*/) {
+ byte ch = *sourceString--;
+ _tempStringLen1--;
+ len--;
+ charWidth = font.getCharWidth(ch) + font.getSpacing() - 1;
+ width -= charWidth;
+ }
+ width += charWidth;
+ sourceString++;
+ _tempStringLen1 -= len;
+ _tempStringLen2 = len + 1;
+
+ drawString(_verbLineX - 1 - (width / 2), y, 0xF9, 0xFF, _fontResIndexArray[0]);
+
+ destString = _tempString;
+ width = 0;
+ preprocessText(_fontResIndexArray[0], _verbLineWidth, width, sourceString, destString, len);
+
+ _tempStringLen1 += len;
+ y += 9;
+ }
+ y += 9;
+ }
+
+ _tempStringLen1 -= len;
+ _tempStringLen2 = len;
+
+ drawString(_verbLineX - 1 - (width / 2), y, 0xF9, 0xFF, _fontResIndexArray[0]);
+
+}
+
+void Screen::updateTalkText(int16 slotIndex, int16 slotOffset) {
+
+ int16 x, y, maxWidth, width, length;
+ byte durationModifier = 1;
+ byte *textData = _vm->_script->getSlotData(slotIndex) + slotOffset;
+
+ TalkTextItem *item = &_talkTextItems[_talkTextItemNum];
+
+ item->fontNum = 0;
+ item->color = _talkTextFontColor;
+
+ //debug(0, "## _talkTextMaxWidth = %d", _talkTextMaxWidth);
+
+ x = CLIP<int16>(_talkTextX - _vm->_cameraX, 120, _talkTextMaxWidth);
+ y = CLIP<int16>(_talkTextY - _vm->_cameraY, 4, _vm->_cameraHeight - 16);
+
+ maxWidth = 624 - ABS(x - 320) * 2;
+
+ while (1) {
+ if (*textData == 0x0A) {
+ x = CLIP<int16>(textData[3], 120, _talkTextMaxWidth);
+ y = CLIP<int16>(READ_LE_UINT16(&textData[1]), 4, _vm->_cameraHeight - 16);
+ maxWidth = 624 - ABS(x - 320) * 2;
+ textData += 4;
+ } else if (*textData == 0x14) {
+ item->color = textData[1];
+ textData += 2;
+ } else if (*textData == 0x19) {
+ durationModifier = textData[1];
+ textData += 2;
+ } else if (*textData < 0x0A) {
+ item->fontNum = textData[1];
+ textData += 2;
+ } else
+ break;
+ }
+
+ item->slotIndex = slotIndex;
+ item->slotOffset = textData - _vm->_script->getSlotData(slotIndex);
+
+ width = 0;
+ length = 0;
+
+ item->rectCount = 0;
+
+ Font font(_vm->_res->load(_fontResIndexArray[item->fontNum]));
+ int16 wordLength, wordWidth;
+
+ while (*textData < 0xF0) {
+ if (*textData == 0x1E) {
+ textData++;
+ addTalkTextRect(font, x, y, length, width, item);
+ // CHECKME?
+ width = 0;
+ length = 0;
+ } else {
+ wordLength = 0;
+ wordWidth = 0;
+ while (*textData >= 0x20 && *textData < 0xF0) {
+ byte ch = *textData++;
+ wordLength++;
+ if (ch == 0x20) {
+ wordWidth += font.getWidth();
+ break;
+ } else {
+ wordWidth += font.getCharWidth(ch) + font.getSpacing() - 1;
+ }
+ }
+
+ debug(0, "## width = %d; wordWidth = %d; width + wordWidth = %d; maxWidth + font.getWidth() = %d",
+ width, wordWidth, width + wordWidth, maxWidth + font.getWidth());
+
+ if (width + wordWidth > maxWidth + font.getWidth()) {
+ addTalkTextRect(font, x, y, length, width, item);
+ width = wordWidth;
+ length = wordLength;
+ } else {
+ width += wordWidth;
+ length += wordLength;
+ }
+ }
+ }
+
+ addTalkTextRect(font, x, y, length, width, item);
+
+ debug(0, "## item->rectCount = %d", item->rectCount);
+
+ int16 textDurationMultiplier = item->duration + 8;
+ // TODO: Check sound/text flags
+ if (*textData == 0xFE) {
+ //textDurationMultiplier += 100;
+ }
+ item->duration = 4 * textDurationMultiplier * durationModifier;
+
+}
+
+void Screen::addTalkTextRect(Font &font, int16 x, int16 &y, int16 length, int16 width, TalkTextItem *item) {
+
+ if (width > 0) {
+ TextRect *textRect = &item->rects[item->rectCount];
+ width = width + 1 - font.getSpacing();
+ textRect->width = width;
+ item->duration += length;
+ textRect->length = length;
+ textRect->y = y;
+ textRect->x = CLIP<int16>(x - width / 2, 0, 640);
+ item->rectCount++;
+ }
+
+ y += font.getHeight() - 1;
+
+}
+
+void Screen::drawTalkTextItems() {
+
+ //debug(0, "## _talkTextItemNum = %d", _talkTextItemNum);
+
+ for (int16 i = 0; i <= _talkTextItemNum; i++) {
+ TalkTextItem *item = &_talkTextItems[i];
+ byte *text = _vm->_script->getSlotData(item->slotIndex) + item->slotOffset;
+
+ if (item->fontNum == -1 || item->duration == 0)
+ continue;
+
+ item->duration -= _vm->_counter01;
+ if (item->duration < 0)
+ item->duration = 0;
+
+ Font font(_vm->_res->load(_fontResIndexArray[item->fontNum]));
+ for (byte j = 0; j < item->rectCount; j++) {
+ int16 x = item->rects[j].x;
+ for (byte pos = 0; pos < item->rects[j].length; pos++) {
+ byte ch = *text++;
+ if (ch < 0x20)
+ continue;
+ if (ch == 0x20) {
+ x += font.getWidth();
+ } else {
+ drawChar2(font, _frontScreen, x, item->rects[j].y, ch, item->color);
+ x += font.getCharWidth(ch) + font.getSpacing() - 1;
+ }
+ }
+ }
+ }
+
+}
+
+int16 Screen::getTalkTextDuration() {
+ return _talkTextItems[_talkTextItemNum].duration;
+}
+
+void Screen::registerFont(uint fontIndex, uint resIndex) {
+ _fontResIndexArray[fontIndex] = resIndex;
+}
+
+void Screen::printText(byte *textData) {
+
+ int16 x = 0, y = 0;
+
+ // Really strange stuff.
+ for (int i = 30; i >= 0; i--) {
+ if (textData[i] >= 0xF0)
+ break;
+ if (i == 0)
+ return;
+ }
+
+ do {
+
+ if (*textData == 0x0A) {
+ // Set text position
+ y = textData[1];
+ x = READ_LE_UINT32(textData + 2);
+ textData += 4;
+ } else if (*textData == 0x0B) {
+ // Inc text position
+ y += textData[1]; // CHECKME: Maybe these are signed?
+ x += textData[2];
+ textData += 3;
+ } else {
+ byte *destString = _tempString;
+ int width = 0;
+ _tempStringLen1 = 0;
+ preprocessText(_fontResIndexArray[1], 640, width, textData, destString, _tempStringLen2);
+ drawString(x - width / 2, y, _fontColor1, _fontColor2, _fontResIndexArray[1]);
+ }
+
+ } while (*textData != 0xFF);
+
+}
+
+void Screen::preprocessText(uint fontResIndex, int maxWidth, int &width, byte *&sourceString, byte *&destString, byte &len) {
+
+ Font font(_vm->_res->load(fontResIndex));
+
+ len = 0;
+ while (*sourceString >= 0x20 && *sourceString < 0xF0) {
+ byte ch = *sourceString;
+ byte charWidth;
+ if (ch <= 0x20)
+ charWidth = font.getWidth();
+ else
+ charWidth = font.getCharWidth(ch) + font.getSpacing() - 1;
+ if (width + charWidth >= maxWidth)
+ break;
+ len++;
+ width += charWidth;
+ *destString++ = *sourceString++;
+ }
+}
+
+void Screen::drawString(int16 x, int16 y, byte fontColor1, byte fontColor2, uint fontResIndex) {
+
+ debug(0, "Screen::drawString(%d, %d, %d, %d, %d) _tempStringLen1 = %d; _tempStringLen2 = %d", x, y, fontColor1, fontColor2, fontResIndex, _tempStringLen1, _tempStringLen2);
+
+ Font font(_vm->_res->load(fontResIndex));
+
+ byte color = fontColor1;
+ byte *text = _tempString;
+ byte len = _tempStringLen1 + _tempStringLen2;
+ int16 yadd = 1;
+
+ for (byte pos = 0; pos < len; pos++) {
+ if (pos == _tempStringLen1) {
+ color = fontColor2;
+ }
+ byte ch = *text++;
+ if (ch <= 0x20) {
+ x += font.getWidth();
+ } else {
+ drawChar(font, _frontScreen, x + 1, y + _vm->_cameraHeight - yadd, ch, color);
+ x += font.getCharWidth(ch) + font.getSpacing() - 1;
+ yadd = -yadd;
+ }
+ }
+
+}
+
+// TODO: Merge drawChar and drawChar2
+
+void Screen::drawChar(const Font &font, byte *dest, int16 x, int16 y, byte ch, byte color) {
+
+ int16 charWidth, charHeight;
+ byte *charData;
+
+ dest += x + (y * 640);
+
+ charWidth = font.getCharWidth(ch);
+ charHeight = font.getHeight() - 2;
+ charData = font.getCharData(ch);
+
+ while (charHeight--) {
+ byte lineWidth = charWidth;
+ while (lineWidth > 0) {
+ byte count = charData[0] & 0x0F;
+ byte flags = charData[0] & 0xF0;
+ charData++;
+ lineWidth -= count;
+ if (!(flags & 0x80) && (flags & 0x10)) {
+ memset(dest, color, count);
+ }
+ dest += count;
+ }
+ dest += 640 - charWidth;
+ }
+
+}
+
+void Screen::drawChar2(const Font &font, byte *dest, int16 x, int16 y, byte ch, byte color) {
+
+ int16 charWidth, charHeight;
+ byte *charData;
+
+ dest += x + (y * 640);
+
+ charWidth = font.getCharWidth(ch);
+ charHeight = font.getHeight() - 2;
+ charData = font.getCharData(ch);
+
+ while (charHeight--) {
+ byte lineWidth = charWidth;
+ while (lineWidth > 0) {
+ byte count = charData[0] & 0x0F;
+ byte flags = charData[0] & 0xF0;
+ charData++;
+ lineWidth -= count;
+
+ if ((flags & 0x80) == 0) {
+ if ((flags & 0x10) == 0) {
+ memset(dest, 0, count);
+ } else {
+ memset(dest, color, count);
+ }
+ }
+
+ dest += count;
+ }
+ dest += 640 - charWidth;
+ }
+
+}
+
+/*
+void Screen::update() {
+}
+*/
+
+} // End of namespace Toltecs
diff --git a/engines/toltecs/screen.h b/engines/toltecs/screen.h
new file mode 100644
index 0000000000..352eeaec29
--- /dev/null
+++ b/engines/toltecs/screen.h
@@ -0,0 +1,378 @@
+/* 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 TOLTECS_SCREEN_H
+#define TOLTECS_SCREEN_H
+
+#include "common/scummsys.h"
+#include "common/endian.h"
+#include "common/util.h"
+#include "common/file.h"
+#include "common/savefile.h"
+#include "common/system.h"
+#include "common/hash-str.h"
+#include "common/events.h"
+#include "common/keyboard.h"
+#include "common/list.h"
+#include "common/array.h"
+
+#include "graphics/surface.h"
+
+#include "sound/audiostream.h"
+#include "sound/mixer.h"
+#include "sound/voc.h"
+#include "sound/audiocd.h"
+
+#include "engines/engine.h"
+
+namespace Toltecs {
+
+struct DrawRequest {
+ int16 x, y;
+ int16 resIndex;
+ uint16 flags;
+ int16 baseColor;
+ int8 scaling;
+};
+
+struct SpriteDrawItem {
+ int16 x, y;
+ int16 width, height;
+ int16 origWidth, origHeight;
+ int16 resIndex;
+ uint32 offset;
+ int16 xdelta, ydelta;
+ uint16 flags;
+ int16 value1, yerror;
+ int16 ybottom;
+ int16 baseColor;
+};
+
+struct SpriteFrameEntry {
+ int16 y, x, h, w;
+ uint32 offset;
+ SpriteFrameEntry() {
+ }
+ SpriteFrameEntry(byte *data) {
+ y = READ_LE_UINT16(data + 0);
+ x = READ_LE_UINT16(data + 2);
+ h = READ_LE_UINT16(data + 4);
+ w = READ_LE_UINT16(data + 6);
+ offset = READ_LE_UINT32(data + 8);
+ }
+};
+
+class Font {
+public:
+ Font(byte *fontData) : _fontData(fontData) {
+ }
+ ~Font() {
+ }
+ int16 getSpacing() const {
+ return _fontData[1];
+ }
+ int16 getHeight() const {
+ return _fontData[2];
+ }
+ int16 getWidth() const {
+ return _fontData[3];
+ }
+ int16 getCharWidth(byte ch) const {
+ return _fontData[4 + (ch - 0x21)];
+ }
+ byte *getCharData(byte ch) const {
+ return _fontData + 0x298 + READ_LE_UINT16(&_fontData[0xE0 + (ch - 0x21) * 2]);
+ }
+protected:
+ byte *_fontData;
+};
+
+//*BEGIN*TEST*CODE********************************************************************************************
+
+struct PixelPacket {
+ byte count;
+ byte pixel;
+};
+
+enum SpriteReaderStatus {
+ kSrsPixelsLeft,
+ kSrsEndOfLine,
+ kSrsEndOfSprite
+};
+
+class SpriteFilter {
+public:
+ SpriteFilter(SpriteDrawItem *sprite) : _sprite(sprite) {
+ }
+ virtual SpriteReaderStatus readPacket(PixelPacket &packet) = 0;
+protected:
+ SpriteDrawItem *_sprite;
+};
+
+class SpriteReader : public SpriteFilter {
+public:
+ SpriteReader(byte *source, SpriteDrawItem *sprite) : SpriteFilter(sprite), _source(source) {
+ _curWidth = _sprite->origWidth;
+ _curHeight = _sprite->origHeight;
+ }
+ SpriteReaderStatus readPacket(PixelPacket &packet) {
+ if ((_sprite->flags & 0x40) || (_sprite->flags & 0x10)) {
+ packet.pixel = *_source++;
+ packet.count = *_source++;
+ } else {
+ packet.count = _source[0] & 0x0F;
+ packet.pixel = (_source[0] & 0xF0) >> 4;
+ _source++;
+ }
+ _curWidth -= packet.count;
+ if (_curWidth <= 0) {
+ _curHeight--;
+ if (_curHeight == 0) {
+ return kSrsEndOfSprite;
+ } else {
+ _curWidth = _sprite->origWidth;
+ return kSrsEndOfLine;
+ }
+ } else {
+ return kSrsPixelsLeft;
+ }
+ }
+ byte *getSource() {
+ return _source;
+ }
+ void setSource(byte *source) {
+ _source = source;
+ _curHeight++;
+ }
+protected:
+ byte *_source;
+ int16 _curWidth, _curHeight;
+};
+
+class SpriteFilterScaleDown : public SpriteFilter {
+public:
+ SpriteFilterScaleDown(SpriteDrawItem *sprite, SpriteReader *reader) : SpriteFilter(sprite), _reader(reader) {
+ _height = _sprite->height;
+ _yerror = _sprite->yerror;
+ _origHeight = _sprite->origHeight;
+ _scalerStatus = 0;
+ }
+ SpriteReaderStatus readPacket(PixelPacket &packet) {
+ SpriteReaderStatus status;
+ if (_scalerStatus == 0) {
+ _xerror = _sprite->xdelta;
+ _yerror -= 100;
+ while (_yerror <= 0) {
+ do {
+ status = _reader->readPacket(packet);
+ } while (status == kSrsPixelsLeft);
+ _yerror += _sprite->ydelta - 100;
+ }
+ if (status == kSrsEndOfSprite)
+ return kSrsEndOfSprite;
+ _scalerStatus = 1;
+ }
+ if (_scalerStatus == 1) {
+ status = _reader->readPacket(packet);
+ byte updcount = packet.count;
+ while (updcount--) {
+ _xerror -= 100;
+ if (_xerror <= 0) {
+ if (packet.count > 0)
+ packet.count--;
+ _xerror += _sprite->xdelta;
+ }
+ }
+ if (status == kSrsEndOfLine) {
+ if (--_height == 0)
+ return kSrsEndOfSprite;
+ _scalerStatus = 0;
+ return kSrsEndOfLine;
+ }
+ }
+ return kSrsPixelsLeft;
+ }
+protected:
+ SpriteReader *_reader;
+ int16 _xerror, _yerror;
+ int16 _height;
+ int16 _origHeight;
+ int _scalerStatus;
+};
+
+class SpriteFilterScaleUp : public SpriteFilter {
+public:
+ SpriteFilterScaleUp(SpriteDrawItem *sprite, SpriteReader *reader) : SpriteFilter(sprite), _reader(reader) {
+ _height = _sprite->height;
+ _yerror = _sprite->yerror;
+ _origHeight = _sprite->origHeight;
+ _scalerStatus = 0;
+ }
+ SpriteReaderStatus readPacket(PixelPacket &packet) {
+ SpriteReaderStatus status;
+ if (_scalerStatus == 0) {
+ _xerror = _sprite->xdelta;
+ _sourcep = _reader->getSource();
+ _scalerStatus = 1;
+ }
+ if (_scalerStatus == 1) {
+ status = _reader->readPacket(packet);
+ byte updcount = packet.count;
+ while (updcount--) {
+ _xerror -= 100;
+ if (_xerror <= 0) {
+ packet.count++;
+ _xerror += _sprite->xdelta;
+ }
+ }
+ if (status == kSrsEndOfLine) {
+ if (--_height == 0)
+ return kSrsEndOfSprite;
+ _yerror -= 100;
+ if (_yerror <= 0) {
+ _reader->setSource(_sourcep);
+ _yerror += _sprite->ydelta + 100;
+ }
+ _scalerStatus = 0;
+ return kSrsEndOfLine;
+ }
+ }
+ return kSrsPixelsLeft;
+ }
+protected:
+ SpriteReader *_reader;
+ byte *_sourcep;
+ int16 _xerror, _yerror;
+ int16 _height;
+ int16 _origHeight;
+ int _scalerStatus;
+};
+
+//*END*TEST*CODE**********************************************************************************************
+
+struct TextRect {
+ int16 x, y;
+ int16 width, length;
+};
+
+struct TalkTextItem {
+ int16 duration;
+ int16 slotIndex;
+ int16 slotOffset;
+ int16 fontNum;
+ byte color;
+ byte rectCount;
+ TextRect rects[15];
+};
+
+class Screen {
+public:
+ Screen(ToltecsEngine *vm);
+ ~Screen();
+
+ void unpackRle(byte *source, byte *dest, uint16 width, uint16 height);
+
+ void loadMouseCursor(uint resIndex);
+
+ void drawGuiImage(int16 x, int16 y, uint resIndex);
+
+ void startShakeScreen(int16 shakeCounter);
+ void stopShakeScreen();
+ void updateShakeScreen();
+
+ // Sprite list
+ void addStaticSprite(byte *spriteItem);
+ void addAnimatedSprite(int16 x, int16 y, int16 fragmentId, byte *data, int16 *spriteArray, bool loop, int mode);
+ void clearSprites();
+
+ // Sprite drawing
+ void drawSprite(SpriteDrawItem *sprite);
+ void drawSpriteCore(byte *dest, SpriteFilter &reader, SpriteDrawItem *sprite);
+ void drawSprites();
+
+ // Verb line
+ void updateVerbLine(int16 slotIndex, int16 slotOffset);
+
+ // Talk text
+ void updateTalkText(int16 slotIndex, int16 slotOffset);
+ void addTalkTextRect(Font &font, int16 x, int16 &y, int16 length, int16 width, TalkTextItem *item);
+ void drawTalkTextItems();
+ int16 getTalkTextDuration();
+
+ // Font/text
+ void registerFont(uint fontIndex, uint resIndex);
+ void printText(byte *textData);
+ void preprocessText(uint fontResIndex, int maxWidth, int &width, byte *&sourceString, byte *&destString, byte &len);
+ void drawString(int16 x, int16 y, byte fontColor1, byte fontColor2, uint fontResIndex);
+ void drawChar(const Font &font, byte *dest, int16 x, int16 y, byte ch, byte color);
+ void drawChar2(const Font &font, byte *dest, int16 x, int16 y, byte ch, byte color);
+
+//protected:
+public:
+
+ struct VerbLineItem {
+ int16 slotIndex;
+ int16 slotOffset;
+ };
+
+ struct Rect {
+ int16 x, y, width, height;
+ };
+
+ ToltecsEngine *_vm;
+
+ byte *_frontScreen, *_backScreen;
+
+ Common::List<SpriteDrawItem> _spriteDrawList;
+
+ uint _fontResIndexArray[10];
+ byte _fontColor1, _fontColor2;
+
+ byte _tempString[100];
+ byte _tempStringLen1, _tempStringLen2;
+
+ // Screen shaking
+ bool _shakeActive;
+ int16 _shakeCounterInit, _shakeCounter;
+ int _shakePos;
+
+ // Verb line
+ int16 _verbLineNum;
+ VerbLineItem _verbLineItems[8];
+ int16 _verbLineX, _verbLineY, _verbLineWidth;
+ int16 _verbLineCount;
+
+ // Talk text
+ int16 _talkTextX, _talkTextY;
+ int16 _talkTextMaxWidth;
+ byte _talkTextFontColor;
+ int16 _talkTextItemNum;
+ TalkTextItem _talkTextItems[5];
+
+ void addDrawRequest(const DrawRequest &drawRequest);
+
+};
+
+} // End of namespace Toltecs
+
+#endif /* TOLTECS_SCREEN_H */
diff --git a/engines/toltecs/script.cpp b/engines/toltecs/script.cpp
new file mode 100644
index 0000000000..5d7e55b49d
--- /dev/null
+++ b/engines/toltecs/script.cpp
@@ -0,0 +1,1219 @@
+/* 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 "common/events.h"
+#include "common/keyboard.h"
+#include "common/file.h"
+#include "common/savefile.h"
+#include "common/config-manager.h"
+
+#include "base/plugins.h"
+#include "base/version.h"
+
+#include "sound/mixer.h"
+
+#include "toltecs/toltecs.h"
+#include "toltecs/animation.h"
+#include "toltecs/input.h"
+#include "toltecs/palette.h"
+#include "toltecs/resource.h"
+#include "toltecs/script.h"
+#include "toltecs/screen.h"
+#include "toltecs/segmap.h"
+
+namespace Toltecs {
+
+ScriptInterpreter::ScriptInterpreter(ToltecsEngine *vm) : _vm(vm) {
+
+ _stack = new byte[4096 + 4];
+
+ memset(_slots, 0, sizeof(_slots));
+
+ _savedSp = 0;
+
+}
+
+ScriptInterpreter::~ScriptInterpreter() {
+ delete[] _stack;
+}
+
+void ScriptInterpreter::loadScript(uint resIndex, uint slotIndex) {
+
+ if (_slots[slotIndex].data) {
+ delete[] _slots[slotIndex].data;
+ }
+
+ _slots[slotIndex].resIndex = resIndex;
+ byte *scriptData = _vm->_res->load(resIndex);
+ _slots[slotIndex].size = _vm->_res->getCurItemSize();
+ _slots[slotIndex].data = new byte[_slots[slotIndex].size];
+ memcpy(_slots[slotIndex].data, scriptData, _slots[slotIndex].size);
+
+}
+
+void ScriptInterpreter::runScript(uint slotIndex) {
+
+ _switchStack1 = true;
+ _switchStack2 = false;
+ _switchStack3 = false;
+ _scriptFlag01 = false;
+
+ _regs.reg0 = 0;
+ _regs.reg1 = 0;
+ _regs.reg2 = 0;
+ _regs.reg3 = 0;
+ _regs.reg4 = slotIndex;
+ _regs.reg5 = 0;
+ _regs.reg6 = 0;
+ _regs.sp = 4096;
+ _regs.reg8 = 0;
+
+ _code = getSlotData(_regs.reg4);
+
+ while (1) {
+
+ if (_vm->_movieSceneFlag)
+ _vm->_input->_mouseButton = 0;
+
+ if (_switchStack1) {
+ _switchStack1 = false;
+ _localData = getSlotData(_regs.reg4);
+ }
+
+ if (_switchStack2) {
+ _switchStack2 = false;
+ _localData = getSlotData(_regs.reg5);
+ _switchStack1 = true;
+ }
+
+ if (_switchStack3) {
+ _switchStack3 = false;
+ _localData = _stack + 2;
+ _switchStack1 = true;
+ }
+
+ byte opcode = readByte();
+ execOpcode(opcode);
+
+ // Call updateScreen roughly every 10ms else the mouse cursor will be jerky
+ if (_vm->_system->getMillis() % 10 == 0)
+ _vm->_system->updateScreen();
+
+ }
+
+}
+
+byte ScriptInterpreter::readByte() {
+ return *_code++;
+}
+
+int16 ScriptInterpreter::readInt16() {
+ int16 value = READ_LE_UINT16(_code);
+ _code += 2;
+ return value;
+}
+
+void look(byte *code) {
+ char ln[256];
+ snprintf(ln, 256, "\t\t\t%02X %02X %02X %02X %02X %02X %02X %02X",
+ code[0], code[1], code[2], code[3], code[4], code[5], code[6], code[7]);
+ debug(1, "%s", ln);
+}
+
+void ScriptInterpreter::execOpcode(byte opcode) {
+
+#if 0
+ char ln[256];
+ snprintf(ln, 256, "\t\t\t%02X %02X %02X %02X %02X %02X %02X %02X",
+ _code[0], _code[1], _code[2], _code[3], _code[4], _code[5], _code[6], _code[7]);
+ debug(1, "%s", ln);
+#endif
+
+ int16 ofs;
+
+ debug(1, "opcode = %d", opcode);
+
+ switch (opcode) {
+ case 0:
+ {
+ // ok
+ _subCode = _code;
+ byte length = readByte();
+ debug(1, "length = %d", length);
+ uint16 kernelOpcode = readInt16();
+ debug(1, "callKernel %d", kernelOpcode);
+ execKernelOpcode(kernelOpcode);
+ _code += length - 2;
+ break;
+ }
+ case 1:
+ // ok
+ _regs.reg0 = readInt16();
+ debug(1, "mov reg0, #%d", _regs.reg0);
+ break;
+ case 2:
+ // ok
+ _regs.reg1 = readInt16();
+ debug(1, "mov reg1, #%d", _regs.reg1);
+ break;
+ case 3:
+ // ok
+ _regs.reg3 = readInt16();
+ debug(1, "mov reg3, #%d", _regs.reg3);
+ break;
+ case 4:
+ // ok
+ _regs.reg5 = _regs.reg0;
+ debug(1, "mov reg5, reg0");
+ break;
+ case 5:
+ // ok
+ _regs.reg3 = _regs.reg0;
+ debug(1, "mov reg3, reg0");
+ break;
+ case 6:
+ // ok
+ _regs.reg1 = _regs.reg0;
+ debug(1, "mov reg1, reg0");
+ break;
+ case 7:
+ _regs.reg1 = localRead16(_regs.reg3);
+ debug(1, "mov reg1, *%d", _regs.reg3);
+ break;
+ case 8:
+ localWrite16(_regs.reg3, _regs.reg0);
+ break;
+ case 9:
+ localWrite16(readInt16(), _regs.reg0);
+ break;
+ case 10:
+ localWrite8(readInt16(), _regs.reg0);
+ break;
+ case 11:
+ localWrite16(readInt16(), _regs.reg5);
+ break;
+ case 12:
+ localWrite16(readInt16(), _regs.reg4);
+ break;
+ case 13:
+ localWrite16(readInt16(), _regs.reg3);
+ break;
+ case 14:
+ _regs.reg3 = localRead16(readInt16());
+ break;
+ case 15:
+ _regs.reg2 = localRead16(_regs.reg1);
+ break;
+ case 16:
+ _regs.reg2 = localRead16(_regs.reg1 + readInt16());
+ break;
+ case 17:
+ _regs.reg2 = _regs.reg0;
+ break;
+ case 18:
+ _regs.reg0 += readInt16();
+ break;
+ case 19:
+ localWrite16(_regs.reg3, localRead16(_regs.reg3) + _regs.reg0);
+ break;
+ case 20:
+ _regs.reg0 += _regs.reg2;
+ break;
+ case 21:
+ _regs.reg3 += _regs.sp;
+ break;
+ case 22:
+ _regs.reg1 += _regs.sp;
+ break;
+ case 23:
+ localWrite16(_regs.reg3, localRead16(_regs.reg3) - _regs.reg0);
+ break;
+ case 24:
+ _regs.reg0 /= readInt16();
+ break;
+ case 25:
+ localWrite16(_regs.reg3, localRead16(_regs.reg3) / _regs.reg0);
+ break;
+ case 26:
+ // NOP
+ break;
+ case 27:
+ _regs.reg0 *= readInt16();
+ break;
+ case 28:
+ localWrite16(_regs.reg3, localRead16(_regs.reg3) * _regs.reg0);
+ break;
+ case 29:
+ _regs.reg0 *= _regs.reg2;
+ break;
+ case 30:
+ localWrite16(_regs.reg3, localRead16(_regs.reg3) + 1);
+ break;
+ case 31:
+ localWrite16(_regs.reg3, localRead16(_regs.reg3) - 1);
+ break;
+ case 32:
+ _switchStack2 = true;
+ break;
+ case 33:
+ _switchStack3 = true;
+ break;
+ case 34:
+ push16(_regs.reg0);
+ debug(1, "pushw reg0");
+ break;
+ case 35:
+ push16(_regs.reg1);
+ debug(1, "pushw reg1");
+ break;
+ case 36:
+ _regs.reg1 = pop16();
+ debug(1, "popw reg1");
+ break;
+ case 37:
+ _regs.reg0 = pop16();
+ debug(1, "popw reg0");
+ break;
+ case 38:
+ _regs.reg2 = -_regs.reg2;
+ break;
+ case 39:
+ _regs.reg8 = readInt16();
+ _scriptFlag01 = false;
+ break;
+ case 40:
+ _regs.reg8 = _regs.reg0;
+ _scriptFlag01 = false;
+ break;
+ case 41:
+ _regs.reg8 = readInt16();
+ _scriptFlag01 = true;
+ break;
+ case 42:
+ _regs.reg8 = _regs.reg0;
+ _scriptFlag01 = true;
+ break;
+ case 43:
+ debug(1, "retn (slot: %d; ofs: %04X)\n", _regs.reg4, _regs.reg0);
+ _code = getSlotData(_regs.reg4) + _regs.reg0;
+ break;
+ case 44:
+ debug(1, "retf (slot: %d; ofs: %04X)\n", _regs.reg5, _regs.reg0);
+ _code = getSlotData(_regs.reg5) + _regs.reg0;
+ _regs.reg4 = _regs.reg5;
+ _switchStack1 = true;
+ break;
+ case 45:
+ debug(1, "callnear %04X (slot: %d; ofs: %04X)\n", _regs.reg0, _regs.reg4, _regs.reg0);
+ push16(_code - getSlotData(_regs.reg4));
+ push16(_regs.reg4);
+ _code = getSlotData(_regs.reg4) + _regs.reg0;
+ break;
+ case 46:
+ debug(1, "callfar %04X (slot: %d; ofs: %04X)\n", _regs.reg0, _regs.reg5, _regs.reg0);
+ push16(_code - getSlotData(_regs.reg4));
+ push16(_regs.reg4);
+ _code = getSlotData(_regs.reg5) + _regs.reg0;
+ _regs.reg4 = _regs.reg5;
+ _switchStack1 = true;
+ break;
+ case 47:
+ _regs.reg4 = pop16();
+ ofs = pop16();
+ _code = getSlotData(_regs.reg4) + ofs;
+ debug(1, "ret (slot: %d; ofs: %04X)\n", _regs.reg4, ofs);
+ //_code = getSlotData(_regs.reg4) + pop16();
+ _switchStack1 = true;
+ break;
+ case 48:
+ _regs.reg4 = pop16();
+ ofs = pop16();
+ _code = getSlotData(_regs.reg4) + ofs;
+ debug(1, "retsp (slot: %d; ofs: %04X)\n", _regs.reg4, ofs);
+ //_code = getSlotData(_regs.reg4) + pop16();
+ _regs.sp += _regs.reg0;
+ _switchStack1 = true;
+ break;
+ case 49:
+ ofs = readByte();
+ debug(0, "49, len = %d", ofs);
+ _code += ofs;
+ break;
+ case 50:
+ if (_scriptFlag01) {
+ _regs.reg1 &= _regs.reg8;
+ if (_regs.reg1 == 0)
+ _code += 4;
+ } else {
+ if (_regs.reg1 == _regs.reg8)
+ _code += 4;
+ }
+ _code++;
+ break;
+ case 51:
+ if (_scriptFlag01) {
+ _regs.reg1 &= _regs.reg8;
+ if (_regs.reg1 != 0)
+ _code += 4;
+ } else {
+ if (_regs.reg1 != _regs.reg8)
+ _code += 4;
+ }
+ _code++;
+ break;
+ case 52:
+ if (_regs.reg1 >= _regs.reg8)
+ _code += 4;
+ _code++;
+ break;
+ case 53:
+ if (_regs.reg1 <= _regs.reg8)
+ _code += 4;
+ _code++;
+ break;
+ case 54:
+ if (_regs.reg1 < _regs.reg8)
+ _code += 4;
+ _code++;
+ break;
+ case 55:
+ if (_regs.reg1 > _regs.reg8)
+ _code += 4;
+ _code++;
+ break;
+ default:
+ {
+ /*
+ FILE *ex = fopen("error.0", "wb");
+ fwrite(_code - 8, 4096, 1, ex);
+ fclose(ex);
+ */
+ error("Invalid opcode %d", opcode);
+ }
+ }
+
+}
+
+void ScriptInterpreter::execKernelOpcode(uint16 kernelOpcode) {
+
+ switch (kernelOpcode) {
+
+ case 0:
+ case 1:
+ // ok, NOPs
+ break;
+
+ case 2:// ok
+ {
+ debug(0, "o2_getGameVar(%d, %d)", arg16(3), arg16(5));
+ int16 value = getGameVar(arg16(3));
+ localWrite16(arg16(5), value);
+ break;
+ }
+
+ case 3:// ok
+ {
+ debug(0, "o2_setGameVar(%d, %d)", arg16(3), arg16(5));
+ VarType varType = getGameVarType(arg16(3));
+ int16 value;
+ if (varType == vtByte)
+ value = arg8(5);
+ else if (varType == vtWord)
+ value = arg16(5);
+ setGameVar(arg16(3), value);
+ break;
+ }
+
+ case 4:
+ {
+
+ debug(0, "o2_updateScreen()");
+
+ // TODO? updateSamples();
+
+ _vm->_screen->updateShakeScreen();
+
+ if (_vm->_quitGame)
+ return;
+
+ if (!_vm->_movieSceneFlag)
+ _vm->_input->update();
+ else
+ _vm->_input->_mouseButton = 0;
+
+ // TODO? Check keyb
+
+ _vm->_counter01--;
+ if (_vm->_counter01 <= 0) {
+ _vm->_counter01 = MIN(_vm->_counter02, 30);
+ _vm->_counter02 = 0;
+ _vm->updateScreen();
+ _vm->_flag01 = 1;
+ _vm->_system->delayMillis(5);
+ _vm->_counter02 = 1; // ?
+ } else {
+ _vm->_screen->clearSprites();
+ _vm->_flag01 = 0;
+ //_vm->_system->updateScreen();
+ }
+
+ // TODO
+ break;
+
+ }
+
+ case 5:// ok
+ {
+ debug(0, "o2_mouseDeltaStuff(%d)", arg16(3));
+ localWrite16(arg16(5), _vm->_input->getMouseDeltaStuff(arg16(3)));
+ break;
+ }
+
+ case 6:// ok
+ {
+ debug(0, "o2_printText()");
+ _vm->_screen->printText((byte*)localPtr(arg16(3)));
+ break;
+ }
+
+ case 7:// ok
+ {
+ debug(0, "o2_updateVerbLine(slot: %d; offset: %04X)", arg16(5), arg16(3));
+ _vm->_screen->updateVerbLine(arg16(5), arg16(3));
+ break;
+ }
+
+ case 8:// ok
+ {
+ debug(0, "o2_setFontColor(%d)", arg8(3));
+ _vm->_screen->_fontColor1 = 0;
+ _vm->_screen->_fontColor2 = arg8(3);
+ break;
+ }
+
+ case 9:// ok
+ {
+ debug(0, "o2_getTalkTextDuration()");
+ int16 duration = _vm->_screen->getTalkTextDuration();
+ localWrite16(arg16(3), duration);
+ break;
+ }
+
+ case 10:// ok
+ {
+ debug(0, "o2_talk(slot: %d; offset: %d)", arg16(5), arg16(3));
+ _vm->talk(arg16(5), arg16(3));
+ break;
+ }
+
+ case 11:// ok
+ {
+ debug(0, "o2_findFragment(%d, %d)", arg16(3), arg16(5));
+ localWrite16(arg16(5), _vm->_palette->findFragment(arg16(3)));
+ break;
+ }
+
+ case 12:// ok
+ {
+ debug(0, "o2_clearPaletteFragments()");
+ _vm->_palette->clearFragments();
+ break;
+ }
+
+ case 13:// ok
+ {
+ debug(0, "o2_addFragment(%d, %d)", arg16(3), arg16(5));
+ _vm->_palette->addFragment(arg16(3), arg16(5));
+ break;
+ }
+
+ case 14:// ok
+ {
+ debug(0, "o2_setDeltaPalette(animPalette, %d, %d, %d, %d)", arg8(6), arg8(5), arg8(4), arg8(3));
+ _vm->_palette->setDeltaPalette(_vm->_anim->_palette, arg8(6), (char)arg8(5), arg8(4), arg8(3));
+ break;
+ }
+
+ case 16:// TODO
+ {
+ debug(0, "o2_makeTransColorTable");
+ break;
+ }
+
+ case 17:// ok
+ {
+ debug(0, "o2_setDeltaPalette(mainPalette, %d, %d, %d, %d)", arg8(6), arg8(5), arg8(4), arg8(3));
+ _vm->_palette->setDeltaPalette(_vm->_palette->getMainPalette(), arg8(6), (char)arg8(5), arg8(4), arg8(3));
+ break;
+ }
+
+ case 18:// ok
+ {
+ debug(0, "o2_loadScript(resIndex: %d; slotIndex: %d)", arg16(4), arg8(3));
+ int16 codeOfs = _code - getSlotData(_regs.reg4);
+ loadScript(arg16(4), arg8(3));
+ _code = getSlotData(_regs.reg4) + codeOfs;
+ _switchStack1 = true;
+ break;
+ }
+
+ case 19:// ok
+ {
+ debug(0, "o2_registerFont(%d, %d)", arg8(3), arg16(4));
+ _vm->_screen->registerFont(arg8(3), arg16(4));
+ break;
+ }
+
+ case 20:// ok
+ {
+ debug(0, "o2_loadAddPalette(startIndex: %d; resIndex: %d)", arg8(3), arg16(4));
+ _vm->_palette->loadAddPalette(arg16(4), arg8(3));
+ break;
+ }
+
+ case 21:// TODO
+ {
+ debug(0, "o2_loadScene(resIndex: %d; flag: %d)", arg16(4), arg8(3));
+ if (arg8(3) == 0) {
+ _vm->loadScene(arg16(4));
+ } else {
+ _vm->_screen->loadMouseCursor(arg16(4));
+ }
+ break;
+ }
+
+ case 22:// ok
+ {
+ debug(0, "o2_setCameraTop(%d)", arg8(3));
+ _vm->setCameraTop(arg8(3));
+ break;
+ }
+
+ case 23:// ok
+ {
+ debug(0, "o2_findMouseInRectIndex1(offset: %d; slot: %d; elemSize: %d; var: %d; index: %d)", arg16(3), arg16(5), arg16(7), arg16(9), arg16(11));
+ int16 index = -1;
+ if (_vm->_input->_mouseY < _vm->_cameraHeight) {
+ index = _vm->findRectAtPoint(getSlotData(arg16(5)) + arg16(3),
+ _vm->_input->_mouseX + _vm->_cameraX,
+ _vm->_input->_mouseY + _vm->_cameraY,
+ arg16(11) + 1, arg16(7));
+ }
+ localWrite16(arg16(9), index);
+ break;
+ }
+
+ case 24:// ok
+ {
+ debug(0, "o2_findMouseInRectIndex2(offset: %d, slot: %d, elemSize: %d, var: %d)", arg16(3), arg16(5), arg16(7), arg16(9));
+ int16 index = -1;
+
+ debug(0, "_vm->_input->_mouseDisabled = %d", _vm->_input->_mouseDisabled);
+
+ /* FIXME: This opcode is called after the Revistronic logo at the beginning,
+ but at the slot/offset there's bytecode and not a rect array as expected.
+ To avoid crashes we skip searching the rectangle index for now when scene 215 is active.
+ I don't know yet whether this is a bug in the original engine as well or just here.
+ Needs some more checking.
+ */
+ if (_vm->_sceneResIndex != 215) {
+ if (_vm->_input->_mouseY < _vm->_cameraHeight) {
+ index = _vm->findRectAtPoint(getSlotData(arg16(5)) + arg16(3),
+ _vm->_input->_mouseX + _vm->_cameraX,
+ _vm->_input->_mouseY + _vm->_cameraY,
+ 0, arg16(7));
+ }
+ }
+
+ localWrite16(arg16(9), index);
+
+ break;
+ }
+
+ case 25:// ok
+ {
+ debug(0, "o2_drawGuiImage(x: %d; y: %d; resIndex: %d)", arg16(5), arg16(3), arg16(7));
+ _vm->_screen->drawGuiImage(arg16(5), arg16(3), arg16(7));
+ break;
+ }
+
+ case 26:// ok
+ {
+ debug(0, "o2_addAnimatedSpriteNoLoop(2; x: %d; y: %d; fragmentId: %d; offset: %d)", arg16(5), arg16(3), arg16(7), arg16(9));
+ _vm->_screen->addAnimatedSprite(arg16(5), arg16(3), arg16(7), (byte*)localPtr(0), (int16*)localPtr(arg16(9)), false, 2);
+ break;
+ }
+
+ case 27:// ok
+ {
+ debug(0, "o2_addAnimatedSprite(2; x: %d; y: %d; fragmentId: %d; offset: %d)", arg16(5), arg16(3), arg16(7), arg16(9));
+ _vm->_screen->addAnimatedSprite(arg16(5), arg16(3), arg16(7), (byte*)localPtr(0), (int16*)localPtr(arg16(9)), true, 2);
+ break;
+ }
+
+ case 28:// ok
+ {
+ debug(1, "o2_addStaticSprite()");
+ _vm->_screen->addStaticSprite(_subCode + 3);
+ break;
+ }
+
+ case 29:// ok
+ {
+ debug(0, "o2_addAnimatedSprite(1; x: %d; y: %d; value: %d; offset: %d)", arg16(5), arg16(3), arg16(7), arg16(9));
+ _vm->_screen->addAnimatedSprite(arg16(5), arg16(3), arg16(7), (byte*)localPtr(0), (int16*)localPtr(arg16(9)), true, 1);
+ break;
+ }
+
+ case 30:// ok
+ {
+ debug(0, "o2_findPath(sourceX: %d; sourceY: %d; destX: %d; destY: %d; slotIndex: %d; offset: %d)", arg16(5), arg16(3), arg16(9), arg16(7), arg16(13), arg16(11));
+ _vm->_segmap->findPath((int16*)(getSlotData(arg16(13)) + arg16(11)), arg16(9), arg16(7), arg16(5), arg16(3));
+ break;
+ }
+
+ case 31:// ok
+ {
+ debug(0, "o2_walk()");
+ _vm->walk(getSlotData(arg16(5)) + arg16(3));
+ break;
+ }
+
+ case 32:// ok
+ {
+ debug(0, "o2_scrollCameraUp()");
+ _vm->scrollCameraUp(4);
+ break;
+ }
+
+ case 33:// ok
+ {
+ debug(0, "o2_scrollCameraDown()");
+ _vm->scrollCameraDown(4);
+ break;
+ }
+
+ case 34:// ok
+ {
+ debug(0, "o2_scrollCameraLeft()");
+ _vm->scrollCameraLeft(4);
+ break;
+ }
+
+ case 35:// ok
+ {
+ debug(0, "o2_scrollCameraRight()");
+ _vm->scrollCameraRight(4);
+ break;
+ }
+
+ case 36:// ok
+ {
+ debug(0, "o2_scrollCameraUpEx(%d)", arg16(3));
+ _vm->scrollCameraUp(arg16(3));
+ break;
+ }
+
+ case 37:// ok
+ {
+ debug(0, "o2_scrollCameraDownEx(%d)", arg16(3));
+ _vm->scrollCameraDown(arg16(3));
+ break;
+ }
+
+ case 38:// ok
+ {
+ debug(0, "o2_scrollCameraLeftEx(%d)", arg16(3));
+ _vm->scrollCameraLeft(arg16(3));
+ break;
+ }
+
+ case 39:// ok
+ {
+ debug(0, "o2_scrollCameraRightEx(%d)", arg16(3));
+ _vm->scrollCameraRight(arg16(3));
+ break;
+ }
+
+ case 40:// ok
+ {
+ debug(0, "o2_setCamera(%d, %d)", arg16(5), arg16(3));
+ _vm->setCamera(arg16(5), arg16(3));
+ break;
+ }
+
+ case 42:// ok
+ {
+ debug(0, "o2_getRgbModifiertAtPoint(x: %d; y: %d; id: %d; varSlot: %d; varOffset: %d)", arg16(5), arg16(3), arg16(7), arg16(11), arg16(9));
+ byte *rgb = getSlotData(arg16(11)) + arg16(9);
+ _vm->_segmap->getRgbModifiertAtPoint(arg16(5), arg16(3), arg16(7), rgb[0], rgb[1], rgb[2]);
+ break;
+ }
+
+ case 43:// ok
+ {
+ debug(0, "o2_startAnim(%d)", arg16(3));
+ _vm->_anim->start(arg16(3));
+ break;
+ }
+
+ case 44:// ok
+ {
+ debug(0, "o2_animNextFrame()");
+ _vm->_anim->nextFrame();
+ break;
+ }
+
+ case 45:// ok
+ {
+ // NOP
+ break;
+ }
+
+ case 46:// ok
+ {
+ debug(0, "o2_getAnimFrameNumber(%d)", arg16(3));
+ localWrite16(arg16(3), _vm->_anim->getFrameNumber());
+ break;
+ }
+
+ case 47:
+ {
+ // almost ok
+ debug(0, "o2_getAnimStatus()");
+ int16 status = _vm->_anim->getStatus();
+ if (status == 0 || status == 1) {
+ // TODO mov screenFlag01, 0
+ }
+ localWrite16(arg16(3), status);
+ break;
+ }
+
+ case 48:// ok
+ {
+ _vm->_screen->startShakeScreen(arg16(3));
+ break;
+ }
+
+ case 49:// ok
+ {
+ _vm->_screen->stopShakeScreen();
+ break;
+ }
+
+ case 50:// TODO
+ {
+ debug(0, "o2_startSequence");
+ break;
+ }
+
+ case 51:// TODO
+ {
+ debug(0, "o2_endSequence");
+ break;
+ }
+
+ case 52:// TODO
+ {
+ debug(0, "o2_sequenceVolumeStuff");
+ break;
+ }
+
+ case 53:// TODO
+ {
+ debug(0, "o2_playSound1(%d, %d, %d, %d)", arg16(9), arg16(7), arg16(5), arg16(3));
+ break;
+ }
+
+ case 54:// TODO
+ {
+ debug(0, "o2_playSound2(%d, %d, %d)", arg16(7), arg16(5), arg16(3));
+ break;
+ }
+
+ case 55:// TODO
+ debug(0, "o2_clearScreen()");
+ break;
+
+ case 56:// ok
+ {
+ // NOP
+ break;
+ }
+
+ case 57:// TODO
+ {
+ debug(0, "o2_handleInput");
+ int16 varOfs = arg16(3);
+
+ localWrite16(varOfs, 0);
+
+ //_vm->_input->update();
+ break;
+ }
+
+ case 58:// TODO
+ {
+ debug(0, "o2_runOptionsScreen(%d, %d)", arg16(5), arg16(3));
+ break;
+ }
+
+ case 59:// TODO
+ {
+ debug(0, "o2_precacheResources(%04X)", arg16(3));
+ break;
+ }
+
+ case 60:// TODO
+ {
+ debug(0, "o2_precacheSounds1(%04X)", arg16(3));
+ // CHECKME
+ _vm->_screen->clearSprites();
+ break;
+ }
+
+ case 61:// TODO
+ {
+ debug(0, "o2_deleteAllPbfFilesByExternalArray()");
+ break;
+ }
+
+ case 63:// ok
+ {
+ _regs.sp = _savedSp;
+ break;
+ }
+
+ case 64:// ok
+ {
+ _savedSp = _regs.sp;
+ break;
+ }
+
+ case 65:// TODO
+ {
+ debug(0, "o2_playMovie(%d, %d)", arg16(3), arg16(5));
+ break;
+ }
+
+ case 66:
+ // NOP
+ break;
+
+ default:
+ error("Invalid kernel opcode %d", kernelOpcode);
+ }
+
+}
+
+ScriptInterpreter::VarType ScriptInterpreter::getGameVarType(uint variable) {
+ switch (variable) {
+ case 0: return vtByte;
+ case 1: return vtWord;
+ case 2: return vtWord;
+ case 3: return vtByte;
+ case 4: return vtWord;
+ case 5: return vtWord;
+ case 6: return vtWord;
+ case 7: return vtWord;
+ case 8: return vtWord;
+ case 9: return vtWord;
+ case 10: return vtWord;
+ case 11: return vtWord;
+ case 12: return vtByte;
+ case 13: return vtWord;
+ case 14: return vtWord;
+ case 15: return vtWord;
+ case 16: return vtWord;
+ case 17: return vtWord;
+ case 18: return vtWord;
+ case 19: return vtWord;
+ case 20: return vtWord;
+ case 21: return vtWord;
+ default:
+ error("Invalid game variable");
+ }
+}
+
+const char *getVarName(uint variable) {
+ switch (variable) {
+ case 0: return "mouseDisabled";
+ case 1: return "mouseY";
+ case 2: return "mouseX";
+ case 3: return "mouseButton";
+ case 4: return "verbLineY";
+ case 5: return "verbLineX";
+ case 6: return "verbLineWidth";
+ case 7: return "verbLineCount";
+ case 8: return "verbLineNum";
+ case 9: return "talkTextItemNum";
+ case 10: return "talkTextY";
+ case 11: return "talkTextX";
+ case 12: return "talkTextFontColor";
+ case 13: return "cameraY";
+ case 14: return "cameraX";
+ case 15: return "walkSpeedY";
+ case 16: return "walkSpeedX";
+ case 17: return "flag01";
+ case 18: return "sceneResIndex";
+ case 19: return "cameraTop";
+ case 20: return "sceneHeight";
+ case 21: return "sceneWidth";
+ }
+ return "(invalid)";
+}
+
+int16 ScriptInterpreter::getGameVar(uint variable) {
+ debug(0, "ScriptInterpreter::getGameVar(%d{%s})", variable, getVarName(variable));
+
+ int16 value = 0;
+
+ switch (variable) {
+ case 0:
+ value = _vm->_input->_mouseDisabled;
+ break;
+ case 1:
+ value = _vm->_input->_mouseY;
+ break;
+ case 2:
+ value = _vm->_input->_mouseX;
+ break;
+ case 3:
+ value = _vm->_input->_mouseButton;
+ break;
+ case 4:
+ value = _vm->_screen->_verbLineY;
+ break;
+ case 5:
+ value = _vm->_screen->_verbLineX;
+ break;
+ case 6:
+ value = _vm->_screen->_verbLineWidth;
+ break;
+ case 7:
+ value = _vm->_screen->_verbLineCount;
+ break;
+ case 8:
+ value = _vm->_screen->_verbLineNum;
+ break;
+ case 9:
+ value = _vm->_screen->_talkTextItemNum;
+ break;
+ case 10:
+ value = _vm->_screen->_talkTextY;
+ break;
+ case 11:
+ value = _vm->_screen->_talkTextX;
+ break;
+ case 12:
+ value = _vm->_screen->_talkTextFontColor;
+ break;
+ case 13:
+ value = _vm->_cameraY;
+ break;
+ case 14:
+ value = _vm->_cameraX;
+ break;
+ case 15:
+ value = _vm->_walkSpeedY;
+ break;
+ case 16:
+ value = _vm->_walkSpeedX;
+ break;
+ case 17:
+ value = _vm->_flag01;
+ break;
+ case 18:
+ value = _vm->_sceneResIndex;
+ break;
+ case 19:
+ value = _vm->_cameraTop;
+ break;
+ case 20:
+ value = _vm->_sceneHeight;
+ break;
+ case 21:
+ value = _vm->_sceneWidth;
+ break;
+ default:
+ warning("Getting unimplemented game variable %s (%d)", getVarName(variable), variable);
+ break;
+ }
+
+
+ return value;
+
+}
+
+void ScriptInterpreter::setGameVar(uint variable, int16 value) {
+ debug(0, "ScriptInterpreter::setGameVar(%d{%s}, %d)", variable, getVarName(variable), value);
+
+ switch (variable) {
+ case 0:
+ _vm->_input->_mouseDisabled = value;
+ break;
+ case 3:
+ _vm->_input->_mouseButton = value;
+ break;
+ case 4:
+ _vm->_screen->_verbLineY = value;
+ break;
+ case 5:
+ _vm->_screen->_verbLineX = value;
+ break;
+ case 6:
+ _vm->_screen->_verbLineWidth = value;
+ break;
+ case 7:
+ _vm->_screen->_verbLineCount = value;
+ break;
+ case 8:
+ _vm->_screen->_verbLineNum = value;
+ break;
+ case 9:
+ _vm->_screen->_talkTextItemNum = value;
+ break;
+ case 10:
+ _vm->_screen->_talkTextY = value;
+ break;
+ case 11:
+ _vm->_screen->_talkTextX = value;
+ break;
+ case 12:
+ _vm->_screen->_talkTextFontColor = value;
+ break;
+ case 13:
+ _vm->_cameraY = value;
+ break;
+ case 14:
+ _vm->_cameraX = value;
+ break;
+ case 15:
+ _vm->_walkSpeedY = value;
+ break;
+ case 16:
+ _vm->_walkSpeedX = value;
+ break;
+ case 17:
+ _vm->_flag01 = value != 0;
+ break;
+ case 18:
+ _vm->_sceneResIndex = value;
+ break;
+ case 19:
+ _vm->_cameraTop = value;
+ break;
+ case 20:
+ _vm->_sceneHeight = value;
+ break;
+ case 21:
+ _vm->_sceneWidth = value;
+ break;
+ case 1:
+ case 2:
+ default:
+ warning("Setting unimplemented game variable %s (%d) to %d", getVarName(variable), variable, value);
+ break;
+ }
+
+
+}
+
+byte ScriptInterpreter::arg8(int16 offset) {
+ return _subCode[offset];
+}
+
+int16 ScriptInterpreter::arg16(int16 offset) {
+ return READ_LE_UINT16(&_subCode[offset]);
+}
+
+int32 ScriptInterpreter::arg32(int16 offset) {
+ return READ_LE_UINT32(&_subCode[offset]);
+}
+
+void ScriptInterpreter::push8(byte value) {
+ _stack[_regs.sp] = value;
+ _regs.sp--;
+}
+
+byte ScriptInterpreter::pop8() {
+ _regs.sp++;
+ return _stack[_regs.sp];
+}
+
+void ScriptInterpreter::push16(int16 value) {
+ WRITE_LE_UINT16(_stack + _regs.sp, value);
+ _regs.sp -= 2;
+}
+
+int16 ScriptInterpreter::pop16() {
+ _regs.sp += 2;
+ return READ_LE_UINT16(_stack + _regs.sp);
+}
+
+void ScriptInterpreter::push32(int32 value) {
+ WRITE_LE_UINT32(_stack + _regs.sp, value);
+ _regs.sp -= 4;
+}
+
+int32 ScriptInterpreter::pop32() {
+ _regs.sp += 4;
+ return READ_LE_UINT32(_stack + _regs.sp);
+}
+
+void ScriptInterpreter::localWrite8(int16 offset, byte value) {
+ debug(1, "localWrite8(%d, %d)", offset, value);
+ _localData[offset] = value;
+}
+
+byte ScriptInterpreter::localRead8(int16 offset) {
+ debug(1, "localRead8(%d) -> %d", offset, _localData[offset]);
+ return _localData[offset];
+}
+
+void ScriptInterpreter::localWrite16(int16 offset, int16 value) {
+ debug(1, "localWrite16(%d, %d)", offset, value);
+ WRITE_LE_UINT16(&_localData[offset], value);
+}
+
+int16 ScriptInterpreter::localRead16(int16 offset) {
+ debug(1, "localRead16(%d) -> %d", offset, (int16)READ_LE_UINT16(&_localData[offset]));
+ return (int16)READ_LE_UINT16(&_localData[offset]);
+}
+
+void ScriptInterpreter::localWrite32(int16 offset, int32 value) {
+ debug(1, "localWrite32(%d, %d)", offset, value);
+ WRITE_LE_UINT32(&_localData[offset], value);
+}
+
+int32 ScriptInterpreter::localRead32(int16 offset) {
+ debug(1, "localRead32(%d) -> %d", offset, (int32)READ_LE_UINT32(&_localData[offset]));
+ return (int32)READ_LE_UINT32(&_localData[offset]);
+}
+
+byte *ScriptInterpreter::localPtr(int16 offset) {
+ debug(1, "localPtr(%d)", offset);
+ return &_localData[offset];
+}
+
+} // End of namespace Toltecs
diff --git a/engines/toltecs/script.h b/engines/toltecs/script.h
new file mode 100644
index 0000000000..6f2d5b7365
--- /dev/null
+++ b/engines/toltecs/script.h
@@ -0,0 +1,132 @@
+/* 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 TOLTECS_SCRIPT_H
+#define TOLTECS_SCRIPT_H
+
+#include "common/scummsys.h"
+#include "common/endian.h"
+#include "common/util.h"
+#include "common/file.h"
+#include "common/savefile.h"
+#include "common/system.h"
+#include "common/hash-str.h"
+#include "common/events.h"
+#include "common/keyboard.h"
+#include "common/array.h"
+
+#include "sound/audiostream.h"
+#include "sound/mixer.h"
+#include "sound/voc.h"
+#include "sound/audiocd.h"
+
+#include "engines/engine.h"
+
+namespace Toltecs {
+
+const int kMaxScriptSlots = 50;
+
+class ScriptInterpreter {
+public:
+ ScriptInterpreter(ToltecsEngine *vm);
+ ~ScriptInterpreter();
+
+ void loadScript(uint resIndex, uint slotIndex);
+ void runScript(uint slotIndex);
+
+ byte *getSlotData(int slotIndex) const { return _slots[slotIndex].data; }
+
+protected:
+
+ enum VarType {
+ vtByte,
+ vtWord
+ };
+
+ struct ScriptRegs {
+ int16 reg0;
+ int16 reg1;
+ int16 reg2;
+ int16 reg3;
+ int16 reg4;
+ int16 reg5;
+ int16 reg6;
+ int16 sp;
+ int16 reg8;
+ };
+
+ struct ScriptSlot {
+ byte *data;
+ int32 size;
+ uint resIndex;
+ };
+
+ ToltecsEngine *_vm;
+
+ byte *_stack;
+
+ byte *_code, *_subCode;
+ byte *_localData;
+ bool _switchStack1, _switchStack2, _switchStack3;
+ bool _scriptFlag01;
+
+ ScriptSlot _slots[kMaxScriptSlots];
+
+ ScriptRegs _regs;
+ int16 _savedSp;
+
+ byte readByte();
+ int16 readInt16();
+
+ void execOpcode(byte opcode);
+ void execKernelOpcode(uint16 kernelOpcode);
+
+ VarType getGameVarType(uint variable);
+ int16 getGameVar(uint variable);
+ void setGameVar(uint variable, int16 value);
+
+ byte arg8(int16 offset);
+ int16 arg16(int16 offset);
+ int32 arg32(int16 offset);
+
+ void push8(byte value);
+ byte pop8();
+ void push16(int16 value);
+ int16 pop16();
+ void push32(int32 value);
+ int32 pop32();
+
+ void localWrite8(int16 offset, byte value);
+ byte localRead8(int16 offset);
+ void localWrite16(int16 offset, int16 value);
+ int16 localRead16(int16 offset);
+ void localWrite32(int16 offset, int32 value);
+ int32 localRead32(int16 offset);
+ byte *localPtr(int16 offset);
+
+};
+
+
+} // End of namespace Toltecs
+
+#endif /* TOLTECS_H */
diff --git a/engines/toltecs/segmap.cpp b/engines/toltecs/segmap.cpp
new file mode 100644
index 0000000000..6c4796f76a
--- /dev/null
+++ b/engines/toltecs/segmap.cpp
@@ -0,0 +1,535 @@
+/* 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 "common/events.h"
+#include "common/keyboard.h"
+#include "common/file.h"
+#include "common/savefile.h"
+#include "common/config-manager.h"
+#include "common/stream.h"
+
+#include "graphics/primitives.h"
+
+#include "base/plugins.h"
+#include "base/version.h"
+
+#include "sound/mixer.h"
+
+#include "toltecs/toltecs.h"
+#include "toltecs/resource.h"
+#include "toltecs/screen.h"
+#include "toltecs/segmap.h"
+
+namespace Toltecs {
+
+SegmentMap::SegmentMap(ToltecsEngine *vm) : _vm(vm) {
+ _maskRectData = new byte[32768];
+}
+
+SegmentMap::~SegmentMap() {
+ delete[] _maskRectData;
+}
+
+void SegmentMap::load(byte *source) {
+
+ // TODO: Use MemoryReadStream
+
+ _maskRects.clear();
+ _pathRects.clear();
+ _infoRects.clear();
+
+ // Load mask rects
+ uint16 maskSize = READ_LE_UINT16(source);
+ source += 2;
+ uint16 maskRectCount = READ_LE_UINT16(source);
+ source += 2;
+ uint16 maskRectDataSize = maskRectCount * 12 + 2;
+
+ debug(0, "SegmentMap::load() maskRectCount = %d", maskRectCount);
+
+ for (uint16 i = 0; i < maskRectCount; i++) {
+ SegmapMaskRect maskRect;
+ maskRect.y = READ_LE_UINT16(source);
+ maskRect.x = READ_LE_UINT16(source + 2);
+ maskRect.height = READ_LE_UINT16(source + 4);
+ maskRect.width = READ_LE_UINT16(source + 6);
+ maskRect.maskOffset = READ_LE_UINT16(source + 8);
+ maskRect.maskOffset -= maskRectDataSize;
+ maskRect.ybottom = READ_LE_UINT16(source + 10);
+
+ debug(0, "SegmentMap::load() (%d, %d, %d, %d, %04X, %d)",
+ maskRect.x, maskRect.y, maskRect.width, maskRect.height, maskRect.maskOffset, maskRect.ybottom);
+
+ source += 12;
+ _maskRects.push_back(maskRect);
+ }
+
+ memcpy(_maskRectData, source, maskSize - maskRectDataSize);
+ source += maskSize - maskRectDataSize;
+
+ // Load path rects
+
+ source += 2; // skip rects array size
+
+ uint16 pathRectCount = READ_LE_UINT16(source);
+ source += 2;
+
+ debug(0, "SegmentMap::load() pathRectCount = %d", pathRectCount);
+
+ for (uint16 i = 0; i < pathRectCount; i++) {
+ SegmapPathRect pathRect;
+ pathRect.y = READ_LE_UINT16(source);
+ pathRect.x = READ_LE_UINT16(source + 2);
+ pathRect.height = READ_LE_UINT16(source + 4);
+ pathRect.width = READ_LE_UINT16(source + 6);
+
+ debug(0, "SegmentMap::load() (%d, %d, %d, %d)", pathRect.x, pathRect.y, pathRect.width, pathRect.height);
+
+ source += 8;
+ _pathRects.push_back(pathRect);
+ }
+
+ // Load info rects
+
+ source += 2; // skip rects array size
+
+ uint16 infoRectCount = READ_LE_UINT16(source);
+ source += 2;
+ debug(0, "SegmentMap::load() infoRectCount = %d", infoRectCount);
+ for (uint16 i = 0; i < infoRectCount; i++) {
+ SegmapInfoRect infoRect;
+ infoRect.y = READ_LE_UINT16(source);
+ infoRect.x = READ_LE_UINT16(source + 2);
+ infoRect.height = READ_LE_UINT16(source + 4);
+ infoRect.width = READ_LE_UINT16(source + 6);
+ infoRect.id = source[8];
+ infoRect.a = source[9];
+ infoRect.b = source[10];
+ infoRect.c = source[11];
+
+ debug(0, "SegmentMap::load() (%d, %d, %d, %d) (%d, %d, %d, %d)",
+ infoRect.x, infoRect.y, infoRect.width, infoRect.height,
+ infoRect.id, (int8)infoRect.a, (int8)infoRect.b, (int8)infoRect.c);
+
+ source += 12;
+ _infoRects.push_back(infoRect);
+ }
+
+ // TODO Other stuff
+
+
+}
+
+int SegmentMap::findPathRectAtPoint(int x, int y) {
+ for (uint rectIndex = 0; rectIndex < _pathRects.size(); rectIndex++) {
+ if (y >= _pathRects[rectIndex].y && y <= _pathRects[rectIndex].y + _pathRects[rectIndex].height &&
+ x >= _pathRects[rectIndex].x && x <= _pathRects[rectIndex].x + _pathRects[rectIndex].width) {
+ return rectIndex;
+ }
+ }
+ return -1;
+}
+
+void SegmentMap::adjustPathPoint(int x, int y) {
+
+ if (findPathRectAtPoint(x, y) != -1)
+ return;
+
+ uint32 minDistance = 0xFFFFFFFF, distance;
+ int x2, y2;
+
+ for (uint rectIndex = 0; rectIndex < _pathRects.size(); rectIndex++) {
+
+ if (ABS(x - _pathRects[rectIndex].x) >= ABS((x - (_pathRects[rectIndex].x + _pathRects[rectIndex].width)))) {
+ x2 = _pathRects[rectIndex].x + _pathRects[rectIndex].width;
+ } else {
+ x2 = _pathRects[rectIndex].x;
+ }
+
+ if (ABS(y - _pathRects[rectIndex].y) >= ABS((y - (_pathRects[rectIndex].y + _pathRects[rectIndex].height)))) {
+ y2 = _pathRects[rectIndex].y + _pathRects[rectIndex].height;
+ } else {
+ y2 = _pathRects[rectIndex].y;
+ }
+
+ if (x >= _pathRects[rectIndex].x && x < _pathRects[rectIndex].x + _pathRects[rectIndex].width) {
+ x2 = x;
+ }
+
+ distance = ABS(y - y2) + ABS(x - x2);
+ if (distance < minDistance) {
+ if (y >= _pathRects[rectIndex].y && y <= _pathRects[rectIndex].y + _pathRects[rectIndex].height)
+ _y = y;
+ else
+ _y = y2;
+ if (x >= _pathRects[rectIndex].x && x <= _pathRects[rectIndex].x + _pathRects[rectIndex].width)
+ _x = x;
+ else
+ _x = x2;
+ minDistance = distance;
+ }
+
+ }
+
+}
+
+int SegmentMap::findNextPathRect(int srcRectIndex) {
+
+ uint v28;
+ int result;
+ int minDistance, distance;
+ int x1, y1, x2, y2;
+ int nx1, nx2, nx3;
+ int ny, ny2, ny3;
+
+ result = -1;
+ minDistance = 65535;
+
+ x1 = _pathRects[srcRectIndex].x;
+ y1 = _pathRects[srcRectIndex].y;
+
+ x2 = x1 + _pathRects[srcRectIndex].width;
+ y2 = y1 + _pathRects[srcRectIndex].height;
+
+ for (uint rectIndex = 0; rectIndex < _pathRects.size(); ++rectIndex) {
+
+ if ( y1 == _pathRects[rectIndex].height + _pathRects[rectIndex].y && x1 < _pathRects[rectIndex].x + _pathRects[rectIndex].width && x2 > _pathRects[rectIndex].x ) {
+ ny = y1;
+
+LABEL_28:
+ if ( x1 >= _pathRects[rectIndex].x ) {
+ nx1 = x1;
+ } else {
+ nx1 = _pathRects[rectIndex].x;
+ }
+ if ( x2 <= _pathRects[rectIndex].x + _pathRects[rectIndex].width ) {
+ nx2 = x2 - 1;
+ } else {
+ nx2 = _pathRects[rectIndex].x + _pathRects[rectIndex].width - 1;
+ }
+ if ( ABS(_x - nx1) >= ABS(_x - nx2) ) {
+ nx3 = nx2 - 1;
+ } else {
+ nx3 = nx1;
+ }
+ if ( _x > nx1 && _x < nx2 ) {
+ nx3 = _x;
+ }
+ goto LABEL_55;
+ }
+ if ( y2 == _pathRects[rectIndex].y && x1 < _pathRects[rectIndex].x + _pathRects[rectIndex].width && x2 > _pathRects[rectIndex].x ) {
+ ny = y2 - 1;
+ goto LABEL_28;
+ }
+ if ( x1 == _pathRects[rectIndex].x + _pathRects[rectIndex].width && y1 < _pathRects[rectIndex].y + _pathRects[rectIndex].height && y2 > _pathRects[rectIndex].y ) {
+ nx3 = x1;
+ } else {
+ if ( x2 != _pathRects[rectIndex].x || y1 >= _pathRects[rectIndex].y + _pathRects[rectIndex].height || y2 <= _pathRects[rectIndex].y )
+ continue;
+ nx3 = x2 - 1;
+ }
+ if ( y1 >= _pathRects[rectIndex].y ) {
+ ny3 = y1;
+ } else {
+ ny3 = _pathRects[rectIndex].y;
+ }
+ if ( y2 <= _pathRects[rectIndex].y + _pathRects[rectIndex].height ) {
+ ny2 = y2 - 1;
+ } else {
+ ny2 = _pathRects[rectIndex].y + _pathRects[rectIndex].height - 1;
+ }
+ if ( ABS(_y - ny3) >= ABS(_y - ny2) ) {
+ ny = ny2 - 1;
+ } else {
+ ny = ny3;
+ }
+ if ( _y > ny3 && _y < ny2 ) {
+ ny = _y;
+ }
+
+LABEL_55:
+ distance = ABS(_x - nx3) + ABS(_y - ny);
+ v28 = 0;
+ while ( v28 < _rectIndexArray2Count ) {
+ if ( rectIndex == _rectIndexArray2[v28] ) {
+ distance = minDistance;
+ break;
+ }
+ ++v28;
+ }
+
+ v28 = 0;
+ while ( v28 < _rectIndexArray1Count ) {
+ if ( rectIndex == _rectIndexArray1[v28] ) {
+ distance = minDistance;
+ break;
+ }
+ ++v28;
+ }
+
+ if ( distance < minDistance ) {
+ result = rectIndex;
+ minDistance = distance;
+ _pointsArray[_pointsCount].y = ny;
+ _pointsArray[_pointsCount].x = nx3;
+ }
+
+ }
+
+ return result;
+}
+
+struct LineData {
+ int pitch;
+ byte *surf;
+};
+
+void plotProc(int x, int y, int color, void *data) {
+ LineData *ld = (LineData*)data;
+ ld->surf[x + y * ld->pitch] = color;
+}
+
+void SegmentMap::findPath(int16 *pointsArray, int destX, int destY, int x, int y) {
+
+ int index;
+ int sourceRectIndex, destRectIndex;
+ int pointsCount;
+
+ pointsCount = 2;
+ index = 0;
+
+ debug(0, "SegmentMap::findPath(fromX: %d; fromY: %d; toX: %d; toY: %d)", x, y, destX, destY);
+
+ sourceRectIndex = findPathRectAtPoint(x, y);
+ if ( sourceRectIndex == -1 ) {
+ adjustPathPoint(x, y);
+ x = _x;
+ y = _y;
+ }
+
+ _rectIndexArray1Count = 0;
+ _rectIndexArray2Count = 0;
+ _pointsCount = 0;
+
+ _x = destX;
+ _y = destY;
+
+ adjustPathPoint(_x, _y);
+ destRectIndex = findPathRectAtPoint(_x, _y);
+ sourceRectIndex = findPathRectAtPoint(x, y);
+ if ( sourceRectIndex != -1 ) {
+ if ( destRectIndex != sourceRectIndex ) {
+ while ( 1 ) {
+ do {
+ _rectIndexArray2[_rectIndexArray2Count++] = sourceRectIndex;
+ sourceRectIndex = findNextPathRect(sourceRectIndex);
+ _pointsCount++;
+ } while ( sourceRectIndex != -1 && sourceRectIndex != destRectIndex );
+ if ( sourceRectIndex != -1 && sourceRectIndex == destRectIndex )
+ break;
+ _rectIndexArray1[_rectIndexArray1Count++] = _rectIndexArray2[--_rectIndexArray2Count];
+ _pointsCount -= 2;
+ sourceRectIndex = _rectIndexArray2[--_rectIndexArray2Count];
+ }
+ sourceRectIndex = 0;
+ while ( sourceRectIndex < _pointsCount ) {
+ pointsArray[pointsCount++] = _pointsArray[sourceRectIndex].y;
+ pointsArray[pointsCount++] = _pointsArray[sourceRectIndex].x;
+ index++;
+ sourceRectIndex++;
+ }
+ }
+
+ pointsArray[pointsCount++] = _y;
+ pointsArray[pointsCount++] = _x;
+
+ pointsArray[0] = 0;
+ pointsArray[1] = index + 1;
+ }
+
+ debug(0, "SegmentMap::findPath() count = %d", pointsArray[1]);
+
+ /*
+ int sx = x, sy = y;
+ LineData ld;
+ ld.pitch = _vm->_sceneWidth;
+ ld.surf = _vm->_screen->_backScreen;
+ for (int16 i = 0; i < pointsArray[1] * 2; i+=2) {
+ debug(0, "x = %d; y = %d", pointsArray[3+i], pointsArray[2+i]);
+ Graphics::drawLine(sx, sy, pointsArray[3+i], pointsArray[2+i], 0xFF, plotProc, &ld);
+ sx = pointsArray[3+i];
+ sy = pointsArray[2+i];
+ }
+ */
+
+}
+
+int8 SegmentMap::getScalingAtPoint(int16 x, int16 y) {
+ int8 scaling = 0;
+ for (uint i = 0; i < _infoRects.size(); i++) {
+ if (_infoRects[i].id == 0 &&
+ y >= _infoRects[i].y && y <= _infoRects[i].y + _infoRects[i].height &&
+ x >= _infoRects[i].x && x <= _infoRects[i].x + _infoRects[i].width) {
+ char topScaling = (char)_infoRects[i].b;
+ char bottomScaling = (char)_infoRects[i].c;
+ if (y - _infoRects[i].y > 0) {
+ scaling = (ABS(y - _infoRects[i].y) * (bottomScaling - topScaling) / _infoRects[i].height) + topScaling;
+ }
+ }
+ }
+ return scaling;
+}
+
+void SegmentMap::getRgbModifiertAtPoint(int16 x, int16 y, int16 id, byte &r, byte &g, byte &b) {
+ r = 0;
+ g = 0;
+ b = 0;
+ for (uint i = 0; i < _infoRects.size(); i++) {
+ if (_infoRects[i].id == id &&
+ y >= _infoRects[i].y && y <= _infoRects[i].y + _infoRects[i].height &&
+ x >= _infoRects[i].x && x <= _infoRects[i].x + _infoRects[i].width) {
+
+ r = _infoRects[i].a;
+ g = _infoRects[i].b;
+ b = _infoRects[i].c;
+ }
+ }
+ debug(0, "SegmentMap::getRgbModifiertAtPoint() r: %d; g: %d; b: %d", r, g, b);
+}
+
+void SegmentMap::restoreMasksBySprite(SpriteDrawItem *sprite) {
+ // TODO: This needs more optimization
+ for (uint i = 0; i < _maskRects.size(); i++) {
+
+#if 0
+ if ( *(__int16 *)((char *)&spriteDrawList[0].y2 + v5) <= (unsigned __int16)v3->ybottom )
+ {
+ if ( (unsigned __int16)(*(__int16 *)((char *)&spriteDrawList[0].height + v5)
+ + *(__int16 *)((char *)&spriteDrawList[0].y + v5)) > v3->y )
+ {
+ if ( (unsigned __int16)(v3->height + v3->y) > *(__int16 *)((char *)&spriteDrawList[0].y + v5) )
+ {
+ if ( (unsigned __int16)(*(__int16 *)((char *)&spriteDrawList[0].width + v5)
+ + *(__int16 *)((char *)&spriteDrawList[0].x + v5)) > v3->x )
+ {
+ if ( (unsigned __int16)(v3->width + v3->x) > *(__int16 *)((char *)&spriteDrawList[0].x + v5) )
+ {
+
+#endif
+
+ if (sprite->ybottom <= _maskRects[i].ybottom) {
+ restoreMask(i);
+ }
+ }
+
+}
+
+void SegmentMap::restoreMask(int16 index) {
+ // TODO: This needs more optimization
+ SegmapMaskRect *maskRect = &_maskRects[index];
+
+ int16 maskX = maskRect->x, maskY = maskRect->y;
+ int16 skipX = 0;
+ int16 x = maskRect->x - _vm->_cameraX;
+ int16 y = maskRect->y - _vm->_cameraY;
+ int16 width = maskRect->width;
+ int16 height = maskRect->height;
+ byte *mask = _maskRectData + maskRect->maskOffset;
+
+ debug(0, "SegmentMap::restoreMask() screenX = %d; screenY = %d; maskX = %d; maskY = %d",
+ x, y, maskRect->x, maskRect->y);
+
+ // Not on screen, skip
+ if (x + width < 0 || y + height < 0 || x >= 640 || y >= _vm->_cameraHeight)
+ return;
+
+ if (x < 0) {
+ skipX = -x;
+ x = 0;
+ }
+
+ if (y < 0) {
+ int16 skipY = -y;
+ for (int16 h = 0; h < skipY; h++) {
+ int16 w = width;
+ while (w > 0) {
+ w -= (*mask++) & 0x7F;
+ }
+ }
+ y = 0;
+ height -= skipY;
+ maskY += skipY;
+ }
+
+ if (x + width >= 640) {
+ width -= x + width - 640;
+ }
+
+ if (y + height >= _vm->_cameraHeight) {
+ height -= y + height - _vm->_cameraHeight;
+ }
+
+ byte *backScreen = _vm->_screen->_backScreen + maskX + (maskY * _vm->_sceneWidth);
+ byte *frontScreen = _vm->_screen->_frontScreen + x + (y * 640);
+
+ for (int16 h = 0; h < height; h++) {
+ byte *src = backScreen;
+ byte *dst = frontScreen;
+ byte maskLine[640], *maskLineP = maskLine;
+
+ int16 w = width;
+ while (w > 0) {
+ byte m = *mask++;
+ byte count = m & 0x7F;
+ if (m & 0x80)
+ memset(maskLineP, 1, count);
+ else
+ memset(maskLineP, 0, count);
+ maskLineP += count;
+ w -= count;
+ }
+
+ src += skipX;
+ for (int16 c = skipX; c < width; c++) {
+ if (maskLine[c] == 1)
+ *dst = *src;
+ dst++;
+ src++;
+ }
+
+ backScreen += _vm->_sceneWidth;
+ frontScreen += 640;
+ }
+
+}
+
+void SegmentMap::debugDrawRects(Graphics::Surface *surf) {
+ for (uint16 i = 0; i < _pathRects.size(); i++) {
+ SegmapPathRect pathRect = _pathRects[i];
+ surf->frameRect(
+ Common::Rect(pathRect.x, pathRect.y, pathRect.x + pathRect.width, pathRect.y + pathRect.height),
+ 255);
+ }
+}
+
+} // End of namespace Toltecs
diff --git a/engines/toltecs/segmap.h b/engines/toltecs/segmap.h
new file mode 100644
index 0000000000..0ebb3f407e
--- /dev/null
+++ b/engines/toltecs/segmap.h
@@ -0,0 +1,134 @@
+/* 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 TOLTECS_SEGMAP_H
+#define TOLTECS_SEGMAP_H
+
+#include "common/scummsys.h"
+#include "common/endian.h"
+#include "common/util.h"
+#include "common/file.h"
+#include "common/savefile.h"
+#include "common/system.h"
+#include "common/hash-str.h"
+#include "common/events.h"
+#include "common/keyboard.h"
+#include "common/array.h"
+
+#include "sound/audiostream.h"
+#include "sound/mixer.h"
+#include "sound/voc.h"
+#include "sound/audiocd.h"
+
+#include "graphics/surface.h"
+
+#include "engines/engine.h"
+
+#include "toltecs/screen.h"
+
+namespace Toltecs {
+
+struct ScriptWalk {
+ int16 y, x;
+ int16 y1, x1, y2, x2;
+ int16 yerror, xerror;
+ int16 mulValue;
+ int16 scaling;
+};
+
+class SegmentMap {
+public:
+ SegmentMap(ToltecsEngine *vm);
+ ~SegmentMap();
+
+ void load(byte *source);
+
+ int findPathRectAtPoint(int x, int y);
+ void adjustPathPoint(int x, int y);
+
+ void findPath(int16 *pointsArray, int destX, int destY, int x, int y);
+
+ int8 getScalingAtPoint(int16 x, int16 y);
+ void getRgbModifiertAtPoint(int16 x, int16 y, int16 id, byte &r, byte &g, byte &b);
+
+ void restoreMasksBySprite(SpriteDrawItem *sprite);
+ void restoreMask(int16 index);
+
+ void debugDrawRects(Graphics::Surface *surf);
+
+//protected:
+public: // for debugging purposes
+
+ struct SegmapMaskRect {
+ int16 y, x;
+ int16 height, width;
+ int16 maskOffset;
+ int16 ybottom;
+ };
+
+ struct SegmapPathRect {
+ int16 y, x;
+ int16 height, width;
+ };
+
+ struct SegmapInfoRect {
+ int16 y, x;
+ int16 height, width;
+ byte id;
+ byte a, b, c;
+ };
+
+ struct PathPoint {
+ int16 y, x;
+ };
+
+ typedef Common::Array<SegmapMaskRect> SegmapMaskRectArray;
+ typedef Common::Array<SegmapPathRect> SegmapPathRectArray;
+ typedef Common::Array<SegmapInfoRect> SegmapInfoRectArray;
+
+ ToltecsEngine *_vm;
+
+ SegmapMaskRectArray _maskRects;
+ byte *_maskRectData;
+
+ SegmapPathRectArray _pathRects;
+ SegmapInfoRectArray _infoRects;
+
+ int _rectIndexArray1[1000];
+ uint _rectIndexArray1Count;
+
+ int _rectIndexArray2[1000];
+ uint _rectIndexArray2Count;
+
+ PathPoint _pointsArray[1000];
+ int16 _pointsCount;
+
+ int _x, _y;
+
+ int findNextPathRect(int srcRectIndex);
+
+};
+
+} // End of namespace Toltecs
+
+#endif /* TOLTECS_SEGMAP_H */
diff --git a/engines/toltecs/toltecs.cpp b/engines/toltecs/toltecs.cpp
new file mode 100644
index 0000000000..78f3e23afe
--- /dev/null
+++ b/engines/toltecs/toltecs.cpp
@@ -0,0 +1,483 @@
+/* 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 "common/events.h"
+#include "common/keyboard.h"
+#include "common/file.h"
+#include "common/savefile.h"
+#include "common/config-manager.h"
+#include "common/str.h"
+
+#include "base/plugins.h"
+#include "base/version.h"
+
+#include "graphics/surface.h"
+#include "graphics/cursorman.h"
+#include "graphics/primitives.h"
+
+#include "sound/mixer.h"
+
+#include "toltecs/toltecs.h"
+#include "toltecs/animation.h"
+#include "toltecs/input.h"
+#include "toltecs/palette.h"
+#include "toltecs/resource.h"
+#include "toltecs/script.h"
+#include "toltecs/screen.h"
+#include "toltecs/segmap.h"
+
+namespace Toltecs {
+
+struct GameSettings {
+ const char *gameid;
+ const char *description;
+ byte id;
+ uint32 features;
+ const char *detectname;
+};
+
+ToltecsEngine::ToltecsEngine(OSystem *syst, const ToltecsGameDescription *gameDesc) : Engine(syst), _gameDescription(gameDesc) {
+
+ // Setup mixer
+ _mixer->setVolumeForSoundType(Audio::Mixer::kSFXSoundType, ConfMan.getInt("sfx_volume"));
+ _mixer->setVolumeForSoundType(Audio::Mixer::kMusicSoundType, ConfMan.getInt("music_volume"));
+
+ _rnd = new Common::RandomSource();
+ syst->getEventManager()->registerRandomSource(*_rnd, "toltecs");
+
+ int cd_num = ConfMan.getInt("cdrom");
+ if (cd_num >= 0)
+ _system->openCD(cd_num);
+
+}
+
+ToltecsEngine::~ToltecsEngine() {
+ delete _rnd;
+}
+
+int ToltecsEngine::init() {
+ // Initialize backend
+ _system->beginGFXTransaction();
+ initCommonGFX(false);
+ _system->initSize(640, 400);
+ _system->endGFXTransaction();
+ return 0;
+}
+
+int ToltecsEngine::go() {
+
+ _system->setFeatureState(OSystem::kFeatureAutoComputeDirtyRects, true);
+
+ _quitGame = false;
+ _counter01 = 0;
+ _counter02 = 0;
+ _movieSceneFlag = false;
+ _flag01 = 0;
+
+ _cameraX = 0;
+ _cameraY = 0;
+ _newCameraX = 0;
+ _newCameraY = 0;
+ _cameraTop = 26;
+ _cameraHeight = 0;
+ _yetAnotherX = 0;
+
+ _sceneWidth = 0;
+ _sceneHeight = 0;
+
+ _doSpeech = true;
+ _doText = true;
+
+ _walkSpeedY = 5;
+ _walkSpeedX = 1;
+
+ _arc = new ArchiveReader();
+ _arc->openArchive("WESTERN");
+
+ _res = new ResourceCache(this);
+
+ _screen = new Screen(this);
+
+ _script = new ScriptInterpreter(this);
+ _anim = new AnimationPlayer(this);
+ _palette = new Palette(this);
+ _segmap = new SegmentMap(this);
+ _input = new Input(this);
+
+ _system->showMouse(true);
+
+#if 1
+
+ _script->loadScript(0, 0);
+ _script->runScript(0);
+
+#endif
+
+ delete _arc;
+ delete _res;
+ delete _screen;
+ delete _script;
+ delete _anim;
+ delete _palette;
+ delete _segmap;
+ delete _input;
+
+ return 0;
+}
+
+void ToltecsEngine::loadScene(uint resIndex) {
+ // TODO
+
+ byte *scene = _res->load(resIndex);
+
+ uint32 imageSize = READ_LE_UINT32(scene);
+ _sceneResIndex = resIndex;
+ _sceneHeight = READ_LE_UINT16(scene + 4);
+ _sceneWidth = READ_LE_UINT16(scene + 6);
+
+ // Load scene palette
+ _palette->loadAddPaletteFrom(scene + 8, 0, 128);
+
+ // Load scene background
+ byte *source = scene + 392;
+ byte *destp = _screen->_backScreen;
+ byte *destEnd = destp + _sceneWidth * _sceneHeight;
+ while (destp < destEnd) {
+ int count = 1;
+ byte pixel = *source++;
+ if (pixel & 0x80) {
+ pixel &= 0x7F;
+ count = *source++;
+ count += 2;
+ }
+ memset(destp, pixel, count);
+ destp += count;
+ }
+
+ debug(0, "_sceneWidth = %d; _sceneHeight = %d", _sceneWidth, _sceneHeight);
+
+ // Load scene segmap
+ _segmap->load(scene + imageSize + 4);
+
+}
+
+void ToltecsEngine::updateScreen() {
+ // TODO
+
+ byte *destp = _screen->_frontScreen;
+ byte *srcp = _screen->_backScreen + _cameraX + _cameraY * _sceneWidth;
+ for (uint y = 0; y < MIN<uint>(_cameraHeight, 400); y++) {
+ memcpy(destp, srcp, MIN<uint>(_sceneWidth, 640));
+ destp += 640;
+ srcp += _sceneWidth;
+ }
+
+ _screen->drawSprites();
+ _screen->clearSprites();
+
+ _screen->drawTalkTextItems();
+
+ _system->copyRectToScreen((const byte *)_screen->_frontScreen, 640, 0, 0, 640, 400);
+ _system->updateScreen();
+
+ updateCamera();
+}
+
+void ToltecsEngine::setCamera(int16 x, int16 y) {
+
+ // TODO font_sub_4B5BB()
+
+ if (x > _sceneWidth)
+ x = _sceneWidth;
+
+ if (y > _sceneHeight - _cameraHeight)
+ y = _sceneHeight - _cameraHeight;
+
+ // TODO DirtyRect clearing stuff
+
+ _screen->clearSprites();
+
+ _cameraX = x;
+ _newCameraX = x;
+
+ _cameraY = y;
+ _newCameraY = y;
+
+ // TODO More DirtyRect clearing stuff
+
+}
+
+void ToltecsEngine::setCameraTop(int16 top) {
+ if (top != _cameraTop) {
+ _cameraTop = top;
+ _cameraHeight = 400 - _cameraTop;
+ debug(0, "ToltecsEngine::setCameraTop() _cameraTop = %d; _cameraHeight = %d", _cameraTop, _cameraHeight);
+ // TODO: clearScreen();
+ }
+}
+
+void ToltecsEngine::scrollCameraUp(int16 delta) {
+ if (_newCameraY > 0) {
+ if (_newCameraY < delta)
+ _newCameraY = 0;
+ else
+ _newCameraY -= delta;
+ // TODO: font_sub_4B5BB();
+ }
+}
+
+void ToltecsEngine::scrollCameraDown(int16 delta) {
+ debug(0, "ToltecsEngine::scrollCameraDown(%d)", delta);
+ if (_newCameraY != _sceneHeight - _cameraHeight) {
+ if (_sceneHeight - _cameraHeight < _newCameraY + delta)
+ delta += (_sceneHeight - _cameraHeight) - (delta + _newCameraY);
+ _newCameraY += delta;
+ debug(0, "ToltecsEngine::scrollCameraDown() _newCameraY = %d; delta = %d", _newCameraY, delta);
+ // TODO: font_sub_4B5BB();
+ }
+}
+
+void ToltecsEngine::scrollCameraLeft(int16 delta) {
+ if (_newCameraX > 0) {
+ if (_newCameraX < delta)
+ _newCameraX = 0;
+ else
+ _newCameraX -= delta;
+ // TODO: font_sub_4B5BB();
+ }
+}
+
+void ToltecsEngine::scrollCameraRight(int16 delta) {
+ debug(0, "ToltecsEngine::scrollCameraRight(%d)", delta);
+ if (_newCameraX != _sceneWidth - 640) {
+ if (_sceneWidth - 640 < delta + _newCameraX)
+ delta += (_sceneWidth - 640) - (delta + _newCameraX);
+ _newCameraX += delta;
+ debug(0, "ToltecsEngine::scrollCameraRight() _newCameraX = %d; delta = %d", _newCameraY, delta);
+ // TODO: font_sub_4B5BB();
+ }
+}
+
+void ToltecsEngine::updateCamera() {
+
+ _yetAnotherX = _newCameraX;
+ if (_cameraX != _yetAnotherX) {
+ //dirtyFullRefresh = -1;
+ }
+ _cameraX = _yetAnotherX;
+
+ if (_cameraY != _newCameraY) {
+ if (_cameraY < _newCameraY) {
+ /*
+ drawRequest.resIndex = -(cameraY - anotherY);
+ drawRequest.y = cameraHeight + cameraY;
+ drawRequest.x = cameraX;
+ drawRequest.flags = 640;
+ */
+ debug(0, "ToltecsEngine::updateCamera() a: (%d, %d, %d, %d)",
+ -(_cameraY - _newCameraY), _cameraHeight + _cameraY, _cameraX, 640);
+ //dirtyFullRefresh = -1;
+ } else {
+ /*
+ drawRequest.resIndex = cameraY - anotherY;
+ drawRequest.y = anotherY;
+ drawRequest.x = cameraX;
+ drawRequest.flags = 640;
+ */
+ debug(0, "ToltecsEngine::updateCamera() b: (%d, %d, %d, %d)",
+ _cameraY - _newCameraY, _newCameraY, _cameraX, 640);
+ //dirtyFullRefresh = -1;
+ }
+ }
+ _cameraY = _newCameraY;
+
+ debug(0, "ToltecsEngine::checkCamera() _cameraX = %d; _cameraY = %d", _cameraX, _cameraY);
+
+}
+
+void ToltecsEngine::talk(int16 slotIndex, int16 slotOffset) {
+
+ byte *scanData = _script->getSlotData(slotIndex) + slotOffset;
+
+ while (*scanData < 0xF0) {
+
+ if (*scanData == 0x19) {
+ scanData++;
+ } else if (*scanData == 0x14) {
+ scanData++;
+ } else if (*scanData == 0x0A) {
+ scanData += 4;
+ } else if (*scanData < 0x0A) {
+ scanData++;
+ }
+
+ scanData++;
+ }
+
+ if (*scanData == 0xFE) {
+ if (_doSpeech) {
+ int16 resIndex = READ_LE_UINT16(scanData + 1);
+ debug(0, "ToltecsEngine::talk() playSound(resIndex: %d)", resIndex);
+ }
+ if (_doText) {
+ _screen->updateTalkText(slotIndex, slotOffset);
+ } else {
+ // TODO: font_sub_4B3E2
+ }
+ } else {
+ _screen->updateTalkText(slotIndex, slotOffset);
+ }
+
+}
+
+void ToltecsEngine::playText(int16 slotIndex, int16 slotOffset) {
+
+ byte *textData = _script->getSlotData(slotIndex) + slotOffset;
+
+ debug(0, "ToltecsEngine::playText() [textData = %s]", (char*)textData);
+
+ Common::String str;
+ while (*textData < 0xF0) {
+ if (*textData >= 32)
+ str += (char)*textData;
+ textData++;
+ }
+
+ debug(0, "ToltecsEngine::playText() [%s]", str.c_str());
+
+}
+
+void ToltecsEngine::walk(byte *walkData) {
+
+ int16 xdelta, ydelta, v8, v10, v11;
+ int16 xstep, ystep;
+ ScriptWalk walkInfo;
+
+ walkInfo.y = READ_LE_UINT16(walkData + 0);
+ walkInfo.x = READ_LE_UINT16(walkData + 2);
+ walkInfo.y1 = READ_LE_UINT16(walkData + 4);
+ walkInfo.x1 = READ_LE_UINT16(walkData + 6);
+ walkInfo.y2 = READ_LE_UINT16(walkData + 8);
+ walkInfo.x2 = READ_LE_UINT16(walkData + 10);
+ walkInfo.yerror = READ_LE_UINT16(walkData + 12);
+ walkInfo.xerror = READ_LE_UINT16(walkData + 14);
+ walkInfo.mulValue = READ_LE_UINT16(walkData + 16);
+ walkInfo.scaling = READ_LE_UINT16(walkData + 18);
+
+ walkInfo.scaling = -_segmap->getScalingAtPoint(walkInfo.x, walkInfo.y);
+
+ if (walkInfo.y1 < walkInfo.y2)
+ ystep = -1;
+ else
+ ystep = 1;
+ ydelta = ABS(walkInfo.y1 - walkInfo.y2) * _walkSpeedY;
+
+ if (walkInfo.x1 < walkInfo.x2)
+ xstep = -1;
+ else
+ xstep = 1;
+ xdelta = ABS(walkInfo.x1 - walkInfo.x2) * _walkSpeedX;
+
+ debug(0, "ToltecsEngine::walk() xdelta = %d; ydelta = %d", xdelta, ydelta);
+
+ if (xdelta > ydelta)
+ SWAP(xdelta, ydelta);
+
+ v8 = 100 * xdelta;
+ if (v8 != 0) {
+ if (walkInfo.scaling > 0)
+ v8 -= v8 * ABS(walkInfo.scaling) / 100;
+ else
+ v8 += v8 * ABS(walkInfo.scaling) / 100;
+ if (ydelta != 0)
+ v8 /= ydelta;
+ }
+
+ if (ydelta > ABS(walkInfo.x1 - walkInfo.x2) * _walkSpeedX) {
+ v10 = 100 - walkInfo.scaling;
+ v11 = v8;
+ } else {
+ v10 = v8;
+ v11 = 100 - walkInfo.scaling;
+ }
+
+ walkInfo.yerror += walkInfo.mulValue * v10;
+ while (walkInfo.yerror >= 100 * _walkSpeedY) {
+ walkInfo.yerror -= 100 * _walkSpeedY;
+ if (walkInfo.y == walkInfo.y1) {
+ walkInfo.x = walkInfo.x1;
+ break;
+ }
+ walkInfo.y += ystep;
+ }
+
+ walkInfo.xerror += walkInfo.mulValue * v11;
+ while (walkInfo.xerror >= 100 * _walkSpeedX) {
+ walkInfo.xerror -= 100 * _walkSpeedX;
+ if (walkInfo.x == walkInfo.x1) {
+ walkInfo.y = walkInfo.y1;
+ break;
+ }
+ walkInfo.x += xstep;
+ }
+
+ WRITE_LE_UINT16(walkData + 0, walkInfo.y);
+ WRITE_LE_UINT16(walkData + 2, walkInfo.x);
+ WRITE_LE_UINT16(walkData + 4, walkInfo.y1);
+ WRITE_LE_UINT16(walkData + 6, walkInfo.x1);
+ WRITE_LE_UINT16(walkData + 8, walkInfo.y2);
+ WRITE_LE_UINT16(walkData + 10, walkInfo.x2);
+ WRITE_LE_UINT16(walkData + 12, walkInfo.yerror);
+ WRITE_LE_UINT16(walkData + 14, walkInfo.xerror);
+ WRITE_LE_UINT16(walkData + 16, walkInfo.mulValue);
+ WRITE_LE_UINT16(walkData + 18, walkInfo.scaling);
+
+}
+
+int16 ToltecsEngine::findRectAtPoint(byte *rectData, int16 x, int16 y, int16 index, int16 itemSize) {
+
+ rectData += index * itemSize;
+
+ while (1) {
+ int16 rectY = READ_LE_UINT16(rectData);
+ if (rectY == -10)
+ break;
+ int16 rectX = READ_LE_UINT16(rectData + 2);
+ int16 rectH = READ_LE_UINT16(rectData + 4);
+ int16 rectW = READ_LE_UINT16(rectData + 6);
+
+ debug(0, "x = %d; y = %d; x1 = %d; y2 = %d; w = %d; h = %d",
+ x, y, rectX, rectY, rectW, rectH);
+
+ if (x >= rectX && x <= rectX + rectW && y >= rectY && y <= rectY + rectH) {
+ return index;
+ }
+ index++;
+ rectData += itemSize;
+ }
+
+ return -1;
+
+}
+
+} // End of namespace Toltecs
diff --git a/engines/toltecs/toltecs.h b/engines/toltecs/toltecs.h
new file mode 100644
index 0000000000..47c7a9441a
--- /dev/null
+++ b/engines/toltecs/toltecs.h
@@ -0,0 +1,130 @@
+/* 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 TOLTECS_H
+#define TOLTECS_H
+
+#include "common/scummsys.h"
+#include "common/endian.h"
+#include "common/util.h"
+#include "common/file.h"
+#include "common/savefile.h"
+#include "common/system.h"
+#include "common/hash-str.h"
+#include "common/events.h"
+#include "common/keyboard.h"
+
+#include "sound/audiostream.h"
+#include "sound/mixer.h"
+#include "sound/voc.h"
+#include "sound/audiocd.h"
+
+#include "engines/engine.h"
+
+namespace Toltecs {
+
+enum ToltecsGameFeatures {
+ GF_PACKED = (1 << 0)
+};
+
+struct ToltecsGameDescription;
+
+class AnimationPlayer;
+class ArchiveReader;
+class Input;
+class Palette;
+class ResourceCache;
+class ScriptInterpreter;
+class Screen;
+class SegmentMap;
+
+class ToltecsEngine : public ::Engine {
+ Common::KeyState _keyPressed;
+
+protected:
+ int init();
+ int go();
+// void shutdown();
+
+public:
+ ToltecsEngine(OSystem *syst, const ToltecsGameDescription *gameDesc);
+ virtual ~ToltecsEngine();
+
+ Common::RandomSource *_rnd;
+ const ToltecsGameDescription *_gameDescription;
+ uint32 getFeatures() const;
+ Common::Language getLanguage() const;
+
+ void loadScene(uint resIndex);
+
+ void updateScreen();
+
+ void setCamera(int16 x, int16 y);
+ void setCameraTop(int16 top);
+ void scrollCameraUp(int16 delta);
+ void scrollCameraDown(int16 delta);
+ void scrollCameraLeft(int16 delta);
+ void scrollCameraRight(int16 delta);
+ void updateCamera();
+
+ void talk(int16 slotIndex, int16 slotOffset);
+ void playText(int16 slotIndex, int16 slotOffset);
+
+ void walk(byte *walkData);
+
+ int16 findRectAtPoint(byte *rectData, int16 x, int16 y, int16 index, int16 itemSize);
+
+public:
+ AnimationPlayer *_anim;
+ ArchiveReader *_arc;
+ Input *_input;
+ Palette *_palette;
+ ResourceCache *_res;
+ ScriptInterpreter *_script;
+ Screen *_screen;
+ SegmentMap *_segmap;
+
+ uint _sceneResIndex;
+ int16 _sceneWidth, _sceneHeight;
+ //byte _scenePalette[768];
+
+ bool _quitGame;
+ int _counter01, _counter02;
+ bool _movieSceneFlag;
+ byte _flag01;
+
+ // TODO: Move camera stuff into own Scene class
+ int16 _cameraX, _cameraY;
+ int16 _newCameraX, _newCameraY;
+ int16 _cameraTop, _cameraHeight;
+ int16 _yetAnotherX;
+
+ bool _doSpeech, _doText;
+
+ int16 _walkSpeedY, _walkSpeedX;
+
+};
+
+} // End of namespace Toltecs
+
+#endif /* TOLTECS_H */