[Scummvm-cvs-logs] SF.net SVN: scummvm:[55362] scummvm/trunk/engines/mohawk

fuzzie at users.sourceforge.net fuzzie at users.sourceforge.net
Thu Jan 20 22:35:00 CET 2011


Revision: 55362
          http://scummvm.svn.sourceforge.net/scummvm/?rev=55362&view=rev
Author:   fuzzie
Date:     2011-01-20 21:35:00 +0000 (Thu, 20 Jan 2011)

Log Message:
-----------
MOHAWK: Add CSTime engine.

Modified Paths:
--------------
    scummvm/trunk/engines/mohawk/console.cpp
    scummvm/trunk/engines/mohawk/console.h
    scummvm/trunk/engines/mohawk/detection.cpp
    scummvm/trunk/engines/mohawk/graphics.cpp
    scummvm/trunk/engines/mohawk/graphics.h
    scummvm/trunk/engines/mohawk/module.mk

Added Paths:
-----------
    scummvm/trunk/engines/mohawk/cstime.cpp
    scummvm/trunk/engines/mohawk/cstime.h
    scummvm/trunk/engines/mohawk/cstime_cases.cpp
    scummvm/trunk/engines/mohawk/cstime_cases.h
    scummvm/trunk/engines/mohawk/cstime_game.cpp
    scummvm/trunk/engines/mohawk/cstime_game.h
    scummvm/trunk/engines/mohawk/cstime_ui.cpp
    scummvm/trunk/engines/mohawk/cstime_ui.h
    scummvm/trunk/engines/mohawk/cstime_view.cpp
    scummvm/trunk/engines/mohawk/cstime_view.h

Modified: scummvm/trunk/engines/mohawk/console.cpp
===================================================================
--- scummvm/trunk/engines/mohawk/console.cpp	2011-01-20 21:34:19 UTC (rev 55361)
+++ scummvm/trunk/engines/mohawk/console.cpp	2011-01-20 21:35:00 UTC (rev 55362)
@@ -31,6 +31,7 @@
 #include "mohawk/riven.h"
 #include "mohawk/riven_external.h"
 #include "mohawk/livingbooks.h"
+#include "mohawk/cstime.h"
 #include "mohawk/sound.h"
 #include "mohawk/video.h"
 
@@ -703,4 +704,54 @@
 	return true;
 }
 
+CSTimeConsole::CSTimeConsole(MohawkEngine_CSTime *vm) : GUI::Debugger(), _vm(vm) {
+	DCmd_Register("playSound",			WRAP_METHOD(CSTimeConsole, Cmd_PlaySound));
+	DCmd_Register("stopSound",			WRAP_METHOD(CSTimeConsole, Cmd_StopSound));
+	DCmd_Register("drawImage",			WRAP_METHOD(CSTimeConsole, Cmd_DrawImage));
+	DCmd_Register("drawSubimage",			WRAP_METHOD(CSTimeConsole, Cmd_DrawSubimage));
+}
+
+CSTimeConsole::~CSTimeConsole() {
+}
+
+bool CSTimeConsole::Cmd_PlaySound(int argc, const char **argv) {
+	if (argc == 1) {
+		DebugPrintf("Usage: playSound <value>\n");
+		return true;
+	}
+
+	_vm->_sound->stopSound();
+	_vm->_sound->playSound((uint16)atoi(argv[1]));
+	return false;
+}
+
+bool CSTimeConsole::Cmd_StopSound(int argc, const char **argv) {
+	DebugPrintf("Stopping Sound\n");
+
+	_vm->_sound->stopSound();
+	return true;
+}
+
+bool CSTimeConsole::Cmd_DrawImage(int argc, const char **argv) {
+	if (argc == 1) {
+		DebugPrintf("Usage: drawImage <value>\n");
+		return true;
+	}
+
+	_vm->_gfx->copyAnimImageToScreen((uint16)atoi(argv[1]));
+	_vm->_system->updateScreen();
+	return false;
+}
+
+bool CSTimeConsole::Cmd_DrawSubimage(int argc, const char **argv) {
+	if (argc < 3) {
+		DebugPrintf("Usage: drawSubimage <value> <subimage>\n");
+		return true;
+	}
+
+	_vm->_gfx->copyAnimSubImageToScreen((uint16)atoi(argv[1]), (uint16)atoi(argv[2]));
+	_vm->_system->updateScreen();
+	return false;
+}
+
 } // End of namespace Mohawk

Modified: scummvm/trunk/engines/mohawk/console.h
===================================================================
--- scummvm/trunk/engines/mohawk/console.h	2011-01-20 21:34:19 UTC (rev 55361)
+++ scummvm/trunk/engines/mohawk/console.h	2011-01-20 21:35:00 UTC (rev 55362)
@@ -33,6 +33,7 @@
 class MohawkEngine_Myst;
 class MohawkEngine_Riven;
 class MohawkEngine_LivingBooks;
+class MohawkEngine_CSTime;
 
 class MystConsole : public GUI::Debugger {
 public:
@@ -99,6 +100,20 @@
 	bool Cmd_ChangePage(int argc, const char **argv);
 };
 
+class CSTimeConsole : public GUI::Debugger {
+public:
+	CSTimeConsole(MohawkEngine_CSTime *vm);
+	virtual ~CSTimeConsole(void);
+
+private:
+	MohawkEngine_CSTime *_vm;
+
+	bool Cmd_PlaySound(int argc, const char **argv);
+	bool Cmd_StopSound(int argc, const char **argv);
+	bool Cmd_DrawImage(int argc, const char **argv);
+	bool Cmd_DrawSubimage(int argc, const char **argv);
+};
+
 } // End of namespace Mohawk
 
 #endif

