Moved engines to the new engines/ directory
svn-id: r20582
This commit is contained in:
parent
2a9a0d4211
commit
26ee630756
531 changed files with 454 additions and 454 deletions
806
engines/saga/script.cpp
Normal file
806
engines/saga/script.cpp
Normal file
|
@ -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
|
Loading…
Add table
Add a link
Reference in a new issue