From 7c2835313ee3c68e6ac753782b63a9dd485b0a60 Mon Sep 17 00:00:00 2001 From: Eugene Sandulenko Date: Mon, 4 Aug 2008 11:28:57 +0000 Subject: TOLTECS: Initial checkin --- engines/toltecs/animation.cpp | 139 +++++ engines/toltecs/animation.h | 85 +++ engines/toltecs/detection.cpp | 121 ++++ engines/toltecs/input.cpp | 133 +++++ engines/toltecs/input.h | 76 +++ engines/toltecs/module.mk | 21 + engines/toltecs/palette.cpp | 157 ++++++ engines/toltecs/palette.h | 87 +++ engines/toltecs/resource.cpp | 161 ++++++ engines/toltecs/resource.h | 115 ++++ engines/toltecs/screen.cpp | 971 ++++++++++++++++++++++++++++++++ engines/toltecs/screen.h | 378 +++++++++++++ engines/toltecs/script.cpp | 1219 +++++++++++++++++++++++++++++++++++++++++ engines/toltecs/script.h | 132 +++++ engines/toltecs/segmap.cpp | 535 ++++++++++++++++++ engines/toltecs/segmap.h | 134 +++++ engines/toltecs/toltecs.cpp | 483 ++++++++++++++++ engines/toltecs/toltecs.h | 130 +++++ 18 files changed, 5077 insertions(+) create mode 100644 engines/toltecs/animation.cpp create mode 100644 engines/toltecs/animation.h create mode 100644 engines/toltecs/detection.cpp create mode 100644 engines/toltecs/input.cpp create mode 100644 engines/toltecs/input.h create mode 100644 engines/toltecs/module.mk create mode 100644 engines/toltecs/palette.cpp create mode 100644 engines/toltecs/palette.h create mode 100644 engines/toltecs/resource.cpp create mode 100644 engines/toltecs/resource.h create mode 100644 engines/toltecs/screen.cpp create mode 100644 engines/toltecs/screen.h create mode 100644 engines/toltecs/script.cpp create mode 100644 engines/toltecs/script.h create mode 100644 engines/toltecs/segmap.cpp create mode 100644 engines/toltecs/segmap.h create mode 100644 engines/toltecs/toltecs.cpp create mode 100644 engines/toltecs/toltecs.h (limited to 'engines/toltecs') 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(rgb + deltaValue, 0, 63) << 2; + rgb = *palPtr++; + if (mask & 2) colors[index * 4 + 1] = CLIP(rgb + deltaValue, 0, 63) << 2; + rgb = *palPtr++; + if (mask & 4) colors[index * 4 + 2] = CLIP(rgb + deltaValue, 0, 63) << 2; + index++; + } + } else { + while (count--) { + rgb = *palPtr++; + if (mask & 1) colors[index * 4 + 0] = CLIP(rgb - deltaValue, deltaValue, 255) << 2; + rgb = *palPtr++; + if (mask & 2) colors[index * 4 + 1] = CLIP(rgb - deltaValue, deltaValue, 255) << 2; + rgb = *palPtr++; + if (mask & 4) colors[index * 4 + 2] = CLIP(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 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 _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::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::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(_talkTextX - _vm->_cameraX, 120, _talkTextMaxWidth); + y = CLIP(_talkTextY - _vm->_cameraY, 4, _vm->_cameraHeight - 16); + + maxWidth = 624 - ABS(x - 320) * 2; + + while (1) { + if (*textData == 0x0A) { + x = CLIP(textData[3], 120, _talkTextMaxWidth); + y = CLIP(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(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 _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 SegmapMaskRectArray; + typedef Common::Array SegmapPathRectArray; + typedef Common::Array 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(_cameraHeight, 400); y++) { + memcpy(destp, srcp, MIN(_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 */ -- cgit v1.2.3