Added: scummvm/trunk/engines/mohawk/cstime.cpp
===================================================================
--- scummvm/trunk/engines/mohawk/cstime.cpp	                        (rev 0)
+++ scummvm/trunk/engines/mohawk/cstime.cpp	2011-01-20 21:35:00 UTC (rev 55362)
@@ -0,0 +1,529 @@
+/* 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.h"
+#include "mohawk/cstime_cases.h"
+#include "mohawk/cstime_game.h"
+#include "mohawk/cstime_ui.h"
+#include "mohawk/cstime_view.h"
+#include "mohawk/resource.h"
+#include "mohawk/cursors.h"
+#include "mohawk/sound.h"
+#include "mohawk/video.h"
+
+#include "common/events.h"
+#include "common/EventRecorder.h"
+
+#include "engines/util.h"
+
+namespace Mohawk {
+
+MohawkEngine_CSTime::MohawkEngine_CSTime(OSystem *syst, const MohawkGameDescription *gamedesc) : MohawkEngine(syst, gamedesc) {
+	_rnd = new Common::RandomSource();
+	g_eventRec.registerRandomSource(*_rnd, "cstime");
+
+	_state = kCSTStateStartup;
+
+	reset();
+}
+
+MohawkEngine_CSTime::~MohawkEngine_CSTime() {
+	delete _interface;
+	delete _view;
+	delete _console;
+	delete _gfx;
+	delete _rnd;
+}
+
+Common::Error MohawkEngine_CSTime::run() {
+	MohawkEngine::run();
+
+	_console = new CSTimeConsole(this);
+	_gfx = new CSTimeGraphics(this);
+	_cursor = new DefaultCursorManager(this, ID_CURS);
+
+	_interface = new CSTimeInterface(this);
+
+	_view = new CSTimeView(this);
+	_view->setupView();
+	_view->setModule(new CSTimeModule(this));
+
+	while (!shouldQuit()) {
+		switch (_state) {
+		case kCSTStateStartup:
+			// We just jump straight to the case for now.
+			_state = kCSTStateNewCase;
+			break;
+
+		case kCSTStateNewCase:
+			initCase();
+			_state = kCSTStateNewScene;
+			break;
+
+		case kCSTStateNewScene:
+			nextScene();
+			_state = kCSTStateNormal;
+			break;
+
+		case kCSTStateNormal:
+			update();
+			break;
+		}
+	}
+
+	return Common::kNoError;
+}
+
+void MohawkEngine_CSTime::update() {
+	Common::Event event;
+	while (_eventMan->pollEvent(event)) {
+		switch (event.type) {
+		case Common::EVENT_MOUSEMOVE:
+			_interface->mouseMove(event.mouse);
+			_needsUpdate = true;
+			break;
+
+		case Common::EVENT_LBUTTONUP:
+			_interface->mouseUp(event.mouse);
+			break;
+
+		case Common::EVENT_LBUTTONDOWN:
+			_interface->mouseDown(event.mouse);
+			break;
+
+		case Common::EVENT_RBUTTONDOWN:
+			// (All of this case is only run if the relevant option is enabled.)
+
+			// FIXME: Don't do these if the options are open.
+			if (_case->getCurrScene()->_activeChar->_flappingState != 0xffff)
+				_case->getCurrScene()->_activeChar->interruptFlapping();
+			if (getCurrentEventType() == kCSTimeEventWaitForClick)
+				mouseClicked();
+
+			// TODO: This is always run, even if not in-game.
+			//pauseCurrentNIS();
+			//stopSound();
+			// FIXME: There's some more stuff here.
+			break;
+
+		case Common::EVENT_KEYDOWN:
+			switch (event.kbd.keycode) {
+			case Common::KEYCODE_d:
+				if (event.kbd.flags & Common::KBD_CTRL) {
+					_console->attach();
+					_console->onFrame();
+				}
+				break;
+
+			case Common::KEYCODE_SPACE:
+				pauseGame();
+				break;
+
+			default:
+				break;
+			}
+			break;
+
+		default:
+			break;
+		}
+	}
+
+	_needsUpdate = true;
+
+	if (_video->updateMovies())
+		_needsUpdate = true;
+
+	if (_needsUpdate) {
+		_view->_needsUpdate = true;
+		_needsUpdate = false;
+	}
+
+	eventIdle();
+	_interface->idle();
+
+	// Cut down on CPU usage
+	_system->delayMillis(10);
+}
+
+void MohawkEngine_CSTime::initCase() {
+	_interface->openResFile();
+	_interface->install();
+	_interface->cursorInstall();
+	// TODO: _interface->paletteOff(true);
+	_interface->cursorActivate(true);
+	_interface->cursorSetShape(1, false);
+	for (uint i = 0; i < 19; i++)
+		_haveInvItem[i] = 0;
+	_interface->getInventoryDisplay()->clearDisplay();
+	_interface->getCarmenNote()->clearPieces();
+	// TODO: fixup book rect for case 20
+	for (uint i = 0; i < 20; i++)
+		_caseVariable[i] = 0;
+	_case = new CSTimeCase1(this); // TODO
+	_interface->getInventoryDisplay()->install();
+	_nextSceneId = 1;
+}
+
+void MohawkEngine_CSTime::nextScene() {
+	_case->setCurrScene(_nextSceneId);
+	CSTimeScene *scene = _case->getCurrScene();
+	// TODO: scene->setState(1);
+	scene->installGroup();
+
+	_interface->draw();
+	scene->buildScene();
+	scene->setupAmbientAnims();
+	_interface->cursorSetShape(1, false);
+
+	addEvent(CSTimeEvent(kCSTimeEventWait, 0xffff, 500));
+	scene->idleAmbientAnims();
+	// TODO: startEnvironmentSound();
+	// TODO: queue one of the scene event queues, depending on whether a value is <= 1 or not
+	addEventList(scene->getEvents(false));
+	_view->idleView();
+	// TODO: maybe startMusic();
+}
+
+void MohawkEngine_CSTime::loadResourceFile(Common::String name) {
+	MohawkArchive *archive = new MohawkArchive();
+	if (!archive->open(name + ".mhk"))
+		error("failed to open %s.mhk", name.c_str());
+	_mhk.push_back(archive);
+}
+
+void MohawkEngine_CSTime::addEvent(const CSTimeEvent &event) {
+	_events.push_back(event);
+}
+
+void MohawkEngine_CSTime::addEventList(const Common::Array<CSTimeEvent> &list) {
+	for (uint i = 0; i < list.size(); i++)
+		addEvent(list[i]);
+}
+
+void MohawkEngine_CSTime::insertEventAtFront(const CSTimeEvent &event) {
+	if (_events.empty())
+		_events.push_front(event);
+	else
+		_events.insert(++_events.begin(), event);
+}
+
+uint16 MohawkEngine_CSTime::getCurrentEventType() {
+	if (_events.empty())
+		return 0xffff;
+	else
+		return _events.front().type;
+}
+
+void MohawkEngine_CSTime::eventIdle() {
+	bool done = false;
+	while (_events.size() && !done && true /* TODO: !_options->getState() */) {
+		_lastTimeout = ~0;
+
+		bool advanceQueue = true;
+		bool processEvent = true;
+		CSTimeEvent &event = _events.front();
+
+		switch (event.type) {
+		case kCSTimeEventCharPlayNIS:
+			if (_NISRunning) {
+				CSTimeChar *chr = _case->getCurrScene()->getChar(event.param1);
+				if (chr->NISIsDone()) {
+					chr->removeNIS();
+					_NISRunning = false;
+					chr->setupAmbientAnims(true);
+					_events.pop_front();
+					processEvent = false;
+				} else {
+					done = true;
+				}
+			} else {
+				advanceQueue = false;
+			}
+			break;
+
+		case kCSTimeEventNewScene:
+			if (_processingEvent) {
+				processEvent = false;
+				_events.pop_front();
+				_processingEvent = false;
+				// FIXME: check skip global, if set:
+				// stopMusic(), stopEnvironmentSound(), set scene to _nextSceneId,
+				// set scene state to 1, set state to idle loop
+			} else {
+				triggerEvent(event);
+				done = true;
+				_processingEvent = true;
+			}
+			break;
+
+		case kCSTimeEventCharStartFlapping:
+			assert(_case->getCurrScene()->_activeChar);
+			switch (_case->getCurrScene()->_activeChar->_flappingState) {
+			case 0xffff:
+				// FIXME: check skip global, if set, processEvent = false and pop event
+				advanceQueue = false;
+				break;
+			case 0:
+				_case->getCurrScene()->_activeChar->_flappingState = 0xffff;
+				_events.pop_front();
+				processEvent = false;
+				break;
+			default:
+				done = true;
+				break;
+			}
+			break;
+
+		default:
+			break;
+		}
+
+		if (!done && processEvent) {
+			_interface->cursorSetWaitCursor();
+			triggerEvent(event);
+			if (advanceQueue)
+				_events.pop_front();
+		}
+
+		if (!_events.size()) {
+			Common::Point pos = _system->getEventManager()->getMousePos();
+			if (_interface->_sceneRect.contains(pos))
+				_case->getCurrScene()->setCursorForCurrentPoint();
+			else
+				_interface->setCursorForCurrentPoint();
+			_interface->mouseMove(pos);
+			resetTimeout();
+		}
+	}
+}
+
+void MohawkEngine_CSTime::resetTimeout() {
+	_lastTimeout = _system->getMillis();
+}
+
+void MohawkEngine_CSTime::mouseClicked() {
+	// TODO
+}
+
+bool MohawkEngine_CSTime::NISIsRunning() {
+	if (_NISRunning || (!_events.empty() && _events.front().type == kCSTimeEventUnused63))
+		return true;
+
+	return false;
+}
+
+void MohawkEngine_CSTime::reset() {
+	_NISRunning = false;
+	_lastTimeout = ~0;
+	_processingEvent = false;
+}
+
+void MohawkEngine_CSTime::triggerEvent(CSTimeEvent &event) {
+	debug("triggerEvent: type %d, param1 %d, param2 %d", event.type, event.param1, event.param2);
+
+	switch (event.type) {
+	case kCSTimeEventNothing:
+	case kCSTimeEventUnused8:
+	case kCSTimeEventUnused21:
+	case kCSTimeEventUnused63:
+		break;
+
+	case kCSTimeEventCondition:
+		_case->handleConditionalEvent(event);
+		break;
+
+	case kCSTimeEventCharPlayNIS:
+		_case->getCurrScene()->getChar(event.param1)->playNIS(event.param2);
+		_NISRunning = true;
+		break;
+
+	case kCSTimeEventStartConversation:
+		_case->setConversation(event.param2);
+		_case->getCurrConversation()->setSourceChar(event.param1);
+		_case->getCurrConversation()->incrementTalkCount();
+		_case->getCurrConversation()->start();
+		break;
+
+	case kCSTimeEventNewScene:
+		if (_case->getCurrConversation()->getState() != (uint)~0)
+			_case->getCurrConversation()->end(false);
+		_interface->clearTextLine();
+		// TODO: _interface->fadeDown();
+		_interface->cursorSetShape(1);
+		// TODO: swap cursor
+		// TODO: unloadPreloadedSounds?
+		if (_interface->getInventoryDisplay()->getState() == 4) {
+			_interface->getInventoryDisplay()->hide();
+			_interface->getInventoryDisplay()->setState(0);
+		}
+		// TODO: stupid case 20 handling
+		_case->getCurrScene()->leave();
+		// TODO: set dim palette(true)
+		_view->_needsUpdate = true;
+		_view->idleView();
+		// TODO: set dim palette(false)
+		_nextSceneId = event.param2;
+		_state = kCSTStateNewScene;
+		break;
+
+	case kCSTimeEventCharStartFlapping:
+		{
+		CSTimeChar *chr = _case->getCurrScene()->getChar(event.param1);
+		if (!chr->_enabled) {
+			// FIXME
+			warning("chr not enabled in kCSTimeEventCharStartFlapping");
+			break;
+		}
+
+		chr->startFlapping(event.param2);
+		if (event.param2)
+			_interface->drawTextIdToBubble(event.param2);
+
+		CSTimeEvent newEvent;
+		newEvent.param1 = 0xffff;
+		newEvent.param2 = 0xffff;
+
+		newEvent.type = kCSTimeEventUnknown70;
+		insertEventAtFront(newEvent);
+
+		newEvent.type = kCSTimeEventUpdateBubble;
+		insertEventAtFront(newEvent);
+
+		newEvent.type = kCSTimeEventUnknown69;
+		insertEventAtFront(newEvent);
+		}
+		break;
+
+	case kCSTimeEventDropItemInInventory:
+		_interface->dropItemInInventory(event.param2);
+		break;
+
+	case kCSTimeEventAddNotePiece:
+		_interface->clearTextLine();
+		_interface->getCarmenNote()->addPiece(event.param2, event.param1);
+		break;
+
+	case kCSTimeEventDisableHotspot:
+		_case->getCurrScene()->getHotspot(event.param2).state = 0;
+		break;
+
+	case kCSTimeEventDisableFeature:
+		if (!_case->getCurrScene()->_objectFeatures[event.param2])
+			break;
+		_view->removeFeature(_case->getCurrScene()->_objectFeatures[event.param2], true);
+		_case->getCurrScene()->_objectFeatures[event.param2] = NULL;
+		break;
+
+	case kCSTimeEventAddFeature:
+		// TODO: merge this with buildScene somehow?
+		if (_case->getCurrScene()->_objectFeatures[event.param2]) {
+			_case->getCurrScene()->_objectFeatures[event.param2]->resetFeatureScript(1, 0);
+			break;
+		}
+		{
+		uint32 flags = kFeatureSortStatic | kFeatureNewNoLoop | kFeatureNewDisableOnReset;
+		_case->getCurrScene()->_objectFeatures[event.param2] = _view->installViewFeature(_case->getCurrScene()->getSceneId() + event.param2, flags, NULL);
+		// FIXME: a mess of priority stuff
+		}
+		break;
+
+	case kCSTimeEventEnableHotspot:
+		_case->getCurrScene()->getHotspot(event.param2).state = 1;
+		break;
+
+	case kCSTimeEventSetAsked:
+		uint qar, entry;
+		qar = event.param2 / 5;
+		entry = event.param2 % 5;
+		if (qar > 7)
+			error("SetAsked event out of range");
+		_case->getCurrConversation()->setAsked(qar, entry);
+		break;
+
+	case kCSTimeEventShowBigNote:
+		_interface->getCarmenNote()->drawBigNote();
+		break;
+
+	case kCSTimeEventActivateCuffs:
+		_interface->getInventoryDisplay()->activateCuffs(true);
+		break;
+
+	case kCSTimeEventUnknown25:
+		_case->getCurrScene()->getChar(event.param1)->_unknown2 = 1;
+		break;
+
+	case kCSTimeEventUnknown26:
+		_case->getCurrScene()->getChar(event.param1)->_unknown2 = 0;
+		break;
+
+	case kCSTimeEventWait:
+		warning("ignoring wait");
+		// FIXME
+		break;
+
+	case kCSTimeEventUpdateBubble:
+		switch (event.param2) {
+		case 0:
+			// FIXME
+			warning("ignoring bubble update (queue events)");
+			break;
+		case 1:
+			// FIXME
+			warning("ignoring bubble update (install)");
+			break;
+		default:
+			_interface->closeBubble();
+			break;
+		}
+		break;
+
+	case kCSTimeEventInitScene:
+		_interface->displayTextLine("");
+
+		// FIXME: install palette
+
+		// FIXME: swapCursor(true)
+		break;
+
+	case kCSTimeEventUnknown69:
+		// TODO: if persistent text, insert a kCSTimeEventWaitForClick in front of the queue
+		break;
+
+	case kCSTimeEventUnknown70:
+		if (_case->getCurrConversation()->getState() != 0xffff && _case->getCurrConversation()->getState()) {
+			_case->getCurrConversation()->finishProcessingQaR();
+		} else {
+			// FIXME: handle help stuff
+			warning("ignoring unknown 70");
+		}
+		break;
+
+	default:
+		error("unknown scene event type %d", event.type);
+	}
+}
+
+} // End of namespace Mohawk


Property changes on: scummvm/trunk/engines/mohawk/cstime.cpp
___________________________________________________________________
Added: svn:mime-type
   + text/plain
Added: svn:keywords
   + Date Rev Author URL Id
Added: svn:eol-style
   + native

