aboutsummaryrefslogtreecommitdiff
path: root/engines/toltecs/toltecs.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'engines/toltecs/toltecs.cpp')
-rw-r--r--engines/toltecs/toltecs.cpp641
1 files changed, 641 insertions, 0 deletions
diff --git a/engines/toltecs/toltecs.cpp b/engines/toltecs/toltecs.cpp
new file mode 100644
index 0000000000..d403e0499b
--- /dev/null
+++ b/engines/toltecs/toltecs.cpp
@@ -0,0 +1,641 @@
+/* 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/config-manager.h"
+#include "common/events.h"
+#include "common/random.h"
+#include "common/str.h"
+#include "common/error.h"
+#include "common/textconsole.h"
+
+#include "base/plugins.h"
+#include "base/version.h"
+
+#include "graphics/cursorman.h"
+
+#include "engines/util.h"
+
+#include "audio/mixer.h"
+
+#include "toltecs/toltecs.h"
+#include "toltecs/animation.h"
+#include "toltecs/menu.h"
+#include "toltecs/movie.h"
+#include "toltecs/music.h"
+#include "toltecs/palette.h"
+#include "toltecs/render.h"
+#include "toltecs/resource.h"
+#include "toltecs/script.h"
+#include "toltecs/screen.h"
+#include "toltecs/segmap.h"
+#include "toltecs/sound.h"
+#include "toltecs/microtiles.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("toltecs");
+}
+
+ToltecsEngine::~ToltecsEngine() {
+ delete _rnd;
+}
+
+Common::Error ToltecsEngine::run() {
+ initGraphics(640, 400, true);
+
+ _isSaveAllowed = true;
+
+ _counter01 = 0;
+ _counter02 = 0;
+ _movieSceneFlag = false;
+ _flag01 = 0;
+
+ _saveLoadRequested = 0;
+
+ _cameraX = 0;
+ _cameraY = 0;
+ _newCameraX = 0;
+ _newCameraY = 0;
+ _cameraHeight = 0;
+
+ _guiHeight = 26;
+
+ _sceneWidth = 0;
+ _sceneHeight = 0;
+
+ _doSpeech = true;
+ _doText = true;
+
+ _walkSpeedY = 5;
+ _walkSpeedX = 1;
+
+ _mouseX = 0;
+ _mouseY = 0;
+ _mouseDblClickTicks = 60;
+ _mouseWaitForRelease = false;
+ _mouseButton = 0;
+ _mouseDisabled = 0;
+ _leftButtonDown = false;
+ _rightButtonDown = false;
+
+ _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);
+ _moviePlayer = new MoviePlayer(this);
+ _music = new Music(_arc);
+ _menuSystem = new MenuSystem(this);
+
+ _sound = new Sound(this);
+
+ syncSoundSettings();
+
+ CursorMan.showMouse(true);
+
+ setupSysStrings();
+
+//#define TEST_MENU
+#ifdef TEST_MENU
+ _screen->registerFont(0, 0x0D);
+ _screen->registerFont(1, 0x0E);
+ _screen->loadMouseCursor(12);
+ _palette->loadAddPalette(9, 224);
+ _palette->setDeltaPalette(_palette->getMainPalette(), 7, 0, 31, 224);
+ _screen->finishTalkTextItems();
+ _screen->clearSprites();
+ _menuSystem->run();
+ /*
+ while (1) {
+ //updateInput();
+ _menuSystem->update();
+ updateScreen();
+ }
+ */
+ return Common::kNoError;
+#endif
+
+ // Start main game loop
+ setTotalPlayTime(0);
+ _script->loadScript(0, 0);
+ _script->setMainScript(0);
+ if (ConfMan.hasKey("save_slot")) {
+ int saveSlot = ConfMan.getInt("save_slot");
+ if (saveSlot >= 0 && saveSlot <= 99) {
+ _screen->loadMouseCursor(12);
+ loadGameState(saveSlot);
+ }
+ }
+ _script->runScript();
+
+ _music->stopSequence();
+ _sound->stopAll();
+
+ delete _arc;
+ delete _res;
+ delete _screen;
+ delete _script;
+ delete _anim;
+ delete _palette;
+ delete _segmap;
+ delete _music;
+ delete _moviePlayer;
+ delete _menuSystem;
+
+ delete _sound;
+
+ return Common::kNoError;
+}
+
+void ToltecsEngine::setupSysStrings() {
+ Resource *sysStringsResource = _res->load(15);
+ const char *sysStrings = (const char*)sysStringsResource->data;
+ for (int i = 0; i < kSysStrCount; i++) {
+ debug(1, "sysStrings[%d] = [%s]", i, sysStrings);
+ _sysStrings[i] = sysStrings;
+ sysStrings += strlen(sysStrings) + 1;
+ }
+ // TODO: Set yes/no chars
+}
+
+void ToltecsEngine::requestSavegame(int slotNum, Common::String &description) {
+ _saveLoadRequested = 2;
+ _saveLoadSlot = slotNum;
+ _saveLoadDescription = description;
+}
+
+void ToltecsEngine::requestLoadgame(int slotNum) {
+ _saveLoadRequested = 1;
+ _saveLoadSlot = slotNum;
+}
+
+void ToltecsEngine::loadScene(uint resIndex) {
+
+ Resource *sceneResource = _res->load(resIndex);
+ byte *scene = sceneResource->data;
+
+ 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);
+
+ _screen->_fullRefresh = true;
+ _screen->_renderQueue->clear();
+
+}
+
+void ToltecsEngine::updateScreen() {
+
+ _sound->updateSpeech();
+
+ _screen->updateShakeScreen();
+
+ // TODO: Set quit flag
+ if (shouldQuit())
+ return;
+
+ if (!_movieSceneFlag)
+ updateInput();
+ else
+ _mouseButton = 0;
+
+ // TODO? Check keyb
+
+ _counter01--;
+ if (_counter01 <= 0) {
+ _counter01 = MIN(_counter02, 30);
+ _counter02 = 0;
+ drawScreen();
+ _flag01 = 1;
+ _counter02 = 1;
+ } else {
+ _screen->clearSprites();
+ _flag01 = 0;
+ }
+
+ static uint32 prevUpdateTime = 0;
+ uint32 currUpdateTime;
+ do {
+ currUpdateTime = _system->getMillis();
+ _counter02 = (currUpdateTime - prevUpdateTime) / 13;
+ } while (_counter02 == 0);
+ prevUpdateTime = currUpdateTime;
+
+}
+
+void ToltecsEngine::drawScreen() {
+ // FIXME: Quick hack, sometimes cameraY was negative (the code in updateCamera was at fault)
+ if (_cameraY < 0) _cameraY = 0;
+
+ _segmap->addMasksToRenderQueue();
+ _screen->addTalkTextItemsToRenderQueue();
+
+ _screen->_renderQueue->update();
+
+ //debug("_guiHeight = %d\n", _guiHeight);
+
+ if (_screen->_guiRefresh && _guiHeight > 0 && _cameraHeight > 0) {
+ // Update the GUI when needed and it's visible
+ _system->copyRectToScreen((const byte *)_screen->_frontScreen + _cameraHeight * 640,
+ 640, 0, _cameraHeight, 640, _guiHeight);
+ _screen->_guiRefresh = false;
+ }
+
+ _system->updateScreen();
+
+ updateCamera();
+}
+
+void ToltecsEngine::updateInput() {
+
+ Common::Event event;
+ Common::EventManager *eventMan = _system->getEventManager();
+ while (eventMan->pollEvent(event)) {
+ switch (event.type) {
+ case Common::EVENT_KEYDOWN:
+ _keyState = event.kbd;
+
+ //debug("key: flags = %02X; keycode = %d", _keyState.flags, _keyState.keycode);
+
+ // FIXME: This is just for debugging
+ switch (event.kbd.keycode) {
+ case Common::KEYCODE_F7:
+ savegame("toltecs.001", "Quicksave");
+ break;
+ case Common::KEYCODE_F9:
+ loadgame("toltecs.001");
+ break;
+ case Common::KEYCODE_ESCAPE:
+ // Skip current dialog line, if a dialog is active
+ if (_screen->getTalkTextDuration() > 0) {
+ _sound->stopSpeech();
+ _screen->finishTalkTextItems();
+ _keyState.reset(); // event consumed
+ }
+ break;
+ default:
+ break;
+ }
+
+ break;
+ case Common::EVENT_KEYUP:
+ _keyState.reset();
+ break;
+ case Common::EVENT_QUIT:
+ quitGame();
+ 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) {
+
+ if (_mouseDblClickTicks > 0)
+ _mouseDblClickTicks--;
+
+ byte mouseButtons = 0;
+ if (_leftButtonDown)
+ mouseButtons |= 1;
+ if (_rightButtonDown)
+ mouseButtons |= 2;
+
+ if (mouseButtons != 0) {
+ if (!_mouseWaitForRelease) {
+ _mouseButton = mouseButtons;
+ if (_mouseDblClickTicks > 0)
+ _mouseButton = 0x80;
+ //if (_mouseButton == 0x80) debug("DBL!");
+ _mouseDblClickTicks = 30; // maybe TODO
+ _mouseWaitForRelease = true;
+ } else {
+ _mouseButton = 0;
+ }
+ } else {
+ _mouseWaitForRelease = false;
+ _mouseButton = 0;
+ }
+
+ }
+
+}
+
+void ToltecsEngine::setGuiHeight(int16 guiHeight) {
+ if (guiHeight != _guiHeight) {
+ _guiHeight = guiHeight;
+ _cameraHeight = 400 - _guiHeight;
+ _screen->_guiRefresh = true;
+ debug(0, "ToltecsEngine::setGuiHeight() _guiHeight = %d; _cameraHeight = %d", _guiHeight, _cameraHeight);
+ // TODO: clearScreen();
+ }
+}
+
+void ToltecsEngine::setCamera(int16 x, int16 y) {
+ _screen->finishTalkTextItems();
+
+ _screen->clearSprites();
+
+ _cameraX = x;
+ _newCameraX = x;
+
+ _cameraY = y;
+ _newCameraY = y;
+}
+
+bool ToltecsEngine::getCameraChanged() {
+ return _cameraX != _newCameraX || _cameraY != _newCameraY;
+}
+
+void ToltecsEngine::scrollCameraUp(int16 delta) {
+ if (_newCameraY > 0) {
+ if (_newCameraY < delta)
+ _newCameraY = 0;
+ else
+ _newCameraY -= delta;
+ }
+}
+
+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);
+ }
+}
+
+void ToltecsEngine::scrollCameraLeft(int16 delta) {
+ if (_newCameraX > 0) {
+ if (_newCameraX < delta)
+ _newCameraX = 0;
+ else
+ _newCameraX -= delta;
+ }
+}
+
+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);
+ }
+}
+
+void ToltecsEngine::updateCamera() {
+
+ if (_cameraX != _newCameraX) {
+ _cameraX = _newCameraX;
+ _screen->_fullRefresh = true;
+ _screen->finishTalkTextItems();
+ }
+
+ if (_cameraY != _newCameraY) {
+ _cameraY = _newCameraY;
+ _screen->_fullRefresh = true;
+ _screen->finishTalkTextItems();
+ }
+
+ //debug(0, "ToltecsEngine::updateCamera() _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);
+ _sound->playSpeech(resIndex);
+ }
+ if (_doText) {
+ _screen->updateTalkText(slotIndex, slotOffset);
+ } else {
+ _screen->keepTalkTextItemsAlive();
+ }
+ } else {
+ _screen->updateTalkText(slotIndex, slotOffset);
+ }
+
+}
+
+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,
+ byte *rectDataEnd) {
+
+ rectData += index * itemSize;
+
+ while (rectData < rectDataEnd) {
+ 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