scummvm/engines/mohawk/cstime.cpp

607 lines
15 KiB
C++
Raw Normal View History

/* ScummVM - Graphic Adventure Engine
*
* ScummVM is the legal property of its developers, whose names
* are too numerous to list here. Please refer to the COPYRIGHT
* file distributed with this source distribution.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
*/
#include "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/video.h"
#include "common/config-manager.h"
#include "common/error.h"
#include "common/events.h"
#include "common/fs.h"
#include "common/textconsole.h"
#include "common/system.h"
namespace Mohawk {
MohawkEngine_CSTime::MohawkEngine_CSTime(OSystem *syst, const MohawkGameDescription *gamedesc) : MohawkEngine(syst, gamedesc) {
_rnd = new Common::RandomSource("cstime");
// If the user just copied the CD contents, the fonts are in a subdirectory.
const Common::FSNode gameDataDir(ConfMan.get("path"));
// They're in setup/data32 for 'Where in Time is Carmen Sandiego?'.
SearchMan.addSubDirectoryMatching(gameDataDir, "setup/data32");
// They're in 95instal for 'Carmen Sandiego's Great Chase Through Time'.
SearchMan.addSubDirectoryMatching(gameDataDir, "95instal");
_state = kCSTStateStartup;
reset();
_console = 0;
_gfx = 0;
_cursor = 0;
_interface = 0;
_view = 0;
_needsUpdate = false;
_case = 0;
_nextSceneId = 1;
}
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->_visitCount++;
scene->installGroup();
_interface->draw();
scene->buildScene();
scene->setupAmbientAnims();
_interface->cursorSetShape(1, false);
addEvent(CSTimeEvent(kCSTimeEventWait, 0xffff, 500));
scene->idleAmbientAnims();
// TODO: startEnvironmentSound();
if (scene->_visitCount == 1) {
addEventList(scene->getEvents(false));
} else {
addEventList(scene->getEvents(true));
}
_view->idleView();
// TODO: maybe startMusic();
}
void MohawkEngine_CSTime::loadResourceFile(Common::String name) {
MohawkArchive *archive = new MohawkArchive();
if (!archive->openFile(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 = 0xffffffff;
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;
case kCSTimeEventCharSomeNIS55:
// This is like kCSTimeEventCharPlayNIS, only using a different flag variable.
if (_processingNIS55) {
CSTimeChar *chr = _case->getCurrScene()->getChar(event.param1);
if (chr->NISIsDone()) {
chr->removeNIS();
_processingNIS55 = false;
chr->setupAmbientAnims(true);
_events.pop_front();
processEvent = false;
} else {
done = true;
}
} else {
advanceQueue = false;
}
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;
_processingNIS55 = false;
_lastTimeout = 0xffffffff;
_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->_unknown2) {
_case->getCurrScene()->_activeChar->_flappingState = 0;
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 kCSTimeEventRemoveItemFromInventory:
if (!_interface->getInventoryDisplay()->isItemDisplayed(event.param2))
break;
_haveInvItem[event.param2] = 0;
_interface->getInventoryDisplay()->removeItem(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 kCSTimeEventStartHelp:
_interface->getHelp()->start();
break;
case kCSTimeEventShowBigNote:
_interface->getCarmenNote()->drawBigNote();
break;
case kCSTimeEventActivateCuffs:
_interface->getInventoryDisplay()->activateCuffs(true);
break;
case kCSTimeEventHelperSetupRestPos:
_case->getCurrScene()->getChar(_case->getCurrScene()->getHelperId())->setupRestPos();
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 kCSTimeEventCharSetState:
_case->getCurrScene()->getChar(event.param1)->_enabled = event.param2;
break;
case kCSTimeEventCharSetupRestPos:
_case->getCurrScene()->getChar(event.param1)->setupRestPos();
break;
case kCSTimeEventStopEnvironmentSound:
warning("ignoring stop environment sound");
// FIXME
break;
case kCSTimeEventSetMusic:
warning("ignoring set music");
// FIXME
break;
case kCSTimeEventSetInsertBefore:
warning("ignoring insert before");
// FIXME
break;
case kCSTimeEventCharSomeNIS55:
_processingNIS55 = true;
_case->getCurrScene()->getChar(event.param1)->playNIS(event.param2);
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() != (uint)~0 && _case->getCurrConversation()->getState()) {
_case->getCurrConversation()->finishProcessingQaR();
} else if (_interface->getHelp()->getState() != (uint)~0 && _interface->getHelp()->getState()) {
_interface->getHelp()->cleanupAfterFlapping();
}
break;
default:
error("unknown scene event type %d", event.type);
}
}
} // End of namespace Mohawk