diff options
Diffstat (limited to 'engines/mohawk/cstime_ui.cpp')
-rw-r--r-- | engines/mohawk/cstime_ui.cpp | 1186 |
1 files changed, 1186 insertions, 0 deletions
diff --git a/engines/mohawk/cstime_ui.cpp b/engines/mohawk/cstime_ui.cpp new file mode 100644 index 0000000000..08f70ea291 --- /dev/null +++ b/engines/mohawk/cstime_ui.cpp @@ -0,0 +1,1186 @@ +/* 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" +#include "mohawk/cstime_ui.h" +#include "mohawk/cstime_view.h" +#include "mohawk/resource.h" +#include "common/events.h" + +namespace Mohawk { + +// read a null-terminated string from a stream +static Common::String readString(Common::SeekableReadStream *stream) { + Common::String ret; + while (!stream->eos()) { + byte in = stream->readByte(); + if (!in) + break; + ret += in; + } + return ret; +} + +CSTimeInterface::CSTimeInterface(MohawkEngine_CSTime *vm) : _vm(vm) { + _sceneRect = Common::Rect(0, 0, 640, 340); + _uiRect = Common::Rect(0, 340, 640, 480); + + _bookRect = Common::Rect(_uiRect.right - 95, _uiRect.top + 32, _uiRect.right - 25, _uiRect.top + 122); + _noteRect = Common::Rect(_uiRect.left + 27, _uiRect.top + 31, _uiRect.left + 103, _uiRect.top + 131); + _dialogTextRect = Common::Rect(0 + 125, 340 + 40, 640 - 125, 480 - 20); + + _cursorActive = false; + _cursorShapes[0] = 0xFFFF; + _cursorShapes[1] = 0xFFFF; + _cursorShapes[2] = 0xFFFF; + _cursorNextTime = 0; + + _help = new CSTimeHelp(_vm); + _inventoryDisplay = new CSTimeInventoryDisplay(_vm, _dialogTextRect); + _book = new CSTimeBook(_vm); + _note = new CSTimeCarmenNote(_vm); + _options = new CSTimeOptions(_vm); + + if (!_normalFont.loadFromFON("95instal/EvP14.fon")) + error("failed to load normal font"); + if (!_dialogFont.loadFromFON("95instal/Int1212.fon")) + error("failed to load dialog font"); + if (!_rolloverFont.loadFromFON("95instal/Int1818.fon")) + error("failed to load rollover font"); + + _uiFeature = NULL; + _dialogTextFeature = NULL; + _rolloverTextFeature = NULL; + _bubbleTextFeature = NULL; + + _mouseWasInScene = false; + _state = kCSTimeInterfaceStateNormal; + + _dialogLines.resize(5); + _dialogLineColors.resize(5); +} + +CSTimeInterface::~CSTimeInterface() { + delete _help; + delete _inventoryDisplay; + delete _book; + delete _note; + delete _options; +} + +void CSTimeInterface::cursorInstall() { + _vm->getView()->loadBitmapCursors(200); +} + +void CSTimeInterface::cursorIdle() { + if (!_cursorActive || _cursorShapes[1] == 0xFFFF) + return; + + if (_vm->_system->getMillis() <= _cursorNextTime + 250) + return; + + cursorSetShape(_cursorShapes[1], false); + _cursorShapes[1] = _cursorShapes[2]; + _cursorShapes[2] = 0xFFFF; +} + +void CSTimeInterface::cursorActivate(bool state) { + _cursorActive = state; +} + +void CSTimeInterface::cursorChangeShape(uint16 id) { + if (_cursorShapes[1] == 0xFFFF) + _cursorShapes[1] = id; + else + _cursorShapes[2] = id; +} + +uint16 CSTimeInterface::cursorGetShape() { + if (_cursorShapes[2] != 0xFFFF) + return _cursorShapes[2]; + else if (_cursorShapes[1] != 0xFFFF) + return _cursorShapes[1]; + else + return _cursorShapes[0]; +} + +void CSTimeInterface::cursorSetShape(uint16 id, bool reset) { + if (_cursorShapes[0] != id) { + _cursorShapes[0] = id; + _vm->getView()->setBitmapCursor(id); + _cursorNextTime = _vm->_system->getMillis(); + } +} + +void CSTimeInterface::cursorSetWaitCursor() { + uint16 shape = cursorGetShape(); + switch (shape) { + case 8: + cursorChangeShape(9); + break; + case 9: + break; + case 11: + cursorChangeShape(12); + break; + case 13: + cursorChangeShape(15); + break; + default: + cursorChangeShape(3); + break; + } +} + +void CSTimeInterface::openResFile() { + _vm->loadResourceFile("data/iface"); +} + +void CSTimeInterface::install() { + uint16 resourceId = 100; // TODO + _vm->getView()->installGroup(resourceId, 16, 0, true, 100); + + // TODO: store/reset these + + _dialogTextFeature = _vm->getView()->installViewFeature(0, 0, NULL); + _dialogTextFeature->_data.bounds = _dialogTextRect; + _dialogTextFeature->_data.bitmapIds[0] = 0; + // We don't set a port. + _dialogTextFeature->_moveProc = (Module::FeatureProc)&CSTimeModule::dialogTextMoveProc; + _dialogTextFeature->_drawProc = (Module::FeatureProc)&CSTimeModule::dialogTextDrawProc; + _dialogTextFeature->_timeProc = NULL; + _dialogTextFeature->_flags = kFeatureOldSortForeground; // FIXME: not in original + + _rolloverTextFeature = _vm->getView()->installViewFeature(0, 0, NULL); + _rolloverTextFeature->_data.bounds = Common::Rect(0 + 100, 340 + 5, 640 - 100, 480 - 25); + _rolloverTextFeature->_data.bitmapIds[0] = 0; + _rolloverTextFeature->_moveProc = (Module::FeatureProc)&CSTimeModule::rolloverTextMoveProc; + _rolloverTextFeature->_drawProc = (Module::FeatureProc)&CSTimeModule::rolloverTextDrawProc; + _rolloverTextFeature->_timeProc = NULL; + _rolloverTextFeature->_flags = kFeatureOldSortForeground; // FIXME: not in original +} + +void CSTimeInterface::draw() { + // TODO + if (!_uiFeature) { + uint32 flags = kFeatureSortStatic | kFeatureNewNoLoop; + assert(flags == 0x4800000); + uint16 resourceId = 100; // TODO + _uiFeature = _vm->getView()->installViewFeature(resourceId, flags, NULL); + // TODO: special-case for case 20 + } else { + _uiFeature->resetFeatureScript(1, 0); + // TODO: special-case for case 20 + } + + // TODO: special-case for cases 19 and 20 + + _note->drawSmallNote(); + _book->drawSmallBook(); + _inventoryDisplay->draw(); +} + +void CSTimeInterface::idle() { + // TODO: inv sound handling + + _vm->getCase()->getCurrScene()->idle(); + _inventoryDisplay->idle(); + cursorIdle(); + + _vm->getView()->idleView(); +} + +void CSTimeInterface::mouseDown(Common::Point pos) { + _vm->resetTimeout(); + + if (_options->getState()) { + // TODO: _options->mouseDown(pos); + return; + } + + if (!cursorGetState()) + return; + if (_vm->getCase()->getCurrScene()->eventIsActive()) + return; + + switch (cursorGetShape()) { + case 1: + cursorChangeShape(4); + break; + case 2: + cursorChangeShape(5); + break; + case 13: + cursorChangeShape(14); + break; + } + + if (_book->getState() == 2) { + // TODO: _book->mouseDown(pos); + return; + } + + // TODO: if in sailing puzzle, sailing puzzle mouse down, return + + if (_note->getState() > 0) { + return; + } + + if (_sceneRect.contains(pos)) { + _vm->getCase()->getCurrScene()->mouseDown(pos); + return; + } + + // TODO: case 20 ui craziness is handled seperately.. + + CSTimeConversation *conv = _vm->getCase()->getCurrConversation(); + if (_bookRect.contains(pos) || (_noteRect.contains(pos) && _note->havePiece(0xffff))) { + if (conv->getState() != (uint)~0) + conv->end(false); + if (_help->getState() != (uint)~0) + _help->end(); + return; + } + + if (_help->getState() != (uint)~0) { + // FIXME: _help->mouseDown(pos); + return; + } + + if (conv->getState() != (uint)~0) { + conv->mouseDown(pos); + return; + } + + // TODO: handle symbols + + if (_inventoryDisplay->_invRect.contains(pos)) { + // TODO: special handling for case 6 + + _inventoryDisplay->mouseDown(pos); + } +} + +void CSTimeInterface::mouseMove(Common::Point pos) { + if (_options->getState()) { + // TODO: _options->mouseMove(pos); + return; + } + + if (!cursorGetState()) + return; + + if (_mouseWasInScene && _uiRect.contains(pos)) { + clearTextLine(); + _mouseWasInScene = false; + } + + if (_book->getState() == 2) { + // TODO: _book->mouseMove(pos); + return; + } + + if (_note->getState() == 2) + return; + + // TODO: case 20 ui craziness is handled seperately.. + + if (_sceneRect.contains(pos) && !_vm->getCase()->getCurrScene()->eventIsActive()) { + _vm->getCase()->getCurrScene()->mouseMove(pos); + _mouseWasInScene = true; + return; + } + + if (cursorGetShape() == 13) { + cursorSetShape(1); + return; + } else if (cursorGetShape() == 14) { + cursorSetShape(4); + return; + } + + bool mouseIsDown = _vm->getEventManager()->getButtonState() & 1; + + if (_book->getState() == 1 && !_bookRect.contains(pos)) { + if (_state != kCSTimeInterfaceStateDragging) { + clearTextLine(); + cursorSetShape(mouseIsDown ? 4 : 1); + _book->setState(0); + } + return; + } + + // TODO: case 20 ui craziness again + + if (_note->getState() == 1 && !_noteRect.contains(pos)) { + if (_state != kCSTimeInterfaceStateDragging) { + clearTextLine(); + cursorSetShape(mouseIsDown ? 4 : 1); + _note->setState(0); + } + return; + } + + // TODO: handle symbols + + if (_bookRect.contains(pos)) { + if (_state != kCSTimeInterfaceStateDragging) { + displayTextLine("Open Chronopedia"); + cursorSetShape(mouseIsDown ? 5 : 2); + _book->setState(1); + } + return; + } + + if (_noteRect.contains(pos)) { + if (_state != kCSTimeInterfaceStateDragging && _note->havePiece(0xffff) && !_note->getState()) { + displayTextLine("Look at Note"); + cursorSetShape(mouseIsDown ? 5 : 2); + _note->setState(1); + } + return; + } + + if (_vm->getCase()->getCurrConversation()->getState() != (uint)~0) { + _vm->getCase()->getCurrConversation()->mouseMove(pos); + return; + } + + if (_help->getState() != (uint)~0) { + // FIXME: _help->mouseMove(pos); + return; + } + + if (_state == kCSTimeInterfaceStateDragging) { + // FIXME: dragging + return; + } + + // FIXME: if case is 20, we're done, return + + if (_inventoryDisplay->_invRect.contains(pos)) { + _inventoryDisplay->mouseMove(pos); + } +} + +void CSTimeInterface::mouseUp(Common::Point pos) { + if (_options->getState()) { + // TODO: options->mouseUp(pos); + return; + } + + if (!cursorGetState()) + return; + + if (_state == kCSTimeInterfaceStateDragging) { + stopDragging(); + return; + } + + if (_state == kCSTimeInterfaceStateDragStart) + _state = kCSTimeInterfaceStateNormal; + + switch (cursorGetShape()) { + case 4: + cursorChangeShape(1); + break; + case 5: + cursorChangeShape(2); + break; + case 14: + cursorChangeShape(13); + break; + } + + if (_vm->getCase()->getCurrScene()->eventIsActive()) { + if (_vm->getCurrentEventType() == kCSTimeEventWaitForClick) + _vm->mouseClicked(); + return; + } + + if (_book->getState() == 2) { + // TODO: _book->mouseUp(pos); + return; + } + + if (_note->getState() == 2) { + // TODO: _note->closeNote(); + mouseMove(pos); + return; + } + + // TODO: if in sailing puzzle, sailing puzzle mouse up, return + + // TODO: case 20 ui craziness is handled seperately.. + + if (_sceneRect.contains(pos)) { + _vm->getCase()->getCurrScene()->mouseUp(pos); + return; + } + + if (_vm->getCase()->getCurrConversation()->getState() != (uint)~0) { + _vm->getCase()->getCurrConversation()->mouseUp(pos); + return; + } + + if (_help->getState() != (uint)~0) { + // FIXME: _help->mouseUp(pos); + return; + } + + // TODO: handle symbols + + if (_bookRect.contains(pos)) { + // TODO: handle flashing cuffs + // TODO: _book->open(); + return; + } + + if (_noteRect.contains(pos)) { + // TODO: special-casing for case 19 + if (_note->havePiece(0xffff)) + _note->drawBigNote(); + } + + if (_inventoryDisplay->_invRect.contains(pos)) { + // TODO: special-casing for case 6 + _inventoryDisplay->mouseUp(pos); + } +} + +void CSTimeInterface::cursorOverHotspot() { + if (cursorGetState() != 1) + return; + if (_state == kCSTimeInterfaceStateDragStart || _state == kCSTimeInterfaceStateDragging) + return; + if (cursorGetShape() == 3 || cursorGetShape() == 9) + return; + + bool mouseIsDown = _vm->getEventManager()->getButtonState() & 1; + if (mouseIsDown) + cursorSetShape(5); + else if (cursorGetShape() == 1) + cursorChangeShape(2); +} + +void CSTimeInterface::setCursorForCurrentPoint() { + uint16 shape = 1; + + Common::Point mousePos = _vm->getEventManager()->getMousePos(); + if (_bookRect.contains(mousePos)) { + shape = 2; + } else { + uint convState = _vm->getCase()->getCurrConversation()->getState(); + uint helpState = _help->getState(); + // TODO: symbols too + if (convState == (uint)~0 || convState == 0 || helpState == (uint)~0 || helpState == 0) { + // FIXME: set cursor to 2 if inventory display occupied + } else if (convState == 1 || helpState == 1) { + // FIXME: set cursor to 2 if over conversation rect + } + } + + cursorSetShape(shape); +} + +void CSTimeInterface::clearTextLine() { + _rolloverText.clear(); +} + +void CSTimeInterface::displayTextLine(Common::String text) { + _rolloverText = text; +} + +void CSTimeInterface::clearDialogArea() { + _dialogLines.clear(); + _dialogLines.resize(5); + // TODO: dirty feature +} + +void CSTimeInterface::clearDialogLine(uint line) { + _dialogLines[line].clear(); + // TODO: dirty feature +} + +void CSTimeInterface::displayDialogLine(uint16 id, uint line, byte color) { + Common::SeekableReadStream *stream = _vm->getResource(ID_STRI, id); + Common::String text = readString(stream); + delete stream; + + _dialogLines[line] = text; + _dialogLineColors[line] = color; + // TODO: dirty feature +} + +void CSTimeInterface::drawTextIdToBubble(uint16 id) { + Common::SeekableReadStream *stream = _vm->getResource(ID_STRI, id); + Common::String text = readString(stream); + delete stream; + + drawTextToBubble(&text); +} + +void CSTimeInterface::drawTextToBubble(Common::String *text) { + if (_bubbleTextFeature) + error("Attempt to display two text objects"); + if (!text) + text = &_bubbleText; + if (text->empty()) + return; + + _currentBubbleText = *text; + + uint bubbleId = _vm->getCase()->getCurrScene()->getBubbleType(); + Common::Rect bounds; + switch (bubbleId) { + case 0: + bounds = Common::Rect(15, 7, 625, 80); + break; + case 1: + bounds = Common::Rect(160, 260, 625, 333); + break; + case 2: + bounds = Common::Rect(356, 3, 639, 90); + break; + case 3: + bounds = Common::Rect(10, 7, 380, 80); + break; + case 4: + bounds = Common::Rect(15, 270, 625, 328); + break; + case 5: + bounds = Common::Rect(15, 7, 550, 70); + break; + case 6: + bounds = Common::Rect(0, 0, 313, 76); + break; + case 7: + bounds = Common::Rect(200, 25, 502, 470); + break; + default: + error("unknown bubble type %d in drawTextToBubble", bubbleId); + } + + _bubbleTextFeature = _vm->getView()->installViewFeature(0, 0, NULL); + _bubbleTextFeature->_data.bounds = bounds; + _bubbleTextFeature->_data.bitmapIds[0] = 0; + _bubbleTextFeature->_moveProc = (Module::FeatureProc)&CSTimeModule::bubbleTextMoveProc; + _bubbleTextFeature->_drawProc = (Module::FeatureProc)&CSTimeModule::bubbleTextDrawProc; + _bubbleTextFeature->_timeProc = NULL; + _bubbleTextFeature->_flags = kFeatureOldSortForeground; // FIXME: not in original +} + +void CSTimeInterface::closeBubble() { + if (_bubbleTextFeature) + _vm->getView()->removeFeature(_bubbleTextFeature, true); + _bubbleTextFeature = NULL; +} + +void CSTimeInterface::startDragging(uint16 id) { + CSTimeInventoryObject *invObj = _vm->getCase()->_inventoryObjs[id]; + + cursorSetShape(11); + _draggedItem = id; + + if (_draggedItem == TIME_CUFFS_ID) { + if (_inventoryDisplay->getCuffsShape() == 11) { + _inventoryDisplay->setCuffsFlashing(); + _vm->getView()->idleView(); + } + } + + uint32 dragFlags = (grabbedFromInventory() ? 0x800 : 0x600); + _vm->getView()->dragFeature((NewFeature *)invObj->feature, _grabPoint, 4, dragFlags, NULL); + + if (_vm->getCase()->getId() == 1 && id == 2) { + // Hardcoded behaviour for the torch in the first case. + if (_vm->getCase()->getCurrScene()->getId() == 4) { + // This is the dark tomb. + // FIXME: apply torch hack + _vm->_caseVariable[2]++; + } else { + // FIXME: unapply torch hack + } + } + + _state = kCSTimeInterfaceStateDragging; + + if (grabbedFromInventory()) + return; + + // Hide the associated scene feature, if there is one. + if (invObj->featureId != 0xffff) { + CSTimeEvent event; + event.type = kCSTimeEventDisableFeature; + event.param2 = invObj->featureId; + _vm->addEvent(event); + } + + _vm->addEventList(invObj->events); +} + +void CSTimeInterface::stopDragging() { + CSTimeScene *scene = _vm->getCase()->getCurrScene(); + CSTimeInventoryObject *invObj = _vm->getCase()->_inventoryObjs[_draggedItem]; + + Common::Point mousePos = _vm->_system->getEventManager()->getMousePos(); + _state = kCSTimeInterfaceStateNormal; + + if (_sceneRect.contains(mousePos)) + scene->setCursorForCurrentPoint(); + else + setCursorForCurrentPoint(); + + // Find the inventory object hotspot which is topmost for this drop, if any. + uint foundInvObjHotspot = ~0; + const Common::Array<CSTimeHotspot> &hotspots = scene->getHotspots(); + for (uint i = 0; i < hotspots.size(); i++) { + if (hotspots[i].state != 1) + continue; + if (!hotspots[i].region.containsPoint(mousePos)) + continue; + for (uint j = 0; j < invObj->hotspots.size(); j++) { + if (invObj->hotspots[j].sceneId != scene->getId()) + continue; + if (invObj->hotspots[j].hotspotId != i) + continue; + if (foundInvObjHotspot != (uint)~0 && invObj->hotspots[foundInvObjHotspot].hotspotId < invObj->hotspots[j].hotspotId) + continue; + foundInvObjHotspot = j; + } + } + + // Work out if we're going to consume (nom-nom) the object after the drop. + bool consumeObj = false; + bool runConsumeEvents = false; + if (foundInvObjHotspot != (uint)~0) { + CSTimeInventoryHotspot &hotspot = invObj->hotspots[foundInvObjHotspot]; + + clearTextLine(); + for (uint i = 0; i < invObj->locations.size(); i++) { + if (invObj->locations[i].sceneId != hotspot.sceneId) + continue; + if (invObj->locations[i].hotspotId != hotspot.hotspotId) + continue; + consumeObj = true; + break; + } + + if (_draggedItem == TIME_CUFFS_ID && !_inventoryDisplay->getCuffsState()) { + consumeObj = false; + // Nuh-uh, they're not activated yet. + _vm->addEvent(CSTimeEvent(kCSTimeEventCharStartFlapping, _vm->getCase()->getCurrScene()->getHelperId(), 9902)); + } else { + // FIXME: ding(); + runConsumeEvents = true; + } + } + + // Deal with the actual drop. + if (grabbedFromInventory()) { + if (!consumeObj) { + _vm->getView()->dragFeature((NewFeature *)invObj->feature, mousePos, 2, 0x800, NULL); + // TODO: playSound(151); + } else if (_draggedItem != TIME_CUFFS_ID) { + _vm->getView()->dragFeature((NewFeature *)invObj->feature, mousePos, 2, 0x800, NULL); + _vm->_haveInvItem[_draggedItem] = 0; + // FIXME: the original sets the feature to -2 here, see comment below + invObj->feature = NULL; + _inventoryDisplay->removeItem(_draggedItem); + } else if (!_inventoryDisplay->getCuffsState()) { + // Inactive cuffs. + _vm->getView()->dragFeature((NewFeature *)invObj->feature, mousePos, 2, 0x800, NULL); + invObj->feature = NULL; + } else { + // Active cuffs. + _vm->getView()->dragFeature((NewFeature *)invObj->feature, mousePos, 2, 0x600, NULL); + _vm->_haveInvItem[_draggedItem] = 0; + // FIXME: the original sets the feature to -2 here, see comment below + invObj->feature = NULL; + } + + if (runConsumeEvents) { + _vm->addEventList(invObj->hotspots[foundInvObjHotspot].events); + } + + _inventoryDisplay->draw(); + } else { + uint32 dragFlags = 0x600; + _vm->getView()->dragFeature((NewFeature *)invObj->feature, mousePos, 2, dragFlags, NULL); + + if (_inventoryDisplay->_invRect.contains(mousePos)) { + // Dropped into the inventory. + invObj->feature = NULL; + if (invObj->canTake) { + dropItemInInventory(_draggedItem); + if (invObj->hotspotId) + _vm->addEvent(CSTimeEvent(kCSTimeEventDisableHotspot, 0xffff, invObj->hotspotId)); + } else { + if (invObj->featureId) + _vm->addEvent(CSTimeEvent(kCSTimeEventAddFeature, 0xffff, invObj->featureId)); + } + + for (uint i = 0; i < invObj->hotspots.size(); i++) { + if (invObj->hotspots[i].sceneId != scene->getId()) + continue; + if (invObj->hotspots[i].hotspotId != 0xffff) + continue; + _vm->addEventList(invObj->hotspots[i].events); + } + } else { + // Dropped into the scene. + + CSTimeEvent event; + event.param1 = 0xffff; + if (consumeObj) { + // FIXME: the original sets the feature to -2 here, which is used in the inventory display drawing + // so it knows not to draw the object. we should replace that with a flag. + invObj->feature = NULL; + event.type = kCSTimeEventDisableHotspot; + event.param2 = invObj->hotspotId; + } else { + invObj->feature = NULL; + event.type = kCSTimeEventAddFeature; + event.param2 = invObj->featureId; + } + _vm->addEvent(event); + + if (runConsumeEvents) { + _vm->addEventList(invObj->hotspots[foundInvObjHotspot].events); + } else { + for (uint i = 0; i < invObj->hotspots.size(); i++) { + if (invObj->hotspots[i].sceneId != scene->getId()) + continue; + if (invObj->hotspots[i].hotspotId != 0xfffe) + continue; + _vm->addEventList(invObj->hotspots[i].events); + } + } + } + } + + if (_vm->getCase()->getId() == 1 && _vm->getCase()->getCurrScene()->getId() == 4) { + // Hardcoded behaviour for torches in the dark tomb, in the first case. + if (_draggedItem == 1 && foundInvObjHotspot == (uint)~0) { + // Trying to drag an unlit torch around? + _vm->addEvent(CSTimeEvent(kCSTimeEventCharStartFlapping, 0, 16352)); + } else if (_draggedItem == 2 && _vm->_caseVariable[2] == 1) { + // This the first time we tried dragging the lit torch around. + _vm->addEvent(CSTimeEvent(kCSTimeEventCharStartFlapping, 0, 16354)); + } + } + + // TODO: Is this necessary? + _draggedItem = 0xffff; +} + +void CSTimeInterface::setGrabPoint() { + _grabPoint = _vm->_system->getEventManager()->getMousePos(); +} + +bool CSTimeInterface::grabbedFromInventory() { + return (_inventoryDisplay->_invRect.contains(_grabPoint)); +} + +void CSTimeInterface::dropItemInInventory(uint16 id) { + if (_vm->_haveInvItem[id]) + return; + + _vm->_haveInvItem[id] = 1; + _vm->getCase()->_inventoryObjs[id]->feature = NULL; + + _inventoryDisplay->insertItemInDisplay(id); + + // TODO: deal with symbols + + if (_vm->getCase()->getCurrConversation()->getState() == (uint)~0 || _vm->getCase()->getCurrConversation()->getState() == 0) { + // FIXME: additional check here + // FIXME: play sound 151? + _inventoryDisplay->draw(); + return; + } + + // FIXME: ding(); + clearDialogArea(); + _inventoryDisplay->show(); + _inventoryDisplay->draw(); + _inventoryDisplay->setState(4); +} + +CSTimeHelp::CSTimeHelp(MohawkEngine_CSTime *vm) : _vm(vm) { + _state = ~0; +} + +CSTimeHelp::~CSTimeHelp() { +} + +void CSTimeHelp::end(bool runEvents) { + // FIXME +} + +CSTimeInventoryDisplay::CSTimeInventoryDisplay(MohawkEngine_CSTime *vm, Common::Rect baseRect) : _vm(vm) { + _state = 0; + _cuffsState = false; + _cuffsShape = 10; + + _invRect = baseRect; + + for (uint i = 0; i < MAX_DISPLAYED_ITEMS; i++) { + _itemRect[i].left = baseRect.left + 15 + i * 92; + _itemRect[i].top = baseRect.top + 5; + _itemRect[i].right = _itemRect[i].left + 90; + _itemRect[i].bottom = _itemRect[i].top + 70; + } +} + +CSTimeInventoryDisplay::~CSTimeInventoryDisplay() { +} + +void CSTimeInventoryDisplay::install() { + uint count = _vm->getCase()->_inventoryObjs.size() - 1; + + // FIXME: some cases have hard-coded counts + + _vm->getView()->installGroup(9000, count, 0, true, 9000); +} + +void CSTimeInventoryDisplay::draw() { + for (uint i = 0; i < MAX_DISPLAYED_ITEMS; i++) { + if (_displayedItems[i] == (uint)~0) + continue; + CSTimeInventoryObject *invObj = _vm->getCase()->_inventoryObjs[_displayedItems[i]]; + + // FIXME: ignore on -2 feature (see CSTimeInterface::stopDragging) + + if (invObj->feature) { + invObj->feature->resetFeatureScript(1, 0); + continue; + } + + // TODO: 0x2000 is set! help? + uint32 flags = kFeatureSortStatic | kFeatureNewNoLoop | 0x2000; + if (i == TIME_CUFFS_ID) { + // Time Cuffs are handled differently. + // TODO: Can we not use _cuffsShape here? + uint16 id = 100 + 10; + if (_cuffsState) { + id = 100 + 12; + flags &= ~kFeatureNewNoLoop; + } + invObj->feature = _vm->getView()->installViewFeature(id, flags, NULL); + } else { + Common::Point pos((_itemRect[i].left + _itemRect[i].right) / 2, (_itemRect[i].top + _itemRect[i].bottom) / 2); + uint16 id = 9000 + (invObj->id - 1); + invObj->feature = _vm->getView()->installViewFeature(id, flags, &pos); + } + } +} + +void CSTimeInventoryDisplay::show() { + for (uint i = 0; i < MAX_DISPLAYED_ITEMS; i++) { + if (_displayedItems[i] == (uint)~0) + continue; + CSTimeInventoryObject *invObj = _vm->getCase()->_inventoryObjs[_displayedItems[i]]; + if (!invObj->feature) + continue; + invObj->feature->show(); + } +} + +void CSTimeInventoryDisplay::hide() { + for (uint i = 0; i < MAX_DISPLAYED_ITEMS; i++) { + if (_displayedItems[i] == (uint)~0) + continue; + CSTimeInventoryObject *invObj = _vm->getCase()->_inventoryObjs[_displayedItems[i]]; + if (!invObj->feature) + continue; + invObj->feature->hide(true); + } +} + +void CSTimeInventoryDisplay::idle() { + if (_vm->getInterface()->getCarmenNote()->getState() || + _vm->getCase()->getCurrConversation()->getState() != 0xffff || + _vm->getInterface()->getHelp()->getState() != 0xffff) { + if (_state == 4) { + // FIXME: check timeout! + hide(); + _vm->getCase()->getCurrConversation()->display(); + _state = 0; + } + return; + } + + if (!_state) + return; + + // FIXME: deal with actual inventory stuff +} + +void CSTimeInventoryDisplay::clearDisplay() { + for (uint i = 0; i < MAX_DISPLAYED_ITEMS; i++) + _displayedItems[i] = ~0; + + // We always start out with the Time Cuffs. + _vm->_haveInvItem[TIME_CUFFS_ID] = 1; + insertItemInDisplay(TIME_CUFFS_ID); + + _cuffsState = false; +} + +void CSTimeInventoryDisplay::insertItemInDisplay(uint id) { + for (uint i = 0; i < MAX_DISPLAYED_ITEMS; i++) + if (_displayedItems[i] == id) + return; + + for (uint i = 0; i < MAX_DISPLAYED_ITEMS; i++) + if (_displayedItems[i] == (uint)~0) { + _displayedItems[i] = id; + return; + } + + error("couldn't insert item into display"); +} + +void CSTimeInventoryDisplay::removeItem(uint id) { + CSTimeInventoryObject *invObj = _vm->getCase()->_inventoryObjs[id]; + if (invObj->feature) { + _vm->getView()->removeFeature(invObj->feature, true); + invObj->feature = NULL; + } + for (uint i = 0; i < MAX_DISPLAYED_ITEMS; i++) + if (_displayedItems[i] == id) + _displayedItems[i] = ~0; +} + +void CSTimeInventoryDisplay::mouseDown(Common::Point &pos) { + for (uint i = 0; i < MAX_DISPLAYED_ITEMS; i++) { + if (_displayedItems[i] == (uint)~0) + continue; + if (!_itemRect[i].contains(pos)) + continue; + _draggedItem = i; + _vm->getInterface()->cursorSetShape(8); + _vm->getInterface()->setGrabPoint(); + _vm->getInterface()->setState(kCSTimeInterfaceStateDragStart); + } +} + +void CSTimeInventoryDisplay::mouseMove(Common::Point &pos) { + bool mouseIsDown = _vm->getEventManager()->getButtonState() & 1; + if (mouseIsDown && _vm->getInterface()->cursorGetShape() == 8) { + Common::Point grabPoint = _vm->getInterface()->getGrabPoint(); + if (mouseIsDown && (abs(grabPoint.x - pos.x) > 2 || abs(grabPoint.y - pos.y) > 2)) { + if (_vm->getInterface()->grabbedFromInventory()) { + _vm->getInterface()->startDragging(getLastDisplayedClicked()); + } else { + // TODO: CSTimeScene::mouseMove does quite a lot more, why not here too? + _vm->getInterface()->startDragging(_vm->getCase()->getCurrScene()->getInvObjForCurrentHotspot()); + } + } + } + + for (uint i = 0; i < MAX_DISPLAYED_ITEMS; i++) { + if (_displayedItems[i] == (uint)~0) + continue; + if (!_itemRect[i].contains(pos)) + continue; + CSTimeInventoryObject *invObj = _vm->getCase()->_inventoryObjs[_displayedItems[i]]; + Common::String text = "Pick up "; + // TODO: special-case for case 11, scene 3, inv obj 1 (just use "Read " instead) + text += _vm->getCase()->getRolloverText(invObj->stringId); + _vm->getInterface()->displayTextLine(text); + _vm->getInterface()->cursorOverHotspot(); + // FIXME: there's some trickery here to store the id for the below + return; + } + + if (false /* FIXME: if we get here and the stored id mentioned above is set.. */) { + _vm->getInterface()->clearTextLine(); + if (_vm->getInterface()->getState() != kCSTimeInterfaceStateDragging) { + if (_vm->getInterface()->cursorGetShape() != 3 && _vm->getInterface()->cursorGetShape() != 9) + _vm->getInterface()->cursorSetShape(1); + } + // FIXME: reset that stored id + } +} + +void CSTimeInventoryDisplay::mouseUp(Common::Point &pos) { + for (uint i = 0; i < MAX_DISPLAYED_ITEMS; i++) { + if (_displayedItems[i] == (uint)~0) + continue; + if (!_itemRect[i].contains(pos)) + continue; + // TODO: instead, stupid hack for case 11, scene 3, inv obj 1 (kCSTimeEventUnknown39, 0xffff, 0xffff) + // TODO: instead, stupid hack for case 18, scene not 3, inv obj 4 (kCSTimeEventCondition, 1, 29) + CSTimeEvent event; + event.param1 = _vm->getCase()->getCurrScene()->getHelperId(); + if (event.param1 == 0xffff) + event.type = kCSTimeEventSpeech; + else + event.type = kCSTimeEventCharStartFlapping; + if (i == TIME_CUFFS_ID) { + if (_cuffsState) + event.param2 = 9903; + else + event.param2 = 9902; + } else { + event.param2 = 9905 + _displayedItems[i]; + } + _vm->addEvent(event); + } +} + +void CSTimeInventoryDisplay::activateCuffs(bool active) { + _cuffsState = active; + if (!_cuffsState) + return; + + CSTimeInventoryObject *invObj = _vm->getCase()->_inventoryObjs[TIME_CUFFS_ID]; + _cuffsShape = 11; + if (invObj->feature) + _vm->getView()->removeFeature(invObj->feature, true); + uint32 flags = kFeatureSortStatic | kFeatureNewNoLoop; + invObj->feature = _vm->getView()->installViewFeature(100 + _cuffsShape, flags, NULL); +} + +void CSTimeInventoryDisplay::setCuffsFlashing() { + CSTimeInventoryObject *invObj = _vm->getCase()->_inventoryObjs[TIME_CUFFS_ID]; + _cuffsShape = 12; + if (invObj->feature) + _vm->getView()->removeFeature(invObj->feature, true); + uint32 flags = kFeatureSortStatic | 0x2000; + invObj->feature = _vm->getView()->installViewFeature(100 + _cuffsShape, flags, NULL); +} + +CSTimeBook::CSTimeBook(MohawkEngine_CSTime *vm) : _vm(vm) { + _state = 0; + _smallBookFeature = NULL; +} + +CSTimeBook::~CSTimeBook() { +} + +void CSTimeBook::drawSmallBook() { + if (!_smallBookFeature) { + _smallBookFeature = _vm->getView()->installViewFeature(101, kFeatureSortStatic | kFeatureNewNoLoop, NULL);; + } else { + _smallBookFeature->resetFeature(false, NULL, 0); + } +} + +CSTimeCarmenNote::CSTimeCarmenNote(MohawkEngine_CSTime *vm) : _vm(vm) { + _state = 0; + _feature = NULL; + clearPieces(); +} + +CSTimeCarmenNote::~CSTimeCarmenNote() { +} + +void CSTimeCarmenNote::clearPieces() { + for (uint i = 0; i < NUM_NOTE_PIECES; i++) + _pieces[i] = 0xffff; +} + +bool CSTimeCarmenNote::havePiece(uint16 piece) { + for (uint i = 0; i < NUM_NOTE_PIECES; i++) { + if (piece == 0xffff) { + if (_pieces[i] != 0xffff) + return true; + } else if (_pieces[i] == piece) + return true; + } + + return false; +} + +void CSTimeCarmenNote::addPiece(uint16 piece, uint16 speech) { + uint i; + for (i = 0; i < NUM_NOTE_PIECES; i++) { + if (_pieces[i] == 0xffff) { + _pieces[i] = piece; + break; + } + } + if (i == NUM_NOTE_PIECES) + error("addPiece couldn't add piece to carmen note"); + + // Get the Good Guide to say something. + if (i == 2) + speech = 9900; // Found the third piece. + if (speech != 0xffff) + _vm->addEvent(CSTimeEvent(kCSTimeEventCharStartFlapping, _vm->getCase()->getCurrScene()->getHelperId(), speech)); + + // Remove the note feature, if any. + uint16 noteFeatureId = _vm->getCase()->getNoteFeatureId(piece); + if (noteFeatureId != 0xffff) + _vm->addEvent(CSTimeEvent(kCSTimeEventDisableFeature, 0xffff, noteFeatureId)); + + _vm->addEvent(CSTimeEvent(kCSTimeEventShowBigNote, 0xffff, 0xffff)); + + if (i != 2) + return; + + // TODO: special-casing for case 5 + + _vm->addEvent(CSTimeEvent(kCSTimeEventCharPlayNIS, _vm->getCase()->getCurrScene()->getHelperId(), 3)); + + // TODO: special-casing for case 5 + + _vm->addEvent(CSTimeEvent(kCSTimeEventCharStartFlapping, _vm->getCase()->getCurrScene()->getHelperId(), 9901)); + _vm->addEvent(CSTimeEvent(kCSTimeEventActivateCuffs, 0xffff, 0xffff)); +} + +void CSTimeCarmenNote::drawSmallNote() { + if (!havePiece(0xffff)) + return; + + if (_feature) + _vm->getView()->removeFeature(_feature, true); + + uint16 id = 100; + if (_pieces[2] != 0xffff) + id += 5; + else if (_pieces[1] != 0xffff) + id += 4; + else + id += 2; + + _feature = _vm->getView()->installViewFeature(id, kFeatureSortStatic | kFeatureNewNoLoop, NULL); +} + +void CSTimeCarmenNote::drawBigNote() { + // FIXME +} + +CSTimeOptions::CSTimeOptions(MohawkEngine_CSTime *vm) : _vm(vm) { + _state = 0; +} + +CSTimeOptions::~CSTimeOptions() { +} + +} // End of namespace Mohawk |