Added: scummvm/trunk/engines/mohawk/cstime.h
===================================================================
--- scummvm/trunk/engines/mohawk/cstime.h	                        (rev 0)
+++ scummvm/trunk/engines/mohawk/cstime.h	2011-01-20 21:35:00 UTC (rev 55362)
@@ -0,0 +1,191 @@
+/* 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$
+ *
+ */
+
+#ifndef MOHAWK_CSTIME_H
+#define MOHAWK_CSTIME_H
+
+#include "mohawk/mohawk.h"
+#include "mohawk/console.h"
+#include "mohawk/graphics.h"
+
+#include "common/random.h"
+#include "common/list.h"
+
+#include "sound/mixer.h"
+
+namespace Mohawk {
+
+class CSTimeCase;
+class CSTimeInterface;
+class CSTimeView;
+
+enum {
+	kCSTimeEventNothing = 0xffff,
+	kCSTimeEventCondition = 1,
+	kCSTimeEventCharPlayNIS = 2,
+	kCSTimeEventStartConversation = 3,
+	kCSTimeEventNewScene = 4,
+	kCSTimeEventCharStartFlapping = 5,
+	kCSTimeEventSetCaseVariable = 6,
+	kCSTimeEventSetupAmbientAnims = 7,
+	kCSTimeEventUnused8 = 8,
+	kCSTimeEventDropItemInInventory = 9,
+	kCSTimeEventRemoveItemFromInventory = 10,
+	kCSTimeEventAddNotePiece = 11,
+	kCSTimeEventDisableHotspot = 12,
+	kCSTimeEventDisableFeature = 13,
+	kCSTimeEventAddFeature = 14,
+	kCSTimeEventStartMusic = 15,
+	kCSTimeEventStopMusic = 16,
+	kCSTimeEventEnableHotspot = 17,
+	kCSTimeEventSetAsked = 18,
+	kCSTimeEventStartHelp = 19,
+	kCSTimeEventPlaySound = 20,
+	kCSTimeEventUnused21 = 21,
+	kCSTimeEventShowBigNote = 22,
+	kCSTimeEventActivateCuffs = 23,
+	kCSTimeEventSetupRestPos = 24, // TODO
+	kCSTimeEventUnknown25 = 25,
+	kCSTimeEventUnknown26 = 26,
+	kCSTimeEventRemoveChar = 27,
+	kCSTimeEventUnknown28 = 28,
+	kCSTimeEventUnknown29 = 29,
+	kCSTimeEventUnknown30 = 30,
+	kCSTimeEventUnknown31 = 31,
+	kCSTimeEventCharSomeNIS32 = 32,
+	kCSTimeEventCharResetNIS = 33,
+	kCSTimeEventUnknown34 = 34,
+	kCSTimeEventCharPauseAmbients = 35,
+	kCSTimeEventCharUnauseAmbients = 36,
+	kCSTimeEventCharDisableAmbients = 37,
+	kCSTimeEventStopAmbientAnims = 38,
+	kCSTimeEventUnknown39 = 39,
+	kCSTimeEventWait = 40,
+	kCSTimeEventSpeech = 41,
+	kCSTimeEventUnknown42 = 42,
+	kCSTimeEventUnknown43 = 43,
+	kCSTimeEventCharSetupRestPos = 44, // TODO
+	kCSTimeEventCharStopAmbients = 45,
+	kCSTimeEventCharRestartAmbients = 46,
+	kCSTimeEventStopEnvironmentSound = 47,
+	kCSTimeEventWaitForClick = 48,
+	kCSTimeEventSetMusic = 49,
+	kCSTimeEventStartEnvironmentSound = 50,
+	kCSTimeEventPreloadSound = 51,
+	kCSTimeEventPlayPreloadedSound = 52,
+	kCSTimeEventUnknown53 = 53,
+	kCSTimeEventSetEnvironmentSound = 54,
+	kCSTimeEventCharSomeNIS55 = 55,
+	kCSTimeEventUnknown56 = 56,
+	kCSTimeEventUpdateBubble = 57,
+	kCSTimeEventCharSurfAndFlap = 58,
+	kCSTimeEventInitScene = 59,
+	kCSTimeEventFadeDown = 60,
+	kCSTimeEventCharSomeNIS61 = 61,
+	kCSTimeEventCharPlaySimultaneousAnim = 62,
+	kCSTimeEventUnused63 = 63,
+	kCSTimeEventUnknown64 = 64,
+	kCSTimeEventPrepareSave = 65,
+	kCSTimeEventSave = 66,
+	kCSTimeEventQuit = 67,
+	kCSTimeEventPlayMovie = 68,
+	kCSTimeEventUnknown69 = 69, // queues Unknown48
+	kCSTimeEventUnknown70 = 70 // conv/QaR cleanup
+};
+
+struct CSTimeEvent {
+	CSTimeEvent() { }
+	CSTimeEvent(uint16 t, uint16 p1, uint16 p2) : type(t), param1(p1), param2(p2) { }
+
+	uint16 type;
+	uint16 param1;
+	uint16 param2;
+};
+
+enum CSTimeState {
+	kCSTStateStartup,
+	kCSTStateNewCase,
+	kCSTStateNewScene,
+	kCSTStateNormal
+};
+
+class MohawkEngine_CSTime : public MohawkEngine {
+protected:
+	Common::Error run();
+
+public:
+	MohawkEngine_CSTime(OSystem *syst, const MohawkGameDescription *gamedesc);
+	virtual ~MohawkEngine_CSTime();
+
+	Common::RandomSource *_rnd;
+
+	CSTimeGraphics *_gfx;
+	bool _needsUpdate;
+
+	GUI::Debugger *getDebugger() { return _console; }
+	CSTimeView *getView() { return _view; }
+	CSTimeCase *getCase() { return _case; }
+	CSTimeInterface *getInterface() { return _interface; }
+
+	void loadResourceFile(Common::String name);
+
+	void addEvent(const CSTimeEvent &event);
+	void addEventList(const Common::Array<CSTimeEvent> &list);
+	void insertEventAtFront(const CSTimeEvent &event);
+	uint16 getCurrentEventType();
+	void eventIdle();
+	void resetTimeout();
+	void mouseClicked();
+	bool NISIsRunning();
+
+	uint16 _haveInvItem[19];
+	uint16 _caseVariable[20];
+
+private:
+	CSTimeCase *_case;
+	CSTimeConsole *_console;
+	CSTimeInterface *_interface;
+	CSTimeView *_view;
+
+	CSTimeState _state;
+
+	void initCase();
+	void nextScene();
+	void update();
+
+	uint16 _nextSceneId;
+
+	bool _processingEvent;
+	bool _NISRunning;
+	uint32 _lastTimeout;
+	void reset();
+
+	Common::List<CSTimeEvent> _events;
+	void triggerEvent(CSTimeEvent &event);
+};
+
+} // End of namespace Mohawk
+
+#endif


Property changes on: scummvm/trunk/engines/mohawk/cstime.h
___________________________________________________________________
Added: svn:mime-type
   + text/plain
Added: svn:keywords
   + Date Rev Author URL Id
Added: svn:eol-style
   + native

Added: scummvm/trunk/engines/mohawk/cstime_cases.cpp
===================================================================
--- scummvm/trunk/engines/mohawk/cstime_cases.cpp	                        (rev 0)
+++ scummvm/trunk/engines/mohawk/cstime_cases.cpp	2011-01-20 21:35:00 UTC (rev 55362)
@@ -0,0 +1,241 @@
+/* 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_cases.h"
+#include "mohawk/cstime_ui.h"
+
+namespace Mohawk {
+
+CSTimeCase1::CSTimeCase1(MohawkEngine_CSTime *vm) : CSTimeCase(vm, 1) {
+}
+
+CSTimeCase1::~CSTimeCase1() {
+}
+
+bool CSTimeCase1::checkConvCondition(uint16 conditionId) {
+	const Common::Array<CSTimeHotspot> &hotspots = getCurrScene()->getHotspots();
+
+	bool gotTorch = _vm->_haveInvItem[1];
+
+	// These are all for conversations in the first scene (with the boatman).
+	switch (conditionId) {
+	case 0:
+		// Got the torch?
+		return (gotTorch);
+	case 1:
+		// Is the bag still on land?
+		return (hotspots[5].state == 1);
+	case 2:
+		// Is the bag on the boat, but player hasn't taken the torch?
+		return (hotspots[5].state != 1 && !gotTorch);
+	}
+
+	return false;
+}
+
+bool CSTimeCase1::checkAmbientCondition(uint16 charId, uint16 ambientId) {
+	return true;
+}
+
+bool CSTimeCase1::checkObjectCondition(uint16 objectId) {
+	const Common::Array<CSTimeHotspot> &hotspots = getCurrScene()->getHotspots();
+
+	switch (_currScene) {
+	case 1:
+		switch (objectId) {
+		case 1:
+			// Hide bag on boat if it's not there.
+			return (hotspots[5].state == 1);
+		case 2:
+			// Hide bag on land if it's not there.
+			return (hotspots[5].state != 1);
+		case 3:
+			// Hide torch if it's been picked up.
+			return (hotspots[4].state == 1);
+		}
+		break;
+
+	case 2:
+		// The first note piece.
+		return !_vm->getInterface()->getCarmenNote()->havePiece(0);
+
+	case 3:
+		// The features representing different stages in the body sequence.
+		if (objectId == 6 && _vm->_caseVariable[3] != 0)
+			return false;
+		else if (objectId == 7 && _vm->_caseVariable[3] != 1)
+			return false;
+		else if (objectId == 8 && _vm->_caseVariable[3] != 2)
+			return false;
+		break;
+
+	case 4:
+		// The second note piece?
+		if (objectId == 0)
+			return (hotspots[0].state > 0);
+		break;
+
+	case 5:
+		// The third note piece.
+		if (objectId == 1)
+			return !_vm->getInterface()->getCarmenNote()->havePiece(2);
+	}
+
+	return true;
+}
+
+void CSTimeCase1::selectHelpStrings() {
+	if (_currScene == 1) {
+		if (_vm->_haveInvItem[1]) {
+			// Got the torch, ready to leave.
+			// FIXME
+		} else {
+			// Still don't have the torch.
+			// FIXME
+		}
+	} else {
+		// FIXME
+	}
+
+	// FIXME
+}
+
+void CSTimeCase1::handleConditionalEvent(const CSTimeEvent &event) {
+	CSTimeEvent newEvent;
+
+	switch (event.param2) {
+	case 0:
+		// Trying to enter the first room of the tomb.
+		if (!_conversations[1]->getAsked(2, 0)) {
+			// We need a plan first.
+			_vm->addEvent(CSTimeEvent(kCSTimeEventCharStartFlapping, getCurrScene()->getHelperId(), 12352));
+		} else if (!_vm->getInterface()->getCarmenNote()->havePiece(0)) {
+			// Shouldn't we take a look at that note?
+			_vm->addEvent(CSTimeEvent(kCSTimeEventCharStartFlapping, getCurrScene()->getHelperId(), 10355));
+		} else {
+			// Onward!
+			_vm->addEvent(CSTimeEvent(kCSTimeEventNewScene, event.param1, 3));
+			_vm->addEvent(CSTimeEvent(kCSTimeEventCharStartFlapping, 1, 12551));
+		}
+		break;
+
+	case 1:
+		// Poking at the jars. The response depends on whether the hieroglyphs on the tomb wall
+		// have been seen yet or not.
+		_vm->addEvent(CSTimeEvent(kCSTimeEventCharStartFlapping, getCurrScene()->getHelperId(),
+			_vm->_caseVariable[2] ? 14304 : 14303));
+		break;
+
+	case 2:
+		// FIXME: Leaving the mummy-preparing room?
+		error("cond event 2");
+		break;
+
+	case 3:
+		// FIXME: Body sequence stuff.
+		error("cond event 3");
+		break;
+
+	case 4:
+		// Woven bag dragged.
+		if (_conversations[0]->getAsked(2, 1)) {
+			// We were asked to move it.
+			if (event.param1 == 5) {
+				// Yay, the player got it on the boat!
+				// Congratulate the player and enable the torch.
+				_vm->insertEventAtFront(CSTimeEvent(kCSTimeEventCharStartFlapping, 2, 10551));
+				getCurrScene()->getHotspot(4).invObjId = 1;
+				_vm->insertEventAtFront(CSTimeEvent(kCSTimeEventEnableHotspot, 2, 6));
+				_vm->insertEventAtFront(CSTimeEvent(kCSTimeEventAddFeature, 2, 2));
+			} else {
+				assert(event.param1 < 7);
+				// It didn't get dropped onto the boat, so we complain about it.
+				newEvent.type = kCSTimeEventCharStartFlapping;
+				// Does the Good Guide complain (if we gave it to her, or put it in the inventory)?
+				newEvent.param1 = (event.param1 == 1 || event.param1 == 6) ? getCurrScene()->getHelperId() : 2;
+				// Which string?
+				static const uint16 strings[7] = { 30201, 30103, 30202, 30203, 30203, 0, 10352};
+				newEvent.param2 = strings[event.param1];
+				_vm->insertEventAtFront(newEvent);
+			}
+		} else {
+			// We're just randomly moving the woven bag!
+			_vm->addEvent(CSTimeEvent(kCSTimeEventCharStartFlapping, getCurrScene()->getHelperId(), 10351));
+
+			if (event.param1 == 5) {
+				// This went onto the boat hotspot, so the bag was removed; put it back.
+				_vm->insertEventAtFront(CSTimeEvent(kCSTimeEventEnableHotspot, 0xffff, 5));
+				_vm->insertEventAtFront(CSTimeEvent(kCSTimeEventAddFeature, 0xffff, 1));
+			}
+		}
+		break;
+
+	case 5:
+		// We're ready to shove off!
+		_vm->addEvent(CSTimeEvent(kCSTimeEventCharStartFlapping, getCurrScene()->getHelperId(), 10356));
+		break;
+
+	case 6:
+		// Trying to leave the first scene by walking.
+		if (_vm->_haveInvItem[1]) {
+			// If you have the torch, the Good Guide prods you to use the boat.
+			_vm->addEvent(CSTimeEvent(kCSTimeEventCharStartFlapping, getCurrScene()->getHelperId(), 10305));
+		} else {
+			// Otherwise, the boatman tells you that you can't leave yet.
+			_vm->addEvent(CSTimeEvent(kCSTimeEventCharStartFlapping, 2, 10506));
+		}
+		break;
+
+	case 7:
+		// Clicking on the woven bag.
+		if (_conversations[0]->getAsked(2, 0)) {
+			// If we were asked to move it, the Good Guide prods us to try dragging.
+			_vm->addEvent(CSTimeEvent(kCSTimeEventCharStartFlapping, getCurrScene()->getHelperId(), 10306));
+		} else {
+			// Otherwise, the boatman tells us what it is.
+			_vm->addEvent(CSTimeEvent(kCSTimeEventCharStartFlapping, 2, 10502));
+		}
+		break;
+
+	case 8:
+		// One-time-only reminder that you can re-ask questions.
+		if (_vm->_caseVariable[7])
+			break;
+		_vm->_caseVariable[7] = 1;
+		_vm->addEvent(CSTimeEvent(kCSTimeEventCharStartFlapping, 0, 12359));
+		break;
+
+	case 9:
+		// Trying to give the torch to the Good Guide; you get a different message
+		// depending on whether it's already in your inventory or not.
+		_vm->addEvent(CSTimeEvent(kCSTimeEventCharStartFlapping, 0, _vm->_haveInvItem[1] ? 9906 : 30119));
+		break;
+
+	default:
+		error("unknown Conditional Event type %d for case 1", event.param2);
+	}
+}
+
+} // End of namespace Mohawk


Property changes on: scummvm/trunk/engines/mohawk/cstime_cases.cpp
___________________________________________________________________
Added: svn:mime-type
   + text/plain
Added: svn:keywords
   + Date Rev Author URL Id
Added: svn:eol-style
   + native

Added: scummvm/trunk/engines/mohawk/cstime_cases.h
===================================================================
--- scummvm/trunk/engines/mohawk/cstime_cases.h	                        (rev 0)
+++ scummvm/trunk/engines/mohawk/cstime_cases.h	2011-01-20 21:35:00 UTC (rev 55362)
@@ -0,0 +1,47 @@
+/* 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$
+ *
+ */
+
+#ifndef MOHAWK_CSTIME_CASES_H
+#define MOHAWK_CSTIME_CASES_H
+
+#include "mohawk/cstime_game.h"
+
+namespace Mohawk {
+
+class CSTimeCase1 : public CSTimeCase {
+public:
+	CSTimeCase1(MohawkEngine_CSTime *vm);
+	~CSTimeCase1();
+
+	bool checkConvCondition(uint16 conditionId);
+	bool checkAmbientCondition(uint16 charId, uint16 ambientId);
+	bool checkObjectCondition(uint16 objectId);
+	void selectHelpStrings();
+	void handleConditionalEvent(const CSTimeEvent &event);
+};
+
+} // End of namespace Mohawk
+
+#endif


