diff options
Diffstat (limited to 'engines/mohawk/cstime_view.cpp')
-rw-r--r-- | engines/mohawk/cstime_view.cpp | 537 |
1 files changed, 537 insertions, 0 deletions
diff --git a/engines/mohawk/cstime_view.cpp b/engines/mohawk/cstime_view.cpp new file mode 100644 index 0000000000..bf8305d3ee --- /dev/null +++ b/engines/mohawk/cstime_view.cpp @@ -0,0 +1,537 @@ +/* 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. + * + * $URL$ + * $Id$ + * + */ + +#include "mohawk/cstime_game.h" // debugging.. +#include "mohawk/cstime_ui.h" +#include "mohawk/cstime_view.h" +#include "mohawk/resource.h" +#include "mohawk/cursors.h" + +#include "common/events.h" + +namespace Mohawk { + +CSTimeView::CSTimeView(MohawkEngine_CSTime *vm) : View(vm) { + _timeVm = vm; + _gfx = vm->_gfx; + _bitmapCursorId = 0; +} + +uint32 CSTimeView::getTime() { + return _vm->_system->getMillis(); +} + +void CSTimeView::setupView() { + _rootNode = new NewFeature(this); + _cursorNode = new NewFeature(this); + _rootNode->setNodeDefaults(NULL, _cursorNode); + _rootNode->_id = 1; // TODO: 10 in new? + _rootNode->_data.enabled = 0; + _rootNode->_flags = kFeatureSortBackground; + _rootNode->_moveProc = NULL; + _rootNode->_drawProc = NULL; + _rootNode->_timeProc = NULL; + _cursorNode->setNodeDefaults(_rootNode, NULL); + _cursorNode->_id = 0xffff; // TODO: 1 in new? + _cursorNode->_data.enabled = 0; + _cursorNode->_flags = kFeatureOldSortForeground; // TODO: 0x4000 in new.. + _cursorNode->_moveProc = (Module::FeatureProc)&CSTimeModule::cursorMoveProc; + _cursorNode->_drawProc = (Module::FeatureProc)&CSTimeModule::cursorDrawProc; + _cursorNode->_timeProc = NULL; +} + +Feature *CSTimeView::installViewFeature(uint16 scrbId, uint32 flags, Common::Point *pos) { + Feature *node = _rootNode; + // FIXME: find the right node to insert under + while (node) { + if (node->_next && (node->_next->_id == 0xffff || ((flags & 0x8000) && !(node->_next->_flags & 0x8000)))) + break; + node = node->_next; + } + if (!node) + error("failed to install view feature"); + + NewFeature *feature = new NewFeature(this); + feature->setNodeDefaults(node, node->_next); + + feature->_moveProc = (Module::FeatureProc)&CSTimeModule::defaultMoveProc; + feature->_drawProc = (Module::FeatureProc)&CSTimeModule::defaultDrawProc; + feature->_timeProc = (Module::BooleanProc)&CSTimeModule::defaultTimeProc; + feature->_pickupProc = (Module::PickupProc)&CSTimeModule::defaultPickupProc; + feature->_dropProc = (Module::FeatureProc)&CSTimeModule::defaultDropProc; + feature->_dragMoveProc = (Module::FeatureProc)&CSTimeModule::defaultDragMoveProc; + feature->_oldMoveProc = NULL; + feature->_dragFlags = 0x8000; + + feature->_id = getNewFeatureId(); + node->_next = feature; + feature->_next->_prev = feature; + if (pos) { + feature->_data.currentPos = *pos; + feature->_unknown168 = 1; + } else { + feature->_data.currentPos = Common::Point(); + feature->_unknown168 = 0x7FFFFFFF; + } + feature->_data.nextPos = Common::Point(); + feature->_scrbId = scrbId; + feature->_flags = flags; + feature->_delayTime = 100; + return feature; +} + +void CSTimeView::installGroup(uint16 resourceId, uint size, uint count, bool regs, uint16 baseId) { + // TODO: make sure this is in sync! + assert(_numSCRBGroups < 14); + installFeatureShapes(regs, _numSCRBGroups, resourceId); + if (baseId == 0xffff) + baseId = resourceId; + installGroupOfSCRBs(false, baseId, size, count); +} + +void CSTimeView::removeGroup(uint16 resourceId) { + // FIXME: deal with zero resourceId + if (resourceId == 0) + error("removeGroup got zero resourceId"); + + uint16 groupId = getGroupFromBaseId(resourceId); + if (groupId == 0xffff) + return; + + removeObjectsUsingBaseId(resourceId); + freeShapesUsingGroupId(groupId); + freeScriptsUsingGroupId(groupId); + adjustShapeGroups(groupId); +} + +void CSTimeView::removeObjectsUsingBaseId(uint16 baseId) { + uint16 groupId = getGroupFromBaseId(baseId); + + Feature *node = _rootNode->_next; + while (node->_next) { + Feature *curr = node; + node = node->_next; + if (curr->_data.compoundSHAPIndex == groupId) { + removeFeature(curr, true); + } + } +} + +void CSTimeView::freeShapesUsingGroupId(uint16 groupId) { + _compoundSHAPGroups[groupId] = 0xffff; // FIXME +} + +void CSTimeView::freeScriptsUsingGroupId(uint16 groupId) { + _SCRBGroupBases[groupId] = 0xffff; // FIXME +} + +void CSTimeView::adjustShapeGroups(uint16 groupId) { + // FIXME +} + +void CSTimeView::loadBitmapCursors(uint16 baseId) { + // TODO +} + +void CSTimeView::setBitmapCursor(uint16 id) { + if (_bitmapCursorId == id) + return; + + if (!id) { + _vm->_cursor->showCursor(); + } else { + _vm->_cursor->hideCursor(); + } + + _bitmapCursorId = id; +} + +void CSTimeView::dragFeature(NewFeature *feature, Common::Point pos, uint mode, uint32 flags, Common::Rect *rect) { + feature->_data.hidden = 0; + + if (mode == 2) { + if (feature->_dragFlags & 0x800000) { + feature->_dragFlags |= 0x8000; + if (!(flags & 1)) + (_currentModule->*(feature->_dropProc))(feature); + } + return; + } + + if (feature->_dragFlags & 0x800000) + (_currentModule->*(feature->_dropProc))(feature); + else + (_currentModule->*(feature->_pickupProc))(feature, pos, flags, rect); +} + +void CSTimeView::finishDraw() { + // TODO: This is a kinda stupid hack, here just for debugging. + ((MohawkEngine_CSTime *)_vm)->getCase()->getCurrScene()->drawHotspots(); +} + +CSTimeModule::CSTimeModule(MohawkEngine_CSTime *vm) : _vm(vm) { +} + +void CSTimeModule::defaultMoveProc(Feature *feature) { + if (feature->_data.paused > 0) + return; + + if (!feature->_data.enabled) + return; + + if (feature->_timeProc && !(this->*(feature->_timeProc))(feature)) + return; + + if (feature->_needsReset) { + feature->resetFeatureScript(1, feature->_scrbId); + if ((feature->_flags & kFeatureNewDisable) || (feature->_flags & kFeatureNewDisableOnReset)) { + feature->_data.enabled = 0; + } + feature->_dirty = 1; + if (feature->_flags & kFeatureInternalRegion) { + // TODO: create region [+140] (if not already done) + } + } else { + if (!(feature->_flags & kFeatureNewClip)) { + if (feature->_data.useClipRect) { + // TODO: or clip with _unknown228 + } else if (feature->_region) { + // TODO: or clip with region + } else { + // TODO: or clip with bounds + } + } + feature->_dirty = 1; + if (feature->_flags & kFeatureNewInternalTiming) { + feature->_nextTime += feature->_delayTime; + } else { + feature->_nextTime = _vm->getView()->_lastIdleTime + feature->_delayTime; + } + if (feature->_done) { + if (feature->_flags & kFeatureNewNoLoop) { + // FIXME: sync channel reset + uint16 unknown184 = 1, unknown186 = 1; // FIXME: XXX + if (feature->_flags & kFeatureDisableOnEnd || (unknown184 != 0 && unknown186 != 0)) { // FIXME: XXX + feature->_data.enabled = 0; + if (feature->_doneProc) { + (this->*(feature->_doneProc))(feature); // TODO: with -2 + } + } + return; + } + + feature->_data.currOffset = 26; + feature->_done = 0; + } + if (feature->_flags & kFeatureNewDisable) + feature->_data.enabled = 0; + } + + int xOffset = feature->_data.currentPos.x + feature->_data.nextPos.x; + int yOffset = feature->_data.currentPos.y + feature->_data.nextPos.y; + + Common::SeekableReadStream *ourSCRB = _vm->getView()->getSCRB(feature->_data.scrbIndex); + ourSCRB->seek(feature->_data.currOffset); + + bool setBitmap = false; + uint bitmapId = 0; + bool done = false; + while (!done) { + byte opcode = ourSCRB->readByte(); + byte size = ourSCRB->readByte(); + switch (opcode) { + case 1: + ourSCRB->skip(size - 2); + opcode = ourSCRB->readByte(); + size = ourSCRB->readByte(); + if (opcode != 0) { + ourSCRB->seek(-2, SEEK_CUR); + done = true; + break; + } + case 0: + // TODO: set ptr +176 to 1 + feature->_done = 1; + if (feature->_doneProc) { + (this->*(feature->_doneProc))(feature); // TODO: with -1 + } + done = true; + break; + + case 3: + { + int32 pos = ourSCRB->pos(); + ourSCRB->seek(2); + uint16 base = ourSCRB->readUint16BE(); + ourSCRB->seek(pos); + base += ourSCRB->readUint16BE(); + if (base) { + // FIXME: sound? + } + ourSCRB->skip(size - 4); + } + warning("saw feature opcode 0x3 (size %d)", size); + break; + + case 4: + // FIXME + if (false /* TODO: !+72 */) { + ourSCRB->skip(size - 2); + } else { + uint16 time = ourSCRB->readUint16BE(); + // FIXME: not right + feature->_delayTime = time; + ourSCRB->skip(size - 4); + } + warning("saw feature opcode 0x4 (size %d)", size); + break; + + case 9: + // FIXME + ourSCRB->skip(size - 2); + warning("ignoring feature opcode 0x9 (size %d)", size); + break; + + case 0xf: + // FIXME + ourSCRB->skip(size - 2); + warning("ignoring feature opcode 0xf (size %d)", size); + break; + + case 0x10: + while (bitmapId < 48) { + if (!size) + break; + size--; + feature->_data.bitmapIds[bitmapId] = ourSCRB->readUint16BE() & 0xFFF; + feature->_data.bitmapPos[bitmapId].x = ourSCRB->readUint16BE() + xOffset; + feature->_data.bitmapPos[bitmapId].y = ourSCRB->readUint16BE() + yOffset; + bitmapId++; + } + feature->_data.bitmapIds[bitmapId] = 0; + setBitmap = true; + break; + + default: + warning("unknown new feature opcode %d", opcode); + ourSCRB->skip(size - 2); + break; + } + } + + feature->_data.currOffset = ourSCRB->pos(); + if (!setBitmap) { + // TODO: set fail flag + return; + } + if (feature->_frameProc) { + (this->*(feature->_frameProc))(feature); + } + // TODO: set palette if needed + + // TODO: adjust for regs if needed + Common::Array<int16> regsX, regsY; + Common::SeekableReadStream *regsStream; + uint16 compoundSHAPIndex = _vm->getView()->getCompoundSHAPId(feature->_data.compoundSHAPIndex); + regsStream = _vm->getResource(ID_REGS, compoundSHAPIndex); + while (regsStream->pos() != regsStream->size()) + regsX.push_back(regsStream->readSint16BE()); + delete regsStream; + regsStream = _vm->getResource(ID_REGS, compoundSHAPIndex + 1); + while (regsStream->pos() != regsStream->size()) + regsY.push_back(regsStream->readSint16BE()); + delete regsStream; + for (uint i = 0; i < 48; i++) { + uint16 thisBitmapId = feature->_data.bitmapIds[i]; + if (!thisBitmapId) + break; + feature->_data.bitmapPos[i].x -= regsX[thisBitmapId]; + feature->_data.bitmapPos[i].y -= regsY[thisBitmapId]; + } + + // TODO: set bounds + // TODO: unset fail flag +} + +void CSTimeModule::defaultDrawProc(Feature *feature) { + if (feature->_data.hidden > 0) + return; + + feature->defaultDraw(); +} + +bool CSTimeModule::defaultTimeProc(Feature *feature) { + return (feature->_nextTime <= _vm->getView()->getTime()); +} + +void CSTimeModule::defaultPickupProc(NewFeature *feature, Common::Point pos, uint32 flags, Common::Rect *rect) { + _vm->getView()->removeFeature(feature, false); + + feature->_dragFlags |= flags | 0x800000; + feature->_oldFlags = feature->_flags; + feature->_data.useClipRect = 0; + // TODO: these flags are weird/different + feature->_flags = (feature->_flags & ~kFeatureSortBackground) | kFeatureOldSortForeground | kFeatureSortStatic | 0x2000; + _vm->getView()->insertUnderCursor(feature); + + feature->_nextTime = 0; + // FIXME: preserve old delayTime (see also script op 4) + feature->_delayTime = 50; + + feature->_oldPos = feature->_data.currentPos; + + feature->_posDiff.x = pos.x - feature->_data.currentPos.x; + feature->_posDiff.y = pos.y - feature->_data.currentPos.y; + debug("defaultPickupProc: diff is %d, %d", feature->_posDiff.x, feature->_posDiff.y); + + feature->_oldMoveProc = feature->_moveProc; + feature->_moveProc = feature->_dragMoveProc; + + // FIXME: deal with rect + if (rect) + error("defaultPickupProc doesn't handle rect yet"); +} + +void CSTimeModule::defaultDropProc(NewFeature *feature) { + // FIXME: invalidation + + feature->_flags = feature->_oldFlags; + // FIXME: restore old delayTime + feature->_dragFlags &= ~0x800000; + + if (feature->_dragFlags & 0x800) + feature->moveAndUpdate(feature->_oldPos); + if (feature->_dragFlags & 0x200) + feature->hide(true); + feature->_moveProc = feature->_oldMoveProc; +} + +void CSTimeModule::defaultDragMoveProc(NewFeature *feature) { + // FIXME + + if (feature->_dragFlags & 0x8000) + feature->_currDragPos = _vm->getEventManager()->getMousePos(); + + Common::Point pos = feature->_currDragPos; + pos.x -= feature->_posDiff.x; + pos.y -= feature->_posDiff.y; + + if (feature->_dragFlags & 0x80) { + // FIXME: handle 0x80 case + error("encountered 0x80 case in defaultDragMoveProc"); + } + + feature->moveAndUpdate(pos); + + (this->*(feature->_oldMoveProc))(feature); +} + +void CSTimeModule::cursorMoveProc(Feature *feature) { + uint16 cursor = _vm->getView()->getBitmapCursor(); + if (!cursor) + return; + + Common::Point pos = _vm->getEventManager()->getMousePos(); + + // FIXME: shouldn't be hardcoded + uint16 compoundSHAPIndex = 200; + // FIXME: stupid REGS stuff.. + Common::SeekableReadStream *regsStream = _vm->getResource(ID_REGS, compoundSHAPIndex); + regsStream->seek(cursor * 2); + feature->_data.bounds.left = pos.x - regsStream->readSint16BE(); + delete regsStream; + regsStream = _vm->getResource(ID_REGS, compoundSHAPIndex + 1); + regsStream->seek(cursor * 2); + feature->_data.bounds.top = pos.y - regsStream->readSint16BE(); + delete regsStream; +} + +void CSTimeModule::cursorDrawProc(Feature *feature) { + uint16 cursor = _vm->getView()->getBitmapCursor(); + if (!cursor) + return; + // FIXME: shouldn't be hardcoded + uint16 compoundSHAPIndex = 200; + _vm->getView()->getGfx()->copyAnimSubImageToScreen(compoundSHAPIndex, cursor - 1, feature->_data.bounds.left, feature->_data.bounds.top); +} + +void CSTimeModule::rolloverTextMoveProc(Feature *feature) { + // Should OR the whole bounds into the dirty region, if the text changed. +} + +void CSTimeModule::rolloverTextDrawProc(Feature *feature) { + // TODO: if timeBook->getState() is 2, return + const Common::String &text = _vm->getInterface()->getRolloverText(); + if (!text.empty()) { + Common::Rect &rect = feature->_data.bounds; + Graphics::Surface *screen = g_system->lockScreen(); + _vm->getInterface()->getRolloverFont().drawString(screen, text, rect.left, rect.top, rect.width(), 32, Graphics::kTextAlignCenter); + g_system->unlockScreen(); + } + // TODO: some special case about dragging in case 1, scene 4 (torch?) + // TODO: unset text changed flag +} + +void CSTimeModule::dialogTextMoveProc(Feature *feature) { + // FIXME +} + +void CSTimeModule::dialogTextDrawProc(Feature *feature) { + const Common::Array<Common::String> &lines = _vm->getInterface()->getDialogLines(); + const Common::Array<byte> &colors = _vm->getInterface()->getDialogLineColors(); + const Common::Rect &bounds = feature->_data.bounds; + const Graphics::WinFont &font = _vm->getInterface()->getDialogFont(); + + Graphics::Surface *screen = _vm->_system->lockScreen(); + for (uint i = 0; i < lines.size(); i++) + font.drawString(screen, lines[i], bounds.left, bounds.top + 1 + i*15, bounds.width(), colors[i], Graphics::kTextAlignCenter); + _vm->_system->unlockScreen(); + // FIXME +} + +void CSTimeModule::bubbleTextMoveProc(Feature *feature) { + // FIXME +} + +void CSTimeModule::bubbleTextDrawProc(Feature *feature) { + Common::Rect bounds = feature->_data.bounds; + bounds.grow(-5); + const Graphics::WinFont &font = _vm->getInterface()->getDialogFont(); + uint height = font.getFontHeight(); + + Common::Array<Common::String> lines; + font.wordWrapText(_vm->getInterface()->getCurrBubbleText(), bounds.width(), lines); + + Graphics::Surface *screen = _vm->_system->lockScreen(); + for (int x = -2; x < 2; x++) + for (int y = -1; y < 3; y++) + for (uint i = 0; i < lines.size(); i++) + font.drawString(screen, lines[i], bounds.left + x, bounds.top + y + i*height, bounds.width(), 241, Graphics::kTextAlignCenter); + for (uint i = 0; i < lines.size(); i++) + font.drawString(screen, lines[i], bounds.left, bounds.top + i*height, bounds.width(), 32, Graphics::kTextAlignCenter); + _vm->_system->unlockScreen(); +} + +} // End of namespace Mohawk |