mirror of
https://github.com/scummvm/scummvm.git
synced 2026-06-20 05:45:29 +00:00
754 lines
28 KiB
C++
754 lines
28 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/command.h"
|
|
|
|
#include "engines/stark/debug.h"
|
|
#include "engines/stark/formats/xrc.h"
|
|
#include "engines/stark/resources/animscript.h"
|
|
#include "engines/stark/resources/bookmark.h"
|
|
#include "engines/stark/resources/bonesmesh.h"
|
|
#include "engines/stark/resources/dialog.h"
|
|
#include "engines/stark/resources/floorfield.h"
|
|
#include "engines/stark/resources/fmv.h"
|
|
#include "engines/stark/resources/item.h"
|
|
#include "engines/stark/resources/knowledge.h"
|
|
#include "engines/stark/resources/script.h"
|
|
#include "engines/stark/resources/sound.h"
|
|
#include "engines/stark/resources/speech.h"
|
|
#include "engines/stark/resources/textureset.h"
|
|
#include "engines/stark/services/services.h"
|
|
#include "engines/stark/services/dialogplayer.h"
|
|
#include "engines/stark/services/resourceprovider.h"
|
|
|
|
#include "engines/stark/ui.h"
|
|
|
|
#include "common/random.h"
|
|
|
|
namespace Stark {
|
|
namespace Resources {
|
|
|
|
Command::~Command() {
|
|
}
|
|
|
|
Command::Command(Object *parent, byte subType, uint16 index, const Common::String &name) :
|
|
Object(parent, subType, index, name) {
|
|
_type = TYPE;
|
|
}
|
|
|
|
Command *Command::execute(uint32 callMode, Script *script) {
|
|
switch (_subType) {
|
|
case kCommandBegin:
|
|
return opScriptBegin();
|
|
case kScriptCall:
|
|
return opScriptCall(script, _arguments[1].referenceValue, _arguments[2].intValue);
|
|
case kDialogCall:
|
|
return opDialogCall(script, _arguments[1].referenceValue, _arguments[2].intValue);
|
|
case kSetInteractiveMode:
|
|
return opSetInteractiveMode(_arguments[1].intValue);
|
|
case kLocationGoTo:
|
|
return opLocationGoTo(_arguments[0].stringValue, _arguments[1].stringValue, _arguments[2].referenceValue, _arguments[3].intValue);
|
|
case kScriptPause:
|
|
return opScriptPause(script, _arguments[1].referenceValue);
|
|
case kWalkTo:
|
|
return opWalkTo(_arguments[1].intValue, _arguments[2].referenceValue, _arguments[3].intValue);
|
|
case kGameLoop:
|
|
return opGameLoop(_arguments[1].intValue);
|
|
case kScriptPauseRandom:
|
|
return opPauseRandom(script, _arguments[1].referenceValue);
|
|
case kExit2DLocation:
|
|
return opExit2DLocation(script);
|
|
case kGoto2DLocation:
|
|
return opGoto2DLocation(_arguments[0].stringValue, _arguments[1].stringValue);
|
|
case kRumbleScene:
|
|
return opRumbleScene(_arguments[1].intValue, _arguments[2].intValue);
|
|
case kFadeScene:
|
|
return opFadeScene(_arguments[1].intValue, _arguments[2].intValue, _arguments[3].intValue);
|
|
case kItem3DPlaceOn:
|
|
return opItem3DPlaceOn(_arguments[1].referenceValue, _arguments[2].referenceValue);
|
|
case kItem3DWalkTo:
|
|
return opItem3DWalkTo(_arguments[1].referenceValue, _arguments[2].referenceValue, _arguments[3].intValue);
|
|
case kItemLookAt:
|
|
return opItemLookAt(_arguments[1].referenceValue, _arguments[2].referenceValue, _arguments[3].intValue, _arguments[4].intValue);
|
|
case kItemEnable:
|
|
return opItemEnable(_arguments[1].referenceValue, _arguments[2].intValue);
|
|
case kItemSetActivity:
|
|
return opItemSetActivity(_arguments[1].referenceValue, _arguments[2].intValue, _arguments[3].intValue);
|
|
case kUseAnimHierarchy:
|
|
return opUseAnimHierachy(_arguments[1].referenceValue);
|
|
case kPlayAnimation:
|
|
return opPlayAnimation(_arguments[1].referenceValue, _arguments[2].intValue);
|
|
case kShowPlay:
|
|
return opShowPlay(script, _arguments[1].referenceValue, _arguments[2].intValue);
|
|
case kScriptEnable:
|
|
return opScriptEnable(_arguments[1].referenceValue, _arguments[2].intValue);
|
|
case kSetBoolean:
|
|
return opSetBoolean(_arguments[1].referenceValue, _arguments[2].intValue);
|
|
case kSetInteger:
|
|
return opSetInteger(_arguments[1].referenceValue, _arguments[2].intValue);
|
|
case kEnableFloorField:
|
|
return opEnableFloorField(_arguments[1].referenceValue, _arguments[2].intValue);
|
|
case kPlayAnimScriptItem:
|
|
return opPlayAnimScriptItem(_arguments[1].referenceValue, _arguments[2].intValue);
|
|
case kSoundPlay:
|
|
return opSoundPlay(script, _arguments[1].referenceValue, _arguments[2].intValue);
|
|
case kLookDirection:
|
|
return opLookDirection(_arguments[1].referenceValue, _arguments[2].intValue, _arguments[3].intValue);
|
|
case kStopPlayingSound:
|
|
return opStopPlayingSound(_arguments[1].referenceValue);
|
|
case kGoLayer:
|
|
return opGoLayer(_arguments[1].referenceValue);
|
|
case kScrollSet:
|
|
return opScrollSet(_arguments[1].referenceValue);
|
|
case kPlayFullMotionVideo:
|
|
return opPlayFullMotionVideo(script, _arguments[1].referenceValue, _arguments[2].intValue);
|
|
case kEnableDiaryEntry:
|
|
return opEnableDiaryEntry(_arguments[1].referenceValue);
|
|
case kChangeSound:
|
|
return opChangeSound(_arguments[1].referenceValue, _arguments[2].intValue, _arguments[3].intValue, _arguments[4].intValue, _arguments[5].intValue);
|
|
case kItem3DRunTo:
|
|
return opItem3DRunTo(_arguments[1].referenceValue, _arguments[2].referenceValue, _arguments[3].intValue);
|
|
case kItemPlaceDirection:
|
|
return opItemPlaceDirection(_arguments[1].referenceValue, _arguments[2].intValue);
|
|
case kActivateTexture:
|
|
return opActivateTexture(_arguments[1].referenceValue);
|
|
case kActivateMesh:
|
|
return opActivateMesh(_arguments[1].referenceValue);
|
|
case kSetTarget:
|
|
return opSetTarget(_arguments[1].referenceValue, _arguments[2].referenceValue);
|
|
case kSpeakWithoutTalking:
|
|
return opSpeakWithoutTalking(script, _arguments[1].referenceValue, _arguments[2].intValue);
|
|
case kIsOnFloorField:
|
|
return opIsOnFloorField(_arguments[2].referenceValue, _arguments[3].referenceValue);
|
|
case kIsItemEnabled:
|
|
return opIsItemEnabled(_arguments[2].referenceValue);
|
|
case kIsSet:
|
|
return opIsSet(_arguments[2].referenceValue);
|
|
case kIsIntegerInRange:
|
|
return opIsIntegerInRange(_arguments[2].referenceValue, _arguments[3].intValue, _arguments[4].intValue);
|
|
case kIsIntegerAbove:
|
|
return opIsIntegerAbove(_arguments[2].referenceValue, _arguments[3].intValue);
|
|
case kIsIntegerEqual:
|
|
return opIsIntegerEqual(_arguments[2].referenceValue, _arguments[3].intValue);
|
|
case kIsIntegerLower:
|
|
return opIsIntegerLower(_arguments[2].referenceValue, _arguments[3].intValue);
|
|
case kIsScriptActive:
|
|
return opIsScriptActive(_arguments[2].referenceValue);
|
|
case kIsRandom:
|
|
return opIsRandom(_arguments[2].intValue);
|
|
case kIsOnPlace:
|
|
return opIsOnPlace(_arguments[0].intValue, _arguments[1].intValue, _arguments[2].referenceValue, _arguments[3].referenceValue);
|
|
case kIsOnNearPlace:
|
|
return opIsOnNearPlace(_arguments[0].intValue, _arguments[1].intValue, _arguments[2].referenceValue, _arguments[3].referenceValue, _arguments[4].intValue);
|
|
case kIsAnimPlaying:
|
|
return opIsAnimPlaying(_arguments[0].intValue, _arguments[1].intValue, _arguments[2].referenceValue);
|
|
case kIsAnimAtTime:
|
|
return opIsAnimAtTime(_arguments[0].intValue, _arguments[1].intValue, _arguments[2].referenceValue, _arguments[3].intValue);
|
|
default:
|
|
warning("Unimplemented command %d - %s", _subType, _name.c_str());
|
|
printData();
|
|
break;
|
|
}
|
|
|
|
return nextCommand();
|
|
}
|
|
|
|
Command *Command::opScriptBegin() {
|
|
return nextCommand();
|
|
}
|
|
|
|
Command *Command::opScriptCall(Script *script, const ResourceReference &scriptRef, int32 synchronous) {
|
|
Script *calleeScript = scriptRef.resolve<Script>();
|
|
|
|
if (synchronous) {
|
|
// Store the current command for use when the callee's execution ends
|
|
script->addReturnObject(this);
|
|
|
|
// Run the callee with the current script's execution context
|
|
return calleeScript->getBeginCommand();
|
|
} else {
|
|
// Kickstart the callee script by skipping its Begin command, overriding all checks
|
|
// Both scripts will continue in parallel
|
|
calleeScript->goToNextCommand();
|
|
return nextCommand();
|
|
}
|
|
}
|
|
|
|
Command *Command::opDialogCall(Script *script, const ResourceReference &dialogRef, int32 suspend) {
|
|
DialogPlayer *dialogPlayer = StarkServices::instance().dialogPlayer;
|
|
|
|
Dialog *dialog = dialogRef.resolve<Dialog>();
|
|
dialogPlayer->run(dialog);
|
|
|
|
if (suspend) {
|
|
script->suspend(dialog);
|
|
return this; // Stay on the same command while suspended
|
|
} else {
|
|
return nextCommand();
|
|
}
|
|
}
|
|
|
|
Command *Command::opSetInteractiveMode(bool enabled) {
|
|
assert(_arguments.size() == 2);
|
|
warning("(TODO: Implement) opSetInteractiveMode(%d)", enabled);
|
|
return nextCommand();
|
|
}
|
|
|
|
Command *Command::opLocationGoTo(const Common::String &level, const Common::String &location, const ResourceReference &bookmarkRef, int32 direction) {
|
|
ResourceProvider *resourceProvider = StarkServices::instance().resourceProvider;
|
|
|
|
uint levelIndex = strtol(level.c_str(), nullptr, 16);
|
|
uint locationIndex = strtol(location.c_str(), nullptr, 16);
|
|
resourceProvider->requestLocationChange(levelIndex, locationIndex);
|
|
resourceProvider->setNextLocationPosition(bookmarkRef, direction);
|
|
|
|
return nullptr;
|
|
}
|
|
|
|
|
|
Command *Command::opScriptPause(Script *script, const ResourceReference &durationRef) {
|
|
Knowledge *duration = durationRef.resolve<Knowledge>();
|
|
script->pause(duration->getIntegerValue());
|
|
|
|
return this; // Stay on this command while the script is suspended
|
|
}
|
|
|
|
Command *Command::opWalkTo(int32 unknown, const ResourceReference &bookmarkRef, int32 unknown2) {
|
|
assert(_arguments.size() == 4);
|
|
Object *target = bookmarkRef.resolve<Object>();
|
|
warning("(TODO: Implement) opWalkTo(%d %s %d) : %s", unknown, target->getName().c_str(), unknown2, bookmarkRef.describe().c_str());
|
|
|
|
return nextCommand();
|
|
}
|
|
|
|
Command *Command::opGameLoop(int32 unknown) {
|
|
assert(_arguments.size() == 2);
|
|
assert(_arguments[1].type == Argument::kTypeInteger1 || _arguments[1].type == Argument::kTypeInteger2);
|
|
warning("(TODO: Implement) opGameLoop(%d)", unknown);
|
|
|
|
return nextCommand();
|
|
}
|
|
|
|
Command *Command::opPauseRandom(Script *script, const ResourceReference &ref) {
|
|
Knowledge *duration = ref.resolve<Knowledge>();
|
|
warning("(TODO: Implement) Pause random: %d, %s", duration->getIntegerValue(), ref.describe().c_str());
|
|
// TODO: Actually get a random value here.
|
|
script->pause(1000);
|
|
return this; // Stay on this command while the script is suspended
|
|
}
|
|
|
|
Command *Command::opExit2DLocation(Script *script) {
|
|
warning("(TODO: Implement) Exit 2D Location");
|
|
StarkServices::instance().resourceProvider->returnToPushedLocation();
|
|
return nullptr;
|
|
}
|
|
|
|
Command *Command::opGoto2DLocation(const Common::String &level, const Common::String &location) {
|
|
ResourceProvider *resourceProvider = StarkServices::instance().resourceProvider;
|
|
|
|
warning("TODO: Implement) opGoto2DLocation");
|
|
// TODO: This needs to be handled differently, to allow exiting.
|
|
uint levelIndex = strtol(level.c_str(), nullptr, 16);
|
|
uint locationIndex = strtol(location.c_str(), nullptr, 16);
|
|
resourceProvider->pushAndChangeLocation(levelIndex, locationIndex);
|
|
return nullptr;
|
|
}
|
|
|
|
Command *Command::opRumbleScene(int32 unknown1, int32 unknown2) {
|
|
warning("(TODO: Implement) opRumble(%d, %d)", unknown1, unknown2);
|
|
|
|
return nextCommand();
|
|
}
|
|
|
|
Command *Command::opFadeScene(int32 unknown1, int32 unknown2, int32 unknown3) {
|
|
warning("(TODO: Implement) opFadeScene(%d, %d, %d) : %s", unknown1, unknown2, unknown3, getName().c_str());
|
|
|
|
return nextCommand();
|
|
}
|
|
|
|
Command *Command::opItem3DPlaceOn(const ResourceReference &itemRef, const ResourceReference &targetRef) {
|
|
FloorPositionedItem *item = itemRef.resolve<FloorPositionedItem>();
|
|
Object *target = targetRef.resolve<Object>();
|
|
|
|
switch (target->getType().get()) {
|
|
case Type::kBookmark:
|
|
item->placeOnBookmark(Object::cast<Bookmark>(target));
|
|
break;
|
|
default:
|
|
warning("Unimplemented op3DPlaceOn target type %s", target->getType().getName());
|
|
}
|
|
|
|
return nextCommand();
|
|
}
|
|
|
|
Command *Command::opItem3DWalkTo(const ResourceReference &itemRef, const ResourceReference &targetRef, int32 unknown) {
|
|
assert(_arguments.size() == 4);
|
|
Object *item = itemRef.resolve<Object>();
|
|
Object *target = targetRef.resolve<Object>();
|
|
warning("(TODO: Implement) opItem3DWalkTo(%s, %s, %d), %s : %s", item->getName().c_str(), target->getName().c_str(), unknown, itemRef.describe().c_str(), targetRef.describe().c_str());
|
|
|
|
return nextCommand();
|
|
}
|
|
|
|
Command *Command::opItemLookAt(const ResourceReference &itemRef1, const ResourceReference &itemRef2, int32 unknown1, int32 unknown2) {
|
|
assert(_arguments.size() == 5);
|
|
Object *item1 = itemRef1.resolve<Object>();
|
|
Object *item2 = itemRef2.resolve<Object>();
|
|
warning("(TODO: Implement) opItemLookAt(%s, %s, %d, %d), %s : %s", item1->getName().c_str(), item2->getName().c_str(), unknown1, unknown2, itemRef1.describe().c_str(), itemRef2.describe().c_str());
|
|
|
|
return nextCommand();
|
|
}
|
|
|
|
Command *Command::opItemEnable(const ResourceReference &itemRef, int32 enable) {
|
|
Item *item = itemRef.resolve<Item>();
|
|
|
|
bool previousState = item->isEnabled();
|
|
|
|
switch (enable) {
|
|
case 0:
|
|
item->setEnabled(false);
|
|
break;
|
|
case 1:
|
|
if (!previousState) {
|
|
item->setEnabled(true);
|
|
}
|
|
break;
|
|
case 2:
|
|
item->setEnabled(!previousState);
|
|
break;
|
|
default:
|
|
warning("Unhandled item enable comamnd %d", enable);
|
|
break;
|
|
}
|
|
|
|
return nextCommand();
|
|
}
|
|
|
|
Command *Command::opItemSetActivity(const ResourceReference &itemRef, int32 unknown1, int32 unknown2) {
|
|
assert(_arguments.size() == 4);
|
|
Object *itemObj = itemRef.resolve<Object>();
|
|
warning("(TODO: Implement) opSetActivity(%s, %d, %d) : %s", itemObj->getName().c_str(), unknown1, unknown2, itemRef.describe().c_str());
|
|
|
|
return nextCommand();
|
|
}
|
|
|
|
Command *Command::opUseAnimHierachy(const ResourceReference &animHierRef) {
|
|
assert(_arguments.size() == 2);
|
|
Object *animHier = animHierRef.resolve<Object>();
|
|
warning("(TODO: Implement) opUseAnimHierarchy(%s) : %s", animHier->getName().c_str(), animHierRef.describe().c_str());
|
|
|
|
return nextCommand();
|
|
}
|
|
|
|
Command *Command::opPlayAnimation(const ResourceReference &animRef, int32 unknown) {
|
|
assert(_arguments.size() == 3);
|
|
Object *anim = animRef.resolve<Object>();
|
|
warning("(TODO: Implement) opPlayAnimation(%s, %d) : %s", anim->getName().c_str(), unknown, animRef.describe().c_str());
|
|
|
|
return nextCommand();
|
|
}
|
|
|
|
Command *Command::opScriptEnable(const ResourceReference &scriptRef, int32 enable) {
|
|
assert(_arguments.size() == 3);
|
|
Script *script = scriptRef.resolve<Script>();
|
|
warning("(TODO: Implement) opScriptEnable(%s, %d) : %s", script->getName().c_str(), enable, scriptRef.describe().c_str());
|
|
|
|
script->enable(enable);
|
|
|
|
return nextCommand();
|
|
}
|
|
|
|
Command *Command::opShowPlay(Script *script, const ResourceReference &ref, int32 suspend) {
|
|
assert(_arguments.size() == 3);
|
|
Speech *speechObj = ref.resolve<Speech>();
|
|
assert(speechObj->getType().get() == Type::kSpeech);
|
|
DialogPlayer *dialogPlayer = StarkServices::instance().dialogPlayer;
|
|
dialogPlayer->playSingle(speechObj);
|
|
warning("(TODO: Implement) opShowPlay(%s %d) %s : %s", speechObj->getName().c_str(), suspend, speechObj->getPhrase().c_str(), ref.describe().c_str());
|
|
|
|
if (suspend) {
|
|
script->suspend(speechObj);
|
|
return this; // Stay on the same command while suspended
|
|
} else {
|
|
return nextCommand();
|
|
}
|
|
}
|
|
|
|
Command *Command::opSetBoolean(const ResourceReference &knowledgeRef, int32 value) {
|
|
assert(_arguments.size() == 3);
|
|
Knowledge *boolean = knowledgeRef.resolve<Knowledge>();
|
|
warning("(TODO: Implement) opSetBoolean(%s, %d) : %s", boolean->getName().c_str(), value, knowledgeRef.describe().c_str());
|
|
|
|
// This seems to have no effect currently, perhaps because the location is reloaded
|
|
boolean->setBooleanValue(value);
|
|
|
|
return nextCommand();
|
|
}
|
|
|
|
Command *Command::opSetInteger(const ResourceReference &knowledgeRef, int32 value) {
|
|
assert(_arguments.size() == 3);
|
|
Knowledge *integer = knowledgeRef.resolve<Knowledge>();
|
|
warning("(TODO: Implement) opSetInteger(%s, %d) : %s", integer->getName().c_str(), value, knowledgeRef.describe().c_str());
|
|
|
|
// This seems to have no effect currently, perhaps because the location is reloaded
|
|
integer->setIntegerValue(value);
|
|
|
|
return nextCommand();
|
|
}
|
|
|
|
Command *Command::opEnableFloorField(const ResourceReference &floorFieldRef, int32 value) {
|
|
assert(_arguments.size() == 3);
|
|
Object *floorFieldObj = floorFieldRef.resolve<Object>();
|
|
warning("(TODO: Implement) opEnableFloorField(%s, %d) : %s", floorFieldObj->getName().c_str(), value, floorFieldRef.describe().c_str());
|
|
|
|
return nextCommand();
|
|
}
|
|
|
|
Command *Command::opPlayAnimScriptItem(const ResourceReference &animScriptItemRef, int32 value) {
|
|
assert(_arguments.size() == 3);
|
|
Object *animScriptItemObj = animScriptItemRef.resolve<Object>();
|
|
|
|
AnimScript *animScript = animScriptItemObj->findParent<AnimScript>();
|
|
assert(animScript);
|
|
animScript->setCurrentIndex(animScriptItemObj->getIndex());
|
|
// TODO: What is the value good for?
|
|
warning("(TODO: Implement) opPlayAnimScriptItem(%s, %d) : %s", animScriptItemObj->getName().c_str(), value, animScriptItemRef.describe().c_str());
|
|
return nextCommand();
|
|
}
|
|
|
|
Command *Command::opSoundPlay(Script *script, const ResourceReference &soundRef, int32 suspend) {
|
|
Sound *sound = soundRef.resolve<Sound>();
|
|
sound->play();
|
|
|
|
if (suspend) {
|
|
script->suspend(sound);
|
|
return this; // Stay on the same command while suspended
|
|
} else {
|
|
return nextCommand();
|
|
}
|
|
}
|
|
|
|
Command *Command::opLookDirection(const ResourceReference &itemRef, int32 unknown1, int32 unknown2) {
|
|
assert(_arguments.size() == 4);
|
|
Object *itemObj = itemRef.resolve<Object>();
|
|
warning("(TODO: Implement) opLookDirection(%s %d %d) : %s", itemObj->getName().c_str(), unknown1, unknown2, itemRef.describe().c_str());
|
|
|
|
return nextCommand();
|
|
}
|
|
|
|
Command *Command::opStopPlayingSound(const ResourceReference &soundRef) {
|
|
assert(_arguments.size() == 2);
|
|
Object *soundObj = soundRef.resolve<Object>();
|
|
warning("(TODO: Implement) opStopPlayingSound(%s) : %s", soundObj->getName().c_str(), soundRef.describe().c_str());
|
|
|
|
return nextCommand();
|
|
}
|
|
|
|
Command *Command::opGoLayer(const ResourceReference &layerRef) {
|
|
Object *layerObj = layerRef.resolve<Object>();
|
|
warning("(TODO: Implement) opGoLayer(%s) : %s", layerObj->getName().c_str(), layerRef.describe().c_str());
|
|
|
|
return nextCommand();
|
|
}
|
|
|
|
Command *Command::opScrollSet(const ResourceReference &scrollRef) {
|
|
assert(_arguments.size() == 2);
|
|
Object *scroll = scrollRef.resolve<Object>();
|
|
warning("(TODO: Implement) opScrollSet(%s) : %s", scroll->getName().c_str(), scrollRef.describe().c_str());
|
|
|
|
return nextCommand();
|
|
}
|
|
|
|
Command *Command::opPlayFullMotionVideo(Script *script, const ResourceReference &movieRef, int32 unknown) {
|
|
FMV *movie = movieRef.resolve<FMV>();
|
|
warning("(TODO: Implement) opPlayFullMotionVideo(%s) : %s - %d", movie->getName().c_str(), movieRef.describe().c_str(), unknown);
|
|
StarkServices::instance().ui->notifyFMVRequest(movie->getFilename());
|
|
// TODO: Is this unconditional suspension?
|
|
script->suspend(movie);
|
|
return this; // Stay on the same command while suspended
|
|
}
|
|
|
|
Command *Command::opEnableDiaryEntry(const ResourceReference &knowledgeRef) {
|
|
assert(_arguments.size() == 2);
|
|
Knowledge *entry = knowledgeRef.resolve<Knowledge>();
|
|
warning("(TODO: Implement) opEnableDiaryEntry(%s) : %s", entry->getName().c_str(), knowledgeRef.describe().c_str());
|
|
|
|
return nextCommand();
|
|
}
|
|
|
|
Command *Command::opChangeSound(const ResourceReference &soundRef, int32 unknown1, int32 unknown2, int32 unknown3, int32 unknown4) {
|
|
assert(_arguments.size() == 6);
|
|
Object *sound = soundRef.resolve<Object>();
|
|
warning("(TODO: Implement) opChangeSound(%s, %d, %d, %d, %d) : %s", sound->getName().c_str(), unknown1, unknown2, unknown3, unknown4, soundRef.describe().c_str());
|
|
return nextCommand();
|
|
}
|
|
|
|
Command *Command::opItem3DRunTo(const ResourceReference &itemRef, const ResourceReference &bookmarkRef, int32 unknown) {
|
|
assert(_arguments.size() == 4);
|
|
Object *itemObj = itemRef.resolve<Object>();
|
|
Object *bookmarkObj = bookmarkRef.resolve<Object>();
|
|
|
|
warning("(TODO: Implement) opItem3DRunTo(%s, %s, %d) %s : %s", itemObj->getName().c_str(), bookmarkObj->getName().c_str(),unknown, itemRef.describe().c_str(), bookmarkRef.describe().c_str());
|
|
|
|
return nextCommand();
|
|
}
|
|
|
|
Command *Command::opItemPlaceDirection(const ResourceReference &itemRef, int32 direction) {
|
|
FloorPositionedItem *item = itemRef.resolve<FloorPositionedItem>();
|
|
|
|
item->setDirection(abs(direction) % 360);
|
|
|
|
return nextCommand();
|
|
}
|
|
|
|
Command *Command::opActivateTexture(const ResourceReference &textureRef) {
|
|
TextureSet *texture = textureRef.resolve<TextureSet>();
|
|
Item *item = texture->findParent<Item>();
|
|
|
|
if (!item || (item->getSubType() != Item::kItemGlobalTemplate && item->getSubType() != Item::kItemLevelTemplate && item->getSubType() != Item::kItemMesh)) {
|
|
return nextCommand();
|
|
}
|
|
|
|
if (item->getSubType() == Item::kItemMesh) {
|
|
MeshItem *item10 = Object::cast<MeshItem>(item);
|
|
item10->setTexture(texture->getIndex(), texture->getSubType());
|
|
} else {
|
|
ItemTemplate *item13 = Object::cast<ItemTemplate>(item);
|
|
item13->setTexture(texture->getIndex(), texture->getSubType());
|
|
}
|
|
|
|
return nextCommand();
|
|
}
|
|
|
|
Command *Command::opActivateMesh(const ResourceReference &meshRef) {
|
|
BonesMesh *mesh = meshRef.resolve<BonesMesh>();
|
|
Item *item = mesh->findParent<Item>();
|
|
|
|
if (!item || (item->getSubType() != Item::kItemGlobalTemplate && item->getSubType() != Item::kItemLevelTemplate && item->getSubType() != Item::kItemMesh)) {
|
|
return nextCommand();
|
|
}
|
|
|
|
if (item->getSubType() == Item::kItemMesh) {
|
|
MeshItem *item10 = Object::cast<MeshItem>(item);
|
|
item10->setBonesMesh(mesh->getIndex());
|
|
} else {
|
|
ItemTemplate *item13 = Object::cast<ItemTemplate>(item);
|
|
item13->setBonesMesh(mesh->getIndex());
|
|
}
|
|
|
|
return nextCommand();
|
|
}
|
|
|
|
Command *Command::opSetTarget(const ResourceReference &itemRef1, const ResourceReference &itemRef2) {
|
|
Object *itemObj1 = itemRef1.resolve<Object>();
|
|
Object *itemObj2 = itemRef2.resolve<Object>();
|
|
warning("(TODO: Implement) opSetTarget(%s, %s) %s : %s", itemObj1->getName().c_str(), itemObj2->getName().c_str(), itemRef1.describe().c_str(), itemRef2.describe().c_str());
|
|
|
|
return nextCommand();
|
|
}
|
|
|
|
Command *Command::opSpeakWithoutTalking(Script *script, const ResourceReference &speechRef, int32 suspend) {
|
|
assert(_arguments.size() == 3);
|
|
Speech *speech = speechRef.resolve<Speech>();
|
|
warning("(TODO: Implement) opSpeakWithoutTalking(%s, %d) : %s", speech->getName().c_str(), suspend, speechRef.describe().c_str());
|
|
|
|
// TODO: Complete
|
|
DialogPlayer *dialogPlayer = StarkServices::instance().dialogPlayer;
|
|
dialogPlayer->playSingle(speech);
|
|
|
|
if (suspend) {
|
|
script->suspend(speech);
|
|
return this; // Stay on the same command while suspended
|
|
} else {
|
|
return nextCommand();
|
|
}
|
|
}
|
|
|
|
Command *Command::opIsOnFloorField(const ResourceReference &itemRef, const ResourceReference &floorFieldRef) {
|
|
FloorPositionedItem *item = itemRef.resolve<FloorPositionedItem>();
|
|
FloorField *floorField = floorFieldRef.resolve<FloorField>();
|
|
|
|
int32 itemFaceIndex = item->getFloorFaceIndex();
|
|
bool itemOnFloorField = floorField->hasFace(itemFaceIndex);
|
|
|
|
return nextCommandIf(itemOnFloorField);
|
|
}
|
|
|
|
Command *Command::opIsItemEnabled(const ResourceReference &itemRef) {
|
|
Item *itemObj = itemRef.resolve<Item>();
|
|
|
|
return nextCommandIf(itemObj->isEnabled());
|
|
}
|
|
|
|
Command *Command::opIsSet(const ResourceReference &knowledgeRef) {
|
|
Knowledge *value = knowledgeRef.resolve<Knowledge>();
|
|
|
|
return nextCommandIf(value->getBooleanValue());
|
|
}
|
|
|
|
Command *Command::opIsIntegerInRange(const ResourceReference &knowledgeRef, int32 min, int32 max) {
|
|
Knowledge *knowledgeValue = knowledgeRef.resolve<Knowledge>();
|
|
int value = knowledgeValue->getIntegerValue();
|
|
|
|
return nextCommandIf(value >= min && value <= max);
|
|
}
|
|
|
|
Command *Command::opIsIntegerAbove(const ResourceReference &knowledgeRef, int32 value) {
|
|
Knowledge *knowledgeValue = knowledgeRef.resolve<Knowledge>();
|
|
|
|
return nextCommandIf(knowledgeValue->getIntegerValue() > value);
|
|
}
|
|
|
|
Command *Command::opIsIntegerEqual(const ResourceReference &knowledgeRef, int32 value) {
|
|
Knowledge *knowledgeValue = knowledgeRef.resolve<Knowledge>();
|
|
|
|
return nextCommandIf(knowledgeValue->getIntegerValue() == value);
|
|
}
|
|
|
|
Command *Command::opIsIntegerLower(const ResourceReference &knowledgeRef, int32 value) {
|
|
Knowledge *knowledgeValue = knowledgeRef.resolve<Knowledge>();
|
|
|
|
return nextCommandIf(knowledgeValue->getIntegerValue() < value);
|
|
}
|
|
|
|
Command *Command::opIsScriptActive(const ResourceReference &scriptRef) {
|
|
Script *script = scriptRef.resolve<Script>();
|
|
|
|
return nextCommandIf(!script->isOnBegin());
|
|
}
|
|
|
|
Command *Command::opIsRandom(int32 chance) {
|
|
Common::RandomSource *randomSource = StarkServices::instance().randomSource;
|
|
int32 value = randomSource->getRandomNumber(100);
|
|
|
|
return nextCommandIf(value < chance);
|
|
}
|
|
|
|
Command *Command::opIsOnPlace(int branch1, int branch2, const ResourceReference &itemRef, const ResourceReference &position) {
|
|
assert(_arguments.size() == 4);
|
|
Object *itemObj = itemRef.resolve<Object>();
|
|
Object *positionObj = position.resolve<Object>();
|
|
warning("(TODO: Implement) opIsOnPlace(%d, %d, %s, %s) %s : %s", branch1, branch2, itemObj->getName().c_str(), positionObj->getName().c_str(), itemRef.describe().c_str(), position.describe().c_str());
|
|
// TODO: Verify how this logic actually should be handled
|
|
return nextCommandIf(false);
|
|
}
|
|
|
|
Command *Command::opIsOnNearPlace(int branch1, int branch2, const ResourceReference &itemRef, const ResourceReference &position, int32 unknown) {
|
|
assert(_arguments.size() == 5);
|
|
Object *itemObj = itemRef.resolve<Object>();
|
|
Object *positionObj = position.resolve<Object>();
|
|
warning("(TODO: Implement) opIsOnPlace(%d, %d, %s, %s, %d) %s : %s", branch1, branch2, itemObj->getName().c_str(), positionObj->getName().c_str(), unknown, itemRef.describe().c_str(), position.describe().c_str());
|
|
// TODO: Verify how this logic actually should be handled
|
|
return nextCommandIf(true);
|
|
}
|
|
|
|
Command *Command::opIsAnimPlaying(int branch1, int branch2, const ResourceReference &animRef) {
|
|
assert(_arguments.size() == 3);
|
|
Object *animObj = animRef.resolve<Object>();
|
|
warning("(TODO: Implement opIsAnimPlaying(%d %d %s) %s", branch1, branch2, animObj->getName().c_str(), animRef.describe().c_str());
|
|
|
|
// TODO: Just returning true, since we're skipping anims for now.
|
|
return nextCommandIf(false);
|
|
}
|
|
|
|
Command *Command::opIsAnimAtTime(int branch1, int branch2, const ResourceReference &animRef, int32 time) {
|
|
assert(_arguments.size() == 4);
|
|
Object *animObj = animRef.resolve<Object>();
|
|
warning("(TODO: Implement opIsAnimAtTime(%d %d %s %d) %s", branch1, branch2, animObj->getName().c_str(), time, animRef.describe().c_str());
|
|
|
|
// TODO: Just returning true, since we're skipping anims for now.
|
|
return nextCommandIf(true);
|
|
}
|
|
|
|
Command *Command::nextCommand() {
|
|
assert(!_arguments.empty());
|
|
assert(_arguments[0].type == Argument::kTypeInteger1);
|
|
|
|
return resolveArgumentSiblingReference(_arguments[0]);
|
|
}
|
|
|
|
Command *Command::nextCommandIf(bool predicate) {
|
|
assert(_arguments.size() >= 2);
|
|
assert(_arguments[0].type == Argument::kTypeInteger1);
|
|
assert(_arguments[1].type == Argument::kTypeInteger1);
|
|
|
|
if (predicate) {
|
|
return resolveArgumentSiblingReference(_arguments[1]);
|
|
} else {
|
|
return resolveArgumentSiblingReference(_arguments[0]);
|
|
}
|
|
}
|
|
|
|
Command *Command::resolveArgumentSiblingReference(const Argument &argument) {
|
|
return _parent->findChildWithIndex<Command>(argument.intValue);
|
|
}
|
|
|
|
void Command::readData(Formats::XRCReadStream *stream) {
|
|
uint32 count = stream->readUint32LE();
|
|
for (uint i = 0; i < count; i++) {
|
|
Argument argument;
|
|
argument.type = stream->readUint32LE();
|
|
|
|
switch (argument.type) {
|
|
case Argument::kTypeInteger1:
|
|
case Argument::kTypeInteger2:
|
|
argument.intValue = stream->readUint32LE();
|
|
break;
|
|
|
|
case Argument::kTypeResourceReference:
|
|
argument.referenceValue = stream->readResourceReference();
|
|
break;
|
|
case Argument::kTypeString:
|
|
argument.stringValue = stream->readString();
|
|
break;
|
|
default:
|
|
error("Unknown argument type %d", argument.type);
|
|
}
|
|
|
|
_arguments.push_back(argument);
|
|
}
|
|
}
|
|
|
|
void Command::printData() {
|
|
for (uint i = 0; i < _arguments.size(); i++) {
|
|
switch (_arguments[i].type) {
|
|
case Argument::kTypeInteger1:
|
|
case Argument::kTypeInteger2:
|
|
debug("%d: %d", i, _arguments[i].intValue);
|
|
break;
|
|
|
|
case Argument::kTypeResourceReference: {
|
|
debug("%d: %s", i, _arguments[i].referenceValue.describe().c_str());
|
|
}
|
|
break;
|
|
case Argument::kTypeString:
|
|
debug("%d: %s", i, _arguments[i].stringValue.c_str());
|
|
break;
|
|
default:
|
|
error("Unknown argument type %d", _arguments[i].type);
|
|
}
|
|
}
|
|
}
|
|
|
|
} // End of namespace Resources
|
|
} // End of namespace Stark
|