mirror of
https://github.com/libretro/scummvm.git
synced 2024-12-13 21:31:53 +00:00
1245 lines
35 KiB
C++
1245 lines
35 KiB
C++
/* 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 3 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, see <http://www.gnu.org/licenses/>.
|
|
*
|
|
*/
|
|
|
|
#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"
|
|
#include "common/system.h"
|
|
#include "common/textconsole.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 = nullptr;
|
|
_restFeature = nullptr;
|
|
_talkFeature = nullptr;
|
|
|
|
_talkFeature1 = nullptr;
|
|
_talkFeature2 = nullptr;
|
|
_talkFeature3 = nullptr;
|
|
_lastTime1 = 0;
|
|
_lastTime2 = 0;
|
|
_lastTime3 = 0;
|
|
|
|
_unknown1 = _unknown2 = _unknown3 = 0;
|
|
_enabled = false;
|
|
_nextCue = 0;
|
|
_waveStatus = 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 = nullptr;
|
|
}
|
|
|
|
if (restpos)
|
|
setupRestPos();
|
|
}
|
|
|
|
void CSTimeChar::setupRestPos() {
|
|
if (_unknown1 == 0xffff || !_unknown1 || !_unknown2)
|
|
return;
|
|
|
|
if (!_restFeature) {
|
|
uint id = _enabled ? 0 : 13;
|
|
uint32 flags = kFeatureSortStatic | kFeatureNewNoLoop | kFeatureNewDisableOnReset;
|
|
Feature *feature = _vm->getView()->installViewFeature(getChrBaseId() + id, flags, nullptr);
|
|
// 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 (_talkFeature2) // original checks unknown1 > 1, but this is silly when e.g. _enabled is false
|
|
_vm->getView()->removeFeature(_talkFeature2, true);
|
|
}
|
|
|
|
if (_restFeature)
|
|
_vm->getView()->removeFeature(_restFeature, true);
|
|
|
|
_talkFeature1 = nullptr;
|
|
_talkFeature2 = nullptr;
|
|
_talkFeature3 = nullptr;
|
|
|
|
_talkFeature = nullptr;
|
|
_restFeature = nullptr;
|
|
}
|
|
|
|
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, nullptr);
|
|
// 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 = nullptr;
|
|
}
|
|
|
|
void CSTimeChar::startFlapping(uint16 id) {
|
|
if (!_unknown2)
|
|
return;
|
|
|
|
_scene->_activeChar = this;
|
|
if (_restFeature) {
|
|
_vm->getView()->removeFeature(_restFeature, true);
|
|
_restFeature = nullptr;
|
|
}
|
|
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, nullptr);
|
|
// 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, nullptr);
|
|
|
|
_talkFeature3 = _vm->getView()->installViewFeature(getChrBaseId() + (_enabled ? 4 : 15), flags, nullptr);
|
|
if (_enabled) {
|
|
_talkFeature1 = _vm->getView()->installViewFeature(getChrBaseId() + 2, flags, nullptr);
|
|
if (_unknown1 > 1) {
|
|
_talkFeature2 = _vm->getView()->installViewFeature(getChrBaseId() + 10, flags, nullptr);
|
|
}
|
|
}
|
|
// 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 *iface = _vm->getInterface();
|
|
CSTimeInventoryDisplay *invDisplay = iface->getInventoryDisplay();
|
|
if (invDisplay->getState() == 4) {
|
|
invDisplay->hide();
|
|
invDisplay->setState(0);
|
|
}
|
|
|
|
setState((uint)~0);
|
|
_currHover = 0xffff;
|
|
|
|
iface->clearTextLine();
|
|
iface->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 != 0xffff) {
|
|
if (_vm->getInterface()->cursorGetShape() != 3) {
|
|
_vm->getInterface()->cursorSetShape(1, true);
|
|
if (_vm->getInterface()->getInventoryDisplay()->getState() != 4)
|
|
unhighlightLine(_currHover);
|
|
}
|
|
_currHover = 0xffff;
|
|
}
|
|
}
|
|
|
|
void CSTimeConversation::mouseUp(Common::Point &pos) {
|
|
if (_vm->getInterface()->getInventoryDisplay()->getState() == 4)
|
|
return;
|
|
|
|
if (_currEntry == 0xffff)
|
|
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 = (uint)~0;
|
|
_talkCount = 0;
|
|
_sourceChar = 0xffff;
|
|
_currHover = 0xffff;
|
|
_currEntry = 0xffff;
|
|
_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::Path(Common::String::format("Cases/C%dText", id)));
|
|
// We load this early, so we can use the text for debugging.
|
|
loadRolloverText();
|
|
|
|
_vm->loadResourceFile(Common::Path(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::Path(Common::String::format("Cases/C%dArt", id)));
|
|
_vm->loadResourceFile(Common::Path(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 = 0xffff;
|
|
}
|
|
|
|
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 = nullptr;
|
|
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();
|
|
invObj->featureDisabled = false;
|
|
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) {
|
|
_visitCount = 0;
|
|
_activeChar = nullptr;
|
|
_currHotspot = 0xffff;
|
|
_hoverHotspot = 0xffff;
|
|
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 = nullptr;
|
|
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, nullptr);
|
|
_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 = 0xffff;
|
|
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 = 0xffff;
|
|
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 = 0xffff;
|
|
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 == 0xffff)
|
|
_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);
|
|
invObj->featureDisabled = false;
|
|
_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;
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (_hoverHotspot == 0xffff)
|
|
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 = 0xffff;
|
|
}
|
|
|
|
void CSTimeScene::mouseUp(Common::Point &pos) {
|
|
// TODO: if sailing puzzle is active, return
|
|
|
|
if (_currHotspot == 0xffff) {
|
|
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() == kCSTimeInterfaceDroppedInventory;
|
|
}
|
|
|
|
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
|