diff options
Diffstat (limited to 'engines/saga/script.cpp')
-rw-r--r-- | engines/saga/script.cpp | 806 |
1 files changed, 806 insertions, 0 deletions
diff --git a/engines/saga/script.cpp b/engines/saga/script.cpp new file mode 100644 index 0000000000..3d3a626e9f --- /dev/null +++ b/engines/saga/script.cpp @@ -0,0 +1,806 @@ +/* ScummVM - Scumm Interpreter + * Copyright (C) 2004-2006 The ScummVM project + * + * The ReInherit Engine is (C)2000-2003 by Daniel Balsom. + * + * 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$ + * + */ + +// Scripting module: Script resource handling functions +#include "saga/saga.h" + +#include "saga/gfx.h" +#include "saga/console.h" + +#include "saga/script.h" +#include "saga/stream.h" +#include "saga/interface.h" +#include "saga/itedata.h" +#include "saga/scene.h" +#include "saga/events.h" +#include "saga/actor.h" +#include "saga/objectmap.h" +#include "saga/isomap.h" +#include "saga/rscfile.h" + +namespace Saga { + + + +// Initializes the scripting module. +// Loads script resource look-up table, initializes script data system +Script::Script(SagaEngine *vm) : _vm(vm) { + ResourceContext *resourceContext; + byte *resourcePointer; + size_t resourceLength; + int prevTell; + int i, j; + byte *stringsPointer; + size_t stringsLength; + + //initialize member variables + _abortEnabled = true; + _skipSpeeches = false; + _conversingThread = NULL; + + _firstObjectSet = false; + _secondObjectNeeded = false; + _pendingVerb = getVerbType(kVerbNone); + _currentVerb = getVerbType(kVerbNone); + _stickyVerb = getVerbType(kVerbWalkTo); + _leftButtonVerb = getVerbType(kVerbNone); + _rightButtonVerb = getVerbType(kVerbNone); + _pointerObject = ID_NOTHING; + + _staticSize = 0; + _commonBufferSize = COMMON_BUFFER_SIZE; + _commonBuffer = (byte*)malloc(_commonBufferSize); + memset(_commonBuffer, 0, _commonBufferSize); + + debug(8, "Initializing scripting subsystem"); + // Load script resource file context + _scriptContext = _vm->_resource->getContext(GAME_SCRIPTFILE); + if (_scriptContext == NULL) { + error("Script::Script() script context not found"); + } + + resourceContext = _vm->_resource->getContext(GAME_RESOURCEFILE); + if (resourceContext == NULL) { + error("Script::Script() resource context not found"); + } + + debug(3, "Loading module LUT from resource %i", _vm->getResourceDescription()->moduleLUTResourceId); + _vm->_resource->loadResource(resourceContext, _vm->getResourceDescription()->moduleLUTResourceId, resourcePointer, resourceLength); + + + // Create logical script LUT from resource + if (resourceLength % S_LUT_ENTRYLEN_ITECD == 0) { + _modulesLUTEntryLen = S_LUT_ENTRYLEN_ITECD; + } else if (resourceLength % S_LUT_ENTRYLEN_ITEDISK == 0) { + _modulesLUTEntryLen = S_LUT_ENTRYLEN_ITEDISK; + } else { + error("Script::Script() Invalid script lookup table length (%i)", resourceLength); + } + + // Calculate number of entries + _modulesCount = resourceLength / _modulesLUTEntryLen; + + debug(3, "LUT has %i entries", _modulesCount); + + // Allocate space for logical LUT + _modules = (ModuleData *)malloc(_modulesCount * sizeof(*_modules)); + if (_modules == NULL) { + memoryError("Script::Script()"); + } + + // Convert LUT resource to logical LUT + MemoryReadStreamEndian scriptS(resourcePointer, resourceLength, resourceContext->isBigEndian); + for (i = 0; i < _modulesCount; i++) { + memset(&_modules[i], 0, sizeof(ModuleData)); + + prevTell = scriptS.pos(); + _modules[i].scriptResourceId = scriptS.readUint16(); + _modules[i].stringsResourceId = scriptS.readUint16(); + _modules[i].voicesResourceId = scriptS.readUint16(); + + // Skip the unused portion of the structure + for (j = scriptS.pos(); j < prevTell + _modulesLUTEntryLen; j++) { + if (scriptS.readByte() != 0) + warning("Unused scriptLUT part isn't really unused for LUT %d (pos: %d)", i, j); + } + } + + free(resourcePointer); + + // TODO + // + // In ITE, the "main strings" resource contains both the verb strings + // and the object names. + // + // In IHNM, the "main strings" contains the verb strings, but not the + // object names. At least, I think that's the case. + + _vm->_resource->loadResource(resourceContext, _vm->getResourceDescription()->mainStringsResourceId, stringsPointer, stringsLength); + + _vm->loadStrings(_mainStrings, stringsPointer, stringsLength); + free(stringsPointer); + + setupScriptFuncList(); +} + +// Shut down script module gracefully; free all allocated module resources +Script::~Script() { + + debug(8, "Shutting down scripting subsystem."); + + _mainStrings.freeMem(); + + freeModules(); + free(_modules); + + free(_commonBuffer); +} + +void Script::loadModule(int scriptModuleNumber) { + byte *resourcePointer; + size_t resourceLength; + + // Validate script number + if ((scriptModuleNumber < 0) || (scriptModuleNumber >= _modulesCount)) { + error("Script::loadScript() Invalid script module number"); + } + + if (_modules[scriptModuleNumber].loaded) { + return; + } + + // Initialize script data structure + debug(3, "Loading script module #%d", scriptModuleNumber); + + _vm->_resource->loadResource(_scriptContext, _modules[scriptModuleNumber].scriptResourceId, resourcePointer, resourceLength); + + loadModuleBase(_modules[scriptModuleNumber], resourcePointer, resourceLength); + free(resourcePointer); + + _vm->_resource->loadResource(_scriptContext, _modules[scriptModuleNumber].stringsResourceId, resourcePointer, resourceLength); + + _vm->loadStrings(_modules[scriptModuleNumber].strings, resourcePointer, resourceLength); + free(resourcePointer); + + if (_modules[scriptModuleNumber].voicesResourceId > 0) { + _vm->_resource->loadResource(_scriptContext, _modules[scriptModuleNumber].voicesResourceId, resourcePointer, resourceLength); + + loadVoiceLUT(_modules[scriptModuleNumber].voiceLUT, resourcePointer, resourceLength); + free(resourcePointer); + } + + _modules[scriptModuleNumber].staticOffset = _staticSize; + _staticSize += _modules[scriptModuleNumber].staticSize; + if (_staticSize > _commonBufferSize) { + error("Script::loadModule() _staticSize > _commonBufferSize"); + } + _modules[scriptModuleNumber].loaded = true; +} + +void Script::freeModules() { + int i; + for (i = 0; i < _modulesCount; i++) { + if (_modules[i].loaded) { + _modules[i].freeMem(); + } + } + _staticSize = 0; +} + +void Script::loadModuleBase(ModuleData &module, const byte *resourcePointer, size_t resourceLength) { + int i; + + debug(3, "Loading module base..."); + + module.moduleBase = (byte*)malloc(resourceLength); + module.moduleBaseSize = resourceLength; + + memcpy(module.moduleBase, resourcePointer, resourceLength); + + MemoryReadStreamEndian scriptS(module.moduleBase, module.moduleBaseSize, _scriptContext->isBigEndian); + + module.entryPointsCount = scriptS.readUint16(); + scriptS.readUint16(); //skip + module.entryPointsTableOffset = scriptS.readUint16(); + scriptS.readUint16(); //skip + + if ((module.moduleBaseSize - module.entryPointsTableOffset) < (module.entryPointsCount * SCRIPT_TBLENTRY_LEN)) { + error("Script::loadModuleBase() Invalid table offset"); + } + + if (module.entryPointsCount > SCRIPT_MAX) { + error("Script::loadModuleBase()Script limit exceeded"); + } + + module.entryPoints = (EntryPoint *)malloc(module.entryPointsCount * sizeof(*module.entryPoints)); + if (module.entryPoints == NULL) { + memoryError("Script::loadModuleBase"); + } + + // Read in the entrypoint table + + module.staticSize = scriptS.readUint16(); + while (scriptS.pos() < module.entryPointsTableOffset) + scriptS.readByte(); + + for (i = 0; i < module.entryPointsCount; i++) { + // First uint16 is the offset of the entrypoint name from the start + // of the bytecode resource, second uint16 is the offset of the + // bytecode itself for said entrypoint + module.entryPoints[i].nameOffset = scriptS.readUint16(); + module.entryPoints[i].offset = scriptS.readUint16(); + + // Perform a simple range check on offset values + if ((module.entryPoints[i].nameOffset >= module.moduleBaseSize) || (module.entryPoints[i].offset >= module.moduleBaseSize)) { + error("Script::loadModuleBase() Invalid offset encountered in script entrypoint table"); + } + } +} + +void Script::loadVoiceLUT(VoiceLUT &voiceLUT, const byte *resourcePointer, size_t resourceLength) { + uint16 i; + + voiceLUT.voicesCount = resourceLength / 2; + + voiceLUT.voices = (uint16 *)malloc(voiceLUT.voicesCount * sizeof(*voiceLUT.voices)); + if (voiceLUT.voices == NULL) { + error("Script::loadVoiceLUT() not enough memory"); + } + + MemoryReadStreamEndian scriptS(resourcePointer, resourceLength, _scriptContext->isBigEndian); + + for (i = 0; i < voiceLUT.voicesCount; i++) { + voiceLUT.voices[i] = scriptS.readUint16(); + } +} + +// verb +void Script::showVerb(int statusColor) { + const char *verbName; + const char *object1Name; + const char *object2Name; + char statusString[STATUS_TEXT_LEN]; + + if (_leftButtonVerb == getVerbType(kVerbNone)) { + _vm->_interface->setStatusText(""); + return; + } + + verbName = _mainStrings.getString(_leftButtonVerb - 1); + + if (objectTypeId(_currentObject[0]) == kGameObjectNone) { + _vm->_interface->setStatusText(verbName, statusColor); + return; + } + + object1Name = _vm->getObjectName(_currentObject[0]); + + if (!_secondObjectNeeded) { + snprintf(statusString, STATUS_TEXT_LEN, "%s %s", verbName, object1Name); + _vm->_interface->setStatusText(statusString, statusColor); + return; + } + + + if (objectTypeId(_currentObject[1]) != kGameObjectNone) { + object2Name = _vm->getObjectName(_currentObject[1]); + } else { + object2Name = ""; + } + + if (_leftButtonVerb == getVerbType(kVerbGive)) { + snprintf(statusString, STATUS_TEXT_LEN, _vm->getTextString(kTextGiveTo), object1Name, object2Name); + _vm->_interface->setStatusText(statusString, statusColor); + } else { + if (_leftButtonVerb == getVerbType(kVerbUse)) { + snprintf(statusString, STATUS_TEXT_LEN, _vm->getTextString(kTextUseWidth), object1Name, object2Name); + _vm->_interface->setStatusText(statusString, statusColor); + } else { + snprintf(statusString, STATUS_TEXT_LEN, "%s %s", verbName, object1Name); + _vm->_interface->setStatusText(statusString, statusColor); + } + } +} + +int Script::getVerbType(VerbTypes verbType) { + if (_vm->getGameType() == GType_ITE) { + switch (verbType) { + case kVerbNone: + return kVerbITENone; + case kVerbWalkTo: + return kVerbITEWalkTo; + case kVerbGive: + return kVerbITEGive; + case kVerbUse: + return kVerbITEUse; + case kVerbEnter: + return kVerbITEEnter; + case kVerbLookAt: + return kVerbITELookAt; + case kVerbPickUp: + return kVerbITEPickUp; + case kVerbOpen: + return kVerbITEOpen; + case kVerbClose: + return kVerbITEClose; + case kVerbTalkTo: + return kVerbITETalkTo; + case kVerbWalkOnly: + return kVerbITEWalkOnly; + case kVerbLookOnly: + return kVerbITELookOnly; + case kVerbOptions: + return kVerbITEOptions; + } + } + else { + switch (verbType) { + case kVerbNone: + return kVerbIHNMNone; + case kVerbWalkTo: + return kVerbIHNMWalk; + case kVerbGive: + return kVerbIHNMGive; + case kVerbUse: + return kVerbIHNMUse; + case kVerbEnter: + return kVerbIHNMEnter; + case kVerbLookAt: + return kVerbIHNMLookAt; + case kVerbPickUp: + return kVerbIHNMTake; + case kVerbOpen: + return -2; + case kVerbClose: + return -2; + case kVerbTalkTo: + return kVerbIHNMTalkTo; + case kVerbWalkOnly: + return kVerbIHNMWalkOnly; + case kVerbLookOnly: + return kVerbIHNMLookOnly; + case kVerbOptions: + return kVerbIHNMOptions; + } + } + error("Script::getVerbType() unknown verb type %d", verbType); +} + +void Script::setVerb(int verb) { + _pendingObject[0] = ID_NOTHING; + _currentObject[0] = ID_NOTHING; + _pendingObject[1] = ID_NOTHING; + _currentObject[1] = ID_NOTHING; + _firstObjectSet = false; + _secondObjectNeeded = false; + + // The pointer object will be updated again immediately. This way the + // new verb will be applied to it. It's not exactly how the original + // engine did it, but it appears to work. + _pointerObject = ID_NOTHING; + + setLeftButtonVerb( verb ); + showVerb(); +} + +void Script::setLeftButtonVerb(int verb) { + int oldVerb = _currentVerb; + + _currentVerb = _leftButtonVerb = verb; + + if ((_currentVerb != oldVerb) && (_vm->_interface->getMode() == kPanelMain)){ + if (oldVerb > getVerbType(kVerbNone)) + _vm->_interface->setVerbState(oldVerb, 2); + + if (_currentVerb > getVerbType(kVerbNone)) + _vm->_interface->setVerbState(_currentVerb, 2); + } +} + +void Script::setRightButtonVerb(int verb) { + int oldVerb = _rightButtonVerb; + + _rightButtonVerb = verb; + + if ((_rightButtonVerb != oldVerb) && (_vm->_interface->getMode() == kPanelMain)){ + if (oldVerb > getVerbType(kVerbNone)) + _vm->_interface->setVerbState(oldVerb, 2); + + if (_rightButtonVerb > getVerbType(kVerbNone)) + _vm->_interface->setVerbState(_rightButtonVerb, 2); + } +} + +void Script::doVerb() { + int scriptEntrypointNumber = 0; + int scriptModuleNumber = 0; + int objectType; + Event event; + const char *excuseText; + int excuseSampleResourceId; + const HitZone *hitZone; + + objectType = objectTypeId(_pendingObject[0]); + + if (_pendingVerb == getVerbType(kVerbGive)) { + scriptEntrypointNumber = _vm->_actor->getObjectScriptEntrypointNumber(_pendingObject[1]); + if (_vm->_actor->getObjectFlags(_pendingObject[1]) & (kFollower|kProtagonist|kExtended)) { + scriptModuleNumber = 0; + } else { + scriptModuleNumber = _vm->_scene->getScriptModuleNumber(); + } + } else { + if (_pendingVerb == getVerbType(kVerbUse)) { + if ((objectTypeId(_pendingObject[1]) > kGameObjectNone) && (objectType < objectTypeId(_pendingObject[1]))) { + SWAP(_pendingObject[0], _pendingObject[1]); + objectType = objectTypeId(_pendingObject[0]); + } + } + + if (objectType == kGameObjectHitZone) { + scriptModuleNumber = _vm->_scene->getScriptModuleNumber(); + hitZone = _vm->_scene->_objectMap->getHitZone(objectIdToIndex(_pendingObject[0])); + if ((hitZone->getFlags() & kHitZoneExit) == 0) { + scriptEntrypointNumber = hitZone->getScriptNumber(); + } + } else { + if (objectType & (kGameObjectActor | kGameObjectObject)) { + scriptEntrypointNumber = _vm->_actor->getObjectScriptEntrypointNumber(_pendingObject[0]); + + if ((objectType == kGameObjectActor) && !(_vm->_actor->getObjectFlags(_pendingObject[0]) & (kFollower|kProtagonist|kExtended))) { + scriptModuleNumber = _vm->_scene->getScriptModuleNumber(); + } else { + scriptModuleNumber = 0; + } + } + } + } + + if (scriptEntrypointNumber > 0) { + + event.type = kEvTOneshot; + event.code = kScriptEvent; + event.op = kEventExecNonBlocking; + event.time = 0; + event.param = scriptModuleNumber; + event.param2 = scriptEntrypointNumber; + event.param3 = _pendingVerb; // Action + event.param4 = _pendingObject[0]; // Object + event.param5 = _pendingObject[1]; // With Object + event.param6 = (objectType == kGameObjectActor) ? _pendingObject[0] : ID_PROTAG; // Actor + + _vm->_events->queue(&event); + + } else { + _vm->getExcuseInfo(_pendingVerb, excuseText, excuseSampleResourceId); + if (excuseText) { + // In Floppy versions we don't have excuse texts + if (!(_vm->getFeatures() & GF_CD_FX)) + excuseSampleResourceId = -1; + + _vm->_actor->actorSpeech(ID_PROTAG, &excuseText, 1, excuseSampleResourceId, 0); + } + } + + if ((_currentVerb == getVerbType(kVerbWalkTo)) || (_currentVerb == getVerbType(kVerbLookAt))) { + _stickyVerb = _currentVerb; + } + + _pendingVerb = getVerbType(kVerbNone); + _currentObject[0] = _currentObject[1] = ID_NOTHING; + setLeftButtonVerb(_stickyVerb); + + setPointerVerb(); +} + +void Script::setPointerVerb() { + if (_vm->_interface->isActive()) { + _pointerObject = ID_PROTAG; + whichObject(_vm->mousePos()); + } +} + +void Script::hitObject(bool leftButton) { + int verb; + verb = leftButton ? _leftButtonVerb : _rightButtonVerb; + + if (verb > getVerbType(kVerbNone)) { + if (_firstObjectSet) { + if (_secondObjectNeeded) { + _pendingObject[0] = _currentObject[0]; + _pendingObject[1] = _currentObject[1]; + _pendingVerb = verb; + + _leftButtonVerb = verb; + if (_pendingVerb > getVerbType(kVerbNone)) + showVerb(kITEColorBrightWhite); + else + showVerb(); + + _secondObjectNeeded = false; + _firstObjectSet = false; + return; + } + } else { + if (verb == getVerbType(kVerbGive)) { + _secondObjectNeeded = true; + } else { + if (verb == getVerbType(kVerbUse)) { + + if (_currentObjectFlags[0] & kObjUseWith) { + _secondObjectNeeded = true; + } + } + } + + if (!_secondObjectNeeded) { + _pendingObject[0] = _currentObject[0]; + _pendingObject[1] = ID_NOTHING; + _pendingVerb = verb; + + _secondObjectNeeded = false; + _firstObjectSet = false; + } else { + _firstObjectSet = true; + } + } + + _leftButtonVerb = verb; + if (_pendingVerb > getVerbType(kVerbNone)) + showVerb(kITEColorBrightWhite); + else + showVerb(); + } + +} + +void Script::playfieldClick(const Point& mousePoint, bool leftButton) { + Location pickLocation; + const HitZone *hitZone; + Point specialPoint; + + _vm->_actor->abortSpeech(); + + if ((_vm->_actor->_protagonist->_currentAction != kActionWait) && + (_vm->_actor->_protagonist->_currentAction != kActionFreeze) && + (_vm->_actor->_protagonist->_currentAction != kActionWalkToLink) && + (_vm->_actor->_protagonist->_currentAction != kActionWalkToPoint)) { + return; + } + if (_pendingVerb > getVerbType(kVerbNone)) { + setLeftButtonVerb(getVerbType(kVerbWalkTo)); + } + + if (_pointerObject != ID_NOTHING) { + hitObject( leftButton ); + } else { + _pendingObject[0] = ID_NOTHING; + _pendingObject[1] = ID_NOTHING; + _pendingVerb = getVerbType(kVerbWalkTo); + } + + + // tiled stuff + if (_vm->_scene->getFlags() & kSceneFlagISO) { + _vm->_isoMap->screenPointToTileCoords(mousePoint, pickLocation); + } else { + pickLocation.fromScreenPoint(mousePoint); + } + + + hitZone = NULL; + + if (objectTypeId(_pendingObject[0]) == kGameObjectHitZone) { + hitZone = _vm->_scene->_objectMap->getHitZone(objectIdToIndex(_pendingObject[0])); + } else { + if ((_pendingVerb == getVerbType(kVerbUse)) && (objectTypeId(_pendingObject[1]) == kGameObjectHitZone)) { + hitZone = _vm->_scene->_objectMap->getHitZone(objectIdToIndex(_pendingObject[1])); + } + } + + if (hitZone != NULL) { + if (hitZone->getFlags() & kHitZoneNoWalk) { + _vm->_actor->actorFaceTowardsPoint(ID_PROTAG, pickLocation); + doVerb(); + return; + } + + if (hitZone->getFlags() & kHitZoneProject) { + if (!hitZone->getSpecialPoint(specialPoint)) { + // Original behaved this way and this prevents from crash + // at ruins. See bug #1257459 + specialPoint.x = specialPoint.y = 0; + } + + // tiled stuff + if (_vm->_scene->getFlags() & kSceneFlagISO) { + pickLocation.u() = specialPoint.x; + pickLocation.v() = specialPoint.y; + pickLocation.z = _vm->_actor->_protagonist->_location.z; + } else { + pickLocation.fromScreenPoint(specialPoint); + } + } + } + + if ((_pendingVerb == getVerbType(kVerbWalkTo)) || + (_pendingVerb == getVerbType(kVerbPickUp)) || + (_pendingVerb == getVerbType(kVerbOpen)) || + (_pendingVerb == getVerbType(kVerbClose)) || + (_pendingVerb == getVerbType(kVerbUse))) { + _vm->_actor->actorWalkTo(ID_PROTAG, pickLocation); + } else { + if (_pendingVerb == getVerbType(kVerbLookAt)) { + if (objectTypeId(_pendingObject[0]) != kGameObjectActor ) { + _vm->_actor->actorWalkTo(ID_PROTAG, pickLocation); + } else { + doVerb(); + } + } else { + if ((_pendingVerb == getVerbType(kVerbTalkTo)) || + (_pendingVerb == getVerbType(kVerbGive))) { + doVerb(); + } + } + } +} + +void Script::whichObject(const Point& mousePoint) { + uint16 objectId; + int16 objectFlags; + int newRightButtonVerb; + uint16 newObjectId; + ActorData *actor; + ObjectData *obj; + Point pickPoint; + Location pickLocation; + int hitZoneIndex; + const HitZone * hitZone; + PanelButton * panelButton; + + objectId = ID_NOTHING; + objectFlags = 0; + _leftButtonVerb = _currentVerb; + newRightButtonVerb = getVerbType(kVerbNone); + + if (_vm->_actor->_protagonist->_currentAction != kActionWalkDir) { + if (_vm->_scene->getHeight() >= mousePoint.y) { + newObjectId = _vm->_actor->hitTest(mousePoint, true); + + if (newObjectId != ID_NOTHING) { + if (objectTypeId(newObjectId) == kGameObjectObject) { + objectId = newObjectId; + objectFlags = 0; + newRightButtonVerb = getVerbType(kVerbLookAt); + + if ((_currentVerb == getVerbType(kVerbTalkTo)) || ((_currentVerb == getVerbType(kVerbGive)) && _firstObjectSet)) { + objectId = ID_NOTHING; + newObjectId = ID_NOTHING; + } + } else { + actor = _vm->_actor->getActor(newObjectId); + objectId = newObjectId; + objectFlags = kObjUseWith; + newRightButtonVerb = getVerbType(kVerbTalkTo); + + if ((_currentVerb == getVerbType(kVerbPickUp)) || + (_currentVerb == getVerbType(kVerbOpen)) || + (_currentVerb == getVerbType(kVerbClose)) || + ((_currentVerb == getVerbType(kVerbGive)) && !_firstObjectSet) || + ((_currentVerb == getVerbType(kVerbUse)) && !(actor->_flags & kFollower))) { + objectId = ID_NOTHING; + newObjectId = ID_NOTHING; + } + } + } + + if (newObjectId == ID_NOTHING) { + + pickPoint = mousePoint; + + if (_vm->_scene->getFlags() & kSceneFlagISO) { + pickPoint.y -= _vm->_actor->_protagonist->_location.z; + _vm->_isoMap->screenPointToTileCoords(pickPoint, pickLocation); + pickLocation.toScreenPointUV(pickPoint); + } + + hitZoneIndex = _vm->_scene->_objectMap->hitTest(pickPoint); + + if ((hitZoneIndex != -1)) { + hitZone = _vm->_scene->_objectMap->getHitZone(hitZoneIndex); + objectId = hitZone->getHitZoneId(); + objectFlags = 0; + newRightButtonVerb = hitZone->getRightButtonVerb() & 0x7f; + + if (_vm->getGameType() == GType_ITE) { + + if (newRightButtonVerb == getVerbType(kVerbWalkOnly)) { + if (_firstObjectSet) { + objectId = ID_NOTHING; + } else { + newRightButtonVerb = _leftButtonVerb = getVerbType(kVerbWalkTo); + } + } else { + if (newRightButtonVerb == getVerbType(kVerbLookOnly)) { + if (_firstObjectSet) { + objectId = ID_NOTHING; + } else { + newRightButtonVerb = _leftButtonVerb = getVerbType(kVerbLookAt); + } + } + } + + if (newRightButtonVerb >= getVerbType(kVerbOptions)) { + newRightButtonVerb = getVerbType(kVerbNone); + } + } + + if ((_currentVerb == getVerbType(kVerbTalkTo)) || ((_currentVerb == getVerbType(kVerbGive)) && _firstObjectSet)) { + objectId = ID_NOTHING; + newObjectId = ID_NOTHING; + } + + if ((_leftButtonVerb == getVerbType(kVerbUse)) && (hitZone->getRightButtonVerb() & 0x80)) { + objectFlags = kObjUseWith; + } + } + } + } else { + if ((_currentVerb == getVerbType(kVerbTalkTo)) || ((_currentVerb == getVerbType(kVerbGive)) && _firstObjectSet)) { + // no way + } else { + panelButton = _vm->_interface->inventoryHitTest(mousePoint); + if (panelButton) { + objectId = _vm->_interface->getInventoryContentByPanelButton(panelButton); + if (objectId != 0) { + obj = _vm->_actor->getObj(objectId); + newRightButtonVerb = getVerbType(kVerbLookAt); + if (obj->_interactBits & kObjUseWith) { + objectFlags = kObjUseWith; + } + } + } + } + + if ((_currentVerb == getVerbType(kVerbPickUp)) || (_currentVerb == getVerbType(kVerbTalkTo)) || (_currentVerb == getVerbType(kVerbWalkTo))) { + _leftButtonVerb = getVerbType(kVerbLookAt); + } + } + } + + if (objectId != _pointerObject) { + _pointerObject = objectId; + _currentObject[_firstObjectSet ? 1 : 0] = objectId; + _currentObjectFlags[_firstObjectSet ? 1 : 0] = objectFlags; + if (_pendingVerb == getVerbType(kVerbNone)) { + showVerb(); + } + } + + if (newRightButtonVerb != _rightButtonVerb) { + setRightButtonVerb(newRightButtonVerb); + } +} + +} // End of namespace Saga |