aboutsummaryrefslogtreecommitdiff
path: root/engines/mohawk/cstime_ui.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'engines/mohawk/cstime_ui.cpp')
-rw-r--r--engines/mohawk/cstime_ui.cpp1186
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