Property changes on: scummvm/trunk/engines/mohawk/cstime_cases.h
___________________________________________________________________
Added: svn:mime-type
   + text/plain
Added: svn:keywords
   + Date Rev Author URL Id
Added: svn:eol-style
   + native

Added: scummvm/trunk/engines/mohawk/cstime_game.cpp
===================================================================
--- scummvm/trunk/engines/mohawk/cstime_game.cpp	                        (rev 0)
+++ scummvm/trunk/engines/mohawk/cstime_game.cpp	2011-01-20 21:35:00 UTC (rev 55362)
@@ -0,0 +1,1236 @@
+/* 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 "mohawk/sound.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;
+}
+
+// read a rect from a stream
+Common::Rect readRect(Common::SeekableReadStream *stream) {
+	Common::Rect rect;
+
+	rect.left = stream->readSint16BE();
+	rect.top = stream->readSint16BE();
+	rect.right = stream->readSint16BE();
+	rect.bottom = stream->readSint16BE();
+
+	return rect;
+}
+
+void Region::loadFrom(Common::SeekableReadStream *stream) {
+	uint16 rectCount = stream->readUint16BE();
+	if (!rectCount) {
+		// TODO: why this?
+		stream->skip(2);
+		rectCount = stream->readUint16BE();
+	}
+	for (uint i = 0; i < rectCount; i++) {
+		Common::Rect rect = readRect(stream);
+		if (!rect.isValidRect())
+			continue;
+		_rects.push_back(rect);
+	}
+}
+
+bool Region::containsPoint(Common::Point &pos) const {
+	for (uint i = 0; i < _rects.size(); i++)
+		if (_rects[i].contains(pos))
+			return true;
+
+	return false;
+}
+
+CSTimeChar::CSTimeChar(MohawkEngine_CSTime *vm, CSTimeScene *scene, uint id) : _vm(vm), _scene(scene), _id(id) {
+	_resting = true;
+	_flappingState = 0xffff;
+	_surfingState = 0;
+
+	_NIS = NULL;
+	_restFeature = NULL;
+	_talkFeature = NULL;
+
+	_talkFeature1 = NULL;
+	_talkFeature2 = NULL;
+	_talkFeature3 = NULL;
+	_lastTime1 = 0;
+	_lastTime2 = 0;
+	_lastTime3 = 0;
+
+	_playingWaveId = 0;
+}
+
+CSTimeChar::~CSTimeChar() {
+}
+
+void CSTimeChar::idle() {
+	if (!_unknown2)
+		return;
+
+	if (_flappingState == 1) {
+		idleTalk();
+		return;
+	}
+
+	if (!_NIS)
+		idleAmbients();
+}
+
+void CSTimeChar::setupAmbientAnims(bool onetime) {
+	CSTimeConversation *conv = _vm->getCase()->getCurrConversation();
+	if (_unknown1 == 0xffff || !_unknown2 || !_ambients.size() || !_resting || !_enabled ||
+		(conv->getState() != (uint)~0 && conv->getSourceChar() == _id)) {
+		setupRestPos();
+		_resting = true;
+		return;
+	}
+
+	removeChr();
+	for (uint i = 0; i < _ambients.size(); i++) {
+		// FIXME: check ambient condition
+		uint32 flags = kFeatureSortStatic;
+		if (_ambients[i].delay != 0xffff) {
+			flags |= kFeatureNewNoLoop;
+			if (onetime)
+				flags |= kFeatureNewDisableOnReset;
+		}
+		installAmbientAnim(i, flags);
+	}
+}
+
+void CSTimeChar::idleAmbients() {
+	if (_flappingState != 0xffff)
+		return;
+
+	for (uint i = 0; i < _ambients.size(); i++) {
+		if (!_ambients[i].feature)
+			continue;
+		uint16 delay = _ambients[i].delay;
+		if (delay == 0xffff)
+			continue;
+		uint32 now = _vm->_system->getMillis();
+		if (now < _ambients[i].nextTime)
+			continue;
+		_ambients[i].feature->resetFeatureScript(1, 0);
+		_ambients[i].nextTime = now + delay;
+	}
+}
+
+void CSTimeChar::stopAmbients(bool restpos) {
+	for (uint i = 0; i < _ambients.size(); i++) {
+		if (!_ambients[i].feature)
+			continue;
+		_vm->getView()->removeFeature(_ambients[i].feature, true);
+		_ambients[i].feature = NULL;
+	}
+
+	if (restpos)
+		setupRestPos();
+}
+
+void CSTimeChar::setupRestPos() {
+	if (_unknown1 == 0xffff || !_unknown1 || !_unknown2)
+		return;
+
+	if (!_restFeature) {
+		uint id = 0; // FIXME
+		uint32 flags = kFeatureSortStatic | kFeatureNewNoLoop | kFeatureNewDisableOnReset;
+		Feature *feature = _vm->getView()->installViewFeature(getChrBaseId() + id, flags, NULL);
+		// FIXME: fix priorities
+		_restFeature = feature;
+	} else {
+		_restFeature->resetFeatureScript(1, 0);
+	}
+
+	// FIXME: fix more priorities
+}
+
+void CSTimeChar::removeChr() {
+	if (_unknown1 == 0xffff || !_unknown1)
+		return;
+
+	if (_talkFeature) {
+		_vm->getView()->removeFeature(_talkFeature, true);
+		_vm->getView()->removeFeature(_talkFeature3, true);
+		if (_talkFeature1)
+			_vm->getView()->removeFeature(_talkFeature1, true);
+		if (_unknown1 > 1)
+			_vm->getView()->removeFeature(_talkFeature2, true);
+	}
+
+	if (_restFeature)
+		_vm->getView()->removeFeature(_restFeature, true);
+
+	_talkFeature1 = NULL;
+	_talkFeature2 = NULL;
+	_talkFeature3 = NULL;
+
+	_talkFeature = NULL;
+	_restFeature = NULL;
+}
+
+uint16 CSTimeChar::getChrBaseId() {
+	return _scene->getSceneId() + (_id + 1) * 200;
+}
+
+uint CSTimeChar::getScriptCount() {
+	static uint bases[4] = { 0, 10, 13, 21 };
+	assert(_unknown1 < 4);
+	return bases[_unknown1] + _ambients.size() + _unknown3;
+}
+
+void CSTimeChar::playNIS(uint16 id) {
+	if (_NIS)
+		removeNIS();
+	stopAmbients(false);
+	removeChr();
+	uint32 flags = kFeatureSortStatic | kFeatureNewNoLoop;
+	_NIS = _vm->getView()->installViewFeature(getChrTypeScriptBase() + id + _ambients.size(), flags, NULL);
+	// FIXME: fix priorities
+}
+
+bool CSTimeChar::NISIsDone() {
+	return (_NIS->_data.paused || !_NIS->_data.enabled);
+}
+
+void CSTimeChar::removeNIS() {
+	if (!_NIS)
+		return;
+	_vm->getView()->removeFeature(_NIS, true);
+	_NIS = NULL;
+}
+
+void CSTimeChar::startFlapping(uint16 id) {
+	if (!_unknown2)
+		return;
+
+	_scene->_activeChar = this;
+	if (_restFeature) {
+		_vm->getView()->removeFeature(_restFeature, true);
+		_restFeature = NULL;
+	}
+	stopAmbients(false);
+	setupTalk();
+	_flappingState = 1;
+	playFlapWave(id);
+}
+
+void CSTimeChar::interruptFlapping() {
+	if (_playingWaveId)
+		_vm->_sound->stopSound(_playingWaveId);
+	// TODO: kill any other (preload) sound
+	_waveStatus = 'q';
+}
+
+void CSTimeChar::installAmbientAnim(uint id, uint32 flags) {
+	Feature *feature = _vm->getView()->installViewFeature(getChrTypeScriptBase() + id, flags, NULL);
+	// FIXME: fix priorities
+
+	_ambients[id].feature = feature;
+	_ambients[id].nextTime = _vm->_system->getMillis() + _ambients[id].delay;
+}
+
+uint16 CSTimeChar::getChrTypeScriptBase() {
+	static uint bases[4] = { 0, 10, 13, 21 };
+	assert(_unknown1 < 4);
+	return bases[_unknown1] + getChrBaseId();
+}
+
+void CSTimeChar::playFlapWave(uint16 id) {
+	_playingWaveId = id;
+	_vm->_sound->playSound(id, Audio::Mixer::kMaxChannelVolume, false, &_cueList);
+	_nextCue = 0;
+	_waveStatus = 'b';
+}
+
+void CSTimeChar::updateWaveStatus() {
+	// This is a callback in the original, handling audio events.
+	assert(_playingWaveId);
+
+	// FIXME: state 's' for .. something? stopped?
+	if (!_vm->_sound->isPlaying(_playingWaveId)) {
+		_waveStatus = 'q';
+		return;
+	}
+
+	uint samples = _vm->_sound->getNumSamplesPlayed(_playingWaveId);
+	for (uint i = _nextCue; i < _cueList.pointCount; i++) {
+		if (_cueList.points[i].sampleFrame > samples)
+			return;
+		if (_cueList.points[i].name.empty())
+			warning("cue %d reached but was empty", i);
+		else
+			_waveStatus = _cueList.points[i].name[0];
+		_nextCue = i + 1;
+	}
+}
+
+void CSTimeChar::setupTalk() {
+	if (_unknown1 == 0xffff || !_unknown1 || !_unknown2 || _talkFeature)
+		return;
+
+	uint32 flags = kFeatureSortStatic | kFeatureNewNoLoop | kFeatureNewDisableOnReset;
+	_talkFeature = _vm->getView()->installViewFeature(getChrBaseId() + (_enabled ? 1 : 14), flags, NULL);
+
+	_talkFeature3 = _vm->getView()->installViewFeature(getChrBaseId() + (_enabled ? 4 : 15), flags, NULL);
+	if (_enabled) {
+		_talkFeature1 = _vm->getView()->installViewFeature(getChrBaseId() + 2, flags, NULL);
+		if (_unknown1 > 1) {
+			_talkFeature2 = _vm->getView()->installViewFeature(getChrBaseId() + 10, flags, NULL);
+		}
+	}
+	// FIXME: fix priorities
+}
+
+void CSTimeChar::idleTalk() {
+	updateWaveStatus();
+
+	if (_waveStatus == 'q') {
+		if (_surfingState) {
+			// FIXME
+			_surfingState = 0;
+		} else {
+			// FIXME
+			_playingWaveId = 0;
+		}
+		stopFlapping();
+		return;
+	}
+
+	if (_waveStatus == 's' && _surfingState) {
+		// FIXME
+		_waveStatus = 'q';
+		return;
+	}
+
+	CSTimeView *view = _vm->getView();
+
+	if (_enabled && view->getTime() > _lastTime1) {
+		_lastTime1 = view->getTime() + 2000 + _vm->_rnd->getRandomNumberRng(0, 1000);
+		if (_talkFeature1)
+			_talkFeature1->resetFeatureScript(1, getChrBaseId() + 2 + _vm->_rnd->getRandomNumberRng(0, 1));
+	}
+
+	if (_enabled && view->getTime() > _lastTime2) {
+		_lastTime2 = view->getTime() + 3000 + _vm->_rnd->getRandomNumberRng(0, 1000);
+		if (_talkFeature2)
+			_talkFeature2->resetFeatureScript(1, getChrBaseId() + 10 + _vm->_rnd->getRandomNumberRng(0, 2));
+	}
+
+	if (_waveStatus == 'c') {
+		if (_talkFeature3)
+			_talkFeature3->resetFeatureScript(1, getChrBaseId() + (_enabled ? 4 : 15));
+	} else if (view->getTime() > _lastTime3) {
+		_lastTime3 = view->getTime() + 100;
+		if (_talkFeature3)
+			_talkFeature3->resetFeatureScript(1, getChrBaseId() + (_enabled ? 4 : 15) + _vm->_rnd->getRandomNumberRng(1, 5));
+	}
+
+	// FIXME: more animations
+}
+
+void CSTimeChar::stopFlapping() {
+	_flappingState = 0;
+	removeChr();
+	// FIXME: stupid hardcoded hack for case 5
+	setupAmbientAnims(true);
+}
+
+CSTimeConversation::CSTimeConversation(MohawkEngine_CSTime *vm, uint id) : _vm(vm), _id(id) {
+	clear();
+
+	Common::SeekableReadStream *convStream = _vm->getResource(ID_CONV, id * 10 + 500);
+
+	_nameId = convStream->readUint16BE();
+	_greeting = convStream->readUint16BE();
+	_greeting2 = convStream->readUint16BE();
+
+	uint16 qarIds[8];
+	for (uint i = 0; i < 8; i++)
+		qarIds[i] = convStream->readUint16BE();
+
+	delete convStream;
+
+	for (uint i = 0; i < 8; i++) {
+		// FIXME: are they always in order?
+		if (qarIds[i] == 0xffff)
+			continue;
+		_qars.push_back(CSTimeQaR());
+		CSTimeQaR &qar = _qars.back();
+		loadQaR(qar, qarIds[i]);
+	}
+}
+
+void CSTimeConversation::start() {
+	uint16 greeting = _greeting;
+
+	if (_talkCount > 1)
+		greeting = _greeting2;
+
+	_state = 2;
+
+	if (greeting == 0xffff) {
+		finishProcessingQaR();
+		return;
+	}
+
+	CSTimeEvent event;
+	event.type = kCSTimeEventCharStartFlapping;
+	event.param1 = _sourceChar;
+	event.param2 = greeting;
+	_vm->addEvent(event);
+}
+
+void CSTimeConversation::finishProcessingQaR() {
+	if (_state == 2) {
+		_vm->getInterface()->getInventoryDisplay()->hide();
+		_vm->getInterface()->clearTextLine();
+		selectItemsToDisplay();
+		display();
+		return;
+	}
+
+	if (_nextToProcess == 0xffff)
+		return;
+
+	uint qarIndex = _itemsToDisplay[_nextToProcess];
+	CSTimeQaR &qar = _qars[qarIndex];
+
+	if (!qar.nextQaRsId) {
+		end(true);
+		_nextToProcess = 0xffff;
+		return;
+	}
+
+	if (qar.responseStringId != 0xffff) {
+		_vm->addEventList(qar.events);
+	}
+
+	if (qar.nextQaRsId == 0xffff) {
+		_qars.remove_at(qarIndex);
+		_vm->getInterface()->clearDialogLine(_nextToProcess);
+		_nextToProcess = 0xffff;
+		return;
+	}
+
+	loadQaR(qar, qar.nextQaRsId);
+	if (qar.unknown2)
+		qar.finished = true;
+	_vm->getInterface()->displayDialogLine(qar.questionStringId, _nextToProcess, qar.finished ? 13 : 32);
+
+	_nextToProcess = 0xffff;
+}
+
+void CSTimeConversation::end(bool useLastClicked, bool runEvents) {
+	if (runEvents) {
+		uint entry = _currEntry;
+		if (!useLastClicked)
+			entry = _itemsToDisplay.size() - 1;
+		CSTimeQaR &qar = _qars[_itemsToDisplay[entry]];
+		_vm->addEventList(qar.events);
+		if (_sourceChar != 0xffff)
+			_vm->getCase()->getCurrScene()->getChar(_sourceChar)->setupAmbientAnims(true);
+	}
+
+	CSTimeInterface *interface = _vm->getInterface();
+	CSTimeInventoryDisplay *invDisplay = interface->getInventoryDisplay();
+	if (invDisplay->getState() == 4) {
+		invDisplay->hide();
+		invDisplay->setState(0);
+	}
+
+	setState(~0);
+	_currHover = ~0;
+
+	interface->clearTextLine();
+	interface->clearDialogArea();
+	invDisplay->show();
+
+	// TODO: stupid case 20 stuff
+}
+
+void CSTimeConversation::display() {
+	_vm->getInterface()->clearDialogArea();
+
+	for (uint i = 0; i < _itemsToDisplay.size(); i++) {
+		// FIXME: some rect stuff?
+
+		CSTimeQaR &qar = _qars[_itemsToDisplay[i]];
+		_vm->getInterface()->displayDialogLine(qar.questionStringId, i, qar.finished ? 13 : 32);
+	}
+
+	_state = 1;
+}
+
+void CSTimeConversation::selectItemsToDisplay() {
+	_itemsToDisplay.clear();
+
+	for (uint i = 0; i < _qars.size(); i++) {
+		if (_qars[i].unknown1 != 0xffff && !_vm->getCase()->checkConvCondition(_qars[i].unknown1))
+			continue;
+		if (_itemsToDisplay.size() == 5)
+			error("Too many conversation paths");
+		_itemsToDisplay.push_back(i);
+	}
+}
+
+void CSTimeConversation::mouseDown(Common::Point &pos) {
+	if (_vm->getInterface()->getInventoryDisplay()->getState() == 4)
+		return;
+
+	// TODO: case 20 rect check
+
+	for (uint i = 0; i < _itemsToDisplay.size(); i++) {
+		Common::Rect thisRect = _vm->getInterface()->_dialogTextRect;
+		thisRect.top += 1 + i*15;
+		thisRect.bottom = thisRect.top + 15;
+		if (!thisRect.contains(pos))
+			continue;
+
+		_currEntry = i;
+		highlightLine(i);
+		_vm->getInterface()->cursorSetShape(5, true);
+		break;
+	}
+}
+
+void CSTimeConversation::mouseMove(Common::Point &pos) {
+	// TODO: case 20 rect check
+
+	bool mouseIsDown = _vm->getEventManager()->getButtonState() & 1;
+
+	for (uint i = 0; i < _itemsToDisplay.size(); i++) {
+		Common::Rect thisRect = _vm->getInterface()->_dialogTextRect;
+		thisRect.top += 1 + i*15;
+		thisRect.bottom = thisRect.top + 15;
+		if (!thisRect.contains(pos))
+			continue;
+
+		if (mouseIsDown) {
+			if (i != _currEntry)
+				break;
+			highlightLine(i);
+		}
+
+		_vm->getInterface()->cursorOverHotspot();
+		_currHover = i;
+		return;
+	}
+
+	if (_currHover != (uint)~0) {
+		if (_vm->getInterface()->cursorGetState() != 3) {
+			_vm->getInterface()->cursorSetShape(1, true);
+			if (_vm->getInterface()->getInventoryDisplay()->getState() != 4)
+				unhighlightLine(_currHover);
+		}
+		_currHover = ~0;
+	}
+}
+
+void CSTimeConversation::mouseUp(Common::Point &pos) {
+	if (_vm->getInterface()->getInventoryDisplay()->getState() == 4)
+		return;
+
+	if (_currEntry == (uint)~0)
+		return;
+
+	// TODO: case 20 rect check
+
+	CSTimeQaR &qar = _qars[_itemsToDisplay[_currEntry]];
+	Common::Rect thisRect = _vm->getInterface()->_dialogTextRect;
+	thisRect.top += 1 + _currEntry*15;
+	thisRect.bottom = thisRect.top + 15;
+	if (!thisRect.contains(pos))
+		return;
+
+	if (qar.responseStringId != 0xffff) {
+		CSTimeEvent newEvent;
+		newEvent.type = kCSTimeEventCharStartFlapping;
+		newEvent.param1 = _sourceChar;
+		newEvent.param2 = qar.responseStringId;
+		_vm->addEvent(newEvent);
+		_nextToProcess = _currEntry;
+		return;
+	}
+
+	if (!qar.nextQaRsId) {
+		_vm->getInterface()->cursorChangeShape(1);
+		end(true);
+		return;
+	}
+
+	_vm->addEventList(qar.events);
+	_nextToProcess = _currEntry;
+}
+
+void CSTimeConversation::setAsked(uint qar, uint entry) {
+	assert(qar < 8 && entry < 5);
+	_asked[qar][entry] = true;
+}
+
+void CSTimeConversation::clear() {
+	_state = ~0;
+	_talkCount = 0;
+	_sourceChar = 0xffff;
+	_currHover = ~0;
+	_currEntry = ~0;
+	_nextToProcess = 0xffff;
+	for (uint i = 0; i < 8; i++)
+		for (uint j = 0; j < 5; j++)
+			_asked[i][j] = false;
+}
+
+void CSTimeConversation::loadQaR(CSTimeQaR &qar, uint16 id) {
+	Common::SeekableReadStream *qarsStream = _vm->getResource(ID_QARS, id);
+	qar.finished = false;
+	qar.unknown1 = qarsStream->readUint16BE();
+	qar.questionStringId = qarsStream->readUint16BE();
+	qar.responseStringId = qarsStream->readUint16BE();
+	qar.unknown2 = qarsStream->readUint16BE();
+	qar.nextQaRsId = qarsStream->readUint16BE();
+	uint16 numEvents = qarsStream->readUint16BE();
+	for (uint j = 0; j < numEvents; j++) {
+		CSTimeEvent event;
+		event.type = qarsStream->readUint16BE();
+		event.param1 = qarsStream->readUint16BE();
+		event.param2 = qarsStream->readUint16BE();
+		qar.events.push_back(event);
+	}
+}
+
+void CSTimeConversation::highlightLine(uint line) {
+	CSTimeQaR &qar = _qars[_itemsToDisplay[line]];
+	_vm->getInterface()->displayDialogLine(qar.questionStringId, line, 244);
+}
+
+void CSTimeConversation::unhighlightLine(uint line) {
+	CSTimeQaR &qar = _qars[_itemsToDisplay[line]];
+	_vm->getInterface()->displayDialogLine(qar.questionStringId, line, qar.finished ? 13 : 32);
+}
+
+CSTimeCase::CSTimeCase(MohawkEngine_CSTime *vm, uint id) : _vm(vm), _id(id) {
+	_vm->loadResourceFile(Common::String::format("Cases/C%dText", id));
+	// We load this early, so we can use the text for debugging.
+	loadRolloverText();
+
+	_vm->loadResourceFile(Common::String::format("Cases/C%dInfo", id));
+	Common::SeekableReadStream *caseInfoStream = _vm->getResource(ID_CINF, 1);
+	uint16 numScenes = caseInfoStream->readUint16BE();
+	uint16 numInvObjs = caseInfoStream->readUint16BE();
+	uint16 numConversations = caseInfoStream->readUint16BE();
+	for (uint i = 0; i < 3; i++)
+		_noteFeatureId[i] = caseInfoStream->readUint16BE();
+	delete caseInfoStream;
+
+	debug("Loading %d inventory objects...", numInvObjs);
+	for (uint i = 0; i < numInvObjs; i++)
+		_inventoryObjs.push_back(loadInventoryObject(i));
+
+	_vm->loadResourceFile(Common::String::format("Cases/C%dArt", id));
+	_vm->loadResourceFile(Common::String::format("Cases/C%dDlog", id));
+
+	debug("Loading %d scenes...", numScenes);
+	for (uint i = 0; i < numScenes; i++)
+		_scenes.push_back(new CSTimeScene(_vm, this, i + 1));
+
+	debug("Loading %d conversations...", numConversations);
+	for (uint i = 0; i < numConversations; i++)
+		_conversations.push_back(new CSTimeConversation(_vm, i));
+
+	assert(!_conversations.empty());
+	_currConv = _conversations[0];
+
+	_currScene = ~0;
+}
+
+CSTimeCase::~CSTimeCase() {
+}
+
+void CSTimeCase::loadRolloverText() {
+	Common::SeekableReadStream *stringStream = _vm->getResource(ID_STRL, 9100);
+	while (stringStream->pos() < stringStream->size())
+		_rolloverText.push_back(readString(stringStream));
+	for (uint i = 0; i < _rolloverText.size(); i++)
+		debug("string %d: '%s'", i, _rolloverText[i].c_str());
+	delete stringStream;
+}
+
+CSTimeInventoryObject *CSTimeCase::loadInventoryObject(uint id) {
+	CSTimeInventoryObject *invObj = new CSTimeInventoryObject;
+	invObj->feature = NULL;
+	invObj->id = id;
+
+	Common::SeekableReadStream *invObjStream = _vm->getResource(ID_INVO, id + 1);
+	uint16 numHotspots = invObjStream->readUint16BE();
+	invObj->stringId = invObjStream->readUint16BE();
+	invObj->hotspotId = invObjStream->readUint16BE();
+	invObj->featureId = invObjStream->readUint16BE();
+	invObj->canTake = invObjStream->readUint16BE();
+	debug(" invobj '%s', hotspot id %d, feature id %d, can take %d", _rolloverText[invObj->stringId].c_str(), invObj->hotspotId, invObj->featureId, invObj->canTake);
+	uint16 numConsumableLocations = invObjStream->readUint16BE();
+	debug(" Loading %d consumable locations...", numConsumableLocations);
+	for (uint i = 0; i < numConsumableLocations; i++) {
+		CSTimeLocation location;
+		location.sceneId = invObjStream->readUint16BE();
+		location.hotspotId = invObjStream->readUint16BE();
+		invObj->locations.push_back(location);
+	}
+	uint16 numEvents = invObjStream->readUint16BE();
+	debug(" Loading %d events...", numEvents);
+	for (uint i = 0; i < numEvents; i++) {
+		CSTimeEvent event;
+		event.type = invObjStream->readUint16BE();
+		event.param1 = invObjStream->readUint16BE();
+		event.param2 = invObjStream->readUint16BE();
+		invObj->events.push_back(event);
+	}
+	debug(" Loading %d hotspots...", numHotspots);
+	for (uint i = 0; i < numHotspots; i++) {
+		CSTimeInventoryHotspot hotspot;
+		hotspot.sceneId = invObjStream->readUint16BE();
+		hotspot.hotspotId = invObjStream->readUint16BE();
+		hotspot.stringId = invObjStream->readUint16BE();
+		uint16 numHotspotEvents = invObjStream->readUint16BE();
+		debug("  scene %d, hotspot %d, string id %d, with %d hotspot events", hotspot.sceneId, hotspot.hotspotId, hotspot.stringId, numHotspotEvents);
+		for (uint j = 0; j < numHotspotEvents; j++) {
+			CSTimeEvent event;
+			event.type = invObjStream->readUint16BE();
+			event.param1 = invObjStream->readUint16BE();
+			event.param2 = invObjStream->readUint16BE();
+			hotspot.events.push_back(event);
+		}
+		invObj->hotspots.push_back(hotspot);
+	}
+	delete invObjStream;
+
+	return invObj;
+}
+
+CSTimeScene *CSTimeCase::getCurrScene() {
+	return _scenes[_currScene - 1];
+}
+
+CSTimeScene::CSTimeScene(MohawkEngine_CSTime *vm, CSTimeCase *case_, uint id) : _vm(vm), _case(case_), _id(id) {
+	_activeChar = NULL;
+	_currHotspot = ~0;
+	_hoverHotspot = ~0;
+	load();
+}
+
+void CSTimeScene::load() {
+	Common::SeekableReadStream *sceneStream = _vm->getResource(ID_SCEN, _id + 1000);
+	_unknown1 = sceneStream->readUint16BE();
+	_unknown2 = sceneStream->readUint16BE();
+	_helperId = sceneStream->readUint16BE();
+	_bubbleType = sceneStream->readUint16BE();
+	uint16 numHotspots = sceneStream->readUint16BE();
+	_numObjects = sceneStream->readUint16BE();
+	debug("Scene: unknowns %d, %d, %d, bubble type %d, %d objects", _unknown1, _unknown2, _helperId, _bubbleType, _numObjects);
+
+	uint16 numChars = sceneStream->readUint16BE();
+	uint16 numEvents = sceneStream->readUint16BE();
+	debug(" Loading %d events...", numEvents);
+	for (uint i = 0; i < numEvents; i++) {
+		CSTimeEvent event;
+		event.type = sceneStream->readUint16BE();
+		event.param1 = sceneStream->readUint16BE();
+		event.param2 = sceneStream->readUint16BE();
+		_events.push_back(event);
+	}
+	uint16 numEvents2 = sceneStream->readUint16BE();
+	debug(" Loading %d events2...", numEvents2);
+	for (uint i = 0; i < numEvents2; i++) {
+		CSTimeEvent event;
+		event.type = sceneStream->readUint16BE();
+		event.param1 = sceneStream->readUint16BE();
+		event.param2 = sceneStream->readUint16BE();
+		_events2.push_back(event);
+	}
+	debug(" Loading %d chars...", numChars);
+	for (uint i = 0; i < numChars; i++) {
+		CSTimeChar *chr = new CSTimeChar(_vm, this, i);
+		if (!_activeChar)
+			_activeChar = chr;
+		chr->_enabled = true;
+		chr->_unknown1 = sceneStream->readUint16BE();
+		chr->_unknown2 = sceneStream->readUint16BE();
+		uint16 numAmbients = sceneStream->readUint16BE();
+		chr->_unknown3 = sceneStream->readUint16BE();
+		debug("  unknowns %d, %d, %d, with %d ambients", chr->_unknown1, chr->_unknown2, chr->_unknown3, numAmbients);
+		for (uint j = 0; j < numAmbients; j++) {
+			CSTimeAmbient ambient;
+			ambient.delay = sceneStream->readUint16BE();
+			ambient.feature = NULL;
+			chr->_ambients.push_back(ambient);
+		}
+		_chars.push_back(chr);
+	}
+	debug(" Loading %d hotspots...", numHotspots);
+	for (uint i = 0; i < numHotspots; i++) {
+		CSTimeHotspot hotspot;
+		hotspot.stringId = sceneStream->readUint16BE();
+		hotspot.invObjId = sceneStream->readUint16BE();
+		hotspot.cursor = sceneStream->readUint16BE();
+		hotspot.state = sceneStream->readUint16BE();
+		uint16 numHotspotEvents = sceneStream->readUint16BE();
+		debug("  hotspot '%s', inv obj %d, cursor %d, state %d, with %d hotspot events", _case->getRolloverText(hotspot.stringId).c_str(), hotspot.invObjId, hotspot.cursor, hotspot.state, numHotspotEvents);
+		for (uint j = 0; j < numHotspotEvents; j++) {
+			CSTimeEvent event;
+			event.type = sceneStream->readUint16BE();
+			event.param1 = sceneStream->readUint16BE();
+			event.param2 = sceneStream->readUint16BE();
+			hotspot.events.push_back(event);
+		}
+		_hotspots.push_back(hotspot);
+	}
+	delete sceneStream;
+
+	Common::SeekableReadStream *hotspotStream = _vm->getResource(ID_HOTS, _id + 1100);
+	for (uint i = 0; i < _hotspots.size(); i++) {
+		_hotspots[i].region.loadFrom(hotspotStream);
+	}
+	delete hotspotStream;
+}
+
+void CSTimeScene::installGroup() {
+	uint16 resourceId = getSceneId();
+	_vm->getView()->installGroup(resourceId, _numObjects, 0, true, resourceId);
+
+	for (uint i = 0; i < _chars.size(); i++) {
+		uint count = _chars[i]->getScriptCount();
+		if (!count)
+			continue;
+		_vm->getView()->installGroup(resourceId, count, 0, true, _chars[i]->getChrBaseId());
+	}
+}
+
+void CSTimeScene::buildScene() {
+	uint16 resourceId = getSceneId();
+
+	_vm->getView()->installBG(resourceId);
+
+	for (uint i = 0; i < _numObjects; i++) {
+		if (!_case->checkObjectCondition(i)) {
+			_objectFeatures.push_back(NULL);
+			continue;
+		}
+
+		// FIXME: reset object if it already exists
+		// FIXME: deal with NULL
+		uint32 flags = kFeatureSortStatic | kFeatureNewNoLoop | kFeatureNewDisableOnReset;
+		assert(flags == 0x4C00000);
+		Feature *feature = _vm->getView()->installViewFeature(resourceId + i, flags, NULL);
+		_objectFeatures.push_back(feature);
+	}
+}
+
+void CSTimeScene::leave() {
+	for (uint i = 0; i < _objectFeatures.size(); i++) {
+		if (_objectFeatures[i] == NULL)
+			continue;
+		_vm->getView()->removeFeature(_objectFeatures[i], true);
+		_objectFeatures[i] = NULL;
+	}
+
+	for (uint i = 0; i < _chars.size(); i++) {
+		_chars[i]->stopAmbients(false);
+		_chars[i]->removeChr();
+		_chars[i]->removeNIS();
+	}
+
+	_vm->getView()->removeGroup(getSceneId());
+}
+
+uint16 CSTimeScene::getSceneId() {
+	// FIXME: there are a lot of special cases
+	uint16 resourceId = 10000 + 2000 * (_id - 1);
+	return resourceId;
+}
+
+void CSTimeScene::mouseDown(Common::Point &pos) {
+	CSTimeConversation *conv = _vm->getCase()->getCurrConversation();
+	bool convActive = (conv->getState() != (uint)~0);
+	bool helpActive = (_vm->getInterface()->getHelp()->getState() != (uint)~0);
+	if (convActive || helpActive) {
+		bool foundPoint = false;
+		for (uint i = 0; i < _hotspots.size(); i++) {
+			CSTimeHotspot &hotspot = _hotspots[i];
+			if (!hotspot.region.containsPoint(pos))
+				continue;
+			foundPoint = true;
+
+			if (!convActive) {
+				// In help mode, we ignore clicks on any help hotspot.
+				if (!hotspotContainsEvent(i, kCSTimeEventStartHelp))
+					break;
+				_currHotspot = ~0;
+				return;
+			}
+
+			// In conversation mode, we ignore clicks which would restart the current conversation.
+			for (uint j = 0; j < hotspot.events.size(); j++) {
+				if (hotspot.events[j].type != kCSTimeEventStartConversation)
+					continue;
+				// FIXME: check that the conversation *is* the current one
+				_currHotspot = ~0;
+				return;
+			}
+
+			break;
+		}
+
+		if (foundPoint) {
+			// We found a valid hotspot and we didn't ignore it, stop the conversation/help.
+			if (convActive) {
+				conv->end(false);
+			} else {
+				_vm->getInterface()->getHelp()->end();
+			}
+		}
+	} else {
+		// FIXME: check symbols
+	}
+
+	// FIXME: return if sailing puzzle
+
+	_currHotspot = ~0;
+	for (uint i = 0; i < _hotspots.size(); i++) {
+		CSTimeHotspot &hotspot = _hotspots[i];
+		if (!hotspot.region.containsPoint(pos))
+			continue;
+		if (hotspot.state != 1)
+			continue;
+		mouseDownOnHotspot(i);
+		break;
+	}
+
+	if (_currHotspot == (uint)~0)
+		_vm->getInterface()->cursorSetShape(4, false);
+}
+
+void CSTimeScene::mouseMove(Common::Point &pos) {
+	// TODO: if we're in sailing puzzle, return
+
+	bool mouseIsDown = _vm->getEventManager()->getButtonState() & 1;
+
+	if (_vm->getInterface()->getState() == kCSTimeInterfaceStateDragStart) {
+		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(_vm->getInterface()->getInventoryDisplay()->getLastDisplayedClicked());
+			} else {
+				CSTimeHotspot &hotspot = _hotspots[_currHotspot];
+				if (_vm->_haveInvItem[hotspot.invObjId]) {
+					_vm->getInterface()->setState(kCSTimeInterfaceStateNormal);
+				} else {
+					// FIXME: special-casing for cases 9, 13, 15, 18 19
+
+					CSTimeInventoryObject *invObj = _vm->getCase()->_inventoryObjs[hotspot.invObjId];
+					if (invObj->feature)
+						error("Inventory object already had feature when dragging from scene");
+					uint16 id = 9000 + (invObj->id - 1);
+					// FIXME: 0x2000 is set! help?
+					uint32 flags = kFeatureNewNoLoop | 0x2000;
+					invObj->feature = _vm->getView()->installViewFeature(id, flags, &grabPoint);
+					_vm->getInterface()->startDragging(hotspot.invObjId);
+				}
+			}
+		}
+	}
+
+	for (uint i = 0; i < _hotspots.size(); i++) {
+		CSTimeHotspot &hotspot = _hotspots[i];
+		if (hotspot.state != 1)
+			continue;
+		if (!hotspot.region.containsPoint(pos))
+			continue;
+
+		if (_vm->getInterface()->getState() == kCSTimeInterfaceStateDragging) {
+			// Only show a hotspot here if the dragged object can be dropped onto it.
+			CSTimeInventoryObject *invObj = _vm->getCase()->_inventoryObjs[_vm->getInterface()->getDraggedNum()];
+			bool showText = false;
+			for (uint j = 0; j < invObj->hotspots.size(); j++) {
+				if (invObj->hotspots[j].sceneId != _id)
+					continue;
+				if (invObj->hotspots[j].hotspotId != i)
+					continue;
+				showText = true;
+			}
+			if (!showText)
+				continue;
+		} else {
+			// If we're not dragging but the mouse is down, ignore all hotspots
+			// except the one which was clicked on.
+			if (mouseIsDown && (i != _currHotspot))
+				continue;
+		}
+
+		if (i != _hoverHotspot);
+			_vm->getInterface()->clearTextLine();
+		cursorOverHotspot(i);
+		_hoverHotspot = i;
+		return;
+	}
+
+	if (_vm->getInterface()->getState() != kCSTimeInterfaceStateDragging) {
+		switch (_vm->getInterface()->cursorGetShape()) {
+			case 2:
+			case 13:
+				_vm->getInterface()->cursorSetShape(1);
+				break;
+			case 5:
+			case 14:
+				_vm->getInterface()->cursorSetShape(4);
+				break;
+			case 11:
+				_vm->getInterface()->cursorSetShape(10);
+				break;
+		}
+	}
+
+	if (_hoverHotspot == (uint)~0)
+		return;
+
+	CSTimeConversation *conv = _case->getCurrConversation();
+	CSTimeHelp *help = _vm->getInterface()->getHelp();
+	if (conv->getState() != (uint)~0 && conv->getState() != 0) {
+		Common::String text = "Talking to " + _case->getRolloverText(conv->getNameId());
+		_vm->getInterface()->displayTextLine(text);
+	} else if (help->getState() != (uint)~0 && help->getState() != 0) {
+		Common::String text = "Talking to " + _case->getRolloverText(0);
+		_vm->getInterface()->displayTextLine(text);
+	} else if (_vm->getInterface()->getState() == kCSTimeInterfaceStateDragging) {
+		// TODO: check symbols before this
+		CSTimeInventoryObject *invObj = _vm->getCase()->_inventoryObjs[_vm->getInterface()->getDraggedNum()];
+		Common::String text = "Holding " + _case->getRolloverText(invObj->stringId);
+		_vm->getInterface()->displayTextLine(text);
+	} else {
+		_vm->getInterface()->clearTextLine();
+	}
+
+	_hoverHotspot = (uint)~0;
+}
+
+void CSTimeScene::mouseUp(Common::Point &pos) {
+	// TODO: if sailing puzzle is active, return
+
+	if (_currHotspot == (uint)~0) {
+		if (_vm->getInterface()->cursorGetShape() == 4)
+			_vm->getInterface()->cursorChangeShape(1);
+		return;
+	}
+
+	if (_vm->getInterface()->getState() == kCSTimeInterfaceStateDragStart)
+		_vm->getInterface()->setState(kCSTimeInterfaceStateNormal);
+
+	CSTimeHotspot &hotspot = _hotspots[_currHotspot];
+	if (hotspot.region.containsPoint(pos) && hotspot.state == 1) {
+		mouseUpOnHotspot(_currHotspot);
+	} else {
+		if (_vm->getInterface()->cursorGetShape() == 4 || _vm->getInterface()->cursorGetShape() == 14)
+			_vm->getInterface()->cursorChangeShape(1);
+	}
+}
+
+void CSTimeScene::idle() {
+	// TODO: if sailing puzzle is active, idle it instead
+
+	for (uint i = 0; i < _chars.size(); i++)
+		_chars[i]->idle();
+}
+
+void CSTimeScene::setupAmbientAnims() {
+	for (uint i = 0; i < _chars.size(); i++)
+		_chars[i]->setupAmbientAnims(false);
+}
+
+void CSTimeScene::idleAmbientAnims() {
+	if (_vm->NISIsRunning())
+		return;
+
+	for (uint i = 0; i < _chars.size(); i++)
+		_chars[i]->idleAmbients();
+}
+
+bool CSTimeScene::eventIsActive() {
+	return _vm->NISIsRunning() /* TODO || _vm->soundIsPlaying()*/ || _vm->getCurrentEventType() == kCSTimeEventWaitForClick
+		|| _activeChar->_flappingState != 0xffff || _vm->getInterface()->getState() == 4;
+}
+
+void CSTimeScene::cursorOverHotspot(uint id) {
+	CSTimeHotspot &hotspot = _hotspots[id];
+
+	if (!_vm->getInterface()->cursorGetState())
+		return;
+
+	if (_vm->getInterface()->getState() == kCSTimeInterfaceStateDragging) {
+		uint16 stringId = 0xffff;
+
+		uint16 draggedId = _vm->getInterface()->getDraggedNum();
+		CSTimeInventoryObject *invObj = _vm->getCase()->_inventoryObjs[draggedId];
+		for (uint j = 0; j < invObj->hotspots.size(); j++) {
+			if (invObj->hotspots[j].sceneId != _id)
+				continue;
+			if (invObj->hotspots[j].hotspotId != id)
+				continue;
+			stringId = invObj->hotspots[j].stringId;
+			break;
+		}
+
+		if (hotspot.stringId != 0xFFFF) {
+			Common::String textLine;
+			if (false) {
+				// FIXME: special-case time cuffs
+			} else {
+				bool isChar = (hotspot.cursor == 1) && (draggedId != TIME_CUFFS_ID);
+				textLine = (isChar ? "Give " : "Use ");
+				textLine += _case->getRolloverText(invObj->stringId);
+				textLine += (isChar ? " to " : " on ");
+				textLine += _case->getRolloverText(stringId);
+			}
+			_vm->getInterface()->displayTextLine(textLine);
+		}
+	} else {
+		if (hotspot.stringId != 0xFFFF)
+			_vm->getInterface()->displayTextLine(_case->getRolloverText(hotspot.stringId));
+	}
+
+	if (_vm->getEventManager()->getButtonState() & 1) {
+		if (_vm->getInterface()->getState() != kCSTimeInterfaceStateDragStart && _vm->getInterface()->getState() != kCSTimeInterfaceStateDragging) {
+			CSTimeHotspot &currHotspot = _hotspots[_currHotspot];
+			if (currHotspot.cursor == 2)
+				_vm->getInterface()->cursorSetShape(14);
+			else
+				_vm->getInterface()->cursorSetShape(5);
+		}
+	} else {
+		if (hotspot.cursor == 2)
+			_vm->getInterface()->cursorSetShape(13);
+		else if (_vm->getInterface()->cursorGetShape() != 8 && _vm->getInterface()->cursorGetShape() != 11)
+			_vm->getInterface()->cursorSetShape(2);
+	}
+}
+
+void CSTimeScene::mouseDownOnHotspot(uint id) {
+	CSTimeHotspot &hotspot = _hotspots[id];
+
+	_currHotspot = id;
+
+	if (hotspot.invObjId == 0xffff || _vm->_haveInvItem[hotspot.invObjId]) {
+		if (hotspot.cursor == 2)
+			_vm->getInterface()->cursorChangeShape(14);
+		else
+			_vm->getInterface()->cursorChangeShape(5);
+		return;
+	}
+
+	_vm->getInterface()->cursorSetShape(8, true);
+	_vm->getInterface()->setGrabPoint();
+	_vm->getInterface()->setState(kCSTimeInterfaceStateDragStart);
+
+	CSTimeInventoryObject *invObj = _vm->getCase()->_inventoryObjs[hotspot.invObjId];
+	_vm->getInterface()->displayTextLine("Pick up " + _case->getRolloverText(invObj->stringId));
+}
+
+void CSTimeScene::mouseUpOnHotspot(uint id) {
+	CSTimeHotspot &hotspot = _hotspots[id];
+
+	_vm->addEventList(hotspot.events);
+	if (_vm->getInterface()->cursorGetShape() == 8 || (!hotspot.events.empty() && _vm->getInterface()->cursorGetShape() == 11))
+		return;
+	if (hotspot.cursor == 2)
+		_vm->getInterface()->cursorChangeShape(13);
+	else
+		_vm->getInterface()->cursorChangeShape(2);
+}
+
+bool CSTimeScene::hotspotContainsEvent(uint id, uint16 eventType) {
+	CSTimeHotspot &hotspot = _hotspots[id];
+
+	for (uint i = 0; i < hotspot.events.size(); i++)
+		if (hotspot.events[i].type == eventType)
+			return true;
+
+	return false;
+}
+
+void CSTimeScene::setCursorForCurrentPoint() {
+	Common::Point mousePos = _vm->getEventManager()->getMousePos();
+
+	for (uint i = 0; i < _hotspots.size(); i++) {
+		if (!_hotspots[i].region.containsPoint(mousePos))
+			continue;
+		if (_hotspots[i].state != 1)
+			continue;
+		if (_hotspots[i].cursor == 2) {
+			_vm->getInterface()->cursorSetShape(13);
+		} else switch (_vm->getInterface()->cursorGetShape()) {
+		case 8:
+			break;
+		case 12:
+			_vm->getInterface()->cursorSetShape(11);
+			break;
+		default:
+			_vm->getInterface()->cursorSetShape(2);
+			break;
+		}
+		return;
+	}
+
+	_vm->getInterface()->cursorSetShape(1);
+}
+
+void CSTimeScene::drawHotspots() {
+	for (uint i = 0; i < _hotspots.size(); i++) {
+		for (uint j = 0; j < _hotspots[i].region._rects.size(); j++) {
+			_vm->_gfx->drawRect(_hotspots[i].region._rects[j], 10 + 5*i);
+		}
+	}
+}
+
+const Common::Array<CSTimeEvent> &CSTimeScene::getEvents(bool second) {
+	if (second)
+		return _events2;
+	else
+		return _events;
+}
+
+} // End of namespace Mohawk


Property changes on: scummvm/trunk/engines/mohawk/cstime_game.cpp
___________________________________________________________________
Added: svn:mime-type
   + text/plain
Added: svn:keywords
   + Date Rev Author URL Id
Added: svn:eol-style
   + native

Added: scummvm/trunk/engines/mohawk/cstime_game.h
===================================================================
--- scummvm/trunk/engines/mohawk/cstime_game.h	                        (rev 0)
+++ scummvm/trunk/engines/mohawk/cstime_game.h	2011-01-20 21:35:00 UTC (rev 55362)
@@ -0,0 +1,287 @@
+/* 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$
+ *
+ */
+
+#ifndef MOHAWK_CSTIME_GAME_H
+#define MOHAWK_CSTIME_GAME_H
+
+#include "mohawk/cstime.h"
+#include "mohawk/sound.h" // CueList
+
+namespace Mohawk {
+
+class Feature;
+class CSTimeCase;
+class CSTimeScene;
+
+class Region {
+public:
+	void loadFrom(Common::SeekableReadStream *stream);
+	bool containsPoint(Common::Point &pos) const;
+
+	Common::Array<Common::Rect> _rects;
+};
+
+struct CSTimeAmbient {
+	uint16 delay;
+	Feature *feature;
+	uint32 nextTime;
+};
+
+class CSTimeChar {
+public:
+	CSTimeChar(MohawkEngine_CSTime *vm, CSTimeScene *scene, uint id);
+	~CSTimeChar();
+
+	void idle();
+	void setupAmbientAnims(bool onetime);
+	void idleAmbients();
+	void stopAmbients(bool restpos);
+	void setupRestPos();
+	void removeChr();
+	uint16 getChrBaseId();
+	uint getScriptCount();
+	void playNIS(uint16 id);
+	bool NISIsDone();
+	void removeNIS();
+	void startFlapping(uint16 id);
+	void interruptFlapping();
+
+	uint16 _unknown1, _unknown2, _unknown3;
+	Common::Array<CSTimeAmbient> _ambients;
+	bool _enabled;
+	uint16 _flappingState;
+
+protected:
+	MohawkEngine_CSTime *_vm;
+	CSTimeScene *_scene;
+	uint _id;
+
+	Feature *_NIS;
+	Feature *_restFeature;
+	Feature *_talkFeature;
+	Feature *_talkFeature1, *_talkFeature2, *_talkFeature3;
+
+	uint16 _playingWaveId;
+	CueList _cueList;
+	uint _nextCue;
+	uint32 _lastTime1, _lastTime2, _lastTime3;
+
+	bool _resting;
+	byte _waveStatus;
+	byte _surfingState;
+
+	void installAmbientAnim(uint id, uint32 flags);
+	uint16 getChrTypeScriptBase();
+	void playFlapWave(uint16 id);
+	void updateWaveStatus();
+	void setupTalk();
+	void idleTalk();
+	void stopFlapping();
+};
+
+struct CSTimeHotspot {
+	uint16 stringId;
+	uint16 state;
+	uint16 invObjId;
+	uint16 cursor;
+	Common::Array<CSTimeEvent> events;
+	Region region;
+};
+
+struct CSTimeLocation {
+	uint16 sceneId, hotspotId;
+};
+
+struct CSTimeInventoryHotspot {
+	uint16 sceneId, hotspotId, stringId;
+	Common::Array<CSTimeEvent> events;
+};
+
+#define TIME_CUFFS_ID 0
+struct CSTimeInventoryObject {
+	uint16 id, stringId, hotspotId, featureId, canTake;
+	Feature *feature;
+	Common::Array<CSTimeLocation> locations;
+	Common::Array<CSTimeInventoryHotspot> hotspots;
+	Common::Array<CSTimeEvent> events;
+};
+
+struct CSTimeQaR {
+	bool finished;
+	uint16 id;
+	uint16 unknown1;
+	uint16 questionStringId;
+	uint16 responseStringId;
+	uint16 unknown2;
+	uint16 nextQaRsId;
+	Common::Array<CSTimeEvent> events;
+};
+
+class CSTimeConversation {
+public:
+	CSTimeConversation(MohawkEngine_CSTime *vm, uint id);
+	~CSTimeConversation();
+
+	void start();
+	void finishProcessingQaR();
+	void end(bool useLastClicked, bool runEvents = true);
+	void display();
+	void selectItemsToDisplay();
+
+	void mouseDown(Common::Point &pos);
+	void mouseMove(Common::Point &pos);
+	void mouseUp(Common::Point &pos);
+
+	void incrementTalkCount() { _talkCount++; }
+	uint16 getNameId() { return _nameId; }
+	uint16 getSourceChar() { return _sourceChar; }
+	void setSourceChar(uint16 source) { _sourceChar = source; }
+	void setAsked(uint qar, uint entry);
+	bool getAsked(uint qar, uint entry) { return _asked[qar][entry]; }
+
+	void setState(uint state) { _state = state; }
+	uint getState() { return _state; }
+
+protected:
+	MohawkEngine_CSTime *_vm;
+	uint _id;
+
+	uint _state;
+
+	uint16 _nameId;
+	uint16 _greeting, _greeting2;
+
+	uint _talkCount;
+	uint16 _sourceChar;
+
+	uint _currEntry, _currHover;
+	uint16 _nextToProcess;
+
+	bool _asked[8][5];
+	Common::Array<CSTimeQaR> _qars;
+	Common::Array<uint> _itemsToDisplay;
+
+	void clear();
+	void loadQaR(CSTimeQaR &qar, uint16 id);
+
+	void highlightLine(uint line);
+	void unhighlightLine(uint line);
+};
+
+class CSTimeScene {
+public:
+	CSTimeScene(MohawkEngine_CSTime *vm, CSTimeCase *case_, uint id);
+	~CSTimeScene();
+
+	void installGroup();
+	void buildScene();
+	void leave();
+	uint16 getSceneId();
+	void mouseDown(Common::Point &pos);
+	void mouseMove(Common::Point &pos);
+	void mouseUp(Common::Point &pos);
+	void idle();
+	void setupAmbientAnims();
+	void idleAmbientAnims();
+	bool eventIsActive();
+
+	void setCursorForCurrentPoint();
+	void drawHotspots(); // debugging
+
+	uint16 getBubbleType() { return _bubbleType; }
+	const Common::Array<CSTimeEvent> &getEvents(bool second);
+	const Common::Array<CSTimeHotspot> &getHotspots() { return _hotspots; }
+	CSTimeHotspot &getHotspot(uint id) { return _hotspots[id]; }
+	uint16 getInvObjForCurrentHotspot() { return _hotspots[_currHotspot].invObjId; }
+	CSTimeChar *getChar(uint id) { return _chars[id]; }
+	uint16 getHelperId() { return _helperId; }
+	uint getId() { return _id; }
+
+	CSTimeChar *_activeChar;
+
+	Common::Array<Feature *> _objectFeatures;
+
+protected:
+	MohawkEngine_CSTime *_vm;
+	CSTimeCase *_case;
+	uint _id;
+
+	uint _currHotspot;
+	uint _hoverHotspot;
+
+	void load();
+	void cursorOverHotspot(uint id);
+	void mouseDownOnHotspot(uint id);
+	void mouseUpOnHotspot(uint id);
+	bool hotspotContainsEvent(uint id, uint16 eventType);
+
+	uint16 _unknown1, _unknown2, _helperId;
+	uint16 _bubbleType;
+	uint16 _numObjects;
+	Common::Array<CSTimeEvent> _events, _events2;
+	Common::Array<CSTimeChar *> _chars;
+	Common::Array<CSTimeHotspot> _hotspots;
+};
+
+class CSTimeCase {
+public:
+	CSTimeCase(MohawkEngine_CSTime *vm, uint id);
+	virtual ~CSTimeCase();
+
+	uint getId() { return _id; }
+	Common::String &getRolloverText(uint id) { return _rolloverText[id]; }
+	CSTimeScene *getCurrScene();
+	void setCurrScene(uint id) { _currScene = id; }
+	void setConversation(uint id) { _currConv = _conversations[id]; }
+	CSTimeConversation *getCurrConversation() { return _currConv; }
+	uint16 getNoteFeatureId(uint16 id) { return _noteFeatureId[id]; }
+
+	// Hard-coded per-case logic, implemented in subclasses.
+	virtual bool checkConvCondition(uint16 conditionId) = 0;
+	virtual bool checkAmbientCondition(uint16 charId, uint16 ambientId) = 0;
+	virtual bool checkObjectCondition(uint16 objectId) = 0;
+	virtual void selectHelpStrings() = 0;
+	virtual void handleConditionalEvent(const CSTimeEvent &event) = 0;
+
+	Common::Array<CSTimeInventoryObject *> _inventoryObjs;
+
+protected:
+	MohawkEngine_CSTime *_vm;
+	uint _id;
+
+	uint _currScene;
+	uint16 _noteFeatureId[3];
+	Common::Array<Common::String> _rolloverText;
+	Common::Array<CSTimeScene *> _scenes;
+	Common::Array<CSTimeConversation *> _conversations;
+	CSTimeConversation *_currConv;
+
+	void loadRolloverText();
+	CSTimeInventoryObject *loadInventoryObject(uint id);
+};
+
+} // End of namespace Mohawk
+
+#endif


Property changes on: scummvm/trunk/engines/mohawk/cstime_game.h
___________________________________________________________________
Added: svn:mime-type
   + text/plain
Added: svn:keywords
   + Date Rev Author URL Id
Added: svn:eol-style
   + native

Added: scummvm/trunk/engines/mohawk/cstime_ui.cpp
===================================================================
--- scummvm/trunk/engines/mohawk/cstime_ui.cpp	                        (rev 0)
+++ scummvm/trunk/engines/mohawk/cstime_ui.cpp	2011-01-20 21:35:00 UTC (rev 55362)
@@ -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;
+			}

@@ Diff output truncated at 100000 characters. @@

This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.




More information about the Scummvm-git-logs mailing list