2015-01-11 15:57:04 +01:00

249 lines
6.5 KiB
C++

/* ResidualVM - A 3D game interpreter
*
* ResidualVM is the legal property of its developers, whose names
* are too numerous to list here. Please refer to the AUTHORS
* 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 "engines/stark/resources/script.h"
#include "engines/stark/resources/command.h"
#include "engines/stark/resources/item.h"
#include "engines/stark/services/dialogplayer.h"
#include "engines/stark/services/global.h"
#include "engines/stark/services/services.h"
#include "engines/stark/xrcreader.h"
namespace Stark {
Script::~Script() {
}
Script::Script(Resource *parent, byte subType, uint16 index, const Common::String &name) :
Resource(parent, subType, index, name),
_scriptType(0),
_runEvent(0),
_minChapter(0),
_maxChapter(999),
_shouldResetGameSpeed(false),
_enabled(false),
_nextCommand(nullptr),
_pauseTimeLeft(-1),
_suspendingResource(nullptr) {
_type = TYPE;
}
void Script::readData(XRCReadStream *stream) {
uint32 type = stream->readUint32LE();
_runEvent = stream->readUint32LE();
_minChapter = stream->readUint32LE();
_maxChapter = stream->readUint32LE();
_shouldResetGameSpeed = stream->readBool();
_enabled = type == 0;
switch (_subType) {
case kSubTypeGameEvent:
_scriptType = type == 2 ? kScriptTypePassiveDialog : kScriptTypeOnGameEvent;
break;
case kSubTypePlayerAction:
_scriptType = kScriptTypeOnPlayerAction;
break;
case kSubTypeDialog:
_scriptType = kScriptType4;
break;
default:
error("Unknown script subtype %d for script %s", _subType, getName().c_str());
}
}
void Script::onAllLoaded() {
Resource::onAllLoaded();
reset();
}
void Script::onGameLoop() {
Resource::onGameLoop();
execute(kCallModeGameLoop);
}
void Script::reset() {
_nextCommand = findChildWithSubtype<Command>(Command::kCommandBegin);
}
bool Script::isOnBegin() {
return _nextCommand && _nextCommand->getSubType() == Command::kCommandBegin;
}
bool Script::isOnEnd() {
return _nextCommand && _nextCommand->getSubType() == Command::kCommandEnd;
}
bool Script::isEnabled() {
switch (_scriptType) {
case kScriptTypeOnGameEvent:
case kScriptTypeOnPlayerAction:
return _enabled;
case kScriptType3:
return false;
case kScriptTypePassiveDialog:
case kScriptType4:
return true;
default:
error("Unknown script type %d for script %s", _scriptType, getName().c_str());
}
}
bool Script::shouldExecute(uint32 callMode) {
Global *global = StarkServices::instance().global;
if ((!isEnabled() && isOnBegin()) || !_nextCommand) {
return false; // Don't execute disabled scripts
}
if (callMode == kCallModeGameLoop && !isOnBegin()) {
return true; // Continue previously running script
}
if (_scriptType == kScriptTypeOnGameEvent) {
if (_runEvent == kGameEventOnGameLoop && callMode != kCallModeGameLoop) {
return false; // Wrong call mode for this script
}
if (_runEvent == kGameEventOnEnterLocation && callMode != kCallModeEnterLocation) {
return false; // Wrong call mode for this script
}
if (_runEvent == kGameEventOnExitLocation && callMode != kCallModeExitLocation) {
return false; // Wrong call mode for this script
}
Item *parentItem = findParent<Item>();
if (parentItem && !parentItem->isEnabled()) {
return false; // Disabled parent
}
} else if (_scriptType == kScriptTypePassiveDialog) {
if (callMode != kCallModeDialogCreateSelections || callMode != kCallModeDialogAnswer) {
return false; // Wrong call mode for this script
}
} else if (_scriptType == kScriptTypeOnPlayerAction) {
if (callMode != kCallModePlayerAction) {
return false; // Wrong call mode for this script
}
} else {
return false; // Wrong script type
}
uint32 currentChapter = global->getCurrentChapter();
if (currentChapter < _minChapter || currentChapter > _maxChapter) {
return false; // Wrong chapter
}
return true;
}
bool Script::isSuspended() {
return _pauseTimeLeft >= 0 || _suspendingResource;
}
void Script::updateSuspended() {
if (_pauseTimeLeft >= 0) {
// Decrease the remaining pause time
Global *global = StarkServices::instance().global;
_pauseTimeLeft -= global->getMillisecondsPerGameloop();
} else {
_pauseTimeLeft = -1;
}
if (_suspendingResource) {
// Check if the suspending resource is still active
switch (_suspendingResource->getType().get()) {
case ResourceType::kDialog: {
DialogPlayer *dialogPlayer = StarkServices::instance().dialogPlayer;
if (!dialogPlayer->isRunning()) {
// Resume the script execution if the dialog is complete
_suspendingResource = nullptr;
}
break;
}
default:
error("Unhandled suspending resource type %s", _suspendingResource->getType().getName());
}
}
if (!isSuspended()) {
// Resume to the next command
_nextCommand = _nextCommand->nextCommand();
}
}
void Script::pause(int32 msecs) {
_pauseTimeLeft = msecs;
}
void Script::suspend(Resource *cause) {
_suspendingResource = cause;
}
void Script::execute(uint32 callMode) {
if (!shouldExecute(callMode)) {
return;
}
if (isSuspended()) {
// If the script is suspended, check if it can be resumed
updateSuspended();
}
uint32 executedCommands = 0;
while (1) {
if (isSuspended()) {
break;
}
_nextCommand = _nextCommand->execute(callMode, this);
executedCommands++;
if (!_nextCommand) {
break; // No next command, stop here
}
if (isOnEnd()) {
break; // Reached the end of the script
}
if (executedCommands > 50) {
break; // Too many consecutive commands
}
}
if (isOnEnd()) {
// Reset ended scripts so they can be started again
reset();
}
}
void Script::printData() {
debug("scriptType: %d", _scriptType);
debug("runEvent: %d", _runEvent);
debug("minChapter: %d", _minChapter);
debug("maxChapter: %d", _maxChapter);
debug("shouldResetGameSpeed: %d", _shouldResetGameSpeed);
}
} // End of namespace Stark