Initial commit
This commit is contained in:
677
engines/stark/resources/anim.cpp
Normal file
677
engines/stark/resources/anim.cpp
Normal file
@@ -0,0 +1,677 @@
|
||||
/* 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 "common/debug.h"
|
||||
|
||||
#include "engines/stark/debug.h"
|
||||
#include "engines/stark/formats/biffmesh.h"
|
||||
#include "engines/stark/formats/tm.h"
|
||||
#include "engines/stark/formats/xrc.h"
|
||||
|
||||
#include "engines/stark/gfx/driver.h"
|
||||
#include "engines/stark/resources/anim.h"
|
||||
#include "engines/stark/resources/animscript.h"
|
||||
#include "engines/stark/resources/bonesmesh.h"
|
||||
#include "engines/stark/resources/direction.h"
|
||||
#include "engines/stark/resources/image.h"
|
||||
#include "engines/stark/resources/item.h"
|
||||
#include "engines/stark/resources/location.h"
|
||||
#include "engines/stark/resources/textureset.h"
|
||||
|
||||
#include "engines/stark/services/archiveloader.h"
|
||||
#include "engines/stark/services/global.h"
|
||||
#include "engines/stark/services/services.h"
|
||||
#include "engines/stark/services/settings.h"
|
||||
#include "engines/stark/services/stateprovider.h"
|
||||
|
||||
#include "engines/stark/model/animhandler.h"
|
||||
#include "engines/stark/model/skeleton_anim.h"
|
||||
#include "engines/stark/visual/actor.h"
|
||||
#include "engines/stark/visual/prop.h"
|
||||
#include "engines/stark/visual/smacker.h"
|
||||
|
||||
namespace Stark {
|
||||
namespace Resources {
|
||||
|
||||
Object *Anim::construct(Object *parent, byte subType, uint16 index, const Common::String &name) {
|
||||
switch (subType) {
|
||||
case kAnimImages:
|
||||
return new AnimImages(parent, subType, index, name);
|
||||
case kAnimProp:
|
||||
return new AnimProp(parent, subType, index, name);
|
||||
case kAnimVideo:
|
||||
return new AnimVideo(parent, subType, index, name);
|
||||
case kAnimSkeleton:
|
||||
return new AnimSkeleton(parent, subType, index, name);
|
||||
default:
|
||||
error("Unknown anim subtype %d", subType);
|
||||
}
|
||||
}
|
||||
|
||||
Anim::~Anim() {
|
||||
}
|
||||
|
||||
Anim::Anim(Object *parent, byte subType, uint16 index, const Common::String &name) :
|
||||
Object(parent, subType, index, name),
|
||||
_activity(0),
|
||||
_currentFrame(0),
|
||||
_numFrames(0),
|
||||
_refCount(0) {
|
||||
_type = TYPE;
|
||||
}
|
||||
|
||||
void Anim::readData(Formats::XRCReadStream *stream) {
|
||||
_activity = stream->readUint32LE();
|
||||
_numFrames = stream->readUint32LE();
|
||||
}
|
||||
|
||||
void Anim::selectFrame(uint32 frameIndex) {
|
||||
}
|
||||
|
||||
uint32 Anim::getActivity() const {
|
||||
return _activity;
|
||||
}
|
||||
|
||||
void Anim::applyToItem(Item *item) {
|
||||
_refCount++;
|
||||
}
|
||||
void Anim::removeFromItem(Item *item) {
|
||||
_refCount--;
|
||||
}
|
||||
|
||||
bool Anim::isInUse() const {
|
||||
return _refCount > 0;
|
||||
}
|
||||
|
||||
int Anim::getPointHotspotIndex(const Common::Point &point) const {
|
||||
// Most anim types only have one hotspot
|
||||
return 0;
|
||||
}
|
||||
|
||||
void Anim::playAsAction(ItemVisual *item) {
|
||||
AnimScript *animScript = findChild<AnimScript>();
|
||||
animScript->goToScriptItem(0);
|
||||
}
|
||||
|
||||
bool Anim::isAtTime(uint32 time) const {
|
||||
warning("Anim::isAtTime is not implemented");
|
||||
return true;
|
||||
}
|
||||
|
||||
void Anim::shouldResetItem(bool resetItem) {
|
||||
// Script animations don't keep track of the item
|
||||
}
|
||||
|
||||
void Anim::resetItem() {
|
||||
// Script animations don't keep track of the item
|
||||
}
|
||||
|
||||
bool Anim::isDone() const {
|
||||
AnimScript *animScript = findChild<AnimScript>();
|
||||
return animScript->isDone();
|
||||
}
|
||||
|
||||
uint32 Anim::getMovementSpeed() const {
|
||||
return 100;
|
||||
}
|
||||
|
||||
uint32 Anim::getIdleActionFrequency() const {
|
||||
return 1;
|
||||
}
|
||||
|
||||
void Anim::printData() {
|
||||
debug("activity: %d", _activity);
|
||||
debug("numFrames: %d", _numFrames);
|
||||
}
|
||||
|
||||
AnimImages::~AnimImages() {
|
||||
}
|
||||
|
||||
AnimImages::AnimImages(Object *parent, byte subType, uint16 index, const Common::String &name) :
|
||||
Anim(parent, subType, index, name),
|
||||
_field_3C(0),
|
||||
_currentDirection(0),
|
||||
_currentFrameImage(nullptr) {
|
||||
}
|
||||
|
||||
void AnimImages::readData(Formats::XRCReadStream *stream) {
|
||||
Anim::readData(stream);
|
||||
|
||||
_field_3C = stream->readFloatLE();
|
||||
}
|
||||
|
||||
void AnimImages::onAllLoaded() {
|
||||
Anim::onAllLoaded();
|
||||
|
||||
_directions = listChildren<Direction>();
|
||||
}
|
||||
|
||||
void AnimImages::selectFrame(uint32 frameIndex) {
|
||||
if (frameIndex > _numFrames) {
|
||||
// The original silently ignores this as well
|
||||
warning("Request for frame %d for anim '%s' has been ignored, it is above max frame %d", frameIndex, getName().c_str(), _numFrames);
|
||||
_currentFrame = 0;
|
||||
}
|
||||
|
||||
_currentFrame = frameIndex;
|
||||
}
|
||||
|
||||
Visual *AnimImages::getVisual() {
|
||||
Direction *direction = _directions[_currentDirection];
|
||||
_currentFrameImage = direction->findChildWithIndex<Image>(_currentFrame);
|
||||
return _currentFrameImage->getVisual();
|
||||
}
|
||||
|
||||
void AnimImages::printData() {
|
||||
Anim::printData();
|
||||
|
||||
debug("field_3C: %f", _field_3C);
|
||||
}
|
||||
|
||||
int AnimImages::getPointHotspotIndex(const Common::Point &point) const {
|
||||
if (_currentFrameImage) {
|
||||
return _currentFrameImage->indexForPoint(point);
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
Common::Point AnimImages::getHotspotPosition(uint index) const {
|
||||
if (_currentFrameImage) {
|
||||
return _currentFrameImage->getHotspotPosition(index);
|
||||
}
|
||||
return Common::Point(-1, -1);
|
||||
}
|
||||
|
||||
void AnimImages::saveLoad(ResourceSerializer *serializer) {
|
||||
Anim::saveLoad(serializer);
|
||||
|
||||
serializer->syncAsUint32LE(_currentFrame);
|
||||
|
||||
if (serializer->isLoading()) {
|
||||
selectFrame(_currentFrame);
|
||||
}
|
||||
}
|
||||
|
||||
AnimProp::~AnimProp() {
|
||||
delete _visual;
|
||||
}
|
||||
|
||||
AnimProp::AnimProp(Object *parent, byte subType, uint16 index, const Common::String &name) :
|
||||
Anim(parent, subType, index, name),
|
||||
_movementSpeed(100) {
|
||||
_visual = StarkGfx->createPropRenderer();
|
||||
}
|
||||
|
||||
Visual *AnimProp::getVisual() {
|
||||
return _visual;
|
||||
}
|
||||
|
||||
uint32 AnimProp::getMovementSpeed() const {
|
||||
return _movementSpeed;
|
||||
}
|
||||
|
||||
void AnimProp::readData(Formats::XRCReadStream *stream) {
|
||||
Anim::readData(stream);
|
||||
|
||||
_field_3C = stream->readString();
|
||||
|
||||
uint32 meshCount = stream->readUint32LE();
|
||||
for (uint i = 0; i < meshCount; i++) {
|
||||
_meshFilenames.push_back(Common::Path(stream->readString()));
|
||||
}
|
||||
|
||||
_textureFilename = stream->readString();
|
||||
_movementSpeed = stream->readUint32LE();
|
||||
_archiveName = stream->getArchiveName();
|
||||
}
|
||||
|
||||
void AnimProp::onPostRead() {
|
||||
if (_meshFilenames.size() != 1) {
|
||||
error("Unexpected mesh count in prop anim: '%d'", _meshFilenames.size());
|
||||
}
|
||||
|
||||
ArchiveReadStream *stream = StarkArchiveLoader->getFile(_meshFilenames[0], _archiveName);
|
||||
_visual->setModel(Formats::BiffMeshReader::read(stream));
|
||||
delete stream;
|
||||
|
||||
stream = StarkArchiveLoader->getFile(_textureFilename, _archiveName);
|
||||
_visual->setTexture(Formats::TextureSetReader::read(stream));
|
||||
delete stream;
|
||||
}
|
||||
|
||||
void AnimProp::printData() {
|
||||
Anim::printData();
|
||||
|
||||
debug("field_3C: %s", _field_3C.c_str());
|
||||
|
||||
Common::String description;
|
||||
for (uint32 i = 0; i < _meshFilenames.size(); i++) {
|
||||
debug("meshFilename[%d]: %s", i, _meshFilenames[i].toString().c_str());
|
||||
}
|
||||
debug("textureFilename: %s", _textureFilename.toString().c_str());
|
||||
debug("movementSpeed: %d", _movementSpeed);
|
||||
}
|
||||
|
||||
AnimVideo::~AnimVideo() {
|
||||
delete _smacker;
|
||||
}
|
||||
|
||||
AnimVideo::AnimVideo(Object *parent, byte subType, uint16 index, const Common::String &name) :
|
||||
Anim(parent, subType, index, name),
|
||||
_width(0),
|
||||
_height(0),
|
||||
_smacker(nullptr),
|
||||
_frameRateOverride(-1),
|
||||
_preload(false),
|
||||
_loop(false),
|
||||
_actionItem(nullptr),
|
||||
_shouldResetItem(true),
|
||||
_done(false) {
|
||||
}
|
||||
|
||||
void AnimVideo::readData(Formats::XRCReadStream *stream) {
|
||||
Anim::readData(stream);
|
||||
_smackerFile = stream->readString();
|
||||
_width = stream->readUint32LE();
|
||||
_height = stream->readUint32LE();
|
||||
|
||||
_positions.clear();
|
||||
_sizes.clear();
|
||||
|
||||
uint32 size = stream->readUint32LE();
|
||||
for (uint i = 0; i < size; i++) {
|
||||
_positions.push_back(stream->readPoint());
|
||||
_sizes.push_back(stream->readRect());
|
||||
}
|
||||
|
||||
_loop = stream->readBool();
|
||||
_frameRateOverride = stream->readUint32LE();
|
||||
|
||||
if (stream->isDataLeft()) {
|
||||
_preload = stream->readBool();
|
||||
}
|
||||
|
||||
_archiveName = stream->getArchiveName();
|
||||
|
||||
// WORKAROUND: Fix the position of various items being incorrect in the game datafiles
|
||||
Location *location = findParent<Location>();
|
||||
if (_name == "Mountain comes down" && location && location->getName() == "Below Floating Mountain") {
|
||||
for (uint i = 0; i < _sizes.size(); i++) {
|
||||
_positions[i].x = 352;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void AnimVideo::onAllLoaded() {
|
||||
if (!_smacker) {
|
||||
|
||||
_smacker = new VisualSmacker(StarkGfx);
|
||||
|
||||
Common::SeekableReadStream *overrideStreamBink = nullptr;
|
||||
Common::SeekableReadStream *overrideStreamSmacker = nullptr;
|
||||
if (StarkSettings->isAssetsModEnabled() && StarkGfx->supportsModdedAssets()) {
|
||||
overrideStreamBink = openOverrideFile(".bik");
|
||||
if (!overrideStreamBink) {
|
||||
overrideStreamSmacker = openOverrideFile(".smk");
|
||||
}
|
||||
}
|
||||
|
||||
Common::SeekableReadStream *stream = StarkArchiveLoader->getExternalFile(_smackerFile, _archiveName);
|
||||
if (overrideStreamBink) {
|
||||
_smacker->loadBink(overrideStreamBink);
|
||||
_smacker->readOriginalSize(stream);
|
||||
} else if (overrideStreamSmacker) {
|
||||
_smacker->loadSmacker(overrideStreamSmacker);
|
||||
_smacker->readOriginalSize(stream);
|
||||
} else {
|
||||
_smacker->loadSmacker(stream);
|
||||
}
|
||||
|
||||
_smacker->overrideFrameRate(_frameRateOverride);
|
||||
|
||||
updateSmackerPosition();
|
||||
}
|
||||
}
|
||||
|
||||
Common::SeekableReadStream *AnimVideo::openOverrideFile(const Common::String &extension) const {
|
||||
Common::String baseName(_smackerFile.baseName());
|
||||
if (!baseName.hasSuffixIgnoreCase(".sss")) {
|
||||
return nullptr;
|
||||
}
|
||||
baseName = Common::String(baseName.c_str(), baseName.size() - 4) + extension;
|
||||
|
||||
Common::Path filePath(_smackerFile.getParent().appendComponent(baseName));
|
||||
filePath = StarkArchiveLoader->getExternalFilePath(filePath, _archiveName);
|
||||
|
||||
debugC(kDebugModding, "Attempting to load %s", filePath.toString(Common::Path::kNativeSeparator).c_str());
|
||||
|
||||
Common::SeekableReadStream *smkStream = SearchMan.createReadStreamForMember(filePath);
|
||||
if (!smkStream) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
debugC(kDebugModding, "Loaded %s", filePath.toString(Common::Path::kNativeSeparator).c_str());
|
||||
|
||||
return smkStream;
|
||||
}
|
||||
|
||||
void AnimVideo::onGameLoop() {
|
||||
if (!_smacker || !isInUse()) {
|
||||
return; // Animation not in use, no need to update the movie
|
||||
}
|
||||
|
||||
if (_smacker->isDone()) {
|
||||
// The last frame has been reached
|
||||
_done = true;
|
||||
|
||||
if (_shouldResetItem) {
|
||||
resetItem();
|
||||
}
|
||||
|
||||
if (_loop) {
|
||||
_smacker->rewind();
|
||||
}
|
||||
}
|
||||
|
||||
if (!_smacker->isDone()) {
|
||||
_smacker->update();
|
||||
updateSmackerPosition();
|
||||
}
|
||||
}
|
||||
|
||||
void AnimVideo::resetItem() {
|
||||
if (!_loop && _actionItem) {
|
||||
// Reset our item if needed
|
||||
if (_actionItem->getActionAnim() == this) {
|
||||
_actionItem->resetActionAnim();
|
||||
}
|
||||
_actionItem = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
void AnimVideo::onEnginePause(bool pause) {
|
||||
Object::onEnginePause(pause);
|
||||
|
||||
if (_smacker && isInUse()) {
|
||||
_smacker->pause(pause);
|
||||
}
|
||||
}
|
||||
|
||||
Visual *AnimVideo::getVisual() {
|
||||
return _smacker;
|
||||
}
|
||||
|
||||
void AnimVideo::updateSmackerPosition() {
|
||||
int frame = _smacker->getFrameNumber();
|
||||
if (frame == -1) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (frame < (int) _positions.size()) {
|
||||
_smacker->setPosition(_positions[frame]);
|
||||
}
|
||||
}
|
||||
|
||||
void AnimVideo::shouldResetItem(bool resetItem) {
|
||||
_shouldResetItem = resetItem;
|
||||
}
|
||||
|
||||
void AnimVideo::playAsAction(ItemVisual *item) {
|
||||
_actionItem = item;
|
||||
_shouldResetItem = true;
|
||||
_done = false;
|
||||
|
||||
if (!_loop) {
|
||||
_smacker->rewind();
|
||||
}
|
||||
|
||||
// Update here so we have something up to date to show when rendering this frame
|
||||
_smacker->update();
|
||||
}
|
||||
|
||||
bool AnimVideo::isAtTime(uint32 time) const {
|
||||
uint32 currentTime = _smacker->getCurrentTime();
|
||||
return currentTime >= time;
|
||||
}
|
||||
|
||||
void AnimVideo::saveLoadCurrent(ResourceSerializer *serializer) {
|
||||
Anim::saveLoadCurrent(serializer);
|
||||
|
||||
int32 frameNumber = _smacker->getFrameNumber();
|
||||
serializer->syncAsSint32LE(frameNumber);
|
||||
serializer->syncAsSint32LE(_refCount);
|
||||
|
||||
// TODO: Seek to the saved frame number when loading
|
||||
}
|
||||
|
||||
void AnimVideo::printData() {
|
||||
Anim::printData();
|
||||
|
||||
debug("smackerFile: %s", _smackerFile.toString().c_str());
|
||||
debug("size: x %d, y %d", _width, _height);
|
||||
|
||||
Common::String description;
|
||||
for (uint32 i = 0; i < _positions.size(); i++) {
|
||||
description += Common::String::format("(x %d, y %d) ", _positions[i].x, _positions[i].y);
|
||||
}
|
||||
debug("positions: %s", description.c_str());
|
||||
|
||||
description.clear();
|
||||
for (uint32 i = 0; i < _sizes.size(); i++) {
|
||||
description += Common::String::format("(l %d, t %d, r %d, b %d) ",
|
||||
_sizes[i].left, _sizes[i].top, _sizes[i].right, _sizes[i].bottom);
|
||||
}
|
||||
debug("sizes: %s", description.c_str());
|
||||
|
||||
debug("frameRateOverride: %d", _frameRateOverride);
|
||||
debug("preload: %d", _preload);
|
||||
debug("loop: %d", _loop);
|
||||
}
|
||||
|
||||
AnimSkeleton::~AnimSkeleton() {
|
||||
delete _visual;
|
||||
delete _skeletonAnim;
|
||||
}
|
||||
|
||||
AnimSkeleton::AnimSkeleton(Object *parent, byte subType, uint16 index, const Common::String &name) :
|
||||
Anim(parent, subType, index, name),
|
||||
_castsShadow(true),
|
||||
_loop(false),
|
||||
_movementSpeed(100),
|
||||
_idleActionFrequency(1),
|
||||
_skeletonAnim(nullptr),
|
||||
_currentTime(0),
|
||||
_totalTime(0),
|
||||
_done(false),
|
||||
_actionItem(nullptr),
|
||||
_shouldResetItem(true) {
|
||||
_visual = StarkGfx->createActorRenderer();
|
||||
}
|
||||
|
||||
void AnimSkeleton::applyToItem(Item *item) {
|
||||
Anim::applyToItem(item);
|
||||
|
||||
if (!_loop) {
|
||||
_currentTime = 0;
|
||||
}
|
||||
|
||||
if (_currentTime > _totalTime) {
|
||||
_currentTime = 0;
|
||||
}
|
||||
|
||||
debugC(kDebugAnimation, "%s: add %s", item->getName().c_str(), getName().c_str());
|
||||
|
||||
ModelItem *modelItem = Object::cast<ModelItem>(item);
|
||||
|
||||
BonesMesh *mesh = modelItem->findBonesMesh();
|
||||
TextureSet *texture = modelItem->findTextureSet(TextureSet::kTextureNormal);
|
||||
|
||||
AnimHandler *animHandler = modelItem->getAnimHandler();
|
||||
animHandler->setModel(mesh->getModel());
|
||||
animHandler->setAnim(_skeletonAnim);
|
||||
|
||||
_visual->setModel(mesh->getModel());
|
||||
_visual->setAnimHandler(animHandler);
|
||||
_visual->setTexture(texture->getTexture());
|
||||
_visual->setTextureFacial(nullptr);
|
||||
_visual->setTime(_currentTime);
|
||||
_visual->setCastShadow(_castsShadow);
|
||||
}
|
||||
|
||||
void AnimSkeleton::removeFromItem(Item *item) {
|
||||
Anim::removeFromItem(item);
|
||||
|
||||
debugC(kDebugAnimation, "%s: remove %s", item->getName().c_str(), getName().c_str());
|
||||
|
||||
_actionItem = nullptr;
|
||||
}
|
||||
|
||||
Visual *AnimSkeleton::getVisual() {
|
||||
return _visual;
|
||||
}
|
||||
|
||||
void AnimSkeleton::readData(Formats::XRCReadStream *stream) {
|
||||
Anim::readData(stream);
|
||||
|
||||
_animFilename = stream->readString();
|
||||
stream->readString(); // Skipped in the original
|
||||
stream->readString(); // Skipped in the original
|
||||
stream->readString(); // Skipped in the original
|
||||
|
||||
_loop = stream->readBool();
|
||||
_movementSpeed = stream->readUint32LE();
|
||||
|
||||
if (_movementSpeed < 1) {
|
||||
_movementSpeed = 100;
|
||||
}
|
||||
|
||||
if (stream->isDataLeft()) {
|
||||
_castsShadow = stream->readBool();
|
||||
} else {
|
||||
_castsShadow = true;
|
||||
}
|
||||
|
||||
if (stream->isDataLeft()) {
|
||||
_idleActionFrequency = stream->readUint32LE();
|
||||
} else {
|
||||
_idleActionFrequency = 1;
|
||||
}
|
||||
|
||||
_archiveName = stream->getArchiveName();
|
||||
}
|
||||
|
||||
void AnimSkeleton::onPostRead() {
|
||||
ArchiveReadStream *stream = StarkArchiveLoader->getFile(_animFilename, _archiveName);
|
||||
|
||||
_skeletonAnim = new SkeletonAnim();
|
||||
_skeletonAnim->createFromStream(stream);
|
||||
|
||||
delete stream;
|
||||
}
|
||||
|
||||
void AnimSkeleton::onAllLoaded() {
|
||||
Anim::onAllLoaded();
|
||||
|
||||
_totalTime = _skeletonAnim->getLength();
|
||||
_currentTime = 0;
|
||||
}
|
||||
|
||||
void AnimSkeleton::onGameLoop() {
|
||||
Anim::onGameLoop();
|
||||
|
||||
if (isInUse() && _totalTime) {
|
||||
uint32 newTime = _currentTime + StarkGlobal->getMillisecondsPerGameloop();
|
||||
|
||||
if (!_loop && newTime >= _totalTime) {
|
||||
_done = true;
|
||||
|
||||
if (_shouldResetItem) {
|
||||
resetItem();
|
||||
}
|
||||
} else {
|
||||
_currentTime = newTime % _totalTime;
|
||||
_visual->setTime(_currentTime);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void AnimSkeleton::resetItem() {
|
||||
if (_actionItem) {
|
||||
if (_actionItem->getActionAnim() == this) {
|
||||
_actionItem->resetActionAnim();
|
||||
}
|
||||
_actionItem = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
void AnimSkeleton::onPreDestroy() {
|
||||
resetItem();
|
||||
|
||||
Anim::onPreDestroy();
|
||||
}
|
||||
|
||||
uint32 AnimSkeleton::getMovementSpeed() const {
|
||||
return _movementSpeed;
|
||||
}
|
||||
|
||||
uint32 AnimSkeleton::getCurrentTime() const {
|
||||
return _currentTime;
|
||||
}
|
||||
|
||||
uint32 AnimSkeleton::getRemainingTime() const {
|
||||
int32 remainingTime = _totalTime - _currentTime;
|
||||
return CLIP<int32>(remainingTime, 0, _totalTime);
|
||||
}
|
||||
|
||||
void AnimSkeleton::shouldResetItem(bool resetItem) {
|
||||
_shouldResetItem = resetItem;
|
||||
}
|
||||
|
||||
void AnimSkeleton::playAsAction(ItemVisual *item) {
|
||||
_actionItem = item;
|
||||
_done = false;
|
||||
_shouldResetItem = true;
|
||||
|
||||
if (!_loop) {
|
||||
_currentTime = 0;
|
||||
}
|
||||
}
|
||||
|
||||
bool AnimSkeleton::isAtTime(uint32 time) const {
|
||||
return _currentTime >= time;
|
||||
}
|
||||
|
||||
uint32 AnimSkeleton::getIdleActionFrequency() const {
|
||||
return _idleActionFrequency;
|
||||
}
|
||||
|
||||
void AnimSkeleton::printData() {
|
||||
Anim::printData();
|
||||
|
||||
debug("filename: %s", _animFilename.toString().c_str());
|
||||
debug("castsShadow: %d", _castsShadow);
|
||||
debug("loop: %d", _loop);
|
||||
debug("movementSpeed: %d", _movementSpeed);
|
||||
debug("idleActionFrequency: %d", _idleActionFrequency);
|
||||
}
|
||||
|
||||
} // End of namespace Resources
|
||||
} // End of namespace Stark
|
||||
337
engines/stark/resources/anim.h
Normal file
337
engines/stark/resources/anim.h
Normal file
@@ -0,0 +1,337 @@
|
||||
/* 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/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef STARK_RESOURCES_ANIM_H
|
||||
#define STARK_RESOURCES_ANIM_H
|
||||
|
||||
#include "common/path.h"
|
||||
#include "common/rect.h"
|
||||
#include "common/str.h"
|
||||
|
||||
#include "engines/stark/resources/object.h"
|
||||
|
||||
namespace Common {
|
||||
class SeekableReadStream;
|
||||
}
|
||||
|
||||
namespace Stark {
|
||||
|
||||
class SkeletonAnim;
|
||||
class VisualActor;
|
||||
class VisualProp;
|
||||
class VisualSmacker;
|
||||
class Visual;
|
||||
namespace Formats {
|
||||
class XRCReadStream;
|
||||
}
|
||||
|
||||
namespace Resources {
|
||||
|
||||
class Direction;
|
||||
class Image;
|
||||
class Item;
|
||||
class ItemVisual;
|
||||
|
||||
/**
|
||||
* Animation base class
|
||||
*
|
||||
* Animations provide a time dependent visual state to Items
|
||||
*/
|
||||
class Anim : public Object {
|
||||
public:
|
||||
static const Type::ResourceType TYPE = Type::kAnim;
|
||||
|
||||
enum SubType {
|
||||
kAnimImages = 1,
|
||||
kAnimProp = 2,
|
||||
kAnimVideo = 3,
|
||||
kAnimSkeleton = 4
|
||||
};
|
||||
|
||||
enum ActionUsage {
|
||||
kActionUsagePassive = 1,
|
||||
kActionUsageActive = 2
|
||||
};
|
||||
|
||||
enum UIUsage {
|
||||
kUIUsageInventory = 1,
|
||||
kUIUsageUseCursorPassive = 4,
|
||||
kUIUsageUseCursorActive = 5
|
||||
};
|
||||
|
||||
enum ActorActivity {
|
||||
kActorActivityIdle = 1,
|
||||
kActorActivityWalk = 2,
|
||||
kActorActivityTalk = 3,
|
||||
kActorActivityRun = 6,
|
||||
kActorActivityIdleAction = 10
|
||||
};
|
||||
|
||||
/** Anim factory */
|
||||
static Object *construct(Object *parent, byte subType, uint16 index, const Common::String &name);
|
||||
|
||||
Anim(Object *parent, byte subType, uint16 index, const Common::String &name);
|
||||
~Anim() override;
|
||||
|
||||
// Resource API
|
||||
void readData(Formats::XRCReadStream *stream) override;
|
||||
|
||||
/** Get current displayed frame */
|
||||
uint32 getCurrentFrame() { return _currentFrame; }
|
||||
|
||||
/** Sets the animation frame to be displayed */
|
||||
virtual void selectFrame(uint32 frameIndex);
|
||||
|
||||
/** Obtain the Visual to be used to render the animation */
|
||||
virtual Visual *getVisual() = 0;
|
||||
|
||||
/** Associate the animation to an Item */
|
||||
virtual void applyToItem(Item *item);
|
||||
|
||||
/** Dissociate the animation from an item */
|
||||
virtual void removeFromItem(Item *item);
|
||||
|
||||
/** Check is the animation is being used by an item */
|
||||
bool isInUse() const;
|
||||
|
||||
/** Obtain the purpose of this anim */
|
||||
uint32 getActivity() const;
|
||||
|
||||
/** Return the hotspot index for a point given in relative coordinates */
|
||||
virtual int getPointHotspotIndex(const Common::Point &point) const;
|
||||
|
||||
/** Get the hotspot position for a given index of a pat-table */
|
||||
virtual Common::Point getHotspotPosition(uint index) const { return Common::Point(-1, -1); }
|
||||
|
||||
/**
|
||||
* Play the animation as an action for an item.
|
||||
*
|
||||
* This sets up a callback to the item for when the animation completes.
|
||||
*/
|
||||
virtual void playAsAction(ItemVisual *item);
|
||||
|
||||
/** Checks if the elapsed time since the animation start is greater than a specified duration */
|
||||
virtual bool isAtTime(uint32 time) const;
|
||||
|
||||
/** Get the anim movement speed in units per seconds */
|
||||
virtual uint32 getMovementSpeed() const;
|
||||
|
||||
/** Get the chance the animation has to play among other idle actions from the same anim hierarchy */
|
||||
virtual uint32 getIdleActionFrequency() const;
|
||||
|
||||
/**
|
||||
* When this animation is playing as an action should a new animation
|
||||
* be chosen for the item as soon as this one completes based on
|
||||
* the item's activity?
|
||||
* This is true by default, but setting it to false allows scripts
|
||||
* to chose precisely the new animation to play, and to start it
|
||||
* in the same frame as this one is removed.
|
||||
*/
|
||||
virtual void shouldResetItem(bool resetItem);
|
||||
|
||||
/**
|
||||
* Remove this action animation for the item and select a new animation
|
||||
* based on the item's current activity.
|
||||
*/
|
||||
virtual void resetItem();
|
||||
|
||||
/**
|
||||
* Is this animation done playing.
|
||||
*
|
||||
* Only valid for animations started with playAsAction.
|
||||
*/
|
||||
virtual bool isDone() const;
|
||||
|
||||
protected:
|
||||
void printData() override;
|
||||
|
||||
uint32 _activity;
|
||||
uint32 _currentFrame;
|
||||
uint32 _numFrames;
|
||||
int32 _refCount;
|
||||
};
|
||||
|
||||
/**
|
||||
* Displays still images controlled by an AnimScript
|
||||
*/
|
||||
class AnimImages : public Anim {
|
||||
public:
|
||||
AnimImages(Object *parent, byte subType, uint16 index, const Common::String &name);
|
||||
~AnimImages() override;
|
||||
|
||||
// Resource API
|
||||
void readData(Formats::XRCReadStream *stream) override;
|
||||
void onAllLoaded() override;
|
||||
void saveLoad(ResourceSerializer *serializer) override;
|
||||
|
||||
// Anim API
|
||||
void selectFrame(uint32 frameIndex) override;
|
||||
Visual *getVisual() override;
|
||||
int getPointHotspotIndex(const Common::Point &point) const override;
|
||||
Common::Point getHotspotPosition(uint index) const override;
|
||||
|
||||
protected:
|
||||
void printData() override;
|
||||
|
||||
float _field_3C;
|
||||
|
||||
uint32 _currentDirection;
|
||||
Common::Array<Direction *> _directions;
|
||||
|
||||
Image *_currentFrameImage;
|
||||
};
|
||||
|
||||
class AnimProp : public Anim {
|
||||
public:
|
||||
AnimProp(Object *parent, byte subType, uint16 index, const Common::String &name);
|
||||
~AnimProp() override;
|
||||
|
||||
// Resource API
|
||||
void readData(Formats::XRCReadStream *stream) override;
|
||||
void onPostRead() override;
|
||||
|
||||
// Anim API
|
||||
Visual *getVisual() override;
|
||||
uint32 getMovementSpeed() const override;
|
||||
|
||||
protected:
|
||||
void printData() override;
|
||||
|
||||
Common::String _field_3C;
|
||||
Common::Array<Common::Path> _meshFilenames;
|
||||
Common::Path _textureFilename;
|
||||
uint32 _movementSpeed;
|
||||
Common::Path _archiveName;
|
||||
|
||||
VisualProp *_visual;
|
||||
};
|
||||
|
||||
/**
|
||||
* Displays a Smacker video
|
||||
*/
|
||||
class AnimVideo : public Anim {
|
||||
public:
|
||||
AnimVideo(Object *parent, byte subType, uint16 index, const Common::String &name);
|
||||
~AnimVideo() override;
|
||||
|
||||
// Resource API
|
||||
void readData(Formats::XRCReadStream *stream) override;
|
||||
void onAllLoaded() override;
|
||||
void onGameLoop() override;
|
||||
void onEnginePause(bool pause) override;
|
||||
void saveLoadCurrent(ResourceSerializer *serializer) override;
|
||||
|
||||
// Anim API
|
||||
Visual *getVisual() override;
|
||||
void playAsAction(ItemVisual *item) override;
|
||||
void shouldResetItem(bool resetItem) override;
|
||||
void resetItem() override;
|
||||
bool isAtTime(uint32 time) const override;
|
||||
bool isDone() const override { return _done || !isInUse(); }
|
||||
|
||||
protected:
|
||||
typedef Common::Array<Common::Point> PointArray;
|
||||
typedef Common::Array<Common::Rect> RectArray;
|
||||
|
||||
void printData() override;
|
||||
Common::SeekableReadStream *openOverrideFile(const Common::String &extension) const;
|
||||
|
||||
/** Update the position of the video for the current frame */
|
||||
void updateSmackerPosition();
|
||||
|
||||
Common::Path _smackerFile;
|
||||
Common::Path _archiveName;
|
||||
|
||||
VisualSmacker *_smacker;
|
||||
|
||||
uint32 _width;
|
||||
uint32 _height;
|
||||
|
||||
PointArray _positions;
|
||||
RectArray _sizes;
|
||||
|
||||
int32 _frameRateOverride;
|
||||
bool _preload;
|
||||
bool _loop;
|
||||
bool _done;
|
||||
|
||||
ItemVisual *_actionItem;
|
||||
bool _shouldResetItem;
|
||||
};
|
||||
|
||||
/**
|
||||
* Animates a 3D mesh skeleton
|
||||
*/
|
||||
class AnimSkeleton : public Anim {
|
||||
public:
|
||||
AnimSkeleton(Object *parent, byte subType, uint16 index, const Common::String &name);
|
||||
~AnimSkeleton() override;
|
||||
|
||||
// Resource API
|
||||
void readData(Formats::XRCReadStream *stream) override;
|
||||
void onPostRead() override;
|
||||
void onAllLoaded() override;
|
||||
void onGameLoop() override;
|
||||
void onPreDestroy() override;
|
||||
|
||||
// Anim API
|
||||
void applyToItem(Item *item) override;
|
||||
void removeFromItem(Item *item) override;
|
||||
Visual *getVisual() override;
|
||||
void playAsAction(ItemVisual *item) override;
|
||||
bool isAtTime(uint32 time) const override;
|
||||
bool isDone() const override { return _done || !isInUse(); }
|
||||
uint32 getMovementSpeed() const override;
|
||||
uint32 getIdleActionFrequency() const override;
|
||||
void shouldResetItem(bool resetItem) override;
|
||||
void resetItem() override;
|
||||
|
||||
/** Get the duration in milliseconds before the animation loops ends */
|
||||
uint32 getRemainingTime() const;
|
||||
|
||||
/** Get the position in the animation loop in milliseconds */
|
||||
uint32 getCurrentTime() const;
|
||||
|
||||
protected:
|
||||
void printData() override;
|
||||
|
||||
bool _castsShadow;
|
||||
Common::Path _archiveName;
|
||||
Common::Path _animFilename;
|
||||
bool _loop;
|
||||
uint32 _movementSpeed;
|
||||
uint32 _idleActionFrequency;
|
||||
|
||||
uint32 _totalTime;
|
||||
uint32 _currentTime;
|
||||
bool _done;
|
||||
|
||||
SkeletonAnim *_skeletonAnim;
|
||||
VisualActor *_visual;
|
||||
|
||||
ItemVisual *_actionItem;
|
||||
bool _shouldResetItem;
|
||||
};
|
||||
|
||||
} // End of namespace Resources
|
||||
} // End of namespace Stark
|
||||
|
||||
#endif // STARK_RESOURCES_ANIM_H
|
||||
209
engines/stark/resources/animhierarchy.cpp
Normal file
209
engines/stark/resources/animhierarchy.cpp
Normal file
@@ -0,0 +1,209 @@
|
||||
/* 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 "engines/stark/resources/animhierarchy.h"
|
||||
|
||||
#include "common/debug.h"
|
||||
#include "common/random.h"
|
||||
|
||||
#include "engines/stark/formats/xrc.h"
|
||||
#include "engines/stark/resources/anim.h"
|
||||
#include "engines/stark/resources/bonesmesh.h"
|
||||
#include "engines/stark/resources/item.h"
|
||||
#include "engines/stark/resources/textureset.h"
|
||||
#include "engines/stark/services/services.h"
|
||||
|
||||
namespace Stark {
|
||||
namespace Resources {
|
||||
|
||||
AnimHierarchy::~AnimHierarchy() {
|
||||
}
|
||||
|
||||
AnimHierarchy::AnimHierarchy(Object *parent, byte subType, uint16 index, const Common::String &name) :
|
||||
Object(parent, subType, index, name),
|
||||
_currentActivity(0),
|
||||
_currentAnim(nullptr),
|
||||
_field_5C(0),
|
||||
_idleActionsFrequencySum(0) {
|
||||
_type = TYPE;
|
||||
}
|
||||
|
||||
void AnimHierarchy::readData(Formats::XRCReadStream *stream) {
|
||||
_animationReferences.clear();
|
||||
|
||||
uint32 refCount = stream->readUint32LE();
|
||||
for (uint32 i = 0; i < refCount; i++) {
|
||||
_animationReferences.push_back(stream->readResourceReference());
|
||||
}
|
||||
|
||||
_parentAnimHierarchyReference = stream->readResourceReference();
|
||||
_field_5C = stream->readFloatLE();
|
||||
}
|
||||
|
||||
void AnimHierarchy::onAllLoaded() {
|
||||
Object::onAllLoaded();
|
||||
|
||||
loadActivityAnimations();
|
||||
loadIdleAnimations();
|
||||
}
|
||||
|
||||
void AnimHierarchy::loadActivityAnimations() {
|
||||
AnimHierarchy *parentHierarchy = _parentAnimHierarchyReference.resolve<AnimHierarchy>();
|
||||
|
||||
// Activity animations are inherited from the parent ...
|
||||
if (parentHierarchy) {
|
||||
_activityAnimations = parentHierarchy->_activityAnimations;
|
||||
}
|
||||
|
||||
// ... but can be overridden
|
||||
for (uint i = 0; i < _animationReferences.size(); i++) {
|
||||
Anim *anim = _animationReferences[i].resolve<Anim>();
|
||||
|
||||
bool inserted = false;
|
||||
for (uint j = 0; j < _activityAnimations.size(); j++) {
|
||||
if (_activityAnimations[j]->getActivity() == anim->getActivity()) {
|
||||
_activityAnimations[j] = anim;
|
||||
inserted = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (!inserted) {
|
||||
_activityAnimations.push_back(anim);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void AnimHierarchy::loadIdleAnimations() {
|
||||
AnimHierarchy *parentHierarchy = _parentAnimHierarchyReference.resolve<AnimHierarchy>();
|
||||
if (parentHierarchy) {
|
||||
_idleAnimations = parentHierarchy->_idleAnimations;
|
||||
}
|
||||
|
||||
for (uint i = 0; i < _animationReferences.size(); i++) {
|
||||
Anim *anim = _animationReferences[i].resolve<Anim>();
|
||||
if (anim->getActivity() == Anim::kActorActivityIdleAction) {
|
||||
_idleAnimations.push_back(anim);
|
||||
}
|
||||
}
|
||||
|
||||
_idleActionsFrequencySum = 0;
|
||||
for (uint i = 0; i < _idleAnimations.size(); i++) {
|
||||
_idleActionsFrequencySum += _idleAnimations[i]->getIdleActionFrequency();
|
||||
}
|
||||
}
|
||||
|
||||
void AnimHierarchy::setItemAnim(ItemVisual *item, int32 activity) {
|
||||
unselectItemAnim(item);
|
||||
_currentActivity = activity;
|
||||
selectItemAnim(item);
|
||||
}
|
||||
|
||||
void AnimHierarchy::unselectItemAnim(ItemVisual *item) {
|
||||
if (_currentAnim && _currentAnim->isInUse()) {
|
||||
_currentAnim->removeFromItem(item);
|
||||
}
|
||||
|
||||
_currentAnim = nullptr;
|
||||
}
|
||||
|
||||
void AnimHierarchy::selectItemAnim(ItemVisual *item) {
|
||||
// Search for an animation with the appropriate index
|
||||
for (uint i = 0; i < _activityAnimations.size(); i++) {
|
||||
if (_activityAnimations[i]->getActivity() == _currentActivity) {
|
||||
_currentAnim = _activityAnimations[i];
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Default to the first animation
|
||||
if (!_currentAnim && !_activityAnimations.empty()) {
|
||||
_currentAnim = _activityAnimations[0];
|
||||
}
|
||||
|
||||
if (!_currentAnim) {
|
||||
error("Failed to set an animation for item %s", item->getName().c_str());
|
||||
}
|
||||
|
||||
if (!_currentAnim->isInUse()) {
|
||||
_currentAnim->applyToItem(item);
|
||||
}
|
||||
}
|
||||
|
||||
Anim *AnimHierarchy::getCurrentAnim() {
|
||||
return _currentAnim;
|
||||
}
|
||||
|
||||
BonesMesh *AnimHierarchy::findBonesMesh() {
|
||||
return findChild<BonesMesh>();
|
||||
}
|
||||
|
||||
TextureSet *AnimHierarchy::findTextureSet(uint32 textureType) {
|
||||
return findChildWithSubtype<TextureSet>(textureType);
|
||||
}
|
||||
|
||||
Anim *AnimHierarchy::getAnimForActivity(uint32 activity) {
|
||||
// Search for an animation with the appropriate use
|
||||
for (uint i = 0; i < _activityAnimations.size(); i++) {
|
||||
if (_activityAnimations[i]->getActivity() == activity) {
|
||||
return _activityAnimations[i];
|
||||
}
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
Visual *AnimHierarchy::getVisualForUsage(uint32 usage) {
|
||||
Anim *anim = getAnimForActivity(usage);
|
||||
if (anim) {
|
||||
return anim->getVisual();
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
Anim *AnimHierarchy::getIdleActionAnim() const {
|
||||
if (_idleActionsFrequencySum == 0) {
|
||||
return nullptr; // There are no idle animations
|
||||
}
|
||||
|
||||
int pick = StarkRandomSource->getRandomNumber(_idleActionsFrequencySum - 1);
|
||||
for (uint i = 0; i < _idleAnimations.size(); i++) {
|
||||
pick -= _idleAnimations[i]->getIdleActionFrequency();
|
||||
|
||||
if (pick < 0) {
|
||||
return _idleAnimations[i];
|
||||
}
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void AnimHierarchy::printData() {
|
||||
for (uint i = 0; i < _animationReferences.size(); i++) {
|
||||
debug("anim %d: %s", i, _animationReferences[i].describe().c_str());
|
||||
}
|
||||
|
||||
debug("animHierarchy: %s", _parentAnimHierarchyReference.describe().c_str());
|
||||
debug("field_5C: %f", _field_5C);
|
||||
}
|
||||
|
||||
} // End of namespace Resources
|
||||
} // End of namespace Stark
|
||||
110
engines/stark/resources/animhierarchy.h
Normal file
110
engines/stark/resources/animhierarchy.h
Normal file
@@ -0,0 +1,110 @@
|
||||
/* 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/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef STARK_RESOURCES_ANIM_HIERARCHY_H
|
||||
#define STARK_RESOURCES_ANIM_HIERARCHY_H
|
||||
|
||||
#include "common/str.h"
|
||||
|
||||
#include "engines/stark/resources/object.h"
|
||||
#include "engines/stark/resourcereference.h"
|
||||
|
||||
namespace Stark {
|
||||
|
||||
class Visual;
|
||||
|
||||
namespace Formats {
|
||||
class XRCReadStream;
|
||||
}
|
||||
|
||||
namespace Resources {
|
||||
|
||||
class Anim;
|
||||
class BonesMesh;
|
||||
class ItemVisual;
|
||||
class TextureSet;
|
||||
|
||||
/**
|
||||
* An animation hierarchy is a container resource referencing the available
|
||||
* animations for an item.
|
||||
*
|
||||
* This resource keeps track of the currently selected animation.
|
||||
*/
|
||||
class AnimHierarchy : public Object {
|
||||
public:
|
||||
static const Type::ResourceType TYPE = Type::kAnimHierarchy;
|
||||
|
||||
AnimHierarchy(Object *parent, byte subType, uint16 index, const Common::String &name);
|
||||
~AnimHierarchy() override;
|
||||
|
||||
// Resource API
|
||||
void readData(Formats::XRCReadStream *stream) override;
|
||||
void onAllLoaded() override;
|
||||
|
||||
/** Set and apply the current animation kind for an item */
|
||||
void setItemAnim(ItemVisual *item, int32 activity);
|
||||
|
||||
/** Unselect the current animation and remove it from an item */
|
||||
void unselectItemAnim(ItemVisual *item);
|
||||
|
||||
/** Apply the current animation to an item */
|
||||
void selectItemAnim(ItemVisual *item);
|
||||
|
||||
/** Obtain the currently selected animation */
|
||||
Anim *getCurrentAnim();
|
||||
|
||||
/** Retrieve the first bone mesh from the anim hierarchy children, if any */
|
||||
BonesMesh *findBonesMesh();
|
||||
|
||||
/**
|
||||
* Retrieve the first texture of the appropriate type from the anim
|
||||
* hierarchy children, if any
|
||||
*/
|
||||
TextureSet *findTextureSet(uint32 textureType);
|
||||
|
||||
Visual *getVisualForUsage(uint32 usage);
|
||||
|
||||
/** Randomize an idle action animation */
|
||||
Anim *getIdleActionAnim() const;
|
||||
|
||||
protected:
|
||||
void loadActivityAnimations();
|
||||
void loadIdleAnimations();
|
||||
|
||||
Anim *getAnimForActivity(uint32 activity);
|
||||
void printData() override;
|
||||
|
||||
Common::Array<ResourceReference> _animationReferences;
|
||||
Common::Array<Anim *> _activityAnimations;
|
||||
Common::Array<Anim *> _idleAnimations;
|
||||
|
||||
ResourceReference _parentAnimHierarchyReference;
|
||||
|
||||
float _field_5C;
|
||||
uint32 _currentActivity;
|
||||
Anim *_currentAnim;
|
||||
uint32 _idleActionsFrequencySum;
|
||||
};
|
||||
|
||||
} // End of namespace Resources
|
||||
} // End of namespace Stark
|
||||
|
||||
#endif // STARK_RESOURCES_ANIM_HIERARCHY_H
|
||||
211
engines/stark/resources/animscript.cpp
Normal file
211
engines/stark/resources/animscript.cpp
Normal file
@@ -0,0 +1,211 @@
|
||||
/* 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 "engines/stark/resources/animscript.h"
|
||||
|
||||
#include "common/debug.h"
|
||||
#include "common/random.h"
|
||||
|
||||
#include "engines/stark/debug.h"
|
||||
|
||||
#include "engines/stark/formats/xrc.h"
|
||||
|
||||
#include "engines/stark/resources/anim.h"
|
||||
#include "engines/stark/resources/container.h"
|
||||
#include "engines/stark/resources/location.h"
|
||||
#include "engines/stark/resources/sound.h"
|
||||
|
||||
#include "engines/stark/services/global.h"
|
||||
#include "engines/stark/services/services.h"
|
||||
#include "engines/stark/services/stateprovider.h"
|
||||
|
||||
namespace Stark {
|
||||
namespace Resources {
|
||||
|
||||
AnimScript::~AnimScript() {
|
||||
}
|
||||
|
||||
AnimScript::AnimScript(Object *parent, byte subType, uint16 index, const Common::String &name) :
|
||||
Object(parent, subType, index, name),
|
||||
_anim(nullptr),
|
||||
_nextItemIndex(-1),
|
||||
_msecsToNextUpdate(0),
|
||||
_done(false) {
|
||||
_type = TYPE;
|
||||
}
|
||||
|
||||
void AnimScript::onAllLoaded() {
|
||||
Object::onAllLoaded();
|
||||
|
||||
_anim = Object::cast<Anim>(_parent);
|
||||
_items = listChildren<AnimScriptItem>();
|
||||
|
||||
if (!_items.empty()) {
|
||||
// Setup the next item to the first
|
||||
_nextItemIndex = 0;
|
||||
}
|
||||
}
|
||||
|
||||
void AnimScript::onGameLoop() {
|
||||
Object::onGameLoop();
|
||||
|
||||
if (!_anim || !_anim->isInUse() || _nextItemIndex == -1) {
|
||||
// The script is disabled, do nothing
|
||||
return;
|
||||
}
|
||||
|
||||
int executedCommandCount = 0;
|
||||
|
||||
while (_msecsToNextUpdate <= (int32)StarkGlobal->getMillisecondsPerGameloop()) {
|
||||
bool goingBackwards = false;
|
||||
AnimScriptItem *item = _items[_nextItemIndex];
|
||||
_msecsToNextUpdate += item->getDuration();
|
||||
|
||||
switch (item->getOpcode()) {
|
||||
case AnimScriptItem::kDisplayFrame:
|
||||
_anim->selectFrame(item->getOperand());
|
||||
goToNextItem();
|
||||
break;
|
||||
case AnimScriptItem::kPlayAnimSound: {
|
||||
Container *sounds = _parent->findChildWithSubtype<Container>(Container::kSounds);
|
||||
Sound *sound = sounds->findChildWithOrder<Sound>(item->getOperand());
|
||||
sound->play();
|
||||
|
||||
goToNextItem();
|
||||
break;
|
||||
}
|
||||
case AnimScriptItem::kGoToItem:
|
||||
if (item->getOperand() <= (uint32) _nextItemIndex) {
|
||||
goingBackwards = true;
|
||||
}
|
||||
_nextItemIndex = item->getOperand();
|
||||
break;
|
||||
case AnimScriptItem::kDisplayRandomFrame: {
|
||||
uint32 startFrame = item->getOperand() >> 16;
|
||||
uint32 endFrame = item->getOperand() & 0xFFFF;
|
||||
|
||||
uint32 frame = StarkRandomSource->getRandomNumberRng(startFrame, endFrame);
|
||||
_anim->selectFrame(frame);
|
||||
goToNextItem();
|
||||
break;
|
||||
}
|
||||
case AnimScriptItem::kSleepRandomDuration: {
|
||||
uint duration = StarkRandomSource->getRandomNumber(item->getOperand());
|
||||
_msecsToNextUpdate += duration;
|
||||
goToNextItem();
|
||||
break;
|
||||
}
|
||||
case AnimScriptItem::kPlayStockSound: {
|
||||
Location *location = StarkGlobal->getCurrent()->getLocation();
|
||||
Sound *sound = location->findStockSound(item->getOperand());
|
||||
if (sound) {
|
||||
sound->play();
|
||||
}
|
||||
goToNextItem();
|
||||
break;
|
||||
}
|
||||
default:
|
||||
error("Unknown anim script type %d", item->getOpcode());
|
||||
}
|
||||
|
||||
if (_nextItemIndex == 0 || goingBackwards) {
|
||||
_done = true;
|
||||
}
|
||||
|
||||
executedCommandCount++;
|
||||
if (executedCommandCount >= 10) {
|
||||
debugC(kDebugAnimation, "Potential infinite loop in anim script %s", getName().c_str());
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
_msecsToNextUpdate -= StarkGlobal->getMillisecondsPerGameloop();
|
||||
}
|
||||
|
||||
void AnimScript::goToNextItem() {
|
||||
_nextItemIndex += 1;
|
||||
_nextItemIndex %= _items.size();
|
||||
}
|
||||
|
||||
void AnimScript::goToScriptItem(AnimScriptItem *item) {
|
||||
_nextItemIndex = findItemIndex(item);
|
||||
_msecsToNextUpdate = 0;
|
||||
_done = false;
|
||||
|
||||
if (item && item->getOpcode() == AnimScriptItem::kDisplayFrame) {
|
||||
_anim->selectFrame(item->getOperand());
|
||||
}
|
||||
}
|
||||
|
||||
bool AnimScript::hasReached(AnimScriptItem *item) {
|
||||
int32 index = findItemIndex(item);
|
||||
return _nextItemIndex >= index;
|
||||
}
|
||||
|
||||
bool AnimScript::isDone() const {
|
||||
return _done;
|
||||
}
|
||||
|
||||
int32 AnimScript::findItemIndex(AnimScriptItem *item) {
|
||||
if (!item) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
for (uint i = 0; i < _items.size(); i++) {
|
||||
if (_items[i] == item) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void AnimScript::saveLoad(ResourceSerializer *serializer) {
|
||||
serializer->syncAsSint32LE(_nextItemIndex);
|
||||
|
||||
if (serializer->isLoading()) {
|
||||
_msecsToNextUpdate = 0;
|
||||
}
|
||||
}
|
||||
|
||||
AnimScriptItem::~AnimScriptItem() {
|
||||
}
|
||||
|
||||
AnimScriptItem::AnimScriptItem(Object *parent, byte subType, uint16 index, const Common::String &name) :
|
||||
Object(parent, subType, index, name),
|
||||
_opcode(0),
|
||||
_duration(0),
|
||||
_operand(0) {
|
||||
_type = TYPE;
|
||||
}
|
||||
|
||||
void AnimScriptItem::readData(Formats::XRCReadStream *stream) {
|
||||
_opcode = stream->readUint32LE();
|
||||
_duration = stream->readUint32LE();
|
||||
_operand = stream->readUint32LE();
|
||||
}
|
||||
|
||||
void AnimScriptItem::printData() {
|
||||
debug("op: %d, duration: %d ms, operand: %d", _opcode, _duration, _operand);
|
||||
}
|
||||
|
||||
} // End of namespace Resources
|
||||
} // End of namespace Stark
|
||||
127
engines/stark/resources/animscript.h
Normal file
127
engines/stark/resources/animscript.h
Normal file
@@ -0,0 +1,127 @@
|
||||
/* 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/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef STARK_RESOURCES_ANIM_SCRIPT_H
|
||||
#define STARK_RESOURCES_ANIM_SCRIPT_H
|
||||
|
||||
#include "common/str.h"
|
||||
|
||||
#include "engines/stark/resources/object.h"
|
||||
|
||||
namespace Stark {
|
||||
|
||||
namespace Formats {
|
||||
class XRCReadStream;
|
||||
}
|
||||
|
||||
namespace Resources {
|
||||
|
||||
class Anim;
|
||||
class AnimScriptItem;
|
||||
|
||||
/**
|
||||
* Animation scripts control the currently displayed frame for images animation
|
||||
* resources.
|
||||
*
|
||||
* Animation scripts contain animation script items defining which frames
|
||||
* should be displayed and when.
|
||||
*
|
||||
* Animation scripts also allow to play sounds.
|
||||
*/
|
||||
class AnimScript : public Object {
|
||||
public:
|
||||
static const Type::ResourceType TYPE = Type::kAnimScript;
|
||||
|
||||
AnimScript(Object *parent, byte subType, uint16 index, const Common::String &name);
|
||||
virtual ~AnimScript();
|
||||
|
||||
// Resource API
|
||||
void onAllLoaded() override;
|
||||
void onGameLoop() override;
|
||||
void saveLoad(ResourceSerializer *serializer) override;
|
||||
|
||||
/** Go to a script item. Cancel any delay so that it is shown immediately. */
|
||||
void goToScriptItem(AnimScriptItem *item);
|
||||
|
||||
/** Is the current script item later in the script when compared to the specified one? */
|
||||
bool hasReached(AnimScriptItem *item);
|
||||
|
||||
/** Has the script completed playing the last script item at least once since started? */
|
||||
bool isDone() const;
|
||||
|
||||
protected:
|
||||
void goToNextItem();
|
||||
int32 findItemIndex(AnimScriptItem *item);
|
||||
|
||||
Anim *_anim;
|
||||
Common::Array<AnimScriptItem *> _items;
|
||||
|
||||
int32 _nextItemIndex;
|
||||
int32 _msecsToNextUpdate;
|
||||
bool _done;
|
||||
};
|
||||
|
||||
/**
|
||||
* Animation script element
|
||||
*
|
||||
* Has a type defining the operation to perform,
|
||||
* an argument and a duration.
|
||||
*/
|
||||
class AnimScriptItem : public Object {
|
||||
public:
|
||||
static const Type::ResourceType TYPE = Type::kAnimScriptItem;
|
||||
|
||||
enum Opcodes {
|
||||
kDisplayFrame = 0,
|
||||
kPlayAnimSound = 1,
|
||||
kGoToItem = 2,
|
||||
kDisplayRandomFrame = 3,
|
||||
kSleepRandomDuration = 4,
|
||||
kPlayStockSound = 5
|
||||
};
|
||||
|
||||
AnimScriptItem(Object *parent, byte subType, uint16 index, const Common::String &name);
|
||||
virtual ~AnimScriptItem();
|
||||
|
||||
// Resource API
|
||||
void readData(Formats::XRCReadStream *stream) override;
|
||||
|
||||
/** Obtain the operation code */
|
||||
uint32 getOpcode() const { return _opcode; }
|
||||
|
||||
/** Obtain the operation parameter */
|
||||
uint32 getOperand() const { return _operand; }
|
||||
|
||||
/** Obtain the operation duration */
|
||||
uint32 getDuration() const { return _duration; }
|
||||
|
||||
protected:
|
||||
void printData() override;
|
||||
|
||||
uint32 _opcode;
|
||||
uint32 _operand;
|
||||
uint32 _duration;
|
||||
};
|
||||
|
||||
} // End of namespace Resources
|
||||
} // End of namespace Stark
|
||||
|
||||
#endif // STARK_RESOURCES_ANIM_SCRIPT_H
|
||||
101
engines/stark/resources/animsoundtrigger.cpp
Normal file
101
engines/stark/resources/animsoundtrigger.cpp
Normal file
@@ -0,0 +1,101 @@
|
||||
/* 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 "engines/stark/resources/animsoundtrigger.h"
|
||||
|
||||
#include "engines/stark/formats/xrc.h"
|
||||
#include "engines/stark/resources/anim.h"
|
||||
#include "engines/stark/resources/location.h"
|
||||
#include "engines/stark/resources/sound.h"
|
||||
#include "engines/stark/services/global.h"
|
||||
#include "engines/stark/services/services.h"
|
||||
|
||||
namespace Stark {
|
||||
namespace Resources {
|
||||
|
||||
AnimSoundTrigger::~AnimSoundTrigger() {
|
||||
}
|
||||
|
||||
AnimSoundTrigger::AnimSoundTrigger(Object *parent, byte subType, uint16 index, const Common::String &name) :
|
||||
Object(parent, subType, index, name),
|
||||
_soundStockType(0),
|
||||
_soundTriggerTime(0),
|
||||
_anim(nullptr),
|
||||
_alreadyPlayed(false),
|
||||
_timeRemainingBeforeLoop(34) {
|
||||
_type = TYPE;
|
||||
}
|
||||
|
||||
void AnimSoundTrigger::onAllLoaded() {
|
||||
Object::onAllLoaded();
|
||||
_anim = Object::cast<AnimSkeleton>(_parent);
|
||||
}
|
||||
|
||||
void AnimSoundTrigger::onGameLoop() {
|
||||
Object::onGameLoop();
|
||||
|
||||
if (!_anim || !_anim->isInUse()) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (_alreadyPlayed && _anim->getCurrentTime() < 33) {
|
||||
// Animation loop detected, reset
|
||||
_alreadyPlayed = false;
|
||||
}
|
||||
|
||||
if ((!_alreadyPlayed && _anim->getCurrentTime() >= _soundTriggerTime) || _timeRemainingBeforeLoop < 33) {
|
||||
if (_timeRemainingBeforeLoop >= 33) {
|
||||
_alreadyPlayed = true;
|
||||
}
|
||||
|
||||
if (_subType == kAnimTriggerSound) {
|
||||
Location *location = StarkGlobal->getCurrent()->getLocation();
|
||||
Sound *sound = location->findStockSound(_soundStockType);
|
||||
if (sound && !StarkGlobal->isFastForward()) {
|
||||
// TODO: If the location has a 3D layer set the source position of the sound to the item position
|
||||
sound->stop();
|
||||
sound->play();
|
||||
}
|
||||
} else {
|
||||
warning("Unknown animation trigger subtype '%d'", _subType);
|
||||
}
|
||||
}
|
||||
|
||||
// Special handling for trigger times right before the animation loop point
|
||||
if (!_alreadyPlayed && _soundTriggerTime - _anim->getCurrentTime() < 33) {
|
||||
_timeRemainingBeforeLoop = _anim->getRemainingTime();
|
||||
} else {
|
||||
_timeRemainingBeforeLoop = 34;
|
||||
}
|
||||
}
|
||||
|
||||
void AnimSoundTrigger::readData(Formats::XRCReadStream *stream) {
|
||||
_soundTriggerTime = stream->readUint32LE();
|
||||
_soundStockType = stream->readUint32LE();
|
||||
}
|
||||
|
||||
void AnimSoundTrigger::printData() {
|
||||
debug("triggerTime: %d", _soundTriggerTime);
|
||||
debug("soundStockType: %d", _soundStockType);
|
||||
}
|
||||
|
||||
} // End of namespace Resources
|
||||
} // End of namespace Stark
|
||||
73
engines/stark/resources/animsoundtrigger.h
Normal file
73
engines/stark/resources/animsoundtrigger.h
Normal file
@@ -0,0 +1,73 @@
|
||||
/* 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/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef STARK_RESOURCES_ANIM_SOUND_TRIGGER_H
|
||||
#define STARK_RESOURCES_ANIM_SOUND_TRIGGER_H
|
||||
|
||||
#include "common/str.h"
|
||||
|
||||
#include "engines/stark/resources/object.h"
|
||||
|
||||
namespace Stark {
|
||||
|
||||
namespace Formats {
|
||||
class XRCReadStream;
|
||||
}
|
||||
|
||||
namespace Resources {
|
||||
|
||||
class AnimSkeleton;
|
||||
|
||||
/**
|
||||
* An AnimSoundTrigger plays a sound when a certain time of an animation is reached
|
||||
*
|
||||
* The sound is played at most once per animation loop.
|
||||
*/
|
||||
class AnimSoundTrigger : public Object {
|
||||
public:
|
||||
static const Type::ResourceType TYPE = Type::kAnimSoundTrigger;
|
||||
|
||||
enum SubType {
|
||||
kAnimTriggerSound = 1
|
||||
};
|
||||
|
||||
AnimSoundTrigger(Object *parent, byte subType, uint16 index, const Common::String &name);
|
||||
virtual ~AnimSoundTrigger();
|
||||
|
||||
// Resource API
|
||||
void readData(Formats::XRCReadStream *stream) override;
|
||||
void printData() override;
|
||||
void onAllLoaded() override;
|
||||
void onGameLoop() override;
|
||||
|
||||
private:
|
||||
uint32 _soundStockType;
|
||||
uint32 _soundTriggerTime;
|
||||
|
||||
AnimSkeleton *_anim;
|
||||
bool _alreadyPlayed;
|
||||
uint _timeRemainingBeforeLoop;
|
||||
};
|
||||
|
||||
} // End of namespace Resources
|
||||
} // End of namespace Stark
|
||||
|
||||
#endif // STARK_RESOURCES_ANIM_SOUND_TRIGGER_H
|
||||
66
engines/stark/resources/bonesmesh.cpp
Normal file
66
engines/stark/resources/bonesmesh.cpp
Normal file
@@ -0,0 +1,66 @@
|
||||
/* 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 "engines/stark/resources/bonesmesh.h"
|
||||
|
||||
#include "engines/stark/model/animhandler.h"
|
||||
#include "engines/stark/model/model.h"
|
||||
#include "engines/stark/services/archiveloader.h"
|
||||
#include "engines/stark/services/services.h"
|
||||
#include "engines/stark/formats/xrc.h"
|
||||
|
||||
namespace Stark {
|
||||
namespace Resources {
|
||||
|
||||
BonesMesh::~BonesMesh() {
|
||||
delete _model;
|
||||
}
|
||||
|
||||
BonesMesh::BonesMesh(Object *parent, byte subType, uint16 index, const Common::String &name) :
|
||||
Object(parent, subType, index, name),
|
||||
_model(nullptr) {
|
||||
_type = TYPE;
|
||||
}
|
||||
|
||||
void BonesMesh::readData(Formats::XRCReadStream *stream) {
|
||||
_filename = Common::Path(stream->readString());
|
||||
_archiveName = stream->getArchiveName();
|
||||
}
|
||||
|
||||
void BonesMesh::onPostRead() {
|
||||
ArchiveReadStream *stream = StarkArchiveLoader->getFile(_filename, _archiveName);
|
||||
|
||||
_model = new Model();
|
||||
_model->readFromStream(stream);
|
||||
|
||||
delete stream;
|
||||
}
|
||||
|
||||
Model *BonesMesh::getModel() {
|
||||
return _model;
|
||||
}
|
||||
|
||||
void BonesMesh::printData() {
|
||||
debug("filename: %s", _filename.toString().c_str());
|
||||
}
|
||||
|
||||
} // End of namespace Resources
|
||||
} // End of namespace Stark
|
||||
69
engines/stark/resources/bonesmesh.h
Normal file
69
engines/stark/resources/bonesmesh.h
Normal file
@@ -0,0 +1,69 @@
|
||||
/* 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/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef STARK_RESOURCES_BONES_MESH_H
|
||||
#define STARK_RESOURCES_BONES_MESH_H
|
||||
|
||||
#include "common/path.h"
|
||||
#include "common/str.h"
|
||||
|
||||
#include "engines/stark/resources/object.h"
|
||||
|
||||
namespace Stark {
|
||||
|
||||
class Model;
|
||||
|
||||
namespace Formats {
|
||||
class XRCReadStream;
|
||||
}
|
||||
|
||||
namespace Resources {
|
||||
|
||||
/**
|
||||
* Bone mesh resources reference a mesh usable by actor resources
|
||||
*/
|
||||
class BonesMesh : public Object {
|
||||
public:
|
||||
static const Type::ResourceType TYPE = Type::kBonesMesh;
|
||||
|
||||
BonesMesh(Object *parent, byte subType, uint16 index, const Common::String &name);
|
||||
virtual ~BonesMesh();
|
||||
|
||||
// Resource API
|
||||
void readData(Formats::XRCReadStream *stream) override;
|
||||
void onPostRead() override;
|
||||
|
||||
/** Obtain the mesh object */
|
||||
Model *getModel();
|
||||
|
||||
protected:
|
||||
void printData() override;
|
||||
|
||||
Common::Path _filename;
|
||||
Common::Path _archiveName;
|
||||
|
||||
Model *_model;
|
||||
};
|
||||
|
||||
} // End of namespace Resources
|
||||
} // End of namespace Stark
|
||||
|
||||
#endif // STARK_RESOURCES_BONES_MESH_H
|
||||
65
engines/stark/resources/bookmark.cpp
Normal file
65
engines/stark/resources/bookmark.cpp
Normal file
@@ -0,0 +1,65 @@
|
||||
/* 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 "engines/stark/resources/bookmark.h"
|
||||
|
||||
#include "engines/stark/formats/xrc.h"
|
||||
|
||||
#include "engines/stark/resources/floor.h"
|
||||
|
||||
#include "engines/stark/services/global.h"
|
||||
#include "engines/stark/services/services.h"
|
||||
|
||||
namespace Stark {
|
||||
namespace Resources {
|
||||
|
||||
Bookmark::~Bookmark() {
|
||||
}
|
||||
|
||||
Bookmark::Bookmark(Object *parent, byte subType, uint16 index, const Common::String &name) :
|
||||
Object(parent, subType, index, name) {
|
||||
_type = TYPE;
|
||||
}
|
||||
|
||||
Math::Vector3d Bookmark::getPosition() const {
|
||||
Floor *floor = StarkGlobal->getCurrent()->getFloor();
|
||||
|
||||
Math::Vector3d position = _position;
|
||||
|
||||
int32 floorFaceIndex = floor->findFaceContainingPoint(position);
|
||||
floor->computePointHeightInFace(position, floorFaceIndex);
|
||||
|
||||
return position;
|
||||
}
|
||||
|
||||
void Bookmark::readData(Formats::XRCReadStream *stream) {
|
||||
_position.x() = stream->readFloatLE();
|
||||
_position.y() = stream->readFloatLE();
|
||||
_position.z() = 0;
|
||||
}
|
||||
|
||||
void Bookmark::printData() {
|
||||
Common::StreamDebug debug = streamDbg();
|
||||
debug << "position: " << _position << "\n";
|
||||
}
|
||||
|
||||
} // End of namespace Resources
|
||||
} // End of namespace Stark
|
||||
66
engines/stark/resources/bookmark.h
Normal file
66
engines/stark/resources/bookmark.h
Normal file
@@ -0,0 +1,66 @@
|
||||
/* 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/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef STARK_RESOURCES_BOOKMARK_H
|
||||
#define STARK_RESOURCES_BOOKMARK_H
|
||||
|
||||
#include "common/str.h"
|
||||
#include "math/vector3d.h"
|
||||
|
||||
#include "engines/stark/resources/object.h"
|
||||
|
||||
namespace Stark {
|
||||
|
||||
namespace Formats {
|
||||
class XRCReadStream;
|
||||
}
|
||||
|
||||
namespace Resources {
|
||||
|
||||
/**
|
||||
* Bookmark resources are handles for a position on the floor field.
|
||||
*
|
||||
* The height value is not set, it needs to be retrieved by interpolation
|
||||
* from the floor field.
|
||||
*/
|
||||
class Bookmark : public Object {
|
||||
public:
|
||||
static const Type::ResourceType TYPE = Type::kBookmark;
|
||||
|
||||
Bookmark(Object *parent, byte subType, uint16 index, const Common::String &name);
|
||||
virtual ~Bookmark();
|
||||
|
||||
// Resource API
|
||||
void readData(Formats::XRCReadStream *stream) override;
|
||||
|
||||
/** Obtain the position */
|
||||
Math::Vector3d getPosition() const;
|
||||
|
||||
protected:
|
||||
void printData() override;
|
||||
|
||||
Math::Vector3d _position;
|
||||
};
|
||||
|
||||
} // End of namespace Resources
|
||||
} // End of namespace Stark
|
||||
|
||||
#endif // STARK_RESOURCES_BOOKMARK_H
|
||||
103
engines/stark/resources/camera.cpp
Normal file
103
engines/stark/resources/camera.cpp
Normal file
@@ -0,0 +1,103 @@
|
||||
/* 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 "engines/stark/resources/camera.h"
|
||||
|
||||
#include "engines/stark/debug.h"
|
||||
#include "engines/stark/formats/xrc.h"
|
||||
#include "engines/stark/resources/location.h"
|
||||
#include "engines/stark/scene.h"
|
||||
#include "engines/stark/services/services.h"
|
||||
|
||||
namespace Stark {
|
||||
namespace Resources {
|
||||
|
||||
Camera::~Camera() {
|
||||
}
|
||||
|
||||
Camera::Camera(Object *parent, byte subType, uint16 index, const Common::String &name) :
|
||||
Object(parent, subType, index, name),
|
||||
_f1(0),
|
||||
_fov(45),
|
||||
_nearClipPlane(100.0),
|
||||
_farClipPlane(64000.0) {
|
||||
_type = TYPE;
|
||||
}
|
||||
|
||||
void Camera::setClipPlanes(float near, float far) {
|
||||
_nearClipPlane = near;
|
||||
_farClipPlane = far;
|
||||
}
|
||||
|
||||
void Camera::readData(Formats::XRCReadStream *stream) {
|
||||
_position = stream->readVector3();
|
||||
_lookDirection = stream->readVector3();
|
||||
_f1 = stream->readFloatLE();
|
||||
_fov = stream->readFloatLE();
|
||||
_viewSize = stream->readRect();
|
||||
_v4 = stream->readVector3();
|
||||
}
|
||||
|
||||
void Camera::onAllLoaded() {
|
||||
Object::onAllLoaded();
|
||||
|
||||
// Compute scroll coordinates bounds
|
||||
Common::Point maxScroll;
|
||||
maxScroll.x = _viewSize.width() - 640;
|
||||
maxScroll.y = _viewSize.height() - 365;
|
||||
|
||||
Location *location = findParent<Location>();
|
||||
location->initScroll(maxScroll);
|
||||
}
|
||||
|
||||
void Camera::onEnterLocation() {
|
||||
Object::onEnterLocation();
|
||||
|
||||
// Setup the camera
|
||||
StarkScene->initCamera(_position, _lookDirection, _fov, _viewSize, _nearClipPlane, _farClipPlane);
|
||||
|
||||
// Scroll the camera to its initial position
|
||||
Location *location = findParent<Location>();
|
||||
location->setScrollPosition(location->getScrollPosition());
|
||||
}
|
||||
|
||||
Math::Angle Camera::getHorizontalAngle() const {
|
||||
Math::Angle lookDirectionAngle = Math::Vector3d::angle(_lookDirection, Math::Vector3d(1.0, 0.0, 0.0));
|
||||
Math::Vector3d cross = Math::Vector3d::crossProduct(_lookDirection, Math::Vector3d(1.0, 0.0, 0.0));
|
||||
if (cross.z() < 0) {
|
||||
return -lookDirectionAngle;
|
||||
} else {
|
||||
return lookDirectionAngle;
|
||||
}
|
||||
}
|
||||
|
||||
void Camera::printData() {
|
||||
Common::StreamDebug debug = streamDbg();
|
||||
debug << "position: " << _position << "\n";
|
||||
debug << "lookDirection: " << _lookDirection << "\n";
|
||||
debug << "f1: " << _f1 << "\n";
|
||||
debug << "fov: " << _fov << "\n";
|
||||
debug << "viewSize:" << _viewSize.left << _viewSize.top << _viewSize.right << _viewSize.bottom << "\n";
|
||||
debug << "v4: " << _v4 << "\n";
|
||||
}
|
||||
|
||||
} // End of namespace Resources
|
||||
} // End of namespace Stark
|
||||
82
engines/stark/resources/camera.h
Normal file
82
engines/stark/resources/camera.h
Normal file
@@ -0,0 +1,82 @@
|
||||
/* 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/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef STARK_RESOURCES_CAMERA_H
|
||||
#define STARK_RESOURCES_CAMERA_H
|
||||
|
||||
#include "common/array.h"
|
||||
#include "common/rect.h"
|
||||
#include "common/str.h"
|
||||
|
||||
#include "math/angle.h"
|
||||
#include "math/vector3d.h"
|
||||
#include "math/vector4d.h"
|
||||
|
||||
#include "engines/stark/resources/object.h"
|
||||
|
||||
namespace Stark {
|
||||
|
||||
namespace Formats {
|
||||
class XRCReadStream;
|
||||
}
|
||||
|
||||
namespace Resources {
|
||||
|
||||
/**
|
||||
* Camera resources define the camera position, perspective parameters,
|
||||
* and look at direction.
|
||||
*/
|
||||
class Camera : public Object {
|
||||
public:
|
||||
static const Type::ResourceType TYPE = Type::kCamera;
|
||||
|
||||
Camera(Object *parent, byte subType, uint16 index, const Common::String &name);
|
||||
virtual ~Camera();
|
||||
|
||||
// Resource API
|
||||
void onAllLoaded() override;
|
||||
void onEnterLocation() override;
|
||||
|
||||
/** Define the near and far clip planes distances */
|
||||
void setClipPlanes(float near, float far);
|
||||
|
||||
/** Compute the angle between the X vector and the look at direction in the horizontal plane */
|
||||
Math::Angle getHorizontalAngle() const;
|
||||
|
||||
protected:
|
||||
void readData(Formats::XRCReadStream *stream) override;
|
||||
void printData() override;
|
||||
|
||||
Math::Vector3d _position;
|
||||
Math::Vector3d _lookDirection;
|
||||
float _f1;
|
||||
float _fov;
|
||||
Common::Rect _viewSize;
|
||||
Math::Vector3d _v4;
|
||||
|
||||
float _nearClipPlane;
|
||||
float _farClipPlane;
|
||||
};
|
||||
|
||||
} // End of namespace Resources
|
||||
} // End of namespace Stark
|
||||
|
||||
#endif // STARK_RESOURCES_CAMERA_H
|
||||
1360
engines/stark/resources/command.cpp
Normal file
1360
engines/stark/resources/command.cpp
Normal file
File diff suppressed because it is too large
Load Diff
294
engines/stark/resources/command.h
Normal file
294
engines/stark/resources/command.h
Normal file
@@ -0,0 +1,294 @@
|
||||
/* 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/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef STARK_RESOURCES_COMMAND_H
|
||||
#define STARK_RESOURCES_COMMAND_H
|
||||
|
||||
#include "common/array.h"
|
||||
#include "common/str.h"
|
||||
|
||||
#include "math/vector3d.h"
|
||||
|
||||
#include "engines/stark/resources/object.h"
|
||||
#include "engines/stark/resourcereference.h"
|
||||
|
||||
namespace Stark {
|
||||
|
||||
class ResourceReference;
|
||||
namespace Formats {
|
||||
class XRCReadStream;
|
||||
}
|
||||
|
||||
namespace Resources {
|
||||
|
||||
class Script;
|
||||
|
||||
/**
|
||||
* Command resources are script operations.
|
||||
*
|
||||
* The operation code is the resource subtype.
|
||||
*
|
||||
* The operation arguments can be integers, strings or resource references.
|
||||
*/
|
||||
class Command : public Object {
|
||||
public:
|
||||
static const Type::ResourceType TYPE = Type::kCommand;
|
||||
|
||||
Command(Object *parent, byte subType, uint16 index, const Common::String &name);
|
||||
virtual ~Command();
|
||||
|
||||
enum SubType {
|
||||
kCommandBegin = 0,
|
||||
kCommandEnd = 1,
|
||||
kScriptCall = 2,
|
||||
kDialogCall = 3,
|
||||
kSetInteractiveMode = 4,
|
||||
kLocationGoTo = 5,
|
||||
|
||||
kWalkTo = 7,
|
||||
kGameLoop = 8,
|
||||
kScriptPause = 9,
|
||||
kScriptPauseRandom = 10,
|
||||
kScriptPauseSkippable = 11,
|
||||
|
||||
kScriptAbort = 13,
|
||||
|
||||
kExit2DLocation = 16,
|
||||
kGoto2DLocation = 17,
|
||||
|
||||
kRumbleScene = 19,
|
||||
kFadeScene = 20,
|
||||
kSwayScene = 21,
|
||||
|
||||
kLocationGoToNewCD = 22,
|
||||
kGameEnd = 23,
|
||||
kInventoryOpen = 24,
|
||||
kFloatScene = 25,
|
||||
kBookOfSecretsOpen = 26,
|
||||
|
||||
kDoNothing = 80,
|
||||
kItem3DPlaceOn = 81,
|
||||
kItem3DWalkTo = 82,
|
||||
kItem3DFollowPath = 83,
|
||||
kItemLookAt = 84,
|
||||
|
||||
kItem2DFollowPath = 86,
|
||||
kItemEnable = 87,
|
||||
kItemSetActivity = 88,
|
||||
kItemSelectInInventory = 89,
|
||||
|
||||
kUseAnimHierarchy = 92,
|
||||
kPlayAnimation = 93,
|
||||
kScriptEnable = 94,
|
||||
kShowPlay = 95,
|
||||
kKnowledgeSetBoolean = 96,
|
||||
|
||||
kKnowledgeSetInteger = 100,
|
||||
kKnowledgeAddInteger = 101,
|
||||
|
||||
kEnableFloorField = 103,
|
||||
kPlayAnimScriptItem = 104,
|
||||
kItemAnimFollowPath = 105,
|
||||
|
||||
kKnowledgeAssignBool = 107,
|
||||
|
||||
kKnowledgeAssignInteger = 110,
|
||||
kLocationScrollTo = 111,
|
||||
kSoundPlay = 112,
|
||||
|
||||
kKnowledgeSetIntRandom = 115,
|
||||
|
||||
kKnowledgeSubValue = 117,
|
||||
kItemLookDirection = 118,
|
||||
|
||||
kStopPlayingSound = 119,
|
||||
kLayerGoTo = 120,
|
||||
kLayerEnable = 121,
|
||||
kLocationScrollSet = 122,
|
||||
kFullMotionVideoPlay = 123,
|
||||
|
||||
kAnimSetFrame = 125,
|
||||
kKnowledgeAssignNegatedBool = 126,
|
||||
kDiaryEnableEntry = 127,
|
||||
kPATChangeTooltip = 128,
|
||||
kSoundChange = 129,
|
||||
kLightSetColor = 130,
|
||||
kLightFollowPath = 131,
|
||||
kItem3DRunTo = 132,
|
||||
kItemPlaceDirection = 133,
|
||||
kItemRotateDirection = 134,
|
||||
kActivateTexture = 135,
|
||||
kActivateMesh = 136,
|
||||
kItem3DSetWalkTarget = 137,
|
||||
|
||||
kSpeakWithoutTalking = 139,
|
||||
|
||||
kIsOnFloorField = 162,
|
||||
kIsItemEnabled = 163,
|
||||
|
||||
kIsScriptEnabled = 165,
|
||||
kIsKnowledgeBooleanSet = 166,
|
||||
|
||||
kIsKnowledgeIntegerInRange = 170,
|
||||
kIsKnowledgeIntegerAbove = 171,
|
||||
kIsKnowledgeIntegerEqual = 172,
|
||||
kIsKnowledgeIntegerLower = 173,
|
||||
kIsScriptActive = 174,
|
||||
kIsRandom = 175,
|
||||
kIsAnimScriptItemReached = 176,
|
||||
kIsItemOnPlace = 177,
|
||||
|
||||
kIsAnimPlaying = 179,
|
||||
kIsItemActivity = 180,
|
||||
|
||||
kIsItemNearPlace = 183,
|
||||
|
||||
kIsAnimAtTime = 185,
|
||||
kIsLocation2D = 186,
|
||||
kIsInventoryOpen = 187
|
||||
};
|
||||
|
||||
struct Argument {
|
||||
enum Type {
|
||||
kTypeInteger1 = 1,
|
||||
kTypeInteger2 = 2,
|
||||
kTypeResourceReference = 3,
|
||||
kTypeString = 4
|
||||
};
|
||||
|
||||
uint32 type;
|
||||
uint32 intValue;
|
||||
Common::String stringValue;
|
||||
ResourceReference referenceValue;
|
||||
};
|
||||
|
||||
/** Execute the command */
|
||||
Command *execute(uint32 callMode, Script *script);
|
||||
|
||||
/** Obtain the next command to be executed */
|
||||
Command *nextCommand();
|
||||
|
||||
/** Obtain the next command to be executed, depending on a predicate */
|
||||
Command *nextCommandIf(bool predicate);
|
||||
|
||||
/** Get the command's list of arguments */
|
||||
Common::Array<Argument> getArguments() const;
|
||||
|
||||
/** Resume the opcode ItemSetActivity after it has stopped waiting for the action anim to complete */
|
||||
void resumeItemSetActivity();
|
||||
|
||||
protected:
|
||||
void readData(Formats::XRCReadStream *stream) override;
|
||||
|
||||
Command *resolveArgumentSiblingReference(const Argument &argument);
|
||||
|
||||
Math::Vector3d getObjectPosition(const ResourceReference &targetRef, int32 *floorFace = nullptr);
|
||||
|
||||
Command *opScriptBegin();
|
||||
Command *opScriptCall(Script *script, const ResourceReference &scriptRef, int32 synchronous);
|
||||
Command *opDialogCall(Script *script, const ResourceReference &dialogRef, int32 suspend);
|
||||
Command *opSetInteractiveMode(bool enabled);
|
||||
Command *opLocationGoTo(const Common::String &level, const Common::String &location, const ResourceReference &bookmarkRef, int32 direction);
|
||||
Command *opWalkTo(Script *script, const ResourceReference &objectRef, int32 suspend);
|
||||
Command *opScriptPauseGameLoop(Script *script, int32 count);
|
||||
Command *opScriptPause(Script *script, const ResourceReference &durationRef);
|
||||
Command *opScriptPauseRandom(Script *script, const ResourceReference &itemRef);
|
||||
Command *opScriptPauseSkippable(Script *script, const ResourceReference &durationRef);
|
||||
Command *opScriptAbort(ResourceReference scriptRef, bool disable);
|
||||
Command *opExit2DLocation();
|
||||
Command *opGoto2DLocation(const Common::String &level, const Common::String &location);
|
||||
Command *opRumbleScene(Script *script, int32 rumbleDuration, int32 pause);
|
||||
Command *opFadeScene(Script *script, bool fadeOut, int32 fadeDuration, bool pause);
|
||||
Command *opSwayScene(int32 periodMs, int32 angleIn, int32 amplitudeIn, int32 offsetIn);
|
||||
Command *opGameEnd();
|
||||
Command *opInventoryOpen(bool open);
|
||||
Command *opFloatScene(int32 periodMs, int32 amplitudeIn, int32 offsetIn);
|
||||
Command *opBookOfSecretsOpen();
|
||||
Command *opDoNothing();
|
||||
Command *opItem3DPlaceOn(const ResourceReference &itemRef, const ResourceReference &targetRef);
|
||||
Command *opItem3DWalkTo(Script *script, const ResourceReference &itemRef, const ResourceReference &targetRef, bool suspend);
|
||||
Command *opItemFollowPath(Script *script, ResourceReference itemRef, ResourceReference pathRef, uint32 speed, uint32 suspend);
|
||||
Command *opItemLookAt(Script *script, const ResourceReference &itemRef, const ResourceReference &objRef, bool suspend, int32 unknown);
|
||||
Command *opItemEnable(const ResourceReference &itemRef, int32 enable);
|
||||
Command *opItemSetActivity(Script *script, const ResourceReference &itemRef, int32 animActivity, bool wait);
|
||||
Command *opItemSelectInInventory(const ResourceReference &itemRef);
|
||||
Command *opUseAnimHierachy(const ResourceReference &animHierRef);
|
||||
Command *opPlayAnimation(Script *script, const ResourceReference &animRef, bool suspend);
|
||||
Command *opScriptEnable(const ResourceReference &scriptRef, int32 enable);
|
||||
Command *opShowPlay(Script *script, const ResourceReference &ref, int32 suspend);
|
||||
Command *opKnowledgeSetBoolean(const ResourceReference &knowledgeRef, int32 enable);
|
||||
Command *opKnowledgeSetInteger(const ResourceReference &knowledgeRef, int32 value);
|
||||
Command *opKnowledgeSetIntRandom(const ResourceReference &knowledgeRef, uint32 min, uint32 max);
|
||||
Command *opKnowledgeAddInteger(const ResourceReference &knowledgeRef, int32 increment);
|
||||
Command *opKnowledgeSubValue(const ResourceReference &knowledgeRef, const ResourceReference &valueRef);
|
||||
Command *opEnableFloorField(const ResourceReference &floorFieldRef, bool enable);
|
||||
Command *opPlayAnimScriptItem(Script *script, const ResourceReference &animScriptItemRef, int32 suspend);
|
||||
Command *opItemAnimFollowPath(Script *script, const ResourceReference &animRef, const ResourceReference &pathRef, int32 speed, bool suspend);
|
||||
Command *opKnowledgeAssignBool(const ResourceReference &knowledgeRef1, const ResourceReference &knowledgeRef2);
|
||||
Command *opKnowledgeAssignNegatedBool(const ResourceReference &knowledgeRef1, const ResourceReference &knowledgeRef2);
|
||||
Command *opKnowledgeAssignInteger(const ResourceReference &knowledgeRef1, const ResourceReference &knowledgeRef2);
|
||||
Command *opLocationScrollTo(Script *script, const ResourceReference &scrollRef, bool suspend);
|
||||
Command *opSoundPlay(Script *script, const ResourceReference &soundRef, int32 suspend);
|
||||
Command *opItemLookDirection(Script *script, const ResourceReference &itemRef, int32 direction, bool suspend);
|
||||
Command *opStopPlayingSound(const ResourceReference &soundRef);
|
||||
Command *opLayerGoTo(const ResourceReference &layerRef);
|
||||
Command *opLayerEnable(const ResourceReference &layerRef, int32 enable);
|
||||
Command *opLocationScrollSet(const ResourceReference &scrollRef);
|
||||
Command *opFullMotionVideoPlay(Script *script, const ResourceReference &movieRef, int32 unknown);
|
||||
Command *opAnimSetFrame(const ResourceReference &animRef, const ResourceReference &knowledgeRef);
|
||||
Command *opDiaryEnableEntry(const ResourceReference &knowledgeRef);
|
||||
Command *opPATChangeTooltip(const ResourceReference &patRef, const ResourceReference &stringRef);
|
||||
Command *opSoundChange(Script *script, const ResourceReference &soundRef, int32 volume, int32 pan, int32 duration, bool pause);
|
||||
Command *opLightSetColor(const ResourceReference &lightRef, int32 red, int32 green, int32 blue);
|
||||
Command *opLightFollowPath(Script *script, const ResourceReference &itemRef, const ResourceReference &lightRef, const ResourceReference &pathRef, int32 speed, bool suspend);
|
||||
Command *opItem3DRunTo(Script *script, const ResourceReference &itemRef, const ResourceReference &targetRef, int32 suspend);
|
||||
Command *opItemPlaceDirection(const ResourceReference &itemRef, int32 direction);
|
||||
Command *opItemRotateDirection(Script *script, const ResourceReference &itemRef, int32 direction, int32 speed, bool suspend);
|
||||
Command *opActivateTexture(const ResourceReference &textureRef);
|
||||
Command *opActivateMesh(const ResourceReference &meshRef);
|
||||
Command *opItem3DSetWalkTarget(const ResourceReference &itemRef, const ResourceReference &targetRef);
|
||||
Command *opSpeakWithoutTalking(Script *script, const ResourceReference &speechRef, int32 unknown);
|
||||
Command *opIsOnFloorField(const ResourceReference &itemRef, const ResourceReference &floorFieldRef);
|
||||
Command *opIsItemEnabled(const ResourceReference &itemRef);
|
||||
Command *opIsScriptEnabled(const ResourceReference &scriptRef);
|
||||
Command *opIsKnowledgeBooleanSet(const ResourceReference &knowledgeRef);
|
||||
Command *opIsKnowledgeIntegerInRange(const ResourceReference &knowledgeRef, int32 min, int32 max);
|
||||
Command *opIsKnowledgeIntegerAbove(const ResourceReference &knowledgeRef, int32 value);
|
||||
Command *opIsKnowledgeIntegerEqual(const ResourceReference &knowledgeRef, int32 value);
|
||||
Command *opIsKnowledgeIntegerLower(const ResourceReference &knowledgeRef, int32 value);
|
||||
Command *opIsScriptActive(const ResourceReference &scriptRef);
|
||||
Command *opIsRandom(int32 chance);
|
||||
Command *opIsAnimScriptItemReached(const ResourceReference &animScriptItemRef);
|
||||
Command *opIsItemNearPlace(const ResourceReference &itemRef, const ResourceReference &positionRef, int32 testDistance);
|
||||
Command *opIsItemOnPlace(const ResourceReference &itemRef, const ResourceReference &positionRef);
|
||||
Command *opIsAnimPlaying(const ResourceReference &animRef);
|
||||
Command *opIsItemActivity(const ResourceReference &itemRef, int32 value);
|
||||
Command *opIsAnimAtTime(const ResourceReference &animRef, int32 time);
|
||||
Command *opIsLocation2D();
|
||||
Command *opIsInventoryOpen();
|
||||
|
||||
Common::Array<Argument> _arguments;
|
||||
};
|
||||
|
||||
} // End of namespace Resources
|
||||
} // End of namespace Stark
|
||||
|
||||
#endif // STARK_RESOURCES_COMMAND_H
|
||||
38
engines/stark/resources/container.cpp
Normal file
38
engines/stark/resources/container.cpp
Normal file
@@ -0,0 +1,38 @@
|
||||
/* 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 "engines/stark/resources/container.h"
|
||||
|
||||
#include "engines/stark/formats/xrc.h"
|
||||
|
||||
namespace Stark {
|
||||
namespace Resources {
|
||||
|
||||
Container::~Container() {
|
||||
}
|
||||
|
||||
Container::Container(Object *parent, byte subType, uint16 index, const Common::String &name) :
|
||||
Object(parent, subType, index, name) {
|
||||
_type = TYPE;
|
||||
}
|
||||
|
||||
} // End of namespace Resources
|
||||
} // End of namespace Stark
|
||||
52
engines/stark/resources/container.h
Normal file
52
engines/stark/resources/container.h
Normal file
@@ -0,0 +1,52 @@
|
||||
/* 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/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef STARK_RESOURCES_CONTAINER_H
|
||||
#define STARK_RESOURCES_CONTAINER_H
|
||||
|
||||
#include "common/str.h"
|
||||
|
||||
#include "engines/stark/resources/object.h"
|
||||
|
||||
namespace Stark {
|
||||
|
||||
namespace Resources {
|
||||
|
||||
/**
|
||||
* Containers are holder resources for other resources of various kinds
|
||||
*/
|
||||
class Container : public Object {
|
||||
public:
|
||||
static const Type::ResourceType TYPE = Type::kContainer;
|
||||
|
||||
enum SubType {
|
||||
kSounds = 5,
|
||||
kStockSounds = 8
|
||||
};
|
||||
|
||||
Container(Object *parent, byte subType, uint16 index, const Common::String &name);
|
||||
virtual ~Container();
|
||||
};
|
||||
|
||||
} // End of namespace Resources
|
||||
} // End of namespace Stark
|
||||
|
||||
#endif // STARK_RESOURCES_CONTAINER_H
|
||||
334
engines/stark/resources/dialog.cpp
Normal file
334
engines/stark/resources/dialog.cpp
Normal file
@@ -0,0 +1,334 @@
|
||||
/* 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 "engines/stark/resources/dialog.h"
|
||||
|
||||
#include "engines/stark/formats/xrc.h"
|
||||
|
||||
#include "engines/stark/resources/item.h"
|
||||
#include "engines/stark/resources/knowledge.h"
|
||||
#include "engines/stark/resources/script.h"
|
||||
#include "engines/stark/resources/speech.h"
|
||||
|
||||
#include "engines/stark/services/global.h"
|
||||
#include "engines/stark/services/services.h"
|
||||
#include "engines/stark/services/stateprovider.h"
|
||||
|
||||
namespace Stark {
|
||||
namespace Resources {
|
||||
|
||||
Dialog::~Dialog() {
|
||||
}
|
||||
|
||||
Dialog::Dialog(Object *parent, byte subType, uint16 index, const Common::String &name) :
|
||||
Object(parent, subType, index, name),
|
||||
_character(0),
|
||||
_hasAskAbout(0) {
|
||||
_type = TYPE;
|
||||
}
|
||||
|
||||
void Dialog::readData(Formats::XRCReadStream *stream) {
|
||||
Object::readData(stream);
|
||||
|
||||
_hasAskAbout = stream->readUint32LE();
|
||||
_character = stream->readUint32LE();
|
||||
|
||||
uint32 numTopics = stream->readUint32LE();
|
||||
for (uint32 i = 0; i < numTopics; i++) {
|
||||
Topic topic;
|
||||
topic._removeOnceDepleted = stream->readBool();
|
||||
|
||||
uint32 numReplies = stream->readUint32LE();
|
||||
for (uint j = 0; j < numReplies; j++) {
|
||||
Reply reply;
|
||||
|
||||
reply._conditionType = stream->readUint32LE();
|
||||
reply._conditionReference = stream->readResourceReference();
|
||||
reply._conditionScriptReference = stream->readResourceReference();
|
||||
reply._conditionReversed = stream->readUint32LE();
|
||||
reply._field_88 = stream->readUint32LE();
|
||||
reply._minChapter = stream->readUint32LE();
|
||||
reply._maxChapter = stream->readUint32LE();
|
||||
reply._noCaption = stream->readUint32LE();
|
||||
reply._nextDialogIndex = stream->readSint32LE();
|
||||
reply._nextScriptReference = stream->readResourceReference();
|
||||
|
||||
uint32 numLines = stream->readUint32LE();
|
||||
for (uint k = 0; k < numLines; k++) {
|
||||
reply._lines.push_back(stream->readResourceReference());
|
||||
reply._lines.push_back(stream->readResourceReference());
|
||||
}
|
||||
|
||||
topic._replies.push_back(reply);
|
||||
}
|
||||
|
||||
_topics.push_back(topic);
|
||||
}
|
||||
}
|
||||
|
||||
void Dialog::saveLoad(ResourceSerializer *serializer) {
|
||||
for (uint i = 0; i < _topics.size(); i++) {
|
||||
serializer->syncAsSint32LE(_topics[i]._currentReplyIndex);
|
||||
}
|
||||
}
|
||||
|
||||
void Dialog::printData() {
|
||||
Object::printData();
|
||||
|
||||
debug("character: %d", _character);
|
||||
debug("hasAskAbout: %d", _hasAskAbout);
|
||||
|
||||
for (uint32 i = 0; i < _topics.size(); i++) {
|
||||
Topic &topic = _topics[i];
|
||||
debug("topic[%d].removeOnceDepleted: %d", i, topic._removeOnceDepleted);
|
||||
|
||||
for (uint j = 0; j < topic._replies.size(); j++) {
|
||||
Reply reply = topic._replies[j];
|
||||
|
||||
debug("topic[%d].reply[%d].conditionType: %d", i, j, reply._conditionType);
|
||||
debug("topic[%d].reply[%d].conditionReference: %s", i, j, reply._conditionReference.describe().c_str());
|
||||
debug("topic[%d].reply[%d].conditionScriptReference: %s", i, j, reply._conditionScriptReference.describe().c_str());
|
||||
debug("topic[%d].reply[%d].conditionReversed: %d", i, j, reply._conditionReversed);
|
||||
debug("topic[%d].reply[%d].minChapter: %d", i, j, reply._minChapter);
|
||||
debug("topic[%d].reply[%d].maxChapter: %d", i, j, reply._maxChapter);
|
||||
debug("topic[%d].reply[%d].noCaption: %d", i, j, reply._noCaption);
|
||||
debug("topic[%d].reply[%d].field_88: %d", i, j, reply._field_88);
|
||||
debug("topic[%d].reply[%d].nextScriptReference: %s", i, j, reply._nextScriptReference.describe().c_str());
|
||||
debug("topic[%d].reply[%d].nextDialogIndex: %d", i, j, reply._nextDialogIndex);
|
||||
|
||||
for (uint k = 0; k < reply._lines.size(); k++) {
|
||||
debug("topic[%d].reply[%d].line[%d]: %s", i, j, k, reply._lines[k].describe().c_str());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Dialog::TopicArray Dialog::listAvailableTopics() {
|
||||
Common::Array<Dialog::Topic *> topics;
|
||||
|
||||
for (uint i = 0; i < _topics.size(); i++) {
|
||||
Topic *topic = &_topics[i];
|
||||
if (topic->getNextReplyIndex() < 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
topics.push_back(topic);
|
||||
}
|
||||
|
||||
return topics;
|
||||
}
|
||||
|
||||
Dialog::Topic::Topic() :
|
||||
_removeOnceDepleted(true),
|
||||
_currentReplyIndex(-1) {
|
||||
}
|
||||
|
||||
int32 Dialog::Topic::getNextReplyIndex() const {
|
||||
uint32 nextIndex = _currentReplyIndex + 1;
|
||||
|
||||
if (nextIndex >= _replies.size()) {
|
||||
// No more replies ...
|
||||
if (_removeOnceDepleted || _replies.empty()) {
|
||||
// Don't show this topic
|
||||
return -1;
|
||||
} else {
|
||||
// Repeat the last reply
|
||||
nextIndex = _replies.size() - 1;
|
||||
}
|
||||
}
|
||||
|
||||
uint32 currentChapter = StarkGlobal->getCurrentChapter();
|
||||
|
||||
// Skip replies from previous chapters
|
||||
while (nextIndex < _replies.size() && _replies[nextIndex]._maxChapter < currentChapter) {
|
||||
nextIndex++;
|
||||
}
|
||||
|
||||
if (nextIndex >= _replies.size()) {
|
||||
// No more replies ...
|
||||
if (_removeOnceDepleted || _replies.empty()) {
|
||||
// Don't show this topic
|
||||
return -1;
|
||||
} else {
|
||||
// Repeat the last reply
|
||||
nextIndex = _replies.size() - 1;
|
||||
}
|
||||
}
|
||||
|
||||
// Chapter check
|
||||
const Reply &reply = _replies[nextIndex];
|
||||
if (currentChapter < reply._minChapter || currentChapter >= reply._maxChapter) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
return nextIndex;
|
||||
}
|
||||
|
||||
Dialog::Reply *Dialog::Topic::startReply(uint32 index) {
|
||||
_currentReplyIndex = index;
|
||||
|
||||
Reply *reply = &_replies[_currentReplyIndex];
|
||||
reply->start();
|
||||
|
||||
return reply;
|
||||
}
|
||||
|
||||
Dialog::Reply *Dialog::Topic::getReply(uint32 index) {
|
||||
return &_replies[index];
|
||||
}
|
||||
|
||||
Common::String Dialog::Topic::getCaption() const {
|
||||
int32 replyIndex = getNextReplyIndex();
|
||||
if (replyIndex < 0) {
|
||||
error("Trying to obtain the caption of a depleted dialog topic.");
|
||||
}
|
||||
|
||||
const Reply &reply = _replies[replyIndex];
|
||||
|
||||
if (reply._lines.empty()) {
|
||||
error("Trying to obtain the caption of a reply with no lines.");
|
||||
}
|
||||
|
||||
Speech *speech = reply._lines[0].resolve<Speech>();
|
||||
if (speech) {
|
||||
return speech->getPhrase();
|
||||
} else {
|
||||
return "No Caption";
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Dialog::Reply::Reply() :
|
||||
_conditionReversed(0),
|
||||
_field_88(0),
|
||||
_minChapter(0),
|
||||
_maxChapter(999),
|
||||
_conditionType(0),
|
||||
_noCaption(0),
|
||||
_nextDialogIndex(-1),
|
||||
_nextSpeechIndex(-1) {
|
||||
}
|
||||
|
||||
void Dialog::Reply::start() {
|
||||
if (_noCaption) {
|
||||
_nextSpeechIndex = -1;
|
||||
} else {
|
||||
// Skip the first line when it is a caption
|
||||
_nextSpeechIndex = 0;
|
||||
}
|
||||
|
||||
goToNextLine();
|
||||
}
|
||||
|
||||
void Dialog::Reply::goToNextLine() {
|
||||
_nextSpeechIndex++;
|
||||
while ((uint32)_nextSpeechIndex < _lines.size() && _lines[_nextSpeechIndex].empty()) {
|
||||
_nextSpeechIndex++;
|
||||
}
|
||||
|
||||
if ((uint32)_nextSpeechIndex >= _lines.size()) {
|
||||
_nextSpeechIndex = -2; // No more lines
|
||||
}
|
||||
}
|
||||
|
||||
Speech *Dialog::Reply::getCurrentSpeech() {
|
||||
if (_nextSpeechIndex < 0) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return _lines[_nextSpeechIndex].resolve<Speech>();
|
||||
}
|
||||
|
||||
bool Dialog::Reply::checkCondition() const {
|
||||
bool result;
|
||||
|
||||
switch (_conditionType) {
|
||||
case kConditionTypeAlways:
|
||||
result = true;
|
||||
break;
|
||||
case kConditionTypeNoOtherOptions:
|
||||
result = true; // Will be removed from to the options later if some other options are available
|
||||
break;
|
||||
case kConditionTypeHasItem: {
|
||||
Item *item = _conditionReference.resolve<Item>();
|
||||
result = item->isEnabled();
|
||||
break;
|
||||
}
|
||||
case kConditionTypeCheckValue4:
|
||||
case kConditionTypeCheckValue5: {
|
||||
Knowledge *condition = _conditionReference.resolve<Knowledge>();
|
||||
result = condition->getBooleanValue();
|
||||
break;
|
||||
}
|
||||
case kConditionTypeRunScriptCheckValue: {
|
||||
Script *conditionScript = _conditionScriptReference.resolve<Script>();
|
||||
conditionScript->execute(Resources::Script::kCallModeDialogAnswer);
|
||||
|
||||
Knowledge *condition = _conditionReference.resolve<Knowledge>();
|
||||
result = condition->getBooleanValue();
|
||||
break;
|
||||
}
|
||||
default:
|
||||
warning("Unimplemented dialog reply condition %d", _conditionType);
|
||||
result = true;
|
||||
break;
|
||||
}
|
||||
|
||||
if (_conditionReversed && (_conditionType == kConditionTypeHasItem
|
||||
|| _conditionType == kConditionTypeCheckValue4
|
||||
|| _conditionType == kConditionTypeCheckValue5
|
||||
|| _conditionType == kConditionTypeRunScriptCheckValue)) {
|
||||
result = !result;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
bool Dialog::Reply::isLastOnly() const {
|
||||
return _conditionType == kConditionTypeNoOtherOptions;
|
||||
}
|
||||
|
||||
Dialog *Dialog::getNextDialog(Dialog::Reply *reply) {
|
||||
if (reply->_nextDialogIndex < 0) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return _parent->findChildWithIndex<Dialog>(reply->_nextDialogIndex);
|
||||
}
|
||||
|
||||
Script *Dialog::getNextScript(Dialog::Reply *reply) {
|
||||
if (reply->_nextScriptReference.empty()) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return reply->_nextScriptReference.resolve<Script>();
|
||||
}
|
||||
|
||||
Common::String Dialog::getDiaryTitle() const {
|
||||
return _parent->getName();
|
||||
}
|
||||
|
||||
int32 Dialog::getCharacter() const {
|
||||
return _character;
|
||||
}
|
||||
|
||||
} // End of namespace Resources
|
||||
} // End of namespace Stark
|
||||
166
engines/stark/resources/dialog.h
Normal file
166
engines/stark/resources/dialog.h
Normal file
@@ -0,0 +1,166 @@
|
||||
/* 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/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef STARK_RESOURCES_DIALOG_H
|
||||
#define STARK_RESOURCES_DIALOG_H
|
||||
|
||||
#include "common/str.h"
|
||||
|
||||
#include "engines/stark/resources/object.h"
|
||||
#include "engines/stark/resourcereference.h"
|
||||
|
||||
namespace Stark {
|
||||
|
||||
namespace Formats {
|
||||
class XRCReadStream;
|
||||
}
|
||||
|
||||
namespace Resources {
|
||||
|
||||
class Speech;
|
||||
class Script;
|
||||
|
||||
/**
|
||||
* A dialog between two characters.
|
||||
*
|
||||
* Dialogs are made of a list of topics. Each topic has a list of
|
||||
* possible answers, one of which is played when the player selects the topic,
|
||||
* until all the possible answers have been played.
|
||||
*
|
||||
* Answers are made of a list of lines. All of the lines of an answer are played,
|
||||
* one after the other when an answer is played. Lines reference Speech resources.
|
||||
*/
|
||||
class Dialog : public Object {
|
||||
public:
|
||||
static const Type::ResourceType TYPE = Type::kDialog;
|
||||
|
||||
Dialog(Object *parent, byte subType, uint16 index, const Common::String &name);
|
||||
virtual ~Dialog();
|
||||
|
||||
/**
|
||||
* A topic reply
|
||||
*/
|
||||
class Reply {
|
||||
public:
|
||||
Reply();
|
||||
|
||||
enum ConditionType {
|
||||
kConditionTypeAlways = 0,
|
||||
kConditionTypeNoOtherOptions = 1,
|
||||
kConditionTypeHasItem = 3,
|
||||
kConditionTypeCheckValue4 = 4,
|
||||
kConditionTypeCheckValue5 = 5,
|
||||
kConditionTypeRunScriptCheckValue = 6
|
||||
};
|
||||
|
||||
/** Start playing the reply. Sets the current line to the first one */
|
||||
void start();
|
||||
|
||||
/** Select the next line to be played */
|
||||
void goToNextLine();
|
||||
|
||||
/** Obtain the Speech resource for the current line, or null if the reply has ended */
|
||||
Speech *getCurrentSpeech();
|
||||
|
||||
/** Evaluates the reply's condition */
|
||||
bool checkCondition() const;
|
||||
|
||||
/** Should this reply only be made available when there are no other options left? */
|
||||
bool isLastOnly() const;
|
||||
|
||||
// Static data
|
||||
Common::Array<ResourceReference> _lines;
|
||||
uint32 _conditionType;
|
||||
ResourceReference _conditionReference;
|
||||
ResourceReference _conditionScriptReference;
|
||||
uint32 _conditionReversed;
|
||||
uint32 _field_88;
|
||||
uint32 _minChapter;
|
||||
uint32 _maxChapter;
|
||||
uint32 _noCaption;
|
||||
int32 _nextDialogIndex;
|
||||
ResourceReference _nextScriptReference;
|
||||
|
||||
// State
|
||||
int32 _nextSpeechIndex;
|
||||
|
||||
friend class Dialog;
|
||||
};
|
||||
|
||||
/**
|
||||
* A dialog topic
|
||||
*/
|
||||
class Topic {
|
||||
public:
|
||||
Topic();
|
||||
|
||||
/** Compute the next possible reply index after the currently selected reply */
|
||||
int32 getNextReplyIndex() const;
|
||||
|
||||
/** Obtain the caption for the topic */
|
||||
Common::String getCaption() const;
|
||||
|
||||
/** Select a reply from its index */
|
||||
Reply *startReply(uint32 index);
|
||||
|
||||
/** Get the reply with the specified index */
|
||||
Reply *getReply(uint32 index);
|
||||
|
||||
Common::Array<Reply> _replies;
|
||||
|
||||
bool _removeOnceDepleted;
|
||||
int32 _currentReplyIndex;
|
||||
|
||||
friend class Dialog;
|
||||
};
|
||||
|
||||
typedef Common::Array<Topic *> TopicArray;
|
||||
|
||||
// Resource API
|
||||
void readData(Formats::XRCReadStream *stream) override;
|
||||
void saveLoad(ResourceSerializer *serializer) override;
|
||||
|
||||
/** List the currently available topics for this Dialog */
|
||||
TopicArray listAvailableTopics();
|
||||
|
||||
/** Obtain the Dialog which should be played at the outcome of this one, if any */
|
||||
Dialog *getNextDialog(Reply *reply);
|
||||
|
||||
/** Obtain the Script which should be executed after this dialog, if any */
|
||||
Script *getNextScript(Reply *reply);
|
||||
|
||||
/** Get the dialog's title as shown in the diary */
|
||||
Common::String getDiaryTitle() const;
|
||||
|
||||
/** Get the character's id - index in the KnowledgeSet */
|
||||
int32 getCharacter() const;
|
||||
|
||||
void printData() override;
|
||||
|
||||
Common::Array<Topic> _topics;
|
||||
uint32 _character;
|
||||
uint32 _hasAskAbout;
|
||||
};
|
||||
|
||||
} // End of namespace Resources
|
||||
} // End of namespace Stark
|
||||
|
||||
#endif // STARK_RESOURCES_DIALOG_H
|
||||
53
engines/stark/resources/direction.cpp
Normal file
53
engines/stark/resources/direction.cpp
Normal file
@@ -0,0 +1,53 @@
|
||||
/* 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 "engines/stark/resources/direction.h"
|
||||
|
||||
#include "engines/stark/formats/xrc.h"
|
||||
|
||||
namespace Stark {
|
||||
namespace Resources {
|
||||
|
||||
Direction::~Direction() {
|
||||
}
|
||||
|
||||
Direction::Direction(Object *parent, byte subType, uint16 index, const Common::String &name) :
|
||||
Object(parent, subType, index, name),
|
||||
_field_34(0),
|
||||
_field_38(0),
|
||||
_field_3C(0) {
|
||||
_type = TYPE;
|
||||
}
|
||||
|
||||
void Direction::readData(Formats::XRCReadStream *stream) {
|
||||
_field_34 = stream->readUint32LE();
|
||||
_field_38 = stream->readUint32LE();
|
||||
_field_3C = stream->readUint32LE();
|
||||
}
|
||||
|
||||
void Direction::printData() {
|
||||
debug("field_34: %d", _field_34);
|
||||
debug("field_38: %d", _field_38);
|
||||
debug("field_3C: %d", _field_3C);
|
||||
}
|
||||
|
||||
} // End of namespace Resources
|
||||
} // End of namespace Stark
|
||||
57
engines/stark/resources/direction.h
Normal file
57
engines/stark/resources/direction.h
Normal file
@@ -0,0 +1,57 @@
|
||||
/* 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/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef STARK_RESOURCES_DIRECTION_H
|
||||
#define STARK_RESOURCES_DIRECTION_H
|
||||
|
||||
#include "common/str.h"
|
||||
|
||||
#include "engines/stark/resources/object.h"
|
||||
|
||||
namespace Stark {
|
||||
|
||||
namespace Formats {
|
||||
class XRCReadStream;
|
||||
}
|
||||
|
||||
namespace Resources {
|
||||
|
||||
class Direction : public Object {
|
||||
public:
|
||||
static const Type::ResourceType TYPE = Type::kDirection;
|
||||
|
||||
Direction(Object *parent, byte subType, uint16 index, const Common::String &name);
|
||||
virtual ~Direction();
|
||||
|
||||
void readData(Formats::XRCReadStream *stream) override;
|
||||
|
||||
protected:
|
||||
void printData() override;
|
||||
|
||||
uint32 _field_34;
|
||||
uint32 _field_38;
|
||||
uint32 _field_3C;
|
||||
};
|
||||
|
||||
} // End of namespace Resources
|
||||
} // End of namespace Stark
|
||||
|
||||
#endif // STARK_RESOURCES_DIRECTION_H
|
||||
339
engines/stark/resources/floor.cpp
Normal file
339
engines/stark/resources/floor.cpp
Normal file
@@ -0,0 +1,339 @@
|
||||
/* 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 "engines/stark/resources/floor.h"
|
||||
|
||||
#include "engines/stark/formats/xrc.h"
|
||||
|
||||
#include "engines/stark/resources/floorface.h"
|
||||
#include "engines/stark/resources/floorfield.h"
|
||||
|
||||
#include "engines/stark/services/stateprovider.h"
|
||||
|
||||
namespace Stark {
|
||||
namespace Resources {
|
||||
|
||||
Floor::Floor(Object *parent, byte subType, uint16 index, const Common::String &name) :
|
||||
Object(parent, subType, index, name),
|
||||
_facesCount(0) {
|
||||
_type = TYPE;
|
||||
}
|
||||
|
||||
Floor::~Floor() {
|
||||
}
|
||||
|
||||
Math::Vector3d Floor::getVertex(uint32 index) const {
|
||||
return _vertices[index];
|
||||
}
|
||||
|
||||
int32 Floor::findFaceContainingPoint(const Math::Vector3d &point) const {
|
||||
for (uint32 i = 0; i < _faces.size(); i++) {
|
||||
if (_faces[i]->hasVertices() && _faces[i]->isPointInside(point)) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
void Floor::computePointHeightInFace(Math::Vector3d &point, uint32 faceIndex) const {
|
||||
_faces[faceIndex]->computePointHeight(point);
|
||||
}
|
||||
|
||||
int32 Floor::findFaceHitByRay(const Math::Ray &ray, Math::Vector3d &intersection) const {
|
||||
for (uint32 i = 0; i < _faces.size(); i++) {
|
||||
// TODO: Check the ray's intersection with an AABB first if this ends up being slow
|
||||
if (_faces[i]->intersectRay(ray, intersection)) {
|
||||
if (_faces[i]->isEnabled()) {
|
||||
return i;
|
||||
} else {
|
||||
return -1; // Disabled faces block the ray
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
int32 Floor::findFaceClosestToRay(const Math::Ray &ray, Math::Vector3d ¢er) const {
|
||||
float minDistance = FLT_MAX;
|
||||
int32 minFace = -1;
|
||||
|
||||
// For some reason, face 0 is not being considered
|
||||
for (uint32 i = 1; i < _faces.size(); i++) {
|
||||
if (_faces[i]->isEnabled() && _faces[i]->hasVertices()) {
|
||||
float distance = _faces[i]->distanceToRay(ray);
|
||||
if (distance < minDistance) {
|
||||
minFace = i;
|
||||
minDistance = distance;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (minFace >= 0) {
|
||||
center = _faces[minFace]->getCenter();
|
||||
}
|
||||
|
||||
return minFace;
|
||||
}
|
||||
|
||||
float Floor::getDistanceFromCamera(uint32 faceIndex) const {
|
||||
FloorFace *face = _faces[faceIndex];
|
||||
return face->getDistanceFromCamera();
|
||||
}
|
||||
|
||||
FloorFace *Floor::getFace(uint32 index) const {
|
||||
return _faces[index];
|
||||
}
|
||||
|
||||
bool Floor::isSegmentInside(const Math::Line3d &segment) const {
|
||||
// The segment is inside the floor if at least one of its extremities is,
|
||||
// and it does not cross any floor border / disabled floor faces
|
||||
|
||||
int32 beginFace = findFaceContainingPoint(segment.begin());
|
||||
if (beginFace < 0) {
|
||||
// The segment begin point is not on the floor
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!_faces[beginFace]->isEnabled()) {
|
||||
// The segment begin point is not enabled
|
||||
return false;
|
||||
}
|
||||
|
||||
for (uint i = 0; i < _edges.size(); i++) {
|
||||
const FloorEdge &edge = _edges[i];
|
||||
if ((edge.isFloorBorder() || !edge.isEnabled()) && edge.intersectsSegment(this, segment)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void Floor::readData(Formats::XRCReadStream *stream) {
|
||||
_facesCount = stream->readUint32LE();
|
||||
uint32 vertexCount = stream->readUint32LE();
|
||||
|
||||
for (uint i = 0; i < vertexCount; i++) {
|
||||
Math::Vector3d v = stream->readVector3();
|
||||
_vertices.push_back(v);
|
||||
}
|
||||
}
|
||||
|
||||
void Floor::onAllLoaded() {
|
||||
Object::onAllLoaded();
|
||||
|
||||
_faces = listChildren<FloorFace>();
|
||||
|
||||
buildEdgeList();
|
||||
}
|
||||
|
||||
void Floor::saveLoad(ResourceSerializer *serializer) {
|
||||
for (uint i = 0; i < _edges.size(); i++) {
|
||||
_edges[i].saveLoad(serializer);
|
||||
}
|
||||
}
|
||||
|
||||
void Floor::buildEdgeList() {
|
||||
_edges.clear();
|
||||
|
||||
// Add the triangle edges from all our faces
|
||||
for (uint i = 0; i < _faces.size(); i++) {
|
||||
if (_faces[i]->hasVertices()) {
|
||||
addFaceEdgeToList(i, 2, 0);
|
||||
addFaceEdgeToList(i, 0, 1);
|
||||
addFaceEdgeToList(i, 1, 2);
|
||||
}
|
||||
}
|
||||
|
||||
// Add the edges to their faces
|
||||
for (uint i = 0; i < _edges.size(); i++) {
|
||||
int32 faceIndex1 = _edges[i].getFaceIndex1();
|
||||
int32 faceIndex2 = _edges[i].getFaceIndex2();
|
||||
|
||||
if (faceIndex1 >= 0) {
|
||||
_faces[faceIndex1]->addEdge(&_edges[i]);
|
||||
}
|
||||
|
||||
if (faceIndex2 >= 0) {
|
||||
_faces[faceIndex2]->addEdge(&_edges[i]);
|
||||
}
|
||||
}
|
||||
|
||||
// Build a list of neighbours for each edge
|
||||
for (uint i = 0; i < _edges.size(); i++) {
|
||||
_edges[i].buildNeighbours(this);
|
||||
_edges[i].computeMiddle(this);
|
||||
}
|
||||
}
|
||||
|
||||
void Floor::addFaceEdgeToList(uint32 faceIndex, uint32 index1, uint32 index2) {
|
||||
uint32 vertexIndex1 = _faces[faceIndex]->getVertexIndex(index1);
|
||||
uint32 vertexIndex2 = _faces[faceIndex]->getVertexIndex(index2);
|
||||
uint32 startIndex = MIN(vertexIndex1, vertexIndex2);
|
||||
uint32 endIndex = MAX(vertexIndex1, vertexIndex2);
|
||||
|
||||
// Check if we already have an edge with the same vertices
|
||||
for (uint i = 0; i < _edges.size(); i++) {
|
||||
if (_edges[i].hasVertices(startIndex, endIndex)) {
|
||||
_edges[i].setOtherFace(faceIndex);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
_edges.push_back(FloorEdge(startIndex, endIndex, faceIndex));
|
||||
}
|
||||
|
||||
void Floor::enableFloorField(FloorField *floorfield, bool enable) {
|
||||
for (uint i = 0; i < _faces.size(); i++) {
|
||||
if (floorfield->hasFace(i)) {
|
||||
_faces[i]->enable(enable);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Floor::printData() {
|
||||
debug("face count: %d", _facesCount);
|
||||
|
||||
Common::StreamDebug debug = streamDbg();
|
||||
for (uint i = 0; i < _vertices.size(); i++) {
|
||||
debug << i << ": " << _vertices[i] << "\n";
|
||||
}
|
||||
}
|
||||
|
||||
FloorEdge::FloorEdge(uint16 vertexIndex1, uint16 vertexIndex2, uint32 faceIndex1) :
|
||||
_vertexIndex1(vertexIndex1),
|
||||
_vertexIndex2(vertexIndex2),
|
||||
_faceIndex1(faceIndex1),
|
||||
_faceIndex2(-1),
|
||||
_enabled(true) {
|
||||
}
|
||||
|
||||
bool FloorEdge::hasVertices(uint16 vertexIndex1, uint16 vertexIndex2) const {
|
||||
return _vertexIndex1 == vertexIndex1 && _vertexIndex2 == vertexIndex2;
|
||||
}
|
||||
|
||||
void FloorEdge::setOtherFace(uint32 faceIndex) {
|
||||
_faceIndex2 = faceIndex;
|
||||
}
|
||||
|
||||
Common::Array<FloorEdge *> FloorEdge::getNeighbours() const {
|
||||
return _neighbours;
|
||||
}
|
||||
|
||||
float FloorEdge::costTo(const FloorEdge *other) const {
|
||||
return _middle.getDistanceTo(other->_middle);
|
||||
}
|
||||
|
||||
Math::Vector3d FloorEdge::getPosition() const {
|
||||
return _middle;
|
||||
}
|
||||
|
||||
void FloorEdge::buildNeighbours(const Floor *floor) {
|
||||
_neighbours.clear();
|
||||
|
||||
if (_faceIndex1 >= 0) {
|
||||
addNeighboursFromFace(floor->getFace(_faceIndex1));
|
||||
}
|
||||
|
||||
if (_faceIndex2 >= 0) {
|
||||
addNeighboursFromFace(floor->getFace(_faceIndex2));
|
||||
}
|
||||
}
|
||||
|
||||
void FloorEdge::addNeighboursFromFace(const FloorFace *face) {
|
||||
Common::Array<FloorEdge *> faceEdges = face->getEdges();
|
||||
for (uint i = 0; i < faceEdges.size(); i++) {
|
||||
if (faceEdges[i] != this) {
|
||||
_neighbours.push_back(faceEdges[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void FloorEdge::computeMiddle(const Floor *floor) {
|
||||
Math::Vector3d vertex1 = floor->getVertex(_vertexIndex1);
|
||||
Math::Vector3d vertex2 = floor->getVertex(_vertexIndex2);
|
||||
_middle = (vertex1 + vertex2) / 2.0;
|
||||
}
|
||||
|
||||
int32 FloorEdge::getFaceIndex1() const {
|
||||
return _faceIndex1;
|
||||
}
|
||||
|
||||
int32 FloorEdge::getFaceIndex2() const {
|
||||
return _faceIndex2;
|
||||
}
|
||||
|
||||
bool FloorEdge::isFloorBorder() const {
|
||||
return _faceIndex2 == -1;
|
||||
}
|
||||
|
||||
bool FloorEdge::intersectLine2d(const Math::Line3d &s1, const Math::Line3d &s2) {
|
||||
const Math::Vector3d &s1begin = s1.begin();
|
||||
const Math::Vector3d &s1end = s1.end();
|
||||
const Math::Vector3d &s2begin = s2.begin();
|
||||
const Math::Vector3d &s2end = s2.end();
|
||||
|
||||
float denom = ((s2end.y() - s2begin.y()) * (s1end.x() - s1begin.x())) -
|
||||
((s2end.x() - s2begin.x()) * (s1end.y() - s1begin.y()));
|
||||
|
||||
float nume_a = ((s2end.x() - s2begin.x()) * (s1begin.y() - s2begin.y())) -
|
||||
((s2end.y() - s2begin.y()) * (s1begin.x() - s2begin.x()));
|
||||
|
||||
float nume_b = ((s1end.x() - s1begin.x()) * (s1begin.y() - s2begin.y())) -
|
||||
((s1end.y() - s1begin.y()) * (s1begin.x() - s2begin.x()));
|
||||
|
||||
if (denom == 0.0f) {
|
||||
return false; // Segments are collinear
|
||||
}
|
||||
|
||||
float ua = nume_a / denom;
|
||||
float ub = nume_b / denom;
|
||||
|
||||
// Non inclusive bounds check, one of the vertices of one segment being inside
|
||||
// the other segment is not considered to be an intersection.
|
||||
// This is the only difference with Line3d::intersectLine2d.
|
||||
return ua > 0 && ua < 1 && ub > 0 && ub < 1;
|
||||
}
|
||||
|
||||
bool FloorEdge::intersectsSegment(const Floor *floor, const Math::Line3d &segment) const {
|
||||
Math::Vector3d vertex1 = floor->getVertex(_vertexIndex1);
|
||||
Math::Vector3d vertex2 = floor->getVertex(_vertexIndex2);
|
||||
Math::Line3d edgeSegment = Math::Line3d(vertex1, vertex2);
|
||||
|
||||
return intersectLine2d(edgeSegment, segment);
|
||||
}
|
||||
|
||||
void FloorEdge::enable(bool e) {
|
||||
_enabled = e;
|
||||
}
|
||||
|
||||
bool FloorEdge::isEnabled() const {
|
||||
return _enabled;
|
||||
}
|
||||
|
||||
void FloorEdge::saveLoad(ResourceSerializer *serializer) {
|
||||
serializer->syncAsUint32LE(_enabled);
|
||||
}
|
||||
|
||||
} // End of namespace Resources
|
||||
} // End of namespace Stark
|
||||
199
engines/stark/resources/floor.h
Normal file
199
engines/stark/resources/floor.h
Normal file
@@ -0,0 +1,199 @@
|
||||
/* 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/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef STARK_RESOURCES_FLOOR_H
|
||||
#define STARK_RESOURCES_FLOOR_H
|
||||
|
||||
#include "common/array.h"
|
||||
#include "common/str.h"
|
||||
|
||||
#include "math/line3d.h"
|
||||
#include "math/ray.h"
|
||||
#include "math/vector3d.h"
|
||||
|
||||
#include "engines/stark/resources/object.h"
|
||||
|
||||
namespace Stark {
|
||||
|
||||
namespace Formats {
|
||||
class XRCReadStream;
|
||||
}
|
||||
|
||||
namespace Resources {
|
||||
|
||||
class Floor;
|
||||
class FloorFace;
|
||||
class FloorField;
|
||||
|
||||
/**
|
||||
* A floor face (triangle) edge
|
||||
*
|
||||
* Used for path finding
|
||||
*/
|
||||
class FloorEdge {
|
||||
public:
|
||||
FloorEdge(uint16 vertexIndex1, uint16 vertexIndex2, uint32 faceIndex1);
|
||||
|
||||
/** Build a list of neighbour edges in the graph */
|
||||
void buildNeighbours(const Floor *floor);
|
||||
|
||||
/** Set the edge middle position */
|
||||
void computeMiddle(const Floor *floor);
|
||||
|
||||
/** Set the edge's second face */
|
||||
void setOtherFace(uint32 faceIndex);
|
||||
|
||||
/** Check if the edge has the same vertices as the parameters */
|
||||
bool hasVertices(uint16 vertexIndex1, uint16 vertexIndex2) const;
|
||||
|
||||
/** List the edge neighbour edges in the floor */
|
||||
Common::Array<FloorEdge *> getNeighbours() const;
|
||||
|
||||
/**
|
||||
* Computes the cost for going to a neighbour edge
|
||||
*
|
||||
* This is used for pathfinding. The cost is equal to the distance
|
||||
* between the middle of both edges
|
||||
*/
|
||||
float costTo(const FloorEdge *other) const;
|
||||
|
||||
/**
|
||||
* Get the edge position
|
||||
*
|
||||
* This is the middle of the edge
|
||||
*/
|
||||
Math::Vector3d getPosition() const;
|
||||
|
||||
/** Is this edge on the floor border? */
|
||||
bool isFloorBorder() const;
|
||||
|
||||
/** Does the segment intersect the edge in the 2D plane? */
|
||||
bool intersectsSegment(const Floor *floor, const Math::Line3d &segment) const;
|
||||
|
||||
int32 getFaceIndex1() const;
|
||||
int32 getFaceIndex2() const;
|
||||
|
||||
/** Allow or disallow characters to path using this edge */
|
||||
void enable(bool enable);
|
||||
|
||||
/** Is pathing through this edge allowed for characters? */
|
||||
bool isEnabled() const;
|
||||
|
||||
/** Save or restore the edge's status */
|
||||
void saveLoad(ResourceSerializer *serializer);
|
||||
|
||||
private:
|
||||
void addNeighboursFromFace(const FloorFace *face);
|
||||
static bool intersectLine2d(const Math::Line3d &s1, const Math::Line3d &s2);
|
||||
|
||||
uint16 _vertexIndex1;
|
||||
uint16 _vertexIndex2;
|
||||
Math::Vector3d _middle;
|
||||
int32 _faceIndex1;
|
||||
int32 _faceIndex2;
|
||||
|
||||
bool _enabled;
|
||||
|
||||
Common::Array<FloorEdge *> _neighbours;
|
||||
};
|
||||
|
||||
/**
|
||||
* This resource represents the floor of a 3D layer.
|
||||
* Characters can only walk on the floor.
|
||||
*
|
||||
* The floor is made of a list of faces building a mesh.
|
||||
*/
|
||||
class Floor : public Object {
|
||||
public:
|
||||
static const Type::ResourceType TYPE = Type::kFloor;
|
||||
|
||||
Floor(Object *parent, byte subType, uint16 index, const Common::String &name);
|
||||
virtual ~Floor();
|
||||
|
||||
// Resource API
|
||||
void onAllLoaded() override;
|
||||
void saveLoad(ResourceSerializer *serializer) override;
|
||||
|
||||
/** Obtain the vertex for an index */
|
||||
Math::Vector3d getVertex(uint32 index) const;
|
||||
|
||||
/**
|
||||
* Obtain the index of the face containing the point when both the floorfield
|
||||
* and the point are projected on a Z=0 plane.
|
||||
*
|
||||
* Return -1 if no face contains the point.
|
||||
*/
|
||||
int32 findFaceContainingPoint(const Math::Vector3d &point) const;
|
||||
|
||||
/** Fill the z coordinate of the point so that it is on the plane of a face */
|
||||
void computePointHeightInFace(Math::Vector3d &point, uint32 faceIndex) const;
|
||||
|
||||
/**
|
||||
* Check if a ray is intersecting the floor
|
||||
*
|
||||
* Faces where walking is disabled are ignored.
|
||||
*
|
||||
* @param ray The ray
|
||||
* @param intersection The intersection between the ray and the floor. Only valid when the return value is positive.
|
||||
* @return -1 if no face contains the point, the hit face index otherwise
|
||||
*/
|
||||
int32 findFaceHitByRay(const Math::Ray &ray, Math::Vector3d &intersection) const;
|
||||
|
||||
/**
|
||||
* Find the floor face center closest to the ray
|
||||
*
|
||||
* Faces where walking is disabled are ignored.
|
||||
*
|
||||
* @param ray The ray
|
||||
* @param center The closest face center to the ray. Only valid when the return value is positive.
|
||||
* @return -1 if no face was found, the face index with its center closest to the ray otherwise
|
||||
*/
|
||||
int32 findFaceClosestToRay(const Math::Ray &ray, Math::Vector3d ¢er) const;
|
||||
|
||||
/** Obtain the distance to the camera for a face */
|
||||
float getDistanceFromCamera(uint32 faceIndex) const;
|
||||
|
||||
/** Get a floor face by its index */
|
||||
FloorFace *getFace(uint32 index) const;
|
||||
|
||||
/** Check if the segment is entirely inside the floor */
|
||||
bool isSegmentInside(const Math::Line3d &segment) const;
|
||||
|
||||
/** Allow or disallow characters to walk on some faces of the floor */
|
||||
void enableFloorField(FloorField *floorfield, bool enable);
|
||||
|
||||
protected:
|
||||
void readData(Formats::XRCReadStream *stream) override;
|
||||
void printData() override;
|
||||
|
||||
void buildEdgeList();
|
||||
void addFaceEdgeToList(uint32 faceIndex, uint32 index1, uint32 index2);
|
||||
|
||||
uint32 _facesCount;
|
||||
Common::Array<Math::Vector3d> _vertices;
|
||||
Common::Array<FloorFace *> _faces;
|
||||
Common::Array<FloorEdge> _edges;
|
||||
};
|
||||
|
||||
} // End of namespace Resources
|
||||
} // End of namespace Stark
|
||||
|
||||
#endif // STARK_RESOURCES_FLOOR_H
|
||||
218
engines/stark/resources/floorface.cpp
Normal file
218
engines/stark/resources/floorface.cpp
Normal file
@@ -0,0 +1,218 @@
|
||||
/* 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 "engines/stark/resources/floorface.h"
|
||||
|
||||
#include "engines/stark/debug.h"
|
||||
#include "engines/stark/formats/xrc.h"
|
||||
#include "engines/stark/resources/floor.h"
|
||||
|
||||
namespace Stark {
|
||||
namespace Resources {
|
||||
|
||||
FloorFace::FloorFace(Object *parent, byte subType, uint16 index, const Common::String &name) :
|
||||
Object(parent, subType, index, name),
|
||||
_distanceFromCamera(0),
|
||||
_unk2(0) {
|
||||
_type = TYPE;
|
||||
|
||||
for (uint i = 0; i < ARRAYSIZE(_indices); i++) {
|
||||
_indices[i] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
FloorFace::~FloorFace() {
|
||||
}
|
||||
|
||||
bool FloorFace::isPointInside(const Math::Vector3d &point) const {
|
||||
// Compute the barycentric coordinates of the point in the triangle
|
||||
float area = 1.0f / 2.0f
|
||||
* (-_vertices[1].y() * _vertices[2].x()
|
||||
+ _vertices[0].y() * (-_vertices[1].x() + _vertices[2].x())
|
||||
+ _vertices[0].x() * (_vertices[1].y() - _vertices[2].y())
|
||||
+ _vertices[1].x() * _vertices[2].y());
|
||||
|
||||
float s = (_vertices[0].y() * _vertices[2].x() - _vertices[0].x() * _vertices[2].y()
|
||||
+ (_vertices[2].y() - _vertices[0].y()) * point.x()
|
||||
+ (_vertices[0].x() - _vertices[2].x()) * point.y())
|
||||
/ (2.0f * area);
|
||||
|
||||
float t = (_vertices[0].x() * _vertices[1].y() - _vertices[0].y() * _vertices[1].x()
|
||||
+ (_vertices[0].y() - _vertices[1].y()) * point.x()
|
||||
+ (_vertices[1].x() - _vertices[0].x()) * point.y())
|
||||
/ (2.0f * area);
|
||||
|
||||
// Check the coordinates are in the triangle
|
||||
return s > 0.0f && t > 0.0f && (1.0f - s - t) > 0.0f;
|
||||
}
|
||||
|
||||
void FloorFace::computePointHeight(Math::Vector3d &point) const {
|
||||
// Compute the barycentric coordinates of the point in the triangle
|
||||
float area = 1.0f / 2.0f
|
||||
* (-_vertices[1].y() * _vertices[2].x()
|
||||
+ _vertices[0].y() * (-_vertices[1].x() + _vertices[2].x())
|
||||
+ _vertices[0].x() * (_vertices[1].y() - _vertices[2].y())
|
||||
+ _vertices[1].x() * _vertices[2].y());
|
||||
|
||||
float s = (_vertices[0].y() * _vertices[2].x() - _vertices[0].x() * _vertices[2].y()
|
||||
+ (_vertices[2].y() - _vertices[0].y()) * point.x()
|
||||
+ (_vertices[0].x() - _vertices[2].x()) * point.y())
|
||||
/ (2.0f * area);
|
||||
|
||||
float t = (_vertices[0].x() * _vertices[1].y() - _vertices[0].y() * _vertices[1].x()
|
||||
+ (_vertices[0].y() - _vertices[1].y()) * point.x()
|
||||
+ (_vertices[1].x() - _vertices[0].x()) * point.y())
|
||||
/ (2.0f * area);
|
||||
|
||||
// Compute the Z coordinate of the point
|
||||
float pointZ = (1.0f - s - t) * _vertices[0].z() + s * _vertices[1].z() + t * _vertices[2].z();
|
||||
|
||||
point.setValue(2, pointZ);
|
||||
}
|
||||
|
||||
bool FloorFace::intersectRay(const Math::Ray &ray, Math::Vector3d &intersection) const {
|
||||
// Compute the triangle plane normal
|
||||
Math::Vector3d n = Math::Vector3d::crossProduct(_vertices[1] - _vertices[0], _vertices[2] - _vertices[0]);
|
||||
if (n == Math::Vector3d()) {
|
||||
return false; // We don't handle degenerate triangles
|
||||
}
|
||||
|
||||
// Point on triangle plane: dot(P - _vertices[0], n) = 0
|
||||
// Point on ray: P = origin + r * direction
|
||||
// Point on both => r = - dot(n, origin - _vertices[0]) / dot(n, direction)
|
||||
|
||||
float num = -Math::Vector3d::dotProduct(n, ray.getOrigin() - _vertices[0]);
|
||||
float denom = Math::Vector3d::dotProduct(n, ray.getDirection());
|
||||
|
||||
if (fabs(denom) < 0.00001) {
|
||||
// The ray is parallel to the plane
|
||||
return false;
|
||||
}
|
||||
|
||||
float r = num / denom;
|
||||
if (r < 0.0) {
|
||||
// The ray goes away from the triangle
|
||||
return false;
|
||||
}
|
||||
|
||||
// Compute the intersection point between the triangle plane and the ray
|
||||
intersection = ray.getOrigin() + r * ray.getDirection();
|
||||
|
||||
// Check the intersection point is inside the triangle
|
||||
return isPointInside(intersection);
|
||||
}
|
||||
|
||||
float FloorFace::distanceToRay(const Math::Ray &ray) const {
|
||||
Math::Vector3d center = getCenter();
|
||||
return Math::Vector3d::crossProduct(ray.getDirection(), center - ray.getOrigin()).getMagnitude();
|
||||
}
|
||||
|
||||
float FloorFace::getDistanceFromCamera() const {
|
||||
return _distanceFromCamera;
|
||||
}
|
||||
|
||||
int16 FloorFace::getVertexIndex(int32 index) const {
|
||||
assert(index < 3);
|
||||
return _indices[index];
|
||||
}
|
||||
|
||||
void FloorFace::addEdge(FloorEdge *edge) {
|
||||
_edges.push_back(edge);
|
||||
}
|
||||
|
||||
Common::Array<FloorEdge *> FloorFace::getEdges() const {
|
||||
return _edges;
|
||||
}
|
||||
|
||||
FloorEdge *FloorFace::findNearestEdge(const Math::Vector3d &point) const {
|
||||
float minDistance = -1;
|
||||
FloorEdge *edge = nullptr;
|
||||
|
||||
for (uint i = 0; i < _edges.size(); i++) {
|
||||
if (!_edges[i]->isEnabled()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
float distance = (point - _edges[i]->getPosition()).getSquareMagnitude();
|
||||
|
||||
|
||||
if (!edge || distance < minDistance) {
|
||||
minDistance = distance;
|
||||
edge = _edges[i];
|
||||
}
|
||||
}
|
||||
|
||||
return edge;
|
||||
}
|
||||
|
||||
Math::Vector3d FloorFace::getCenter() const {
|
||||
return (_vertices[0] + _vertices[1] + _vertices[2]) / 3.0;
|
||||
}
|
||||
|
||||
bool FloorFace::hasVertices() const {
|
||||
return _indices[0] != 0 || _indices[1] != 0 || _indices[2] != 0;
|
||||
}
|
||||
|
||||
void FloorFace::enable(bool e) {
|
||||
for (uint i = 0; i < _edges.size(); i++) {
|
||||
_edges[i]->enable(e);
|
||||
}
|
||||
}
|
||||
|
||||
bool FloorFace::isEnabled() const {
|
||||
for (uint i = 0; i < _edges.size(); i++) {
|
||||
if (_edges[i]->isEnabled()) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void FloorFace::readData(Formats::XRCReadStream *stream) {
|
||||
for (uint i = 0; i < ARRAYSIZE(_indices); i++) {
|
||||
_indices[i] = stream->readSint16LE();
|
||||
}
|
||||
|
||||
_distanceFromCamera = stream->readFloatLE();
|
||||
|
||||
for (uint i = 0; i < ARRAYSIZE(_indices); i++) {
|
||||
stream->readSint16LE(); // Skipped in the original
|
||||
}
|
||||
|
||||
_unk2 = stream->readFloatLE();
|
||||
}
|
||||
|
||||
void FloorFace::onAllLoaded() {
|
||||
Object::onAllLoaded();
|
||||
Floor *floor = Object::cast<Floor>(_parent);
|
||||
|
||||
for (uint i = 0; i < ARRAYSIZE(_indices); i++) {
|
||||
_vertices[i] = floor->getVertex(_indices[i]);
|
||||
}
|
||||
}
|
||||
|
||||
void FloorFace::printData() {
|
||||
debug("indices: %d %d %d, distanceFromCamera %f, unk2 %f", _indices[0], _indices[1], _indices[2], _distanceFromCamera, _unk2);
|
||||
}
|
||||
|
||||
} // End of namespace Resources
|
||||
} // End of namespace Stark
|
||||
122
engines/stark/resources/floorface.h
Normal file
122
engines/stark/resources/floorface.h
Normal file
@@ -0,0 +1,122 @@
|
||||
/* 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/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef STARK_RESOURCES_FLOOR_FACE_H
|
||||
#define STARK_RESOURCES_FLOOR_FACE_H
|
||||
|
||||
#include "common/array.h"
|
||||
#include "common/str.h"
|
||||
|
||||
#include "math/ray.h"
|
||||
#include "math/vector3d.h"
|
||||
|
||||
#include "engines/stark/resources/object.h"
|
||||
|
||||
namespace Stark {
|
||||
|
||||
namespace Formats {
|
||||
class XRCReadStream;
|
||||
}
|
||||
|
||||
namespace Resources {
|
||||
|
||||
class FloorEdge;
|
||||
|
||||
/**
|
||||
* A floor face is a 3D triangle used to build the floor
|
||||
*/
|
||||
class FloorFace : public Object {
|
||||
public:
|
||||
static const Type::ResourceType TYPE = Type::kFloorFace;
|
||||
|
||||
FloorFace(Object *parent, byte subType, uint16 index, const Common::String &name);
|
||||
virtual ~FloorFace();
|
||||
|
||||
// Resource API
|
||||
void onAllLoaded() override;
|
||||
|
||||
/** Return true if the point is inside the face when both are projected on a Z=0 plane*/
|
||||
bool isPointInside(const Math::Vector3d &point) const;
|
||||
|
||||
/** Fill the z coordinate of the point so that it is on the plane */
|
||||
void computePointHeight(Math::Vector3d &point) const;
|
||||
|
||||
/**
|
||||
* Check if a ray is intersecting this face
|
||||
*
|
||||
* @param origin The ray's origin
|
||||
* @param direction The ray's direction
|
||||
* @param intersection The intersection between the ray and the face. Only valid when the return value is true.
|
||||
* @return true if the ray intersects the face, false otherwise.
|
||||
*/
|
||||
bool intersectRay(const Math::Ray &ray, Math::Vector3d &intersection) const;
|
||||
|
||||
/**
|
||||
* Compute the distance between the face center and the ray
|
||||
*/
|
||||
float distanceToRay(const Math::Ray &ray) const;
|
||||
|
||||
/** Obtain the distance to the camera */
|
||||
float getDistanceFromCamera() const;
|
||||
|
||||
/** Get one of the three vertex indices from the face */
|
||||
int16 getVertexIndex(int32 index) const;
|
||||
|
||||
/** Add an edge to the triangle edge list */
|
||||
void addEdge(FloorEdge *edge);
|
||||
|
||||
/** Get the triangle's edge list */
|
||||
Common::Array<FloorEdge *> getEdges() const;
|
||||
|
||||
/**
|
||||
* Find the edge closest to a point
|
||||
*
|
||||
* Distance are compared using the middle point of each edge of the face
|
||||
*/
|
||||
FloorEdge *findNearestEdge(const Math::Vector3d &point) const;
|
||||
|
||||
/** Get the point at the center of the face's triangle */
|
||||
Math::Vector3d getCenter() const;
|
||||
|
||||
/** Checks if the face is non degenerate */
|
||||
bool hasVertices() const;
|
||||
|
||||
/** Allow or disallow characters to walk on this face */
|
||||
void enable(bool enable);
|
||||
bool isEnabled() const;
|
||||
|
||||
protected:
|
||||
void readData(Formats::XRCReadStream *stream) override;
|
||||
void printData() override;
|
||||
|
||||
int16 _indices[3];
|
||||
Math::Vector3d _vertices[3];
|
||||
|
||||
Common::Array<FloorEdge *> _edges; // Owned by Floor
|
||||
|
||||
float _distanceFromCamera;
|
||||
float _unk2;
|
||||
};
|
||||
|
||||
} // End of namespace Resources
|
||||
} // End of namespace Stark
|
||||
|
||||
#endif // STARK_RESOURCES_FLOOR_FACE_H
|
||||
59
engines/stark/resources/floorfield.cpp
Normal file
59
engines/stark/resources/floorfield.cpp
Normal file
@@ -0,0 +1,59 @@
|
||||
/* 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 "engines/stark/resources/floorfield.h"
|
||||
|
||||
#include "engines/stark/formats/xrc.h"
|
||||
|
||||
namespace Stark {
|
||||
namespace Resources {
|
||||
|
||||
FloorField::~FloorField() {
|
||||
}
|
||||
|
||||
FloorField::FloorField(Object *parent, byte subType, uint16 index, const Common::String &name) :
|
||||
Object(parent, subType, index, name) {
|
||||
_type = TYPE;
|
||||
}
|
||||
|
||||
void FloorField::readData(Formats::XRCReadStream *stream) {
|
||||
uint32 count = stream->readUint32LE();
|
||||
for (uint i = 0; i < count; i++) {
|
||||
_facesInFloorField.push_back(stream->readByte());
|
||||
}
|
||||
}
|
||||
|
||||
bool FloorField::hasFace(int32 floorFaceIndex) const {
|
||||
if (floorFaceIndex < 0 || floorFaceIndex >= (int32) _facesInFloorField.size()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return _facesInFloorField[floorFaceIndex] != 0;
|
||||
}
|
||||
|
||||
void FloorField::printData() {
|
||||
for (uint i = 0; i < _facesInFloorField.size(); i++) {
|
||||
debug("faceInFloorField[%d]: %d", i, _facesInFloorField[i]);
|
||||
}
|
||||
}
|
||||
|
||||
} // End of namespace Resources
|
||||
} // End of namespace Stark
|
||||
63
engines/stark/resources/floorfield.h
Normal file
63
engines/stark/resources/floorfield.h
Normal file
@@ -0,0 +1,63 @@
|
||||
/* 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/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef STARK_RESOURCES_FLOORFIELD_H
|
||||
#define STARK_RESOURCES_FLOORFIELD_H
|
||||
|
||||
#include "common/str.h"
|
||||
|
||||
#include "engines/stark/resources/object.h"
|
||||
|
||||
namespace Stark {
|
||||
|
||||
namespace Formats {
|
||||
class XRCReadStream;
|
||||
}
|
||||
|
||||
namespace Resources {
|
||||
|
||||
/**
|
||||
* A floor field represents a portion of the floor in a 3D layer
|
||||
*
|
||||
* A floor field is bounded by the faces it contains
|
||||
*/
|
||||
class FloorField : public Object {
|
||||
public:
|
||||
static const Type::ResourceType TYPE = Type::kFloorField;
|
||||
|
||||
FloorField(Object *parent, byte subType, uint16 index, const Common::String &name);
|
||||
virtual ~FloorField();
|
||||
|
||||
/** Is the specified face inside the floorfield? */
|
||||
bool hasFace(int32 floorFaceIndex) const;
|
||||
|
||||
protected:
|
||||
void readData(Formats::XRCReadStream *stream) override;
|
||||
void printData() override;
|
||||
|
||||
private:
|
||||
Common::Array<byte> _facesInFloorField;
|
||||
};
|
||||
|
||||
} // End of namespace Resources
|
||||
} // End of namespace Stark
|
||||
|
||||
#endif // STARK_RESOURCES_FLOORFIELD_H
|
||||
64
engines/stark/resources/fmv.cpp
Normal file
64
engines/stark/resources/fmv.cpp
Normal file
@@ -0,0 +1,64 @@
|
||||
/* 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 "engines/stark/resources/fmv.h"
|
||||
|
||||
#include "engines/stark/formats/xrc.h"
|
||||
|
||||
#include "engines/stark/services/services.h"
|
||||
#include "engines/stark/services/diary.h"
|
||||
#include "engines/stark/services/userinterface.h"
|
||||
|
||||
namespace Stark {
|
||||
namespace Resources {
|
||||
|
||||
FMV::~FMV() {
|
||||
}
|
||||
|
||||
FMV::FMV(Object *parent, byte subType, uint16 index, const Common::String &name) :
|
||||
Object(parent, subType, index, name),
|
||||
_diaryAddEntryOnPlay(true),
|
||||
_gameDisc(1) {
|
||||
_type = TYPE;
|
||||
}
|
||||
|
||||
void FMV::readData(Formats::XRCReadStream *stream) {
|
||||
_filename = Common::Path(stream->readString());
|
||||
_diaryAddEntryOnPlay = stream->readBool();
|
||||
_gameDisc = stream->readUint32LE();
|
||||
}
|
||||
|
||||
void FMV::requestPlayback() {
|
||||
if (_diaryAddEntryOnPlay) {
|
||||
StarkDiary->addFMVEntry(_filename, getName(), _gameDisc);
|
||||
}
|
||||
|
||||
StarkUserInterface->requestFMVPlayback(_filename);
|
||||
}
|
||||
|
||||
void FMV::printData() {
|
||||
debug("filename: %s", _filename.toString().c_str());
|
||||
debug("diaryAddEntryOnPlay: %d", _diaryAddEntryOnPlay);
|
||||
debug("gameDisc: %d", _gameDisc);
|
||||
}
|
||||
|
||||
} // End of namespace Resources
|
||||
} // End of namespace Stark
|
||||
65
engines/stark/resources/fmv.h
Normal file
65
engines/stark/resources/fmv.h
Normal file
@@ -0,0 +1,65 @@
|
||||
/* 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/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef STARK_RESOURCES_FMV_H
|
||||
#define STARK_RESOURCES_FMV_H
|
||||
|
||||
#include "common/path.h"
|
||||
#include "common/str.h"
|
||||
|
||||
#include "engines/stark/resources/object.h"
|
||||
|
||||
namespace Stark {
|
||||
|
||||
namespace Formats {
|
||||
class XRCReadStream;
|
||||
}
|
||||
|
||||
namespace Resources {
|
||||
|
||||
/**
|
||||
* A full motion video
|
||||
*/
|
||||
class FMV : public Object {
|
||||
public:
|
||||
static const Type::ResourceType TYPE = Type::kFMV;
|
||||
|
||||
FMV(Object *parent, byte subType, uint16 index, const Common::String &name);
|
||||
virtual ~FMV();
|
||||
|
||||
// Resource API
|
||||
void readData(Formats::XRCReadStream *stream) override;
|
||||
|
||||
/** Request the user interface to start playing the movie */
|
||||
void requestPlayback();
|
||||
|
||||
protected:
|
||||
void printData() override;
|
||||
|
||||
Common::Path _filename;
|
||||
bool _diaryAddEntryOnPlay;
|
||||
uint32 _gameDisc;
|
||||
};
|
||||
|
||||
} // End of namespace Resources
|
||||
} // End of namespace Stark
|
||||
|
||||
#endif // STARK_RESOURCES_FMV_H
|
||||
377
engines/stark/resources/image.cpp
Normal file
377
engines/stark/resources/image.cpp
Normal file
@@ -0,0 +1,377 @@
|
||||
/* 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 "engines/stark/resources/image.h"
|
||||
|
||||
#include "common/debug.h"
|
||||
#include "image/png.h"
|
||||
|
||||
#include "engines/stark/debug.h"
|
||||
#include "engines/stark/formats/xrc.h"
|
||||
#include "engines/stark/gfx/driver.h"
|
||||
#include "engines/stark/resources/location.h"
|
||||
#include "engines/stark/services/archiveloader.h"
|
||||
#include "engines/stark/services/settings.h"
|
||||
#include "engines/stark/services/services.h"
|
||||
#include "engines/stark/visual/effects/bubbles.h"
|
||||
#include "engines/stark/visual/effects/fireflies.h"
|
||||
#include "engines/stark/visual/effects/fish.h"
|
||||
#include "engines/stark/visual/image.h"
|
||||
#include "engines/stark/visual/text.h"
|
||||
|
||||
#include "math/line2d.h"
|
||||
#include "math/vector2d.h"
|
||||
|
||||
namespace Stark {
|
||||
namespace Resources {
|
||||
|
||||
Object *Image::construct(Object *parent, byte subType, uint16 index, const Common::String &name) {
|
||||
switch (subType) {
|
||||
case kImageSub2:
|
||||
case kImageSub3:
|
||||
return new ImageStill(parent, subType, index, name);
|
||||
case kImageText:
|
||||
return new ImageText(parent, subType, index, name);
|
||||
default:
|
||||
error("Unknown image subtype %d", subType);
|
||||
}
|
||||
}
|
||||
|
||||
Image::~Image() {
|
||||
delete _visual;
|
||||
}
|
||||
|
||||
Image::Image(Object *parent, byte subType, uint16 index, const Common::String &name) :
|
||||
Object(parent, subType, index, name),
|
||||
_transparent(false),
|
||||
_transparentColor(0),
|
||||
_field_44_ADF(0),
|
||||
_field_48_ADF(30),
|
||||
_visual(nullptr) {
|
||||
_type = TYPE;
|
||||
}
|
||||
|
||||
void Image::readData(Formats::XRCReadStream *stream) {
|
||||
_filename = stream->readString();
|
||||
_hotspot = stream->readPoint();
|
||||
_transparent = stream->readBool();
|
||||
_transparentColor = stream->readUint32LE();
|
||||
|
||||
uint32 polygonCount = stream->readUint32LE();
|
||||
for (uint32 i = 0; i < polygonCount; i++) {
|
||||
Polygon polygon;
|
||||
|
||||
uint32 pointCount = stream->readUint32LE();
|
||||
for (uint32 j = 0; j < pointCount; j++) {
|
||||
polygon.push_back(stream->readPoint());
|
||||
}
|
||||
|
||||
_polygons.push_back(polygon);
|
||||
}
|
||||
|
||||
_archiveName = stream->getArchiveName();
|
||||
}
|
||||
|
||||
Visual *Image::getVisual() {
|
||||
initVisual();
|
||||
return _visual;
|
||||
}
|
||||
|
||||
void Image::printData() {
|
||||
debug("filename: %s", _filename.toString().c_str());
|
||||
debug("hotspot: x %d, y %d", _hotspot.x, _hotspot.y);
|
||||
debug("transparent: %d", _transparent);
|
||||
debug("transparentColor: %d", _transparentColor);
|
||||
debug("field_44: %d", _field_44_ADF);
|
||||
debug("field_48: %d", _field_48_ADF);
|
||||
|
||||
for (uint32 i = 0; i < _polygons.size(); i++) {
|
||||
Common::String description;
|
||||
for (uint32 j = 0; j < _polygons[i].size(); j++) {
|
||||
description += Common::String::format("(x %d, y %d) ", _polygons[i][j].x, _polygons[i][j].y);
|
||||
}
|
||||
debug("polygon %d: %s", i, description.c_str());
|
||||
}
|
||||
}
|
||||
|
||||
int Image::indexForPoint(const Common::Point &point) const {
|
||||
int index = -1;
|
||||
for (uint32 i = 0; i < _polygons.size(); i++) {
|
||||
if (isPointInPolygon(_polygons[i], point)) {
|
||||
index = i;
|
||||
}
|
||||
}
|
||||
|
||||
return index;
|
||||
}
|
||||
|
||||
bool Image::isPointInPolygon(const Polygon &polygon, const Common::Point &point) const {
|
||||
if (polygon.size() <= 1) {
|
||||
return false; // Empty polygon
|
||||
}
|
||||
|
||||
// A ray cast from the point
|
||||
Math::Segment2d testLine(Math::Vector2d(point.x, point.y), Math::Vector2d(-100, -100));
|
||||
|
||||
// Special case the line created between the last point and the first
|
||||
Math::Vector2d prevPoint = Math::Vector2d(polygon.back().x, polygon.back().y);
|
||||
|
||||
// Count the intersections of the ray with the polygon's edges
|
||||
int intersectCount = 0;
|
||||
for (uint32 j = 0; j < polygon.size(); j++) {
|
||||
Math::Vector2d curPoint = Math::Vector2d(polygon[j].x, polygon[j].y);
|
||||
|
||||
if (Math::Segment2d(prevPoint, curPoint).intersectsSegment(testLine, nullptr)) {
|
||||
intersectCount++;
|
||||
}
|
||||
|
||||
prevPoint = curPoint;
|
||||
}
|
||||
|
||||
// If the ray crosses the polygon an odd number of times, the point is inside the polygon
|
||||
return intersectCount % 2 != 0;
|
||||
}
|
||||
|
||||
Common::Point Image::getHotspotPosition(uint index) const {
|
||||
if (index >= _polygons.size()) {
|
||||
return Common::Point(-1, -1);
|
||||
}
|
||||
|
||||
Polygon polygon = _polygons[index];
|
||||
|
||||
// Return the top-middle point as the hotspot
|
||||
int right = polygon[0].x, top = polygon[0].y;
|
||||
|
||||
for (uint i = 1; i < polygon.size(); ++i) {
|
||||
right += polygon[i].x;
|
||||
if (polygon[i].y < top) {
|
||||
top = polygon[i].y;
|
||||
}
|
||||
}
|
||||
|
||||
right /= polygon.size();
|
||||
|
||||
if (top < 0) {
|
||||
top = 0;
|
||||
}
|
||||
|
||||
return Common::Point(right, top);
|
||||
}
|
||||
|
||||
ImageStill::~ImageStill() {
|
||||
}
|
||||
|
||||
ImageStill::ImageStill(Object *parent, byte subType, uint16 index, const Common::String &name) :
|
||||
Image(parent, subType, index, name),
|
||||
_noName(false) {
|
||||
}
|
||||
|
||||
void ImageStill::readData(Formats::XRCReadStream *stream) {
|
||||
Image::readData(stream);
|
||||
|
||||
if (stream->isDataLeft()) {
|
||||
_field_44_ADF = stream->readUint32LE();
|
||||
_field_44_ADF /= 33;
|
||||
}
|
||||
|
||||
if (stream->isDataLeft()) {
|
||||
_field_48_ADF = stream->readUint32LE();
|
||||
}
|
||||
|
||||
_noName = _filename == "noname" || _filename == "noname.xmg";
|
||||
}
|
||||
|
||||
void ImageStill::onPostRead() {
|
||||
initVisual();
|
||||
}
|
||||
|
||||
void ImageStill::initVisual() {
|
||||
if (_visual) {
|
||||
return; // The visual is already there
|
||||
}
|
||||
|
||||
if (_noName) {
|
||||
return; // No file to load
|
||||
}
|
||||
|
||||
Common::ReadStream *xmgStream = StarkArchiveLoader->getFile(_filename, _archiveName);
|
||||
|
||||
VisualImageXMG *visual = new VisualImageXMG(StarkGfx);
|
||||
|
||||
if (StarkSettings->isAssetsModEnabled() && StarkGfx->supportsModdedAssets() && loadPNGOverride(visual)) {
|
||||
visual->readOriginalSize(xmgStream);
|
||||
} else {
|
||||
visual->load(xmgStream);
|
||||
}
|
||||
|
||||
visual->setHotSpot(_hotspot);
|
||||
|
||||
_visual = visual;
|
||||
|
||||
delete xmgStream;
|
||||
}
|
||||
|
||||
bool ImageStill::loadPNGOverride(VisualImageXMG *visual) const {
|
||||
if (!_filename.baseName().hasSuffixIgnoreCase(".xmg")) {
|
||||
return false;
|
||||
}
|
||||
|
||||
Common::String pngFilename = _filename.baseName();
|
||||
pngFilename = Common::String(pngFilename.c_str(), pngFilename.size() - 4) + ".png";
|
||||
Common::Path pngFilePath = _filename.getParent().appendComponent(pngFilename);
|
||||
pngFilePath = StarkArchiveLoader->getExternalFilePath(pngFilePath, _archiveName);
|
||||
|
||||
debugC(kDebugModding, "Attempting to load %s", pngFilePath.toString(Common::Path::kNativeSeparator).c_str());
|
||||
|
||||
Common::SeekableReadStream *pngStream = SearchMan.createReadStreamForMember(pngFilePath);
|
||||
if (!pngStream) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!visual->loadPNG(pngStream)) {
|
||||
warning("Failed to load %s. It is not a valid PNG file.", pngFilePath.toString(Common::Path::kNativeSeparator).c_str());
|
||||
delete pngStream;
|
||||
return false;
|
||||
}
|
||||
|
||||
debugC(kDebugModding, "Loaded %s", pngFilePath.toString(Common::Path::kNativeSeparator).c_str());
|
||||
|
||||
delete pngStream;
|
||||
return true;
|
||||
}
|
||||
|
||||
void ImageStill::printData() {
|
||||
Image::printData();
|
||||
}
|
||||
|
||||
ImageText::ImageText(Object *parent, byte subType, uint16 index, const Common::String &name) :
|
||||
Image(parent, subType, index, name),
|
||||
_color(Gfx::Color(0, 0, 0)),
|
||||
_font(0) {
|
||||
}
|
||||
|
||||
ImageText::~ImageText() {
|
||||
}
|
||||
|
||||
void ImageText::readData(Formats::XRCReadStream *stream) {
|
||||
Image::readData(stream);
|
||||
|
||||
_size = stream->readPoint();
|
||||
_text = stream->readString();
|
||||
_color.r = stream->readByte();
|
||||
_color.g = stream->readByte();
|
||||
_color.b = stream->readByte();
|
||||
_color.a = 0xFF; stream->readByte();
|
||||
_font = stream->readUint32LE();
|
||||
|
||||
// WORKAROUND: Give more space to text in the Archives' computer
|
||||
// So there are no line breaks in the French version of the game
|
||||
// when using a scaled font.
|
||||
Location *location = findParent<Location>();
|
||||
if (_name == "MAIN" && location && location->getName() == "Archive Database") {
|
||||
_size.x = 80;
|
||||
}
|
||||
}
|
||||
|
||||
void ImageText::initVisual() {
|
||||
if (_visual) {
|
||||
return; // The visual is already there
|
||||
}
|
||||
|
||||
if (_text.hasPrefix("GFX_Bubbles")) {
|
||||
VisualEffectBubbles *bubbles = new VisualEffectBubbles(StarkGfx, _size);
|
||||
bubbles->setParams(_text);
|
||||
_visual = bubbles;
|
||||
} else if (_text.hasPrefix("GFX_FireFlies")) {
|
||||
VisualEffectFireFlies *fireFlies = new VisualEffectFireFlies(StarkGfx, _size);
|
||||
fireFlies->setParams(_text);
|
||||
_visual = fireFlies;
|
||||
} else if (_text.hasPrefix("GFX_Fish")) {
|
||||
VisualEffectFish *fish = new VisualEffectFish(StarkGfx, _size);
|
||||
fish->setParams(_text);
|
||||
_visual = fish;
|
||||
} else if (_text.hasPrefix("GFX_")) {
|
||||
error("Unknown effect '%s'", _text.c_str());
|
||||
} else {
|
||||
VisualText *text = new VisualText(StarkGfx);
|
||||
text->setText(_text);
|
||||
text->setColor(_color);
|
||||
text->setTargetWidth(_size.x);
|
||||
text->setTargetHeight(_size.y);
|
||||
text->setFont(FontProvider::kCustomFont, _font);
|
||||
|
||||
// WORKAROUND: Move the "White Cardinal" hotspot in the Archives'
|
||||
// computer so it matches the text. Fixes the hotspot being hard to
|
||||
// use with scaled fonts in the Spanish version of the game.
|
||||
if (_name == "The Church" && _polygons.size() == 2) {
|
||||
fixWhiteCardinalHotspot(text);
|
||||
}
|
||||
|
||||
_visual = text;
|
||||
}
|
||||
}
|
||||
|
||||
void ImageText::fixWhiteCardinalHotspot(VisualText *text) {
|
||||
Common::Rect textRect = text->getRect();
|
||||
|
||||
Polygon &hotspotPoly = _polygons.back();
|
||||
if (hotspotPoly.size() != 4) {
|
||||
return;
|
||||
}
|
||||
|
||||
Common::Point &topLeft = hotspotPoly[0];
|
||||
Common::Point &topRight = hotspotPoly[1];
|
||||
Common::Point &bottomRight = hotspotPoly[2];
|
||||
Common::Point &bottomLeft = hotspotPoly[3];
|
||||
|
||||
int16 hotspotHeight = bottomLeft.y - topLeft.y;
|
||||
if (hotspotHeight <= 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
bottomLeft .y = textRect.bottom;
|
||||
bottomRight.y = textRect.bottom;
|
||||
topLeft .y = textRect.bottom - hotspotHeight;
|
||||
topRight .y = textRect.bottom - hotspotHeight;
|
||||
}
|
||||
|
||||
void ImageText::resetVisual() {
|
||||
if (!_visual) {
|
||||
return;
|
||||
}
|
||||
|
||||
VisualText *text = _visual->get<VisualText>();
|
||||
if (text) {
|
||||
text->reset();
|
||||
}
|
||||
}
|
||||
|
||||
void ImageText::printData() {
|
||||
Image::printData();
|
||||
|
||||
debug("size: x %d, y %d", _size.x, _size.y);
|
||||
debug("text: %s", _text.c_str());
|
||||
debug("color: (%d, %d, %d, %d)", _color.r, _color.g, _color.b, _color.a);
|
||||
debug("font: %d", _font);
|
||||
}
|
||||
|
||||
} // End of namespace Resources
|
||||
} // End of namespace Stark
|
||||
152
engines/stark/resources/image.h
Normal file
152
engines/stark/resources/image.h
Normal file
@@ -0,0 +1,152 @@
|
||||
/* 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/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef STARK_RESOURCES_IMAGE_H
|
||||
#define STARK_RESOURCES_IMAGE_H
|
||||
|
||||
#include "common/path.h"
|
||||
#include "common/rect.h"
|
||||
#include "common/str.h"
|
||||
|
||||
#include "engines/stark/resources/object.h"
|
||||
#include "engines/stark/gfx/color.h"
|
||||
|
||||
namespace Stark {
|
||||
|
||||
class Visual;
|
||||
class VisualImageXMG;
|
||||
class VisualText;
|
||||
namespace Formats {
|
||||
class XRCReadStream;
|
||||
}
|
||||
|
||||
namespace Resources {
|
||||
|
||||
/**
|
||||
* A still image resource
|
||||
*/
|
||||
class Image : public Object {
|
||||
public:
|
||||
static const Type::ResourceType TYPE = Type::kImage;
|
||||
|
||||
enum SubType {
|
||||
kImageSub2 = 2,
|
||||
kImageSub3 = 3,
|
||||
kImageText = 4
|
||||
};
|
||||
|
||||
/** Image factory */
|
||||
static Object *construct(Object *parent, byte subType, uint16 index, const Common::String &name);
|
||||
|
||||
typedef Common::Array<Common::Point> Polygon;
|
||||
|
||||
Image(Object *parent, byte subType, uint16 index, const Common::String &name);
|
||||
virtual ~Image();
|
||||
|
||||
// Resource API
|
||||
void readData(Formats::XRCReadStream *stream) override;
|
||||
|
||||
/** Initialize the renderable for the image */
|
||||
virtual Visual *getVisual();
|
||||
|
||||
/** Get the pat-table index for a given point */
|
||||
int indexForPoint(const Common::Point &point) const;
|
||||
|
||||
/** Get the hotspot position for a given index of a pat-table */
|
||||
Common::Point getHotspotPosition(uint index) const;
|
||||
|
||||
protected:
|
||||
void printData() override;
|
||||
bool isPointInPolygon(const Polygon &polygon, const Common::Point &point) const;
|
||||
|
||||
virtual void initVisual() = 0;
|
||||
|
||||
Common::Path _filename;
|
||||
Common::Path _archiveName;
|
||||
|
||||
Visual *_visual;
|
||||
|
||||
bool _transparent;
|
||||
uint32 _transparentColor;
|
||||
uint32 _field_44_ADF;
|
||||
uint32 _field_48_ADF;
|
||||
|
||||
Common::Point _hotspot;
|
||||
Common::Array<Polygon> _polygons;
|
||||
};
|
||||
|
||||
/**
|
||||
* A still image resource loading its data from an XMG file
|
||||
*/
|
||||
class ImageStill : public Image {
|
||||
public:
|
||||
ImageStill(Object *parent, byte subType, uint16 index, const Common::String &name);
|
||||
virtual ~ImageStill();
|
||||
|
||||
// Resource API
|
||||
void readData(Formats::XRCReadStream *stream) override;
|
||||
void onPostRead() override;
|
||||
|
||||
protected:
|
||||
// Resource API
|
||||
void printData() override;
|
||||
|
||||
// Image API
|
||||
void initVisual() override;
|
||||
|
||||
bool loadPNGOverride(Stark::VisualImageXMG *visual) const;
|
||||
|
||||
bool _noName;
|
||||
};
|
||||
|
||||
/**
|
||||
* Text image rendered from a TTF font
|
||||
*/
|
||||
class ImageText : public Image {
|
||||
public:
|
||||
ImageText(Object *parent, byte subType, uint16 index, const Common::String &name);
|
||||
virtual ~ImageText();
|
||||
|
||||
// Resource API
|
||||
void readData(Formats::XRCReadStream *stream) override;
|
||||
|
||||
/** Reset the text visual so it is recomputed the next frame it is rendered */
|
||||
void resetVisual();
|
||||
|
||||
protected:
|
||||
// Resource API
|
||||
void printData() override;
|
||||
|
||||
// Image API
|
||||
void initVisual() override;
|
||||
|
||||
void fixWhiteCardinalHotspot(VisualText *text);
|
||||
|
||||
Common::Point _size;
|
||||
Common::String _text;
|
||||
Gfx::Color _color;
|
||||
uint32 _font;
|
||||
};
|
||||
|
||||
} // End of namespace Resources
|
||||
} // End of namespace Stark
|
||||
|
||||
#endif // STARK_RESOURCES_IMAGE_H
|
||||
1125
engines/stark/resources/item.cpp
Normal file
1125
engines/stark/resources/item.cpp
Normal file
File diff suppressed because it is too large
Load Diff
497
engines/stark/resources/item.h
Normal file
497
engines/stark/resources/item.h
Normal file
@@ -0,0 +1,497 @@
|
||||
/* 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/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef STARK_RESOURCES_ITEM_H
|
||||
#define STARK_RESOURCES_ITEM_H
|
||||
|
||||
#include "engines/stark/resources/object.h"
|
||||
#include "engines/stark/resourcereference.h"
|
||||
|
||||
#include "common/rect.h"
|
||||
#include "common/str.h"
|
||||
|
||||
#include "math/vector3d.h"
|
||||
|
||||
namespace Stark {
|
||||
|
||||
class AnimHandler;
|
||||
class Movement;
|
||||
class Visual;
|
||||
|
||||
namespace Gfx {
|
||||
class RenderEntry;
|
||||
}
|
||||
|
||||
namespace Formats {
|
||||
class XRCReadStream;
|
||||
}
|
||||
|
||||
namespace Resources {
|
||||
|
||||
class Anim;
|
||||
class AnimHierarchy;
|
||||
class BonesMesh;
|
||||
class Bookmark;
|
||||
class ItemVisual;
|
||||
class Script;
|
||||
class TextureSet;
|
||||
|
||||
/**
|
||||
* A scene element
|
||||
*
|
||||
* Can be a character, background, animation, ...
|
||||
*/
|
||||
class Item : public Object {
|
||||
public:
|
||||
static const Type::ResourceType TYPE = Type::kItem;
|
||||
|
||||
enum SubType {
|
||||
kItemGlobalTemplate = 1,
|
||||
kItemInventory = 2,
|
||||
kItemLevelTemplate = 3,
|
||||
kItemStaticProp = 5,
|
||||
kItemAnimatedProp = 6,
|
||||
kItemBackgroundElement = 7,
|
||||
kItemBackground = 8,
|
||||
kItemModel = 10
|
||||
};
|
||||
|
||||
/** Item factory */
|
||||
static Object *construct(Object *parent, byte subType, uint16 index, const Common::String &name);
|
||||
|
||||
Item(Object *parent, byte subType, uint16 index, const Common::String &name);
|
||||
virtual ~Item();
|
||||
|
||||
// Resource API
|
||||
void readData(Formats::XRCReadStream *stream) override;
|
||||
void onGameLoop() override;
|
||||
void saveLoad(ResourceSerializer *serializer) override;
|
||||
void saveLoadCurrent(ResourceSerializer *serializer) override;
|
||||
|
||||
/** Is the item present in the scene */
|
||||
bool isEnabled() const;
|
||||
|
||||
/** Enable or disable the item */
|
||||
virtual void setEnabled(bool enabled);
|
||||
|
||||
/** Get the item's character index */
|
||||
int32 getCharacterIndex() const;
|
||||
|
||||
/** Obtain the render entry to use to display the item */
|
||||
virtual Gfx::RenderEntry *getRenderEntry(const Common::Point &positionOffset);
|
||||
|
||||
/** Obtain the concrete instance of an item template */
|
||||
virtual ItemVisual *getSceneInstance() = 0;
|
||||
|
||||
/** Replace the current movement with an other */
|
||||
void setMovement(Movement *movement);
|
||||
|
||||
/** Get the current movement if any */
|
||||
Movement *getMovement() const;
|
||||
|
||||
/**
|
||||
* Set the script waiting for the item's movement to complete.
|
||||
*
|
||||
* This script will be updated with the outcome of the movement
|
||||
* (completion or abortion)
|
||||
*/
|
||||
void setMovementSuspendedScript(Script *script);
|
||||
|
||||
/** Set the currently active anim hierarchy */
|
||||
virtual void setAnimHierarchy(AnimHierarchy *animHierarchy) = 0;
|
||||
|
||||
/** List all the exit positions */
|
||||
virtual Common::Array<Common::Point> listExitPositions();
|
||||
|
||||
protected:
|
||||
void printData() override;
|
||||
|
||||
bool _enabled;
|
||||
int32 _characterIndex;
|
||||
|
||||
Movement *_movement;
|
||||
Script *_movementSuspendedScript;
|
||||
};
|
||||
|
||||
/**
|
||||
* A renderable item
|
||||
*
|
||||
* Renderable items are found in location layers
|
||||
*/
|
||||
class ItemVisual : public Item {
|
||||
public:
|
||||
ItemVisual(Object *parent, byte subType, uint16 index, const Common::String &name);
|
||||
virtual ~ItemVisual();
|
||||
|
||||
// Resource API
|
||||
void readData(Formats::XRCReadStream *stream) override;
|
||||
void onAllLoaded() override;
|
||||
void saveLoad(ResourceSerializer *serializer) override;
|
||||
void saveLoadCurrent(ResourceSerializer *serializer) override;
|
||||
|
||||
// Item API
|
||||
void setEnabled(bool enabled) override;
|
||||
ItemVisual *getSceneInstance() override;
|
||||
void setAnimHierarchy(AnimHierarchy *animHierarchy) override;
|
||||
|
||||
/**
|
||||
* Change the item's 2D position.
|
||||
*
|
||||
* Only applies to 2D items
|
||||
*/
|
||||
virtual void setPosition2D(const Common::Point &position);
|
||||
|
||||
/** Get the hotspot index for an item relative position */
|
||||
int getHotspotIndexForPoint(const Common::Point &point);
|
||||
|
||||
/** Obtain the title for one of the item's hotspots */
|
||||
Common::String getHotspotTitle(uint32 hotspotIndex);
|
||||
|
||||
/** Check whether the item has runnable scripts for the specified action */
|
||||
bool canPerformAction(uint32 action, uint32 hotspotIndex);
|
||||
|
||||
/** Perform an action on one of the item's hotspots */
|
||||
bool doAction(uint32 action, uint32 hotspotIndex);
|
||||
|
||||
/** Define the current animation kind for the item */
|
||||
void setAnimActivity(int32 activity);
|
||||
|
||||
/** Get the current animation kind */
|
||||
int32 getAnimActivity() const;
|
||||
|
||||
/** Get the currently playing animation */
|
||||
Anim *getAnim() const;
|
||||
|
||||
/** Get the currently playing action animation, if any */
|
||||
Anim *getActionAnim() const;
|
||||
|
||||
/** Replace the current generic animation with an action specific animation */
|
||||
void playActionAnim(Anim *anim);
|
||||
|
||||
/** Remove the current specific animation and revert to a generic one */
|
||||
void resetActionAnim();
|
||||
|
||||
protected:
|
||||
// Resource API
|
||||
void printData() override;
|
||||
|
||||
/** Implemented version used in FloorPositionedImageItem and ImageItem */
|
||||
Common::Array<Common::Point> listExitPositionsImpl();
|
||||
|
||||
Visual *getVisual();
|
||||
|
||||
Gfx::RenderEntry *_renderEntry;
|
||||
|
||||
Anim *_actionAnim;
|
||||
AnimHierarchy *_animHierarchy;
|
||||
int32 _currentAnimActivity;
|
||||
bool _clickable;
|
||||
};
|
||||
|
||||
/**
|
||||
* An item template
|
||||
*
|
||||
* Item templates need to be instanciated into renderable items to be displayed
|
||||
*/
|
||||
class ItemTemplate : public Item {
|
||||
public:
|
||||
ItemTemplate(Object *parent, byte subType, uint16 index, const Common::String &name);
|
||||
virtual ~ItemTemplate();
|
||||
|
||||
// Resource API
|
||||
void onAllLoaded() override;
|
||||
void onEnterLocation() override;
|
||||
void saveLoadCurrent(ResourceSerializer *serializer) override;
|
||||
|
||||
// Item API
|
||||
ItemVisual *getSceneInstance() override;
|
||||
void setAnimHierarchy(AnimHierarchy *animHierarchy) override;
|
||||
|
||||
/** Obtain the bone mesh to use to render the item */
|
||||
virtual BonesMesh *findBonesMesh() = 0;
|
||||
|
||||
/** Obtain the texture to use to render the item */
|
||||
virtual TextureSet *findTextureSet(uint32 textureType) = 0;
|
||||
|
||||
/** Obtain the animation hierarchy to fetch animations from */
|
||||
virtual AnimHierarchy *findStockAnimHierarchy() = 0;
|
||||
|
||||
/** Define the anim hierarchy to be persisted across locations */
|
||||
void setStockAnimHierachy(AnimHierarchy *animHierarchy);
|
||||
|
||||
/** Change the item's mesh */
|
||||
void setBonesMesh(int32 index);
|
||||
|
||||
/** Set the mesh main or face texture */
|
||||
void setTexture(int32 index, uint32 textureType);
|
||||
|
||||
/** Set the scene instanciation for this template */
|
||||
void setInstanciatedItem(Item *instance);
|
||||
|
||||
protected:
|
||||
int32 _meshIndex;
|
||||
int32 _textureNormalIndex;
|
||||
int32 _textureFaceIndex;
|
||||
int32 _animHierarchyIndex;
|
||||
|
||||
Item *_instanciatedItem;
|
||||
ItemTemplate *_referencedItem;
|
||||
};
|
||||
|
||||
/**
|
||||
* A global item template
|
||||
*
|
||||
* Global item templates are found in the global level
|
||||
*/
|
||||
class GlobalItemTemplate : public ItemTemplate {
|
||||
public:
|
||||
GlobalItemTemplate(Object *parent, byte subType, uint16 index, const Common::String &name);
|
||||
virtual ~GlobalItemTemplate();
|
||||
|
||||
// ItemTemplate API
|
||||
BonesMesh *findBonesMesh() override;
|
||||
TextureSet *findTextureSet(uint32 textureType) override;
|
||||
AnimHierarchy *findStockAnimHierarchy() override;
|
||||
|
||||
protected:
|
||||
};
|
||||
|
||||
/**
|
||||
* An inventory item
|
||||
*/
|
||||
class InventoryItem : public ItemVisual {
|
||||
public:
|
||||
InventoryItem(Object *parent, byte subType, uint16 index, const Common::String &name);
|
||||
virtual ~InventoryItem();
|
||||
|
||||
// Item API
|
||||
Gfx::RenderEntry *getRenderEntry(const Common::Point &positionOffset) override;
|
||||
void setEnabled(bool enabled) override;
|
||||
|
||||
/** Obtain an action menu icon */
|
||||
Visual *getActionVisual(bool active) const;
|
||||
|
||||
/** Obtain an inventory item cursor */
|
||||
Visual *getCursorVisual() const;
|
||||
|
||||
protected:
|
||||
};
|
||||
|
||||
/**
|
||||
* A level item template
|
||||
*
|
||||
* Level item templates are found in levels so that they can be shared between
|
||||
* locations.
|
||||
*/
|
||||
class LevelItemTemplate : public ItemTemplate {
|
||||
public:
|
||||
LevelItemTemplate(Object *parent, byte subType, uint16 index, const Common::String &name);
|
||||
virtual ~LevelItemTemplate();
|
||||
|
||||
// Resource API
|
||||
void readData(Formats::XRCReadStream *stream) override;
|
||||
void onAllLoaded() override;
|
||||
|
||||
// ItemTemplate API
|
||||
BonesMesh *findBonesMesh() override;
|
||||
TextureSet *findTextureSet(uint32 textureType) override;
|
||||
AnimHierarchy *findStockAnimHierarchy() override;
|
||||
|
||||
/** Get the item's level or global template if any */
|
||||
ItemTemplate *getItemTemplate() const;
|
||||
|
||||
protected:
|
||||
void printData() override;
|
||||
|
||||
ResourceReference _reference;
|
||||
};
|
||||
|
||||
/**
|
||||
* 3D positioned item
|
||||
*
|
||||
* Items with a 3D position, used in 3D layers. The sort key determines the order
|
||||
* in which such items are drawn in.
|
||||
*/
|
||||
class FloorPositionedItem : public ItemVisual {
|
||||
public:
|
||||
FloorPositionedItem(Object *parent, byte subType, uint16 index, const Common::String &name);
|
||||
virtual ~FloorPositionedItem();
|
||||
|
||||
// Object API
|
||||
void saveLoad(ResourceSerializer *serializer) override;
|
||||
|
||||
/** Move the item to a bookmarked position */
|
||||
void placeOnBookmark(Bookmark *target);
|
||||
|
||||
/** Place the item on the center of the first floor face */
|
||||
void placeDefaultPosition();
|
||||
|
||||
/** Get the item position */
|
||||
Math::Vector3d getPosition3D() const;
|
||||
/** Move the item */
|
||||
void setPosition3D(const Math::Vector3d &position);
|
||||
|
||||
/** Get the floor face index the item is standing on */
|
||||
int32 getFloorFaceIndex() const;
|
||||
/** Change the face the item is standing on */
|
||||
void setFloorFaceIndex(int32 faceIndex);
|
||||
|
||||
/** Get a vector pointing in the same direction as the item */
|
||||
Math::Vector3d getDirectionVector() const;
|
||||
|
||||
/** Set the direction the item faces */
|
||||
void setDirection(const Math::Angle &direction);
|
||||
|
||||
/** Obtain the sort value for the item, used to compute the draw order */
|
||||
float getSortKey() const;
|
||||
|
||||
/**
|
||||
* Don't rely on the floor face to compute the sort key, use the provided value instead.
|
||||
*
|
||||
* This can be used to handle cases where the item is not over the floor.
|
||||
*/
|
||||
void overrideSortKey(float sortKey);
|
||||
|
||||
protected:
|
||||
int32 _floorFaceIndex;
|
||||
Math::Vector3d _position3D;
|
||||
float _direction3D;
|
||||
|
||||
bool _sortKeyOverride;
|
||||
float _sortKeyOverridenValue;
|
||||
};
|
||||
|
||||
/**
|
||||
* 3D positioned image item
|
||||
*
|
||||
* Used to display still images or animated images in 3D layers
|
||||
*/
|
||||
class FloorPositionedImageItem : public FloorPositionedItem {
|
||||
public:
|
||||
FloorPositionedImageItem(Object *parent, byte subType, uint16 index, const Common::String &name);
|
||||
virtual ~FloorPositionedImageItem();
|
||||
|
||||
// Resource API
|
||||
void readData(Formats::XRCReadStream *stream) override;
|
||||
|
||||
// Item API
|
||||
Gfx::RenderEntry *getRenderEntry(const Common::Point &positionOffset) override;
|
||||
Common::Array<Common::Point> listExitPositions() override;
|
||||
|
||||
// ItemVisual API
|
||||
void setPosition2D(const Common::Point &position) override;
|
||||
|
||||
protected:
|
||||
void printData() override;
|
||||
|
||||
Common::Point _position;
|
||||
};
|
||||
|
||||
/**
|
||||
* Model item
|
||||
*
|
||||
* Used to draw characters
|
||||
*/
|
||||
class ModelItem : public FloorPositionedItem {
|
||||
public:
|
||||
ModelItem(Object *parent, byte subType, uint16 index, const Common::String &name);
|
||||
virtual ~ModelItem();
|
||||
|
||||
// Resource API
|
||||
void readData(Formats::XRCReadStream *stream) override;
|
||||
void onAllLoaded() override;
|
||||
void onEnterLocation() override;
|
||||
void onExitLocation() override;
|
||||
void saveLoadCurrent(ResourceSerializer *serializer) override;
|
||||
|
||||
// Item API
|
||||
Gfx::RenderEntry *getRenderEntry(const Common::Point &positionOffset) override;
|
||||
|
||||
/** Set the mesh main or face texture */
|
||||
void setTexture(int32 index, uint32 textureType);
|
||||
|
||||
/** Change the item's mesh */
|
||||
void setBonesMesh(int32 index);
|
||||
|
||||
/** Obtain the bone mesh to use to render the item */
|
||||
BonesMesh *findBonesMesh();
|
||||
|
||||
/** Obtain the texture to use to render the item */
|
||||
TextureSet *findTextureSet(uint32 textureType);
|
||||
|
||||
/** Get the item's level or global template if any */
|
||||
ItemTemplate *getItemTemplate() const;
|
||||
|
||||
/** Update the item's animation after a texture / mesh change */
|
||||
void updateAnim();
|
||||
|
||||
/** Reset animation blending */
|
||||
void resetAnimationBlending();
|
||||
|
||||
/** Randomize an idle action animation */
|
||||
Anim *getIdleActionAnim() const;
|
||||
|
||||
AnimHandler *getAnimHandler() const;
|
||||
|
||||
protected:
|
||||
void printData() override;
|
||||
|
||||
int32 _meshIndex;
|
||||
int32 _textureNormalIndex;
|
||||
int32 _textureFaceIndex;
|
||||
|
||||
ResourceReference _reference;
|
||||
ItemTemplate *_referencedItem;
|
||||
|
||||
AnimHandler *_animHandler;
|
||||
};
|
||||
|
||||
/**
|
||||
* 2D positioned image item
|
||||
*
|
||||
* Used to display background elements in 2D layers
|
||||
*/
|
||||
class ImageItem : public ItemVisual {
|
||||
public:
|
||||
ImageItem(Object *parent, byte subType, uint16 index, const Common::String &name);
|
||||
virtual ~ImageItem();
|
||||
|
||||
// Resource API
|
||||
void readData(Formats::XRCReadStream *stream) override;
|
||||
|
||||
// Item API
|
||||
Gfx::RenderEntry *getRenderEntry(const Common::Point &positionOffset) override;
|
||||
Common::Array<Common::Point> listExitPositions() override;
|
||||
|
||||
// ItemVisual API
|
||||
void setPosition2D(const Common::Point &position) override;
|
||||
|
||||
protected:
|
||||
void printData() override;
|
||||
|
||||
ResourceReference _reference;
|
||||
Common::Point _position;
|
||||
};
|
||||
|
||||
} // End of namespace Resources
|
||||
} // End of namespace Stark
|
||||
|
||||
#endif // STARK_RESOURCES_ITEM_H
|
||||
102
engines/stark/resources/knowledge.cpp
Normal file
102
engines/stark/resources/knowledge.cpp
Normal file
@@ -0,0 +1,102 @@
|
||||
/* 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 "engines/stark/resources/knowledge.h"
|
||||
|
||||
#include "engines/stark/formats/xrc.h"
|
||||
|
||||
#include "engines/stark/services/stateprovider.h"
|
||||
|
||||
namespace Stark {
|
||||
namespace Resources {
|
||||
|
||||
Knowledge::~Knowledge() {
|
||||
}
|
||||
|
||||
Knowledge::Knowledge(Object *parent, byte subType, uint16 index, const Common::String &name) :
|
||||
Object(parent, subType, index, name),
|
||||
_booleanValue(false),
|
||||
_integerValue(0) {
|
||||
_type = TYPE;
|
||||
}
|
||||
|
||||
void Knowledge::setBooleanValue(bool value) {
|
||||
_booleanValue = value;
|
||||
}
|
||||
|
||||
bool Knowledge::getBooleanValue() {
|
||||
return _booleanValue;
|
||||
}
|
||||
|
||||
void Knowledge::setIntegerValue(int32 value) {
|
||||
_integerValue = value;
|
||||
}
|
||||
|
||||
int32 Knowledge::getIntegerValue() {
|
||||
return _integerValue;
|
||||
}
|
||||
|
||||
void Knowledge::saveLoad(ResourceSerializer *serializer) {
|
||||
serializer->syncAsSint32LE(_integerValue);
|
||||
serializer->syncAsSint32LE(_booleanValue);
|
||||
serializer->syncAsResourceReference(_referenceValue);
|
||||
}
|
||||
|
||||
void Knowledge::readData(Formats::XRCReadStream *stream) {
|
||||
Object::readData(stream);
|
||||
|
||||
switch (_subType) {
|
||||
case kBoolean:
|
||||
case kBooleanWithChild:
|
||||
_booleanValue = stream->readBool();
|
||||
break;
|
||||
case kInteger:
|
||||
case kInteger2:
|
||||
_integerValue = stream->readSint32LE();
|
||||
break;
|
||||
case kReference:
|
||||
_referenceValue = stream->readResourceReference();
|
||||
break;
|
||||
default:
|
||||
error("Unknown knowledge subtype %d", _subType);
|
||||
}
|
||||
}
|
||||
|
||||
void Knowledge::printData() {
|
||||
switch (_subType) {
|
||||
case kBoolean:
|
||||
case kBooleanWithChild:
|
||||
debug("value: %d", _booleanValue);
|
||||
break;
|
||||
case kInteger:
|
||||
case kInteger2:
|
||||
debug("value: %d", _integerValue);
|
||||
break;
|
||||
case kReference:
|
||||
debug("value: %s", _referenceValue.describe().c_str());
|
||||
break;
|
||||
default:
|
||||
error("Unknown knowledge subtype %d", _subType);
|
||||
}
|
||||
}
|
||||
|
||||
} // End of namespace Resources
|
||||
} // End of namespace Stark
|
||||
83
engines/stark/resources/knowledge.h
Normal file
83
engines/stark/resources/knowledge.h
Normal file
@@ -0,0 +1,83 @@
|
||||
/* 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/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef STARK_RESOURCES_KNOWLEDGE_H
|
||||
#define STARK_RESOURCES_KNOWLEDGE_H
|
||||
|
||||
#include "common/str.h"
|
||||
|
||||
#include "engines/stark/resources/object.h"
|
||||
#include "engines/stark/resourcereference.h"
|
||||
|
||||
namespace Stark {
|
||||
|
||||
namespace Formats {
|
||||
class XRCReadStream;
|
||||
}
|
||||
|
||||
namespace Resources {
|
||||
|
||||
/**
|
||||
* A game logic state value holder
|
||||
*/
|
||||
class Knowledge : public Object {
|
||||
public:
|
||||
static const Type::ResourceType TYPE = Type::kKnowledge;
|
||||
|
||||
enum SubType {
|
||||
kBoolean = 0,
|
||||
kInteger = 2,
|
||||
kInteger2 = 3,
|
||||
kReference = 4,
|
||||
kBooleanWithChild = 5
|
||||
};
|
||||
|
||||
Knowledge(Object *parent, byte subType, uint16 index, const Common::String &name);
|
||||
virtual ~Knowledge();
|
||||
|
||||
// Resource API
|
||||
void readData(Formats::XRCReadStream *stream) override;
|
||||
void saveLoad(ResourceSerializer *serializer) override;
|
||||
|
||||
/** Define the value for boolean Knowledge elements */
|
||||
void setBooleanValue(bool value);
|
||||
|
||||
/** Obtain the value for boolean Knowledge elements */
|
||||
bool getBooleanValue();
|
||||
|
||||
/** Define the value for integer Knowledge elements */
|
||||
void setIntegerValue(int32 value);
|
||||
|
||||
/** Obtain the value for integer Knowledge elements */
|
||||
int32 getIntegerValue();
|
||||
|
||||
protected:
|
||||
void printData() override;
|
||||
|
||||
bool _booleanValue;
|
||||
int32 _integerValue;
|
||||
ResourceReference _referenceValue;
|
||||
};
|
||||
|
||||
} // End of namespace Resources
|
||||
} // End of namespace Stark
|
||||
|
||||
#endif // STARK_RESOURCES_KNOWLEDGE_H
|
||||
126
engines/stark/resources/knowledgeset.cpp
Normal file
126
engines/stark/resources/knowledgeset.cpp
Normal file
@@ -0,0 +1,126 @@
|
||||
/* 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 "engines/stark/resources/knowledgeset.h"
|
||||
|
||||
#include "engines/stark/formats/xrc.h"
|
||||
#include "engines/stark/resources/item.h"
|
||||
#include "engines/stark/services/stateprovider.h"
|
||||
|
||||
namespace Stark {
|
||||
namespace Resources {
|
||||
|
||||
KnowledgeSet::~KnowledgeSet() {
|
||||
}
|
||||
|
||||
KnowledgeSet::KnowledgeSet(Object *parent, byte subType, uint16 index, const Common::String &name) :
|
||||
Object(parent, subType, index, name) {
|
||||
_type = TYPE;
|
||||
}
|
||||
|
||||
void KnowledgeSet::printData() {
|
||||
}
|
||||
|
||||
Gfx::RenderEntryArray KnowledgeSet::getInventoryRenderEntries() const {
|
||||
Common::Array<Resources::Item *> inventoryItems = listChildren<Resources::Item>(Resources::Item::kItemInventory);
|
||||
|
||||
// First add the inventory items from old saves which don't have an order
|
||||
Gfx::RenderEntryArray result;
|
||||
for (uint i = 0; i < inventoryItems.size(); i++) {
|
||||
// The first 4 elements are UI elements (Eye, Mouth, Hand, ...)
|
||||
if (i < 4 || !inventoryItems[i]->isEnabled()) continue;
|
||||
|
||||
bool orderFound = false;
|
||||
for (uint j = 0; j < _inventoryItemOrder.size(); j++) {
|
||||
if (_inventoryItemOrder[j] == inventoryItems[i]->getIndex()) {
|
||||
orderFound = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!orderFound) {
|
||||
result.push_back(inventoryItems[i]->getRenderEntry(Common::Point(0, 0)));
|
||||
}
|
||||
}
|
||||
|
||||
// Then add the inventory items for which an order has been recorded
|
||||
for (uint i = 0; i < _inventoryItemOrder.size(); i++) {
|
||||
for (uint j = 0; j < inventoryItems.size(); j++) {
|
||||
if (inventoryItems[j]->isEnabled() && inventoryItems[j]->getIndex() == _inventoryItemOrder[i]) {
|
||||
result.push_back(inventoryItems[j]->getRenderEntry(Common::Point(0, 0)));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
void KnowledgeSet::addItem(InventoryItem *item) {
|
||||
_inventoryItemOrder.push_back(item->getIndex());
|
||||
}
|
||||
|
||||
void KnowledgeSet::removeItem(InventoryItem *item) {
|
||||
Common::Array<uint16>::iterator it;
|
||||
for (it = _inventoryItemOrder.begin(); it != _inventoryItemOrder.end(); it++) {
|
||||
if (*it == item->getIndex()) {
|
||||
_inventoryItemOrder.erase(it);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void KnowledgeSet::saveLoad(ResourceSerializer *serializer) {
|
||||
if (_subType == kInventory) {
|
||||
serializer->syncArraySize(_inventoryItemOrder);
|
||||
for (uint i = 0; i < _inventoryItemOrder.size(); i++) {
|
||||
serializer->syncAsUint16LE(_inventoryItemOrder[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Visual *KnowledgeSet::getInventoryItemVisual(uint16 itemIndex) {
|
||||
InventoryItem *item = findChildWithIndex<InventoryItem>(itemIndex, Item::kItemInventory);
|
||||
assert(item);
|
||||
|
||||
return item->getCursorVisual();
|
||||
}
|
||||
|
||||
int16 KnowledgeSet::getNeighborInventoryItem(int16 selectedIndex, bool forward) {
|
||||
if (selectedIndex < 0 && !_inventoryItemOrder.empty()) {
|
||||
return forward ? _inventoryItemOrder.front() : _inventoryItemOrder.back();
|
||||
}
|
||||
|
||||
for (uint i = 0; i < _inventoryItemOrder.size(); ++i) {
|
||||
if (_inventoryItemOrder[i] == selectedIndex) {
|
||||
if ((i == 0 && !forward) || (i == _inventoryItemOrder.size() - 1 && forward)) {
|
||||
return -1;
|
||||
} else {
|
||||
i += forward ? 1 : -1;
|
||||
return _inventoryItemOrder[i];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
} // End of namespace Resources
|
||||
} // End of namespace Stark
|
||||
85
engines/stark/resources/knowledgeset.h
Normal file
85
engines/stark/resources/knowledgeset.h
Normal file
@@ -0,0 +1,85 @@
|
||||
/* 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/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef STARK_RESOURCES_KNOWLEDGE_SET_H
|
||||
#define STARK_RESOURCES_KNOWLEDGE_SET_H
|
||||
|
||||
#include "common/str.h"
|
||||
|
||||
#include "engines/stark/gfx/renderentry.h"
|
||||
#include "engines/stark/resources/object.h"
|
||||
|
||||
namespace Stark {
|
||||
|
||||
namespace Formats {
|
||||
class XRCReadStream;
|
||||
}
|
||||
|
||||
namespace Resources {
|
||||
|
||||
class InventoryItem;
|
||||
|
||||
/**
|
||||
* A typed collection of Knowledge resources
|
||||
*/
|
||||
class KnowledgeSet : public Object {
|
||||
public:
|
||||
static const Type::ResourceType TYPE = Type::kKnowledgeSet;
|
||||
|
||||
enum SubType {
|
||||
kInventory = 1,
|
||||
kState = 2,
|
||||
kPersons = 3,
|
||||
kLocations = 4,
|
||||
kDiary = 5
|
||||
};
|
||||
|
||||
KnowledgeSet(Object *parent, byte subType, uint16 index, const Common::String &name);
|
||||
virtual ~KnowledgeSet();
|
||||
|
||||
// Resource API
|
||||
void saveLoad(ResourceSerializer *serializer) override;
|
||||
|
||||
/** Add an inventory item, and keep track of its acquisition order */
|
||||
void addItem(InventoryItem *item);
|
||||
|
||||
/** Remove an inventory item */
|
||||
void removeItem(InventoryItem *item);
|
||||
|
||||
/** Get the render entries for the inventory items, in the order they were obtained */
|
||||
Gfx::RenderEntryArray getInventoryRenderEntries() const;
|
||||
|
||||
/** Get a cursor style visual for an inventory item */
|
||||
Visual *getInventoryItemVisual(uint16 itemIndex);
|
||||
|
||||
/** Get the index of a neighbor inventory item of a selected item, return -1 in corner case */
|
||||
int16 getNeighborInventoryItem(int16 selectedItem, bool forward);
|
||||
|
||||
protected:
|
||||
void printData() override;
|
||||
|
||||
Common::Array<uint16> _inventoryItemOrder;
|
||||
};
|
||||
|
||||
} // End of namespace Resources
|
||||
} // End of namespace Stark
|
||||
|
||||
#endif // STARK_RESOURCES_KNOWLEDGE_SET_H
|
||||
268
engines/stark/resources/layer.cpp
Normal file
268
engines/stark/resources/layer.cpp
Normal file
@@ -0,0 +1,268 @@
|
||||
/* 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 "engines/stark/resources/layer.h"
|
||||
|
||||
#include "engines/stark/formats/xrc.h"
|
||||
|
||||
#include "engines/stark/resources/camera.h"
|
||||
#include "engines/stark/resources/item.h"
|
||||
#include "engines/stark/resources/light.h"
|
||||
|
||||
#include "engines/stark/services/services.h"
|
||||
#include "engines/stark/services/stateprovider.h"
|
||||
|
||||
#include "engines/stark/scene.h"
|
||||
|
||||
#include "common/debug.h"
|
||||
|
||||
namespace Stark {
|
||||
namespace Resources {
|
||||
|
||||
Object *Layer::construct(Object *parent, byte subType, uint16 index, const Common::String &name) {
|
||||
switch (subType) {
|
||||
case kLayer2D:
|
||||
return new Layer2D(parent, subType, index, name);
|
||||
case kLayer3D:
|
||||
return new Layer3D(parent, subType, index, name);
|
||||
default:
|
||||
error("Unknown layer subtype %d", subType);
|
||||
}
|
||||
}
|
||||
|
||||
Layer::~Layer() {
|
||||
}
|
||||
|
||||
Layer::Layer(Object *parent, byte subType, uint16 index, const Common::String &name) :
|
||||
Object(parent, subType, index, name),
|
||||
_scrollScale(1.0),
|
||||
_enabled(true) {
|
||||
_type = TYPE;
|
||||
}
|
||||
|
||||
void Layer::readData(Formats::XRCReadStream *stream) {
|
||||
_scrollScale = stream->readFloatLE();
|
||||
if (_scrollScale > 10.0 || _scrollScale < -1.0)
|
||||
_scrollScale = 0;
|
||||
}
|
||||
|
||||
void Layer::printData() {
|
||||
debug("scrollScale: %f", _scrollScale);
|
||||
debug("enabled: %d", _enabled);
|
||||
}
|
||||
|
||||
void Layer::setScrollPosition(const Common::Point &position) {
|
||||
// The location scroll position is scaled to create a parallax effect
|
||||
_scroll.x = (_scrollScale + 1.0) * (float) position.x;
|
||||
_scroll.y = (_scrollScale + 1.0) * (float) position.y;
|
||||
}
|
||||
|
||||
Common::Point Layer::getScroll() const {
|
||||
return _scroll;
|
||||
}
|
||||
|
||||
void Layer::setScroll(const Common::Point &scroll) {
|
||||
_scroll = scroll;
|
||||
}
|
||||
|
||||
bool Layer::isEnabled() const {
|
||||
return _enabled;
|
||||
}
|
||||
|
||||
void Layer::enable(bool enabled) {
|
||||
_enabled = enabled;
|
||||
}
|
||||
|
||||
Gfx::LightEntryArray Layer::listLightEntries() {
|
||||
Common::Array<Light *> lights = listChildren<Light>();
|
||||
|
||||
Gfx::LightEntryArray lightEntries;
|
||||
for (uint i = 0; i < lights.size(); i++) {
|
||||
lightEntries.push_back(lights[i]->getLightEntry());
|
||||
}
|
||||
|
||||
return lightEntries;
|
||||
}
|
||||
|
||||
void Layer::saveLoad(ResourceSerializer *serializer) {
|
||||
serializer->syncAsSint32LE(_enabled);
|
||||
}
|
||||
|
||||
void Layer::saveLoadCurrent(ResourceSerializer *serializer) {
|
||||
serializer->syncAsSint32LE(_scroll.x);
|
||||
serializer->syncAsSint32LE(_scroll.y);
|
||||
}
|
||||
|
||||
Layer2D::~Layer2D() {
|
||||
}
|
||||
|
||||
Layer2D::Layer2D(Object *parent, byte subType, uint16 index, const Common::String &name) :
|
||||
Layer(parent, subType, index, name) {
|
||||
}
|
||||
|
||||
void Layer2D::readData(Formats::XRCReadStream *stream) {
|
||||
Layer::readData(stream);
|
||||
|
||||
uint32 itemsCount = stream->readUint32LE();
|
||||
for (uint i = 0; i < itemsCount; i++) {
|
||||
uint32 itemIndex = stream->readUint32LE();
|
||||
_itemIndices.push_back(itemIndex);
|
||||
}
|
||||
|
||||
_enabled = stream->readBool();
|
||||
}
|
||||
|
||||
void Layer2D::onEnterLocation() {
|
||||
Layer::onEnterLocation();
|
||||
|
||||
Common::Array<Item *> items = listChildren<Item>();
|
||||
|
||||
// Build the item list in the appropriate order
|
||||
_items.clear();
|
||||
for (uint i = 0; i < _itemIndices.size(); i++) {
|
||||
for (uint j = 0; j < items.size(); j++) {
|
||||
if (items[j]->getIndex() == _itemIndices[i]) {
|
||||
_items.push_back(items[j]);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Layer2D::onExitLocation() {
|
||||
Layer::onExitLocation();
|
||||
|
||||
_items.clear();
|
||||
}
|
||||
|
||||
Gfx::RenderEntryArray Layer2D::listRenderEntries() {
|
||||
Gfx::RenderEntryArray renderEntries;
|
||||
for (uint i = 0; i < _items.size(); i++) {
|
||||
Item *item = _items[i];
|
||||
|
||||
Gfx::RenderEntry *renderEntry = item->getRenderEntry(_scroll);
|
||||
|
||||
if (!renderEntry) {
|
||||
// warning("No render entry for item '%s'", item->getName().c_str());
|
||||
continue;
|
||||
}
|
||||
|
||||
renderEntries.push_back(renderEntry);
|
||||
}
|
||||
|
||||
return renderEntries;
|
||||
}
|
||||
|
||||
void Layer2D::printData() {
|
||||
Layer::printData();
|
||||
}
|
||||
|
||||
Layer3D::~Layer3D() {
|
||||
}
|
||||
|
||||
Layer3D::Layer3D(Object *parent, byte subType, uint16 index, const Common::String &name) :
|
||||
Layer(parent, subType, index, name),
|
||||
_shouldRenderShadows(true),
|
||||
_maxShadowLength(75),
|
||||
_nearClipPlane(100.0),
|
||||
_farClipPlane(64000.0),
|
||||
_backgroundItem(nullptr) {
|
||||
}
|
||||
|
||||
void Layer3D::readData(Formats::XRCReadStream *stream) {
|
||||
Layer::readData(stream);
|
||||
|
||||
_shouldRenderShadows = stream->readBool();
|
||||
_nearClipPlane = stream->readFloatLE();
|
||||
_farClipPlane = stream->readFloatLE();
|
||||
if (stream->isDataLeft()) {
|
||||
_maxShadowLength = stream->readUint32LE();
|
||||
}
|
||||
}
|
||||
|
||||
void Layer3D::onAllLoaded() {
|
||||
Layer::onAllLoaded();
|
||||
|
||||
_items = listChildren<Item>();
|
||||
_backgroundItem = findChildWithSubtype<Item>(Item::kItemBackground);
|
||||
|
||||
Camera *camera = findChild<Camera>();
|
||||
camera->setClipPlanes(_nearClipPlane, _farClipPlane);
|
||||
}
|
||||
|
||||
void Layer3D::onEnterLocation() {
|
||||
Layer::onEnterLocation();
|
||||
|
||||
StarkScene->setupShadows(_shouldRenderShadows, _maxShadowLength / 1000.0f);
|
||||
}
|
||||
|
||||
Gfx::RenderEntry *Layer3D::getBackgroundRenderEntry() {
|
||||
if (!_backgroundItem) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return _backgroundItem->getRenderEntry(_scroll);
|
||||
}
|
||||
|
||||
Gfx::RenderEntryArray Layer3D::listRenderEntries() {
|
||||
// Sort the items by distance to the camera
|
||||
Gfx::RenderEntryArray itemEntries;
|
||||
for (uint i = 0; i < _items.size(); i++) {
|
||||
Item *item = _items[i];
|
||||
|
||||
if (item->getSubType() != Item::kItemBackground) {
|
||||
Gfx::RenderEntry *renderEntry = item->getRenderEntry(_scroll);
|
||||
|
||||
if (!renderEntry) {
|
||||
// warning("No render entry for item '%s'", item->getName().c_str());
|
||||
continue;
|
||||
}
|
||||
|
||||
itemEntries.push_back(renderEntry);
|
||||
}
|
||||
}
|
||||
Common::sort(itemEntries.begin(), itemEntries.end(), Gfx::RenderEntry::compare);
|
||||
|
||||
Gfx::RenderEntryArray renderEntries;
|
||||
|
||||
// Add the background render entry to the list first
|
||||
Gfx::RenderEntry *backgroundRenderEntry = getBackgroundRenderEntry();
|
||||
if (backgroundRenderEntry) {
|
||||
renderEntries.push_back(backgroundRenderEntry);
|
||||
}
|
||||
|
||||
// Add the other items
|
||||
renderEntries.push_back(itemEntries);
|
||||
|
||||
return renderEntries;
|
||||
}
|
||||
|
||||
void Layer3D::printData() {
|
||||
Layer::printData();
|
||||
|
||||
debug("shouldRenderShadows: %d", _shouldRenderShadows);
|
||||
debug("maxShadowLength: %d", _maxShadowLength);
|
||||
debug("nearClipPlane: %f", _nearClipPlane);
|
||||
debug("farClipPlane: %f", _farClipPlane);
|
||||
}
|
||||
|
||||
} // End of namespace Resources
|
||||
} // End of namespace Stark
|
||||
156
engines/stark/resources/layer.h
Normal file
156
engines/stark/resources/layer.h
Normal file
@@ -0,0 +1,156 @@
|
||||
/* 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/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef STARK_RESOURCES_LAYER_H
|
||||
#define STARK_RESOURCES_LAYER_H
|
||||
|
||||
#include "common/array.h"
|
||||
#include "common/str.h"
|
||||
|
||||
#include "engines/stark/gfx/renderentry.h"
|
||||
#include "engines/stark/resources/object.h"
|
||||
|
||||
namespace Stark {
|
||||
|
||||
namespace Formats {
|
||||
class XRCReadStream;
|
||||
}
|
||||
|
||||
namespace Resources {
|
||||
|
||||
class Item;
|
||||
|
||||
/**
|
||||
* A location layer
|
||||
*
|
||||
* Layers own the scene items
|
||||
*/
|
||||
class Layer : public Object {
|
||||
public:
|
||||
static const Type::ResourceType TYPE = Type::kLayer;
|
||||
|
||||
enum SubType {
|
||||
kLayer2D = 1,
|
||||
kLayer3D = 2
|
||||
};
|
||||
|
||||
/** Layer factory */
|
||||
static Object *construct(Object *parent, byte subType, uint16 index, const Common::String &name);
|
||||
|
||||
Layer(Object *parent, byte subType, uint16 index, const Common::String &name);
|
||||
virtual ~Layer();
|
||||
|
||||
// Resource API
|
||||
void readData(Formats::XRCReadStream *stream) override;
|
||||
void saveLoad(ResourceSerializer *serializer) override;
|
||||
void saveLoadCurrent(ResourceSerializer *serializer) override;
|
||||
|
||||
/** Obtain the render entries for all items, including the background */
|
||||
virtual Gfx::RenderEntryArray listRenderEntries() = 0;
|
||||
|
||||
/** Obtain a list of render entries for all the lights in the layer */
|
||||
Gfx::LightEntryArray listLightEntries();
|
||||
|
||||
/** Scroll the layer to the specified position */
|
||||
void setScrollPosition(const Common::Point &position);
|
||||
|
||||
/** Get the current scroll for this layer */
|
||||
Common::Point getScroll() const;
|
||||
|
||||
/** Set the current scroll for this layer */
|
||||
void setScroll(const Common::Point &scroll);
|
||||
|
||||
/** Enable the layer */
|
||||
void enable(bool enabled);
|
||||
|
||||
/** Is the layer enabled? Disabled layers are not drawn. */
|
||||
bool isEnabled() const;
|
||||
|
||||
protected:
|
||||
void printData() override;
|
||||
|
||||
Common::Point _scroll;
|
||||
float _scrollScale; // Used for the parallax effect
|
||||
bool _enabled;
|
||||
};
|
||||
|
||||
/**
|
||||
* A 2D layer
|
||||
*
|
||||
* 2D layers contain 2D positioned items
|
||||
*/
|
||||
class Layer2D : public Layer {
|
||||
public:
|
||||
Layer2D(Object *parent, byte subType, uint16 index, const Common::String &name);
|
||||
virtual ~Layer2D();
|
||||
|
||||
// Resource API
|
||||
void readData(Formats::XRCReadStream *stream) override;
|
||||
void onEnterLocation() override;
|
||||
void onExitLocation() override;
|
||||
|
||||
// Layer API
|
||||
Gfx::RenderEntryArray listRenderEntries() override;
|
||||
|
||||
protected:
|
||||
void printData() override;
|
||||
|
||||
Common::Array<uint32> _itemIndices;
|
||||
Common::Array<Item *> _items;
|
||||
};
|
||||
|
||||
/**
|
||||
* A 3D layer
|
||||
*
|
||||
* 3D layers contain 3D positioned items, a camera and a floorfield
|
||||
*/
|
||||
class Layer3D : public Layer {
|
||||
public:
|
||||
Layer3D(Object *parent, byte subType, uint16 index, const Common::String &name);
|
||||
virtual ~Layer3D();
|
||||
|
||||
// Resource API
|
||||
void readData(Formats::XRCReadStream *stream) override;
|
||||
void onAllLoaded() override;
|
||||
void onEnterLocation() override;
|
||||
|
||||
// Layer API
|
||||
Gfx::RenderEntryArray listRenderEntries() override;
|
||||
|
||||
/** Obtain the render entry for the background item */
|
||||
Gfx::RenderEntry *getBackgroundRenderEntry();
|
||||
|
||||
protected:
|
||||
void printData() override;
|
||||
|
||||
bool _shouldRenderShadows;
|
||||
uint32 _maxShadowLength;
|
||||
float _nearClipPlane;
|
||||
float _farClipPlane;
|
||||
|
||||
Item *_backgroundItem;
|
||||
Common::Array<Item *> _items;
|
||||
};
|
||||
|
||||
} // End of namespace Resources
|
||||
} // End of namespace Stark
|
||||
|
||||
#endif // STARK_RESOURCES_LAYER_H
|
||||
41
engines/stark/resources/level.cpp
Normal file
41
engines/stark/resources/level.cpp
Normal file
@@ -0,0 +1,41 @@
|
||||
/* 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 "engines/stark/resources/level.h"
|
||||
|
||||
#include "engines/stark/formats/xrc.h"
|
||||
|
||||
namespace Stark {
|
||||
namespace Resources {
|
||||
|
||||
Level::~Level() {
|
||||
}
|
||||
|
||||
Level::Level(Object *parent, byte subType, uint16 index, const Common::String &name) :
|
||||
Object(parent, subType, index, name) {
|
||||
_type = TYPE;
|
||||
}
|
||||
|
||||
void Level::printData() {
|
||||
}
|
||||
|
||||
} // End of namespace Resources
|
||||
} // End of namespace Stark
|
||||
59
engines/stark/resources/level.h
Normal file
59
engines/stark/resources/level.h
Normal file
@@ -0,0 +1,59 @@
|
||||
/* 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/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef STARK_RESOURCES_LEVEL_H
|
||||
#define STARK_RESOURCES_LEVEL_H
|
||||
|
||||
#include "common/str.h"
|
||||
|
||||
#include "engines/stark/resources/object.h"
|
||||
|
||||
namespace Stark {
|
||||
|
||||
namespace Resources {
|
||||
|
||||
/**
|
||||
* Levels are holder resources for the locations
|
||||
*
|
||||
* Levels are used to share resources between related locations.
|
||||
* Resources in a level are kept when switching to another location of the same level.
|
||||
*/
|
||||
class Level : public Object {
|
||||
public:
|
||||
static const Type::ResourceType TYPE = Type::kLevel;
|
||||
|
||||
enum SubType {
|
||||
kGlobal = 1,
|
||||
kGame = 2,
|
||||
kStatic = 3
|
||||
};
|
||||
|
||||
Level(Object *parent, byte subType, uint16 index, const Common::String &name);
|
||||
virtual ~Level();
|
||||
|
||||
protected:
|
||||
void printData() override;
|
||||
};
|
||||
|
||||
} // End of namespace Resources
|
||||
} // End of namespace Stark
|
||||
|
||||
#endif // STARK_RESOURCES_LEVEL_H
|
||||
110
engines/stark/resources/light.cpp
Normal file
110
engines/stark/resources/light.cpp
Normal file
@@ -0,0 +1,110 @@
|
||||
/* 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 "engines/stark/resources/light.h"
|
||||
|
||||
#include "engines/stark/formats/xrc.h"
|
||||
#include "engines/stark/gfx/renderentry.h"
|
||||
#include "engines/stark/services/stateprovider.h"
|
||||
|
||||
namespace Stark {
|
||||
namespace Resources {
|
||||
|
||||
Light::~Light() {
|
||||
delete _lightEntry;
|
||||
}
|
||||
|
||||
Light::Light(Object *parent, byte subType, uint16 index, const Common::String &name) :
|
||||
Object(parent, subType, index, name),
|
||||
_outerConeAngle(0),
|
||||
_innerConeAngle(0),
|
||||
_falloffNear(100.0),
|
||||
_falloffFar(500.0),
|
||||
_lightEntry(nullptr),
|
||||
_multiplier(1.0) {
|
||||
_type = TYPE;
|
||||
}
|
||||
|
||||
void Light::readData(Formats::XRCReadStream *stream) {
|
||||
_color = stream->readVector3();
|
||||
_position = stream->readVector3();
|
||||
_direction = stream->readVector3();
|
||||
_outerConeAngle = stream->readFloatLE();
|
||||
_innerConeAngle = stream->readFloatLE();
|
||||
|
||||
if (stream->isDataLeft()) {
|
||||
_falloffNear = stream->readFloatLE();
|
||||
_falloffFar = stream->readFloatLE();
|
||||
}
|
||||
}
|
||||
|
||||
void Light::onPostRead() {
|
||||
Object::onPostRead();
|
||||
|
||||
_lightEntry = new Gfx::LightEntry();
|
||||
_lightEntry->type = (Gfx::LightEntry::Type) _subType;
|
||||
_lightEntry->direction = _direction;
|
||||
_lightEntry->innerConeAngle = _innerConeAngle / 2.0;
|
||||
_lightEntry->outerConeAngle = _outerConeAngle / 2.0;
|
||||
_lightEntry->falloffNear = _falloffNear;
|
||||
_lightEntry->falloffFar = _falloffFar;
|
||||
|
||||
// Negative lights add darkness
|
||||
_multiplier = _name.hasPrefix("x_neg") ? -1.0 : 1.0;
|
||||
}
|
||||
|
||||
void Light::saveLoad(ResourceSerializer *serializer) {
|
||||
Object::saveLoad(serializer);
|
||||
|
||||
serializer->syncAsVector3d(_color);
|
||||
serializer->syncAsVector3d(_position);
|
||||
}
|
||||
|
||||
void Light::setColor(int32 red, int32 green, int32 blue) {
|
||||
_color.x() = (float) red / 255.0f;
|
||||
_color.y() = (float) green / 255.0f;
|
||||
_color.z() = (float) blue / 255.0f;
|
||||
}
|
||||
|
||||
void Light::setPosition(const Math::Vector3d &position) {
|
||||
_position = position;
|
||||
}
|
||||
|
||||
Gfx::LightEntry *Light::getLightEntry() {
|
||||
_lightEntry->color = _multiplier * _color;
|
||||
_lightEntry->position = _position;
|
||||
|
||||
return _lightEntry;
|
||||
}
|
||||
|
||||
void Light::printData() {
|
||||
Common::StreamDebug debug = streamDbg();
|
||||
debug << "color: " << _color << "\n";
|
||||
debug << "position: " << _position << "\n";
|
||||
debug << "direction: " << _direction << "\n";
|
||||
debug << "innerConeAngle: " << _innerConeAngle << "\n";
|
||||
debug << "outerConeAngle: " << _outerConeAngle << "\n";
|
||||
debug << "falloffNear: " << _falloffNear << "\n";
|
||||
debug << "falloffFar: " << _falloffFar << "\n";
|
||||
}
|
||||
|
||||
} // End of namespace Resources
|
||||
} // End of namespace Stark
|
||||
85
engines/stark/resources/light.h
Normal file
85
engines/stark/resources/light.h
Normal file
@@ -0,0 +1,85 @@
|
||||
/* 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/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef STARK_RESOURCES_LIGHT_H
|
||||
#define STARK_RESOURCES_LIGHT_H
|
||||
|
||||
#include "common/str.h"
|
||||
|
||||
#include "math/vector3d.h"
|
||||
|
||||
#include "engines/stark/resources/object.h"
|
||||
|
||||
namespace Stark {
|
||||
|
||||
namespace Formats {
|
||||
class XRCReadStream;
|
||||
}
|
||||
|
||||
namespace Gfx {
|
||||
struct LightEntry;
|
||||
}
|
||||
|
||||
namespace Resources {
|
||||
|
||||
/**
|
||||
* A light source
|
||||
*/
|
||||
class Light : public Object {
|
||||
public:
|
||||
static const Type::ResourceType TYPE = Type::kLight;
|
||||
|
||||
Light(Object *parent, byte subType, uint16 index, const Common::String &name);
|
||||
~Light() override;
|
||||
|
||||
// Resource API
|
||||
void readData(Formats::XRCReadStream *stream) override;
|
||||
void onPostRead() override;
|
||||
void saveLoad(ResourceSerializer *serializer) override;
|
||||
|
||||
/** Get the rendering object used to represent this light */
|
||||
Gfx::LightEntry *getLightEntry();
|
||||
|
||||
/** Change this light's diffuse color */
|
||||
void setColor(int32 red, int32 green, int32 blue);
|
||||
|
||||
/** Change this light's position, in world coordinates */
|
||||
void setPosition(const Math::Vector3d &position);
|
||||
|
||||
protected:
|
||||
void printData() override;
|
||||
|
||||
Math::Vector3d _color;
|
||||
Math::Vector3d _position;
|
||||
Math::Vector3d _direction;
|
||||
float _innerConeAngle;
|
||||
float _outerConeAngle;
|
||||
float _falloffNear;
|
||||
float _falloffFar;
|
||||
float _multiplier;
|
||||
|
||||
Gfx::LightEntry *_lightEntry;
|
||||
};
|
||||
|
||||
} // End of namespace Resources
|
||||
} // End of namespace Stark
|
||||
|
||||
#endif // STARK_RESOURCES_LIGHT_H
|
||||
173
engines/stark/resources/lipsync.cpp
Normal file
173
engines/stark/resources/lipsync.cpp
Normal file
@@ -0,0 +1,173 @@
|
||||
/* 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 "engines/stark/resources/lipsync.h"
|
||||
|
||||
#include "engines/stark/formats/xrc.h"
|
||||
|
||||
#include "engines/stark/resources/anim.h"
|
||||
#include "engines/stark/resources/item.h"
|
||||
#include "engines/stark/resources/textureset.h"
|
||||
|
||||
#include "engines/stark/services/global.h"
|
||||
#include "engines/stark/services/services.h"
|
||||
#include "engines/stark/services/stateprovider.h"
|
||||
|
||||
#include "engines/stark/visual/visual.h"
|
||||
#include "engines/stark/visual/actor.h"
|
||||
|
||||
namespace Stark {
|
||||
namespace Resources {
|
||||
|
||||
LipSync::~LipSync() {
|
||||
}
|
||||
|
||||
LipSync::LipSync(Object *parent, byte subType, uint16 index, const Common::String &name) :
|
||||
Object(parent, subType, index, name),
|
||||
_item(nullptr),
|
||||
_sceneItem(nullptr),
|
||||
_faceTexture(nullptr),
|
||||
_visual(nullptr),
|
||||
_enabled(false),
|
||||
_checkForNewVisual(false),
|
||||
_positionMs(0) {
|
||||
_type = TYPE;
|
||||
}
|
||||
|
||||
void LipSync::readData(Formats::XRCReadStream *stream) {
|
||||
uint32 shapeCount = stream->readUint32LE();
|
||||
for (uint i = 0; i < shapeCount; i++) {
|
||||
uint32 shape = stream->readUint32LE();
|
||||
_shapes.push_back(shape);
|
||||
|
||||
// The original does not use that data
|
||||
stream->skip(4);
|
||||
}
|
||||
|
||||
// The original does not use that data
|
||||
uint32 unkCount = stream->readUint32LE();
|
||||
stream->skip(unkCount);
|
||||
}
|
||||
|
||||
void LipSync::printData() {
|
||||
Object::printData();
|
||||
|
||||
Common::String phrase;
|
||||
for (uint i = 0; i < _shapes.size(); i++) {
|
||||
phrase += _shapes[i];
|
||||
}
|
||||
|
||||
debug("shapes: %s", phrase.c_str());
|
||||
}
|
||||
|
||||
void LipSync::setItem(ItemVisual *item, bool playTalkAnim) {
|
||||
_item = item;
|
||||
_checkForNewVisual = !playTalkAnim;
|
||||
|
||||
if (_item->getSubType() != Item::kItemModel) {
|
||||
return;
|
||||
}
|
||||
|
||||
_sceneItem = Object::cast<ModelItem>(item);
|
||||
_faceTexture = _sceneItem->findTextureSet(TextureSet::kTextureFace);
|
||||
|
||||
if (!_faceTexture) {
|
||||
return;
|
||||
}
|
||||
|
||||
Anim *anim = _item->getAnim();
|
||||
_visual = nullptr;
|
||||
|
||||
if (!anim || anim->getSubType() != Anim::kAnimSkeleton) {
|
||||
return;
|
||||
}
|
||||
|
||||
AnimSkeleton *animSkeleton = Object::cast<AnimSkeleton>(anim);
|
||||
_visual = animSkeleton->getVisual()->get<VisualActor>();
|
||||
|
||||
if (!_visual) {
|
||||
return;
|
||||
}
|
||||
|
||||
_visual->setTextureFacial(_faceTexture->getTexture());
|
||||
_enabled = true;
|
||||
_positionMs = 0;
|
||||
}
|
||||
|
||||
void LipSync::reset() {
|
||||
_enabled = false;
|
||||
_visual = nullptr;
|
||||
_positionMs = 0;
|
||||
_item = nullptr;
|
||||
_sceneItem = nullptr;
|
||||
_checkForNewVisual = false;
|
||||
_faceTexture = nullptr;
|
||||
}
|
||||
|
||||
void LipSync::onGameLoop() {
|
||||
Object::onGameLoop();
|
||||
|
||||
if (!_enabled) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (_checkForNewVisual && _sceneItem && _faceTexture) {
|
||||
Anim *anim = _sceneItem->getAnim();
|
||||
if (anim && anim->getSubType() == Anim::kAnimSkeleton) {
|
||||
AnimSkeleton *animSkeleton = Object::cast<AnimSkeleton>(anim);
|
||||
_visual = animSkeleton->getVisual()->get<VisualActor>();
|
||||
|
||||
if (_visual) {
|
||||
_visual->setTextureFacial(_faceTexture->getTexture());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (_visual) {
|
||||
uint32 shapeIndex = (_positionMs + 100) / 100;
|
||||
if (shapeIndex < _shapes.size()) {
|
||||
_visual->setNewFace(_shapes[shapeIndex]);
|
||||
} else {
|
||||
reset();
|
||||
}
|
||||
|
||||
_positionMs += StarkGlobal->getMillisecondsPerGameloop();
|
||||
}
|
||||
|
||||
if (_enabled && !_visual) {
|
||||
reset();
|
||||
}
|
||||
}
|
||||
|
||||
void LipSync::saveLoadCurrent(ResourceSerializer *serializer) {
|
||||
serializer->syncAsUint32LE(_enabled);
|
||||
if (_enabled) {
|
||||
serializer->syncAsResourceReference(&_item);
|
||||
serializer->syncAsUint32LE(_positionMs);
|
||||
|
||||
if (serializer->isLoading()) {
|
||||
setItem(_item, false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} // End of namespace Resources
|
||||
} // End of namespace Stark
|
||||
81
engines/stark/resources/lipsync.h
Normal file
81
engines/stark/resources/lipsync.h
Normal file
@@ -0,0 +1,81 @@
|
||||
/* 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/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef STARK_RESOURCES_LIPSYNC_H
|
||||
#define STARK_RESOURCES_LIPSYNC_H
|
||||
|
||||
#include "common/str.h"
|
||||
|
||||
#include "engines/stark/resources/object.h"
|
||||
|
||||
namespace Stark {
|
||||
|
||||
class VisualActor;
|
||||
|
||||
namespace Formats {
|
||||
class XRCReadStream;
|
||||
}
|
||||
|
||||
namespace Resources {
|
||||
|
||||
class ItemVisual;
|
||||
class ModelItem;
|
||||
class TextureSet;
|
||||
|
||||
/**
|
||||
* Speech lipsync data
|
||||
*/
|
||||
class LipSync : public Object {
|
||||
public:
|
||||
static const Type::ResourceType TYPE = Type::kLipSync;
|
||||
|
||||
LipSync(Object *parent, byte subType, uint16 index, const Common::String &name);
|
||||
virtual ~LipSync();
|
||||
|
||||
// Resource API
|
||||
void readData(Formats::XRCReadStream *stream) override;
|
||||
void onGameLoop() override;
|
||||
void saveLoadCurrent(ResourceSerializer *serializer) override;
|
||||
|
||||
/** Set the item for which the facial texture should be updated according to the lipsync data */
|
||||
void setItem(ItemVisual *item, bool playTalkAnim);
|
||||
|
||||
/** Removes all item related data from the LipSync object */
|
||||
void reset();
|
||||
|
||||
protected:
|
||||
void printData() override;
|
||||
|
||||
Common::Array<char> _shapes;
|
||||
ItemVisual *_item;
|
||||
ModelItem *_sceneItem;
|
||||
TextureSet *_faceTexture;
|
||||
VisualActor *_visual;
|
||||
|
||||
bool _checkForNewVisual;
|
||||
bool _enabled;
|
||||
uint32 _positionMs;
|
||||
};
|
||||
|
||||
} // End of namespace Resources
|
||||
} // End of namespace Stark
|
||||
|
||||
#endif // STARK_RESOURCES_LIPSYNC_H
|
||||
587
engines/stark/resources/location.cpp
Normal file
587
engines/stark/resources/location.cpp
Normal file
@@ -0,0 +1,587 @@
|
||||
/* 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 "engines/stark/resources/location.h"
|
||||
|
||||
#include "engines/stark/formats/xrc.h"
|
||||
#include "engines/stark/gfx/driver.h"
|
||||
|
||||
#include "engines/stark/movement/movement.h"
|
||||
|
||||
#include "engines/stark/resources/anim.h"
|
||||
#include "engines/stark/resources/container.h"
|
||||
#include "engines/stark/resources/item.h"
|
||||
#include "engines/stark/resources/layer.h"
|
||||
#include "engines/stark/resources/level.h"
|
||||
#include "engines/stark/resources/scroll.h"
|
||||
#include "engines/stark/resources/sound.h"
|
||||
|
||||
#include "engines/stark/scene.h"
|
||||
#include "engines/stark/services/global.h"
|
||||
#include "engines/stark/services/services.h"
|
||||
#include "engines/stark/services/stateprovider.h"
|
||||
#include "engines/stark/services/userinterface.h"
|
||||
|
||||
#include "common/random.h"
|
||||
|
||||
namespace Stark {
|
||||
namespace Resources {
|
||||
|
||||
Location::~Location() {
|
||||
}
|
||||
|
||||
Location::Location(Object *parent, byte subType, uint16 index, const Common::String &name) :
|
||||
Object(parent, subType, index, name),
|
||||
_canScroll(false),
|
||||
_currentLayer(nullptr),
|
||||
_hasActiveScroll(false),
|
||||
_scrollFollowCharacter(false),
|
||||
_rumbleDurationRemaining(0),
|
||||
_fadeOut(false),
|
||||
_fadePosition(0),
|
||||
_fadeDuration(0),
|
||||
_swayPeriodMs(0),
|
||||
_swayAmplitude(0),
|
||||
_swayOffset(0),
|
||||
_swayPosition(0),
|
||||
_idleActionWaitMs(5500),
|
||||
_floatPeriodMs(0),
|
||||
_floatAmplitude(0),
|
||||
_floatPosition(0) {
|
||||
_type = TYPE;
|
||||
}
|
||||
|
||||
void Location::onAllLoaded() {
|
||||
Object::onAllLoaded();
|
||||
|
||||
_layers = listChildren<Layer>();
|
||||
|
||||
Layer *threeDLayer = findChildWithSubtype<Layer>(Layer::kLayer3D);
|
||||
if (threeDLayer) {
|
||||
_modelItems = threeDLayer->listChildren<ModelItem>(Item::kItemModel);
|
||||
}
|
||||
}
|
||||
|
||||
void Location::onEnterLocation() {
|
||||
Object::onEnterLocation();
|
||||
|
||||
StarkScene->setFadeLevel(1.0f);
|
||||
}
|
||||
|
||||
void Location::onGameLoop() {
|
||||
Object::onGameLoop();
|
||||
|
||||
ModelItem *april = StarkGlobal->getCurrent()->getInteractive();
|
||||
if (april) {
|
||||
_idleActionWaitMs -= StarkGlobal->getMillisecondsPerGameloop();
|
||||
if (_idleActionWaitMs <= 0) {
|
||||
if (!april->getActionAnim()
|
||||
&& april->getAnimActivity() == Anim::kActorActivityIdle
|
||||
&& StarkUserInterface->isInteractive()) {
|
||||
|
||||
Anim *idleAction = april->getIdleActionAnim();
|
||||
if (idleAction) {
|
||||
april->playActionAnim(idleAction);
|
||||
}
|
||||
}
|
||||
|
||||
_idleActionWaitMs = 11000; // 330 frames at 30 fps
|
||||
}
|
||||
}
|
||||
|
||||
if (_floatPeriodMs > 0) {
|
||||
_floatPosition += StarkGlobal->getMillisecondsPerGameloop() / (float) _floatPeriodMs;
|
||||
if (_floatPosition > 1.0) {
|
||||
_floatPosition -= 1.0;
|
||||
}
|
||||
|
||||
float floatOffset = sinf(_floatPosition * 2.0f * (float)M_PI) * _floatAmplitude;
|
||||
StarkScene->setFloatOffset(floatOffset);
|
||||
}
|
||||
|
||||
if (_swayPeriodMs > 0) {
|
||||
_swayPosition += StarkGlobal->getMillisecondsPerGameloop() / (float) _swayPeriodMs;
|
||||
if (_swayPosition > 1.0) {
|
||||
_swayPosition -= 1.0;
|
||||
}
|
||||
|
||||
float sway = sinf((_swayOffset + _swayPosition) * 2.0f * (float)M_PI) * _swayAmplitude;
|
||||
StarkScene->setSwayAngle(_swayAngle * sway);
|
||||
}
|
||||
|
||||
if (_fadeDuration > 0) {
|
||||
float fadeSpeed = StarkGlobal->getMillisecondsPerGameloop() / (float) _fadeDuration;
|
||||
|
||||
_fadePosition += fadeSpeed * (_fadeOut ? -1.0 : 1.0);
|
||||
|
||||
if (_fadeOut && _fadePosition < 0.0) {
|
||||
_fadePosition = 0.0;
|
||||
_fadeDuration = 0;
|
||||
} else if (!_fadeOut && _fadePosition > 1.0) {
|
||||
_fadePosition = 1.0;
|
||||
_fadeDuration = 0;
|
||||
}
|
||||
|
||||
StarkScene->setFadeLevel(_fadePosition);
|
||||
}
|
||||
|
||||
if (_hasActiveScroll) {
|
||||
// Script triggered scrolling has precedence over following the character
|
||||
_scrollFollowCharacter = false;
|
||||
}
|
||||
|
||||
if (_scrollFollowCharacter) {
|
||||
assert(april);
|
||||
|
||||
Movement *movement = april->getMovement();
|
||||
|
||||
bool scrollComplete = scrollToCharacter(april);
|
||||
if (scrollComplete && (!movement || movement->hasEnded())) {
|
||||
_scrollFollowCharacter = false;
|
||||
}
|
||||
}
|
||||
|
||||
if (_rumbleDurationRemaining > 0) {
|
||||
_rumbleDurationRemaining -= StarkGlobal->getMillisecondsPerGameloop();
|
||||
}
|
||||
}
|
||||
|
||||
bool Location::has3DLayer() {
|
||||
return findChildWithSubtype<Layer>(Layer::kLayer3D) != nullptr;
|
||||
}
|
||||
|
||||
Gfx::RenderEntryArray Location::listRenderEntries() {
|
||||
Gfx::RenderEntryArray renderEntries;
|
||||
|
||||
for (uint i = 0; i < _layers.size(); i++) {
|
||||
Layer *layer = _layers[i];
|
||||
if (layer->isEnabled()) {
|
||||
Common::Point baseScroll;
|
||||
|
||||
if (_rumbleDurationRemaining > 0) {
|
||||
baseScroll = layer->getScroll();
|
||||
Common::Point offsetScroll = baseScroll;
|
||||
offsetScroll.x = StarkRandomSource->getRandomBit() - 1;
|
||||
offsetScroll.y = StarkRandomSource->getRandomBit() - 1;
|
||||
|
||||
layer->setScroll(offsetScroll);
|
||||
}
|
||||
|
||||
renderEntries.push_back(layer->listRenderEntries());
|
||||
|
||||
if (_rumbleDurationRemaining > 0) {
|
||||
layer->setScroll(baseScroll);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return renderEntries;
|
||||
}
|
||||
|
||||
Gfx::LightEntryArray Location::listLightEntries() {
|
||||
Gfx::LightEntry *ambient = nullptr;
|
||||
Gfx::LightEntryArray others;
|
||||
|
||||
// Build a list of lights from all the layers ...
|
||||
for (uint i = 0; i < _layers.size(); i++) {
|
||||
Layer *layer = _layers[i];
|
||||
if (layer->isEnabled()) {
|
||||
Gfx::LightEntryArray layerLights = layer->listLightEntries();
|
||||
|
||||
for (uint j = 0; j < layerLights.size(); j++) {
|
||||
Gfx::LightEntry *light = layerLights[j];
|
||||
|
||||
// ... but store the ambient light in a separate variable ...
|
||||
if (light->type == Gfx::LightEntry::kAmbient) {
|
||||
ambient = light;
|
||||
} else {
|
||||
Math::Matrix4 view = StarkScene->getViewMatrix();
|
||||
light->worldPosition.x() = light->position.x();
|
||||
light->worldPosition.y() = light->position.y();
|
||||
light->worldPosition.z() = light->position.z();
|
||||
light->worldPosition.w() = 1.0f;
|
||||
light->eyePosition = view * light->worldPosition;
|
||||
light->eyeDirection = view.getRotation() * light->direction;
|
||||
light->eyeDirection.normalize();
|
||||
others.push_back(light);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ... so that it is first in the final light list
|
||||
Gfx::LightEntryArray lightEntries;
|
||||
lightEntries.push_back(ambient);
|
||||
lightEntries.push_back(others);
|
||||
return lightEntries;
|
||||
}
|
||||
|
||||
void Location::initScroll(const Common::Point &maxScroll) {
|
||||
_maxScroll = maxScroll;
|
||||
_canScroll = _maxScroll.x != 0 || _maxScroll.y != 0;
|
||||
}
|
||||
|
||||
Common::Point Location::getScrollPosition() const {
|
||||
return _scroll;
|
||||
}
|
||||
|
||||
void Location::setScrollPosition(const Common::Point &position) {
|
||||
_scroll.x = CLIP<int16>(position.x, 0, _maxScroll.x);
|
||||
_scroll.y = CLIP<int16>(position.y, 0, _maxScroll.y);
|
||||
|
||||
|
||||
// Setup the layers scroll position
|
||||
for (uint i = 0; i < _layers.size(); i++) {
|
||||
_layers[i]->setScrollPosition(_scroll);
|
||||
}
|
||||
|
||||
// Reconfigure the camera
|
||||
Common::Rect viewport(Gfx::Driver::kGameViewportWidth, Gfx::Driver::kGameViewportHeight);
|
||||
viewport.translate(_scroll.x, _scroll.y);
|
||||
StarkScene->scrollCamera(viewport);
|
||||
}
|
||||
|
||||
Common::Point Location::getCharacterScrollPosition(ModelItem *item) {
|
||||
Common::Point position2D = StarkScene->convertPosition3DToGameScreenOriginal(item->getPosition3D());
|
||||
|
||||
Common::Point newScroll;
|
||||
if (_maxScroll.x > 0) {
|
||||
newScroll.x = _scroll.x + position2D.x - Gfx::Driver::kGameViewportWidth / 2;
|
||||
newScroll.y = _scroll.y;
|
||||
} else {
|
||||
Gfx::RenderEntry *renderEntry = item->getRenderEntry(_scroll);
|
||||
Common::Rect boundingRect = renderEntry->getBoundingRect();
|
||||
if (!boundingRect.isEmpty()) {
|
||||
position2D.y = (boundingRect.top + boundingRect.bottom) / 2;
|
||||
}
|
||||
|
||||
newScroll.x = _scroll.x;
|
||||
newScroll.y = _scroll.y + position2D.y - Gfx::Driver::kGameViewportHeight / 2;
|
||||
}
|
||||
|
||||
return newScroll;
|
||||
}
|
||||
|
||||
bool Location::scrollToCharacter(ModelItem *item) {
|
||||
if (!_canScroll) {
|
||||
return true;
|
||||
}
|
||||
|
||||
Common::Point newScroll = getCharacterScrollPosition(item);
|
||||
if (_maxScroll.x > 0) {
|
||||
if (newScroll.x < _scroll.x - 15 || newScroll.x > _scroll.x + 15) {
|
||||
newScroll.x = CLIP<int16>(newScroll.x, 0, _maxScroll.x);
|
||||
return scrollToSmooth(newScroll, true);
|
||||
}
|
||||
} else {
|
||||
if (newScroll.y < _scroll.y - 15 || newScroll.y > _scroll.y + 15) {
|
||||
newScroll.y = CLIP<int16>(newScroll.y, 0, _maxScroll.y);
|
||||
return scrollToSmooth(newScroll, true);
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void Location::scrollToCharacterImmediate() {
|
||||
if (!_canScroll) {
|
||||
return;
|
||||
}
|
||||
|
||||
ModelItem *april = StarkGlobal->getCurrent()->getInteractive();
|
||||
setScrollPosition(getCharacterScrollPosition(april));
|
||||
}
|
||||
|
||||
uint Location::getScrollStepFollow() {
|
||||
ModelItem *april = StarkGlobal->getCurrent()->getInteractive();
|
||||
Common::Point position2D = StarkScene->convertPosition3DToGameScreenOriginal(april->getPosition3D());
|
||||
|
||||
// TODO: Complete
|
||||
|
||||
uint scrollStep;
|
||||
if (_maxScroll.x > 0) {
|
||||
scrollStep = abs((Gfx::Driver::kGameViewportWidth / 2 - position2D.x) / 16);
|
||||
} else {
|
||||
scrollStep = abs((Gfx::Driver::kGameViewportHeight / 2 - position2D.y) / 16);
|
||||
}
|
||||
|
||||
return CLIP<uint>(scrollStep, 1, 4);
|
||||
}
|
||||
|
||||
uint Location::getScrollStep() {
|
||||
uint scrollStep;
|
||||
if (_maxScroll.x > 0) {
|
||||
if (_scroll.x <= _maxScroll.x / 2) {
|
||||
scrollStep = _scroll.x / 16;
|
||||
} else {
|
||||
scrollStep = (_maxScroll.x - _scroll.x) / 16;
|
||||
}
|
||||
} else {
|
||||
if (_scroll.y <= _maxScroll.y / 2) {
|
||||
scrollStep = _scroll.y / 16;
|
||||
} else {
|
||||
scrollStep = (_maxScroll.y - _scroll.y) / 16;
|
||||
}
|
||||
}
|
||||
|
||||
return CLIP<uint>(scrollStep, 1, 4);
|
||||
}
|
||||
|
||||
bool Location::scrollToSmooth(const Common::Point &position, bool followCharacter) {
|
||||
uint scrollStep;
|
||||
if (followCharacter) {
|
||||
scrollStep = getScrollStepFollow();
|
||||
} else {
|
||||
scrollStep = getScrollStep();
|
||||
}
|
||||
|
||||
Common::Point delta;
|
||||
if (position.x < _scroll.x) {
|
||||
delta.x = -(int)scrollStep;
|
||||
delta.x = CLIP<int16>(delta.x, position.x - _scroll.x, 0);
|
||||
} else if (position.x > _scroll.x) {
|
||||
delta.x = scrollStep;
|
||||
delta.x = CLIP<int16>(delta.x, 0, position.x - _scroll.x);
|
||||
}
|
||||
|
||||
if (position.y < _scroll.y) {
|
||||
delta.y = -(int)scrollStep;
|
||||
delta.y = CLIP<int16>(delta.y, position.y - _scroll.y, 0);
|
||||
} else if (position.y > _scroll.y) {
|
||||
delta.y = scrollStep;
|
||||
delta.y = CLIP<int16>(delta.y, 0, position.y - _scroll.y);
|
||||
}
|
||||
|
||||
if (delta.x == 0 && delta.y == 0) {
|
||||
// We already are at the target position, scrolling has completed
|
||||
return true;
|
||||
}
|
||||
|
||||
setScrollPosition(_scroll + delta);
|
||||
return false;
|
||||
}
|
||||
|
||||
bool Location::scrollToCoordinateSmooth(uint32 coordinate) {
|
||||
Common::Point newScroll = getScrollPointFromCoordinate(coordinate);
|
||||
return scrollToSmooth(newScroll, false);
|
||||
}
|
||||
|
||||
void Location::scrollToCoordinateImmediate(uint32 coordinate) {
|
||||
Common::Point newScroll = getScrollPointFromCoordinate(coordinate);
|
||||
return setScrollPosition(newScroll);
|
||||
}
|
||||
|
||||
Common::Point Location::getScrollPointFromCoordinate(uint32 coordinate) const {
|
||||
Common::Point newScroll = _scroll;
|
||||
|
||||
if (_maxScroll.x > 0) {
|
||||
newScroll.x = coordinate;
|
||||
} else {
|
||||
newScroll.y = coordinate;
|
||||
}
|
||||
|
||||
return newScroll;
|
||||
}
|
||||
|
||||
void Location::stopFollowingCharacter() {
|
||||
_scrollFollowCharacter = false;
|
||||
}
|
||||
|
||||
void Location::startFollowingCharacter() {
|
||||
_scrollFollowCharacter = true;
|
||||
}
|
||||
|
||||
void Location::setHasActiveScroll() {
|
||||
_hasActiveScroll = true;
|
||||
}
|
||||
|
||||
void Location::stopAllScrolls() {
|
||||
Common::Array<Scroll *> scrolls = listChildrenRecursive<Scroll>();
|
||||
for (uint i = 0; i < scrolls.size(); i++) {
|
||||
scrolls[i]->stop();
|
||||
}
|
||||
|
||||
_hasActiveScroll = false;
|
||||
}
|
||||
|
||||
void Location::goToLayer(Layer *layer) {
|
||||
if (_currentLayer) {
|
||||
_currentLayer->enable(false);
|
||||
}
|
||||
|
||||
layer->enable(true);
|
||||
_currentLayer = layer;
|
||||
}
|
||||
|
||||
ItemVisual *Location::getCharacterItem(int32 character) const {
|
||||
return _characterItemMap.getValOrDefault(character, nullptr);
|
||||
}
|
||||
|
||||
void Location::registerCharacterItem(int32 character, ItemVisual *item) {
|
||||
if (character >= 0) {
|
||||
_characterItemMap[character] = item;
|
||||
}
|
||||
}
|
||||
|
||||
const Common::Array<ModelItem *> &Location::listModelItems() const {
|
||||
return _modelItems;
|
||||
}
|
||||
|
||||
void Location::printData() {
|
||||
}
|
||||
|
||||
void Location::resetAnimationBlending() {
|
||||
Common::Array<ModelItem *> items = listChildren<ModelItem>(Item::kItemModel);
|
||||
for (uint i = 0; i < items.size(); i++) {
|
||||
items[i]->resetAnimationBlending();
|
||||
}
|
||||
}
|
||||
|
||||
Sound *Location::findStockSound(uint32 stockSoundType) const {
|
||||
Sound *sound = findStockSound(this, stockSoundType);
|
||||
|
||||
if (!sound) {
|
||||
Level *currentLevel = StarkGlobal->getCurrent()->getLevel();
|
||||
sound = findStockSound(currentLevel, stockSoundType);
|
||||
}
|
||||
|
||||
if (!sound) {
|
||||
Level *globalLevel = StarkGlobal->getLevel();
|
||||
sound = findStockSound(globalLevel, stockSoundType);
|
||||
}
|
||||
|
||||
return sound;
|
||||
}
|
||||
|
||||
Sound *Location::findStockSound(const Object *parent, uint32 stockSoundType) const {
|
||||
Container *stockSoundContainer = parent->findChildWithSubtype<Container>(Container::kStockSounds);
|
||||
if (stockSoundContainer) {
|
||||
Common::Array<Sound *> stockSounds = stockSoundContainer->listChildren<Sound>(Sound::kSoundStock);
|
||||
|
||||
for (uint i = 0; i < stockSounds.size(); i++) {
|
||||
Sound *sound = stockSounds[i];
|
||||
if (sound->getStockSoundType() == stockSoundType) {
|
||||
return sound;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void Location::startRumble(int32 rumbleDurationRemaining) {
|
||||
_rumbleDurationRemaining = rumbleDurationRemaining;
|
||||
}
|
||||
|
||||
void Location::fadeInInit(int32 fadeDuration) {
|
||||
_fadeOut = false;
|
||||
_fadePosition = 0.0;
|
||||
_fadeDuration = fadeDuration;
|
||||
}
|
||||
|
||||
void Location::fadeOutInit(int32 fadeDuration) {
|
||||
_fadeOut = true;
|
||||
_fadePosition = 1.0;
|
||||
_fadeDuration = fadeDuration;
|
||||
}
|
||||
|
||||
void Location::swayScene(int32 periodMs, const Math::Angle &angle, float amplitude, float offset) {
|
||||
if (periodMs < 33) {
|
||||
periodMs = 1000;
|
||||
}
|
||||
|
||||
_swayPeriodMs = periodMs;
|
||||
_swayAngle = angle;
|
||||
_swayAmplitude = amplitude;
|
||||
_swayOffset = offset;
|
||||
_swayPosition = offset;
|
||||
}
|
||||
|
||||
void Location::floatScene(int32 periodMs, float amplitude, float offset) {
|
||||
if (periodMs < 33) {
|
||||
periodMs = 1000;
|
||||
}
|
||||
|
||||
_floatPeriodMs = periodMs;
|
||||
_floatAmplitude = amplitude;
|
||||
_floatPosition = offset;
|
||||
}
|
||||
|
||||
void Location::saveLoadCurrent(ResourceSerializer *serializer) {
|
||||
serializer->syncAsSint32LE(_scroll.x);
|
||||
serializer->syncAsSint32LE(_scroll.y);
|
||||
|
||||
if (serializer->isLoading()) {
|
||||
setScrollPosition(_scroll);
|
||||
}
|
||||
|
||||
serializer->syncAsResourceReference(&_currentLayer);
|
||||
|
||||
serializer->syncAsSint32LE(_floatPeriodMs);
|
||||
serializer->syncAsFloat(_floatAmplitude);
|
||||
serializer->syncAsFloat(_floatPosition);
|
||||
|
||||
serializer->syncAsSint32LE(_swayPeriodMs);
|
||||
serializer->syncAsFloat(_swayAmplitude);
|
||||
serializer->syncAsFloat(_swayOffset);
|
||||
serializer->syncAsFloat(_swayPosition);
|
||||
|
||||
float swayAngle = _swayAngle.getDegrees();
|
||||
serializer->syncAsFloat(swayAngle);
|
||||
if (serializer->isLoading()) {
|
||||
_swayAngle = swayAngle;
|
||||
}
|
||||
}
|
||||
|
||||
Layer *Location::getLayerByName(const Common::String &name) {
|
||||
for (uint i = 0; i < _layers.size(); ++i) {
|
||||
if (_layers[i]->getName().equalsIgnoreCase(name)) {
|
||||
return _layers[i];
|
||||
}
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
Gfx::RenderEntry *Location::getRenderEntryByName(const Common::String &name) {
|
||||
Gfx::RenderEntryArray renderEntries = listRenderEntries();
|
||||
for (uint i = 0; i < renderEntries.size(); ++i) {
|
||||
if (renderEntries[i]->getName().equalsIgnoreCase(name)) {
|
||||
return renderEntries[i];
|
||||
}
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
Common::Array<Common::Point> Location::listExitPositions() {
|
||||
Common::Array<Item *> items = listChildrenRecursive<Item>();
|
||||
Common::Array<Common::Point> positions;
|
||||
|
||||
Common::Array<Item *>::iterator element = items.begin();
|
||||
while (element != items.end()) {
|
||||
positions.push_back((*element)->listExitPositions());
|
||||
++element;
|
||||
}
|
||||
|
||||
return positions;
|
||||
}
|
||||
|
||||
} // End of namespace Resources
|
||||
} // End of namespace Stark
|
||||
201
engines/stark/resources/location.h
Normal file
201
engines/stark/resources/location.h
Normal file
@@ -0,0 +1,201 @@
|
||||
/* 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/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef STARK_RESOURCES_LOCATION_H
|
||||
#define STARK_RESOURCES_LOCATION_H
|
||||
|
||||
#include "common/hashmap.h"
|
||||
#include "common/rect.h"
|
||||
#include "common/str.h"
|
||||
|
||||
#include "engines/stark/gfx/renderentry.h"
|
||||
#include "engines/stark/resources/object.h"
|
||||
|
||||
namespace Stark {
|
||||
|
||||
namespace Formats {
|
||||
class XRCReadStream;
|
||||
}
|
||||
|
||||
namespace Resources {
|
||||
|
||||
class ItemVisual;
|
||||
class Layer;
|
||||
class ModelItem;
|
||||
class Sound;
|
||||
|
||||
/**
|
||||
* A location is a scene of the game
|
||||
*
|
||||
* Locations contain layers. The game engine retrieves the list of renderable
|
||||
* items from the current location.
|
||||
*/
|
||||
class Location : public Object {
|
||||
public:
|
||||
static const Type::ResourceType TYPE = Type::kLocation;
|
||||
|
||||
Location(Object *parent, byte subType, uint16 index, const Common::String &name);
|
||||
virtual ~Location();
|
||||
|
||||
// Resource API
|
||||
void onAllLoaded() override;
|
||||
void onEnterLocation() override;
|
||||
void onGameLoop() override;
|
||||
void saveLoadCurrent(ResourceSerializer *serializer) override;
|
||||
|
||||
/** Does the location have a 3D layer ? */
|
||||
bool has3DLayer();
|
||||
|
||||
/** Obtain a list of render entries for all the items in the location */
|
||||
Gfx::RenderEntryArray listRenderEntries();
|
||||
|
||||
/** Obtain a list of render entries for all the lights in the location */
|
||||
Gfx::LightEntryArray listLightEntries();
|
||||
|
||||
/** Initialize scrolling from Camera data */
|
||||
void initScroll(const Common::Point &maxScroll);
|
||||
|
||||
/** Obtain the current scroll position */
|
||||
Common::Point getScrollPosition() const;
|
||||
|
||||
/** Scroll the location to the specified position if possible */
|
||||
void setScrollPosition(const Common::Point &position);
|
||||
|
||||
/** Smoothly scroll to a position in 2D world coordinates */
|
||||
bool scrollToCoordinateSmooth(uint32 coordinate);
|
||||
|
||||
/** Immediatly scroll the character location */
|
||||
void scrollToCharacterImmediate();
|
||||
|
||||
/** Replace the currently active layer */
|
||||
void goToLayer(Layer *layer);
|
||||
|
||||
/**
|
||||
* Indicate on script driven scroll is active.
|
||||
*
|
||||
* This means that the location should not follow the character
|
||||
*/
|
||||
void setHasActiveScroll();
|
||||
|
||||
/**
|
||||
* Stop all script driven scrolls
|
||||
*/
|
||||
void stopAllScrolls();
|
||||
|
||||
/** Tell the location to scroll to follow the character */
|
||||
void startFollowingCharacter();
|
||||
|
||||
/** Tell the location not to scroll to follow the character */
|
||||
void stopFollowingCharacter();
|
||||
|
||||
void scrollToCoordinateImmediate(uint32 coordinate);
|
||||
|
||||
/** Get an item from its character index */
|
||||
ItemVisual *getCharacterItem(int32 character) const;
|
||||
|
||||
/** Register an item as a character to the location */
|
||||
void registerCharacterItem(int32 character, ItemVisual *item);
|
||||
|
||||
/** Get the list of items with a 3d model present in the location */
|
||||
const Common::Array<ModelItem *> &listModelItems() const;
|
||||
|
||||
/** Reset animation blending for all the items in the location */
|
||||
void resetAnimationBlending();
|
||||
|
||||
/** Find a stock sound by its type in the location, the level, or the global level */
|
||||
Sound *findStockSound(uint32 stockSoundType) const;
|
||||
|
||||
/** Set remaining frames to rumble on this lcation */
|
||||
void startRumble(int32 rumbleDurationRemaining);
|
||||
|
||||
/** Setup fading for this location */
|
||||
void fadeInInit(int32 fadeDuration);
|
||||
void fadeOutInit(int32 fadeDuration);
|
||||
|
||||
/** Setup a swaying movement for the 3d items in this location */
|
||||
void swayScene(int32 periodMs, const Math::Angle &angle, float amplitude, float offset);
|
||||
|
||||
/** Setup a up / down floating movement for the 3d items in this location */
|
||||
void floatScene(int32 periodMs, float amplitude, float offset);
|
||||
|
||||
/** Get the layer with a given name, return null when not found */
|
||||
Layer *getLayerByName(const Common::String &name);
|
||||
|
||||
/** Get a render entry with a given name, return null when not found */
|
||||
Gfx::RenderEntry *getRenderEntryByName(const Common::String &name);
|
||||
|
||||
/** Obtain the list of all the inner layers */
|
||||
Common::Array<Layer *> listLayers() { return _layers; }
|
||||
|
||||
/** List all the exit positions */
|
||||
Common::Array<Common::Point> listExitPositions();
|
||||
|
||||
protected:
|
||||
void printData() override;
|
||||
|
||||
private:
|
||||
bool scrollToSmooth(const Common::Point &position, bool followCharacter);
|
||||
bool scrollToCharacter(ModelItem *item);
|
||||
Common::Point getCharacterScrollPosition(ModelItem *item);
|
||||
uint getScrollStepFollow();
|
||||
Common::Point getScrollPointFromCoordinate(uint32 coordinate) const;
|
||||
|
||||
Sound *findStockSound(const Object *parent, uint32 stockSoundType) const;
|
||||
|
||||
Common::Array<Layer *> _layers;
|
||||
Layer *_currentLayer;
|
||||
|
||||
bool _canScroll;
|
||||
bool _hasActiveScroll;
|
||||
bool _scrollFollowCharacter;
|
||||
Common::Point _scroll;
|
||||
Common::Point _maxScroll;
|
||||
|
||||
uint getScrollStep();
|
||||
|
||||
typedef Common::HashMap<int32, ItemVisual *> CharacterMap;
|
||||
CharacterMap _characterItemMap;
|
||||
|
||||
Common::Array<ModelItem *> _modelItems;
|
||||
|
||||
int32 _rumbleDurationRemaining;
|
||||
|
||||
bool _fadeOut;
|
||||
int32 _fadeDuration;
|
||||
float _fadePosition;
|
||||
|
||||
int32 _swayPeriodMs;
|
||||
Math::Angle _swayAngle;
|
||||
float _swayAmplitude;
|
||||
float _swayOffset;
|
||||
float _swayPosition;
|
||||
|
||||
int32 _idleActionWaitMs;
|
||||
|
||||
int32 _floatPeriodMs;
|
||||
float _floatAmplitude;
|
||||
float _floatPosition;
|
||||
};
|
||||
|
||||
} // End of namespace Resources
|
||||
} // End of namespace Stark
|
||||
|
||||
#endif // STARK_RESOURCES_LOCATION_H
|
||||
311
engines/stark/resources/object.cpp
Normal file
311
engines/stark/resources/object.cpp
Normal file
@@ -0,0 +1,311 @@
|
||||
/* 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 "engines/stark/resources/object.h"
|
||||
|
||||
#include "common/debug-channels.h"
|
||||
#include "common/streamdebug.h"
|
||||
#include "common/util.h"
|
||||
|
||||
#include "engines/stark/debug.h"
|
||||
#include "engines/stark/formats/xrc.h"
|
||||
|
||||
namespace Stark {
|
||||
namespace Resources {
|
||||
|
||||
Type::Type(ResourceType type) {
|
||||
_type = type;
|
||||
}
|
||||
|
||||
Type::Type() {
|
||||
_type = kInvalid;
|
||||
}
|
||||
|
||||
const char *Type::getName() const {
|
||||
static const struct {
|
||||
Type::ResourceType type;
|
||||
const char *name;
|
||||
} typeNames[] = {
|
||||
{ Type::kInvalid, "Invalid" },
|
||||
{ Type::kRoot, "Root" },
|
||||
{ Type::kLevel, "Level" },
|
||||
{ Type::kLocation, "Location" },
|
||||
{ Type::kLayer, "Layer" },
|
||||
{ Type::kCamera, "Camera" },
|
||||
{ Type::kFloor, "Floor" },
|
||||
{ Type::kFloorFace, "FloorFace" },
|
||||
{ Type::kItem, "Item" },
|
||||
{ Type::kScript, "Script" },
|
||||
{ Type::kAnimHierarchy, "AnimHierarchy" },
|
||||
{ Type::kAnim, "Anim" },
|
||||
{ Type::kDirection, "Direction" },
|
||||
{ Type::kImage, "Image" },
|
||||
{ Type::kAnimScript, "AnimScript" },
|
||||
{ Type::kAnimScriptItem, "AnimScriptItem" },
|
||||
{ Type::kSoundItem, "SoundItem" },
|
||||
{ Type::kPath, "Path" },
|
||||
{ Type::kFloorField, "FloorField" },
|
||||
{ Type::kBookmark, "Bookmark" },
|
||||
{ Type::kKnowledgeSet, "KnowledgeSet" },
|
||||
{ Type::kKnowledge, "Knowledge" },
|
||||
{ Type::kCommand, "Command" },
|
||||
{ Type::kPATTable, "PATTable" },
|
||||
{ Type::kContainer, "Container" },
|
||||
{ Type::kDialog, "Dialog" },
|
||||
{ Type::kSpeech, "Speech" },
|
||||
{ Type::kLight, "Light" },
|
||||
{ Type::kCursor, "Cursor" },
|
||||
{ Type::kBonesMesh, "BonesMesh" },
|
||||
{ Type::kScroll, "Scroll" },
|
||||
{ Type::kFMV, "FMV" },
|
||||
{ Type::kLipSync, "LipSynch" },
|
||||
{ Type::kAnimSoundTrigger, "AnimSoundTrigger" },
|
||||
{ Type::kString, "String" },
|
||||
{ Type::kTextureSet, "TextureSet" }
|
||||
};
|
||||
|
||||
for (uint i = 0; i < ARRAYSIZE(typeNames); i++) {
|
||||
if (typeNames[i].type == _type) {
|
||||
return typeNames[i].name;
|
||||
}
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
Type::ResourceType Type::get() const {
|
||||
return _type;
|
||||
}
|
||||
|
||||
Object::Object(Object *parent, byte subType, uint16 index, const Common::String &name) :
|
||||
_parent(parent),
|
||||
_type(Type::kInvalid),
|
||||
_subType(subType),
|
||||
_index(index),
|
||||
_name(name) {
|
||||
}
|
||||
|
||||
Object::~Object() {
|
||||
// Delete the children resources
|
||||
Common::Array<Object *>::iterator i = _children.begin();
|
||||
while (i != _children.end()) {
|
||||
delete *i;
|
||||
i++;
|
||||
}
|
||||
}
|
||||
|
||||
void Object::readData(Formats::XRCReadStream *stream) {
|
||||
}
|
||||
|
||||
void Object::printData() {
|
||||
}
|
||||
|
||||
void Object::saveLoad(ResourceSerializer *serializer) {
|
||||
}
|
||||
|
||||
void Object::saveLoadCurrent(ResourceSerializer *serializer) {
|
||||
}
|
||||
|
||||
void Object::onPostRead() {
|
||||
}
|
||||
|
||||
void Object::onAllLoaded() {
|
||||
Common::Array<Object *>::iterator i = _children.begin();
|
||||
while (i != _children.end()) {
|
||||
(*i)->onAllLoaded();
|
||||
i++;
|
||||
}
|
||||
}
|
||||
|
||||
void Object::onEnterLocation() {
|
||||
Common::Array<Object *>::iterator i = _children.begin();
|
||||
while (i != _children.end()) {
|
||||
(*i)->onEnterLocation();
|
||||
i++;
|
||||
}
|
||||
}
|
||||
|
||||
void Object::onGameLoop() {
|
||||
Common::Array<Object *>::iterator i = _children.begin();
|
||||
while (i != _children.end()) {
|
||||
(*i)->onGameLoop();
|
||||
i++;
|
||||
}
|
||||
}
|
||||
|
||||
void Object::onEnginePause(bool pause) {
|
||||
Common::Array<Object *>::iterator i = _children.begin();
|
||||
while (i != _children.end()) {
|
||||
(*i)->onEnginePause(pause);
|
||||
i++;
|
||||
}
|
||||
}
|
||||
|
||||
void Object::onExitLocation() {
|
||||
Common::Array<Object *>::iterator i = _children.begin();
|
||||
while (i != _children.end()) {
|
||||
(*i)->onExitLocation();
|
||||
i++;
|
||||
}
|
||||
}
|
||||
|
||||
void Object::onPreDestroy() {
|
||||
Common::Array<Object *>::iterator i = _children.begin();
|
||||
while (i != _children.end()) {
|
||||
(*i)->onPreDestroy();
|
||||
i++;
|
||||
}
|
||||
}
|
||||
|
||||
void Object::print(uint depth) {
|
||||
printDescription(depth);
|
||||
printData();
|
||||
|
||||
// Recursively print the children resources
|
||||
for (uint i = 0; i < _children.size(); i++) {
|
||||
_children[i]->print(depth + 1);
|
||||
}
|
||||
}
|
||||
|
||||
void Object::printDescription(uint depth) const {
|
||||
// Build the resource type string
|
||||
Common::String type(_type.getName());
|
||||
if (type.empty()) {
|
||||
type = Common::String::format("%d", _type.get());
|
||||
}
|
||||
|
||||
// Build the resource description
|
||||
Common::String description = Common::String::format("%s - %s - (sub=%d, index=%d)", type.c_str(), _name.c_str(), _subType, _index);
|
||||
printWithDepth(depth, description);
|
||||
}
|
||||
|
||||
void Object::printWithDepth(uint depth, const Common::String &string) const {
|
||||
Common::String prefix;
|
||||
for (uint i = 0; i < depth; i++) {
|
||||
prefix += "-";
|
||||
}
|
||||
|
||||
debug("%s %s", prefix.c_str(), string.c_str());
|
||||
}
|
||||
|
||||
Object *Object::findChildWithIndex(Type type, uint16 index, int subType) const {
|
||||
for (uint i = 0; i < _children.size(); i++) {
|
||||
if (_children[i]->getType() == type
|
||||
&& (_children[i]->getSubType() == subType || subType == -1)
|
||||
&& _children[i]->getIndex() == index) {
|
||||
// Found a matching child
|
||||
return _children[i];
|
||||
}
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
Object *Object::findChildWithOrder(Type type, uint16 order, int subType) const {
|
||||
uint16 count = 0;
|
||||
for (uint i = 0; i < _children.size(); i++) {
|
||||
if (_children[i]->getType() == type
|
||||
&& (_children[i]->getSubType() == subType || subType == -1)) {
|
||||
if (count == order) {
|
||||
// Found a matching child
|
||||
return _children[i];
|
||||
}
|
||||
count++;
|
||||
}
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
Object *Object::findChildWithName(Type type, const Common::String &name, int subType) const {
|
||||
for (uint i = 0; i < _children.size(); ++i) {
|
||||
if (_children[i]->getType() == type
|
||||
&& (_children[i]->getSubType() == subType || subType == -1)
|
||||
&& _children[i]->getName() == name) {
|
||||
// Found a matching child
|
||||
return _children[i];
|
||||
}
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
template<>
|
||||
Object *Object::cast<Object>(Object *resource) {
|
||||
// No type check when asking for the abstract resource
|
||||
return resource;
|
||||
}
|
||||
|
||||
template<>
|
||||
Common::Array<Object *> Object::listChildren<Object>(int subType) const {
|
||||
assert(subType == -1);
|
||||
|
||||
Common::Array<Object *> list;
|
||||
|
||||
for (uint i = 0; i < _children.size(); i++) {
|
||||
list.push_back(_children[i]);
|
||||
}
|
||||
|
||||
return list;
|
||||
}
|
||||
|
||||
template<>
|
||||
Object *Object::findParent() {
|
||||
return _parent;
|
||||
}
|
||||
|
||||
void Object::addChild(Object *child) {
|
||||
_children.push_back(child);
|
||||
}
|
||||
|
||||
UnimplementedResource::UnimplementedResource(Object *parent, Type type, byte subType, uint16 index, const Common::String &name) :
|
||||
Object(parent, subType, index, name),
|
||||
_dataLength(0),
|
||||
_data(nullptr) {
|
||||
_type = type;
|
||||
}
|
||||
|
||||
UnimplementedResource::~UnimplementedResource() {
|
||||
// Delete this resource's data
|
||||
delete[] _data;
|
||||
}
|
||||
|
||||
void UnimplementedResource::readData(Formats::XRCReadStream *stream) {
|
||||
// Read the data
|
||||
_dataLength = stream->size();
|
||||
_data = new byte[_dataLength];
|
||||
uint32 bytesRead = stream->read(_data, _dataLength);
|
||||
|
||||
// Verify the whole array could be read
|
||||
if (bytesRead != _dataLength) {
|
||||
error("Stark::UnimplementedResource: data length mismatch (%d != %d)", bytesRead, _dataLength);
|
||||
}
|
||||
}
|
||||
|
||||
void UnimplementedResource::printData() {
|
||||
// Print the resource data
|
||||
if (_data) {
|
||||
Common::hexdump(_data, _dataLength);
|
||||
}
|
||||
}
|
||||
|
||||
} // End of namespace Resources
|
||||
} // End of namespace Stark
|
||||
407
engines/stark/resources/object.h
Normal file
407
engines/stark/resources/object.h
Normal file
@@ -0,0 +1,407 @@
|
||||
/* 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/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef STARK_RESOURCES_RESOURCE_H
|
||||
#define STARK_RESOURCES_RESOURCE_H
|
||||
|
||||
#include "common/array.h"
|
||||
#include "common/str.h"
|
||||
|
||||
namespace Stark {
|
||||
|
||||
namespace Formats {
|
||||
class XRCReadStream;
|
||||
}
|
||||
class ResourceSerializer;
|
||||
|
||||
namespace Resources {
|
||||
|
||||
class Type {
|
||||
public:
|
||||
enum ResourceType {
|
||||
kInvalid = 0,
|
||||
kRoot = 1,
|
||||
kLevel = 2,
|
||||
kLocation = 3,
|
||||
kLayer = 4,
|
||||
kCamera = 5,
|
||||
kFloor = 6,
|
||||
kFloorFace = 7,
|
||||
kItem = 8,
|
||||
kScript = 9,
|
||||
kAnimHierarchy = 10,
|
||||
kAnim = 11,
|
||||
kDirection = 12,
|
||||
kImage = 13,
|
||||
kAnimScript = 14,
|
||||
kAnimScriptItem = 15,
|
||||
kSoundItem = 16,
|
||||
kPath = 17,
|
||||
kFloorField = 18,
|
||||
kBookmark = 19,
|
||||
kKnowledgeSet = 20,
|
||||
kKnowledge = 21,
|
||||
kCommand = 22,
|
||||
kPATTable = 23,
|
||||
kContainer = 26,
|
||||
kDialog = 27,
|
||||
kSpeech = 29,
|
||||
kLight = 30,
|
||||
kCursor = 31, // Not sure about this one
|
||||
kBonesMesh = 32,
|
||||
kScroll = 33,
|
||||
kFMV = 34,
|
||||
kLipSync = 35,
|
||||
kAnimSoundTrigger = 36,
|
||||
kString = 37,
|
||||
kTextureSet = 38
|
||||
};
|
||||
|
||||
Type();
|
||||
Type(ResourceType type);
|
||||
|
||||
ResourceType get() const;
|
||||
const char *getName() const;
|
||||
|
||||
bool operator==(const Type &other) const {
|
||||
return other._type == _type;
|
||||
}
|
||||
|
||||
bool operator!=(const Type &other) const {
|
||||
return other._type != _type;
|
||||
}
|
||||
|
||||
bool operator==(const Type::ResourceType other) const {
|
||||
return other == _type;
|
||||
}
|
||||
|
||||
bool operator!=(const Type::ResourceType other) const {
|
||||
return other != _type;
|
||||
}
|
||||
|
||||
private:
|
||||
ResourceType _type;
|
||||
};
|
||||
|
||||
/**
|
||||
* Game resource base object
|
||||
*
|
||||
* The in-game objects are represented using subclasses of this class.
|
||||
*
|
||||
* The game world is made of a tree of resources, with each level further down
|
||||
* the tree adding further details. An instance of this class is a node in that
|
||||
* tree.
|
||||
*
|
||||
* The first few tree levels are as follow:
|
||||
* - Root
|
||||
* - Level
|
||||
* - Location
|
||||
* - Layer
|
||||
*
|
||||
* The actual world tree is cut off in several sub-trees. There is one sub-tree
|
||||
* per xarc archive. For resource management reasons the sub-trees are not merged
|
||||
* in memory, the sub-trees are loaded and unloaded as needed, according to the
|
||||
* current level / location.
|
||||
*
|
||||
* The xarc archives contain each an xrc file, which is a serialized version
|
||||
* of the initial state of a resource sub-tree. The readData method is called for
|
||||
* each resource by the archive loader when a resource tree is loaded to set up
|
||||
* its initial state.
|
||||
*
|
||||
* As the game plays, modifications are made to the resources to reflect
|
||||
* the game's state. When the resource sub-trees are loaded or unloaded their
|
||||
* state is restored or persisted by the state provider. The saveLoad method
|
||||
* is called to perform the serialization / deserialization of a resource.
|
||||
* The saveLoadCurrent method is additionally called when loading or saving
|
||||
* a sub-tree corresponding to the current level / location. This allows to
|
||||
* persist additional data needed when restoring an active location.
|
||||
*
|
||||
* The OnEnterLocation and OnExitLocation methods are called by the resource
|
||||
* provider when entering or leaving a level / location.
|
||||
*
|
||||
* The OnGameLoop method is called during the game loop.
|
||||
*
|
||||
*/
|
||||
class Object {
|
||||
public:
|
||||
virtual ~Object();
|
||||
|
||||
/** Get the resource type */
|
||||
Type getType() const { return _type; }
|
||||
|
||||
/** Get the resource sub type */
|
||||
byte getSubType() const { return _subType; }
|
||||
|
||||
/** Get the resource index */
|
||||
uint16 getIndex() const { return _index; }
|
||||
|
||||
/** Get the resource index as a string */
|
||||
Common::String getIndexAsString() const { return Common::String::format("%02x", _index); }
|
||||
|
||||
/** Get the name of the resource */
|
||||
Common::String getName() const { return _name; }
|
||||
|
||||
/**
|
||||
* Deserialize the resource static data and initial state.
|
||||
*/
|
||||
virtual void readData(Formats::XRCReadStream *stream);
|
||||
|
||||
/**
|
||||
* Persist / restore the resource state
|
||||
*/
|
||||
virtual void saveLoad(ResourceSerializer *serializer);
|
||||
|
||||
/**
|
||||
* Persist / restore the resource state
|
||||
*
|
||||
* Called only for active locations
|
||||
*/
|
||||
virtual void saveLoadCurrent(ResourceSerializer *serializer);
|
||||
|
||||
/**
|
||||
* Called when the node's initialization is complete.
|
||||
*
|
||||
* Allows to load additional data from file.
|
||||
*/
|
||||
virtual void onPostRead();
|
||||
|
||||
/**
|
||||
* Called when the resource sub-tree is entirely loaded.
|
||||
*
|
||||
* Allows to load data from other nodes.
|
||||
*/
|
||||
virtual void onAllLoaded();
|
||||
|
||||
/**
|
||||
* Called when entering a location
|
||||
*/
|
||||
virtual void onEnterLocation();
|
||||
|
||||
/**
|
||||
* Called once per game loop
|
||||
*/
|
||||
virtual void onGameLoop();
|
||||
|
||||
/**
|
||||
* Called when ScummVM pauses or resumes the engine
|
||||
*/
|
||||
virtual void onEnginePause(bool pause);
|
||||
|
||||
/**
|
||||
* Called when exiting a location
|
||||
*/
|
||||
virtual void onExitLocation();
|
||||
|
||||
/**
|
||||
* Called before a resource sub-tree is unloaded.
|
||||
*/
|
||||
virtual void onPreDestroy();
|
||||
|
||||
/**
|
||||
* Cast a resource, performing a type check
|
||||
*/
|
||||
template<class T>
|
||||
static T *cast(Object *resource);
|
||||
|
||||
/** Find the first parent resource with the specified type */
|
||||
template<class T>
|
||||
T *findParent();
|
||||
|
||||
/** Find a child resource matching the specified type, index and subtype */
|
||||
Object *findChildWithIndex(Type type, uint16 index, int subType = -1) const;
|
||||
|
||||
/** Find a child resource matching the specified type, order in the children list and subtype */
|
||||
Object *findChildWithOrder(Type type, uint16 order, int subType = -1) const;
|
||||
|
||||
/** Find a child resource matching the specified type, name and subtype */
|
||||
Object *findChildWithName(Type type, const Common::String &name, int subType = -1) const;
|
||||
|
||||
/** Find a child matching the template parameter type */
|
||||
template<class T>
|
||||
T *findChild(bool mustBeUnique = true) const;
|
||||
|
||||
/** Find a child matching the template parameter type and the specified subtype */
|
||||
template<class T>
|
||||
T *findChildWithSubtype(int subType, bool mustBeUnique = true) const;
|
||||
|
||||
/** Find a child matching the template parameter type and the specified index */
|
||||
template<class T>
|
||||
T *findChildWithIndex(uint16 index, int subType = -1) const;
|
||||
|
||||
/** Find a child matching the template parameter type, order in the children list and subtype */
|
||||
template<class T>
|
||||
T *findChildWithOrder(uint16 order, int subType = -1) const;
|
||||
|
||||
/** Find a child matching the template parameter type, name and subtype */
|
||||
template<class T>
|
||||
T *findChildWithName(const Common::String &name, int subType = -1) const;
|
||||
|
||||
/** List children matching the template parameter type and the specified subtype */
|
||||
template<class T>
|
||||
Common::Array<T *> listChildren(int subType = -1) const;
|
||||
|
||||
/** List children recursively matching the template parameter type and the specified subtype */
|
||||
template<class T>
|
||||
Common::Array<T *> listChildrenRecursive(int subType = -1);
|
||||
|
||||
/** Add a resource to the children list */
|
||||
void addChild(Object *child);
|
||||
|
||||
/** Print debug information for the resource */
|
||||
virtual void print(uint depth = 0);
|
||||
|
||||
protected:
|
||||
Object(Object *parent, byte subType, uint16 index, const Common::String &name);
|
||||
|
||||
void printWithDepth(uint depth, const Common::String &string) const;
|
||||
void printDescription(uint depth) const;
|
||||
virtual void printData();
|
||||
|
||||
Type _type;
|
||||
byte _subType;
|
||||
uint16 _index;
|
||||
Common::String _name;
|
||||
|
||||
Object *_parent;
|
||||
Common::Array<Object *> _children;
|
||||
};
|
||||
|
||||
/**
|
||||
* An unimplemented resource type.
|
||||
*
|
||||
* Used to display the raw resource data when dumping a resource tree.
|
||||
* To be removed once all the resource types are implemented.
|
||||
*/
|
||||
class UnimplementedResource : public Object {
|
||||
public:
|
||||
UnimplementedResource(Object *parent, Type type, byte subType, uint16 index, const Common::String &name);
|
||||
virtual ~UnimplementedResource();
|
||||
|
||||
protected:
|
||||
void readData(Formats::XRCReadStream *stream) override;
|
||||
void printData() override;
|
||||
|
||||
uint32 _dataLength;
|
||||
byte *_data;
|
||||
};
|
||||
|
||||
template <class T>
|
||||
T* Object::cast(Object *resource) {
|
||||
if (resource && resource->_type != T::TYPE) {
|
||||
error("Unexpected resource type when casting resource %s instead of %s",
|
||||
resource->_type.getName(), Type(T::TYPE).getName());
|
||||
}
|
||||
|
||||
return (T *) resource;
|
||||
}
|
||||
|
||||
template<>
|
||||
Object *Object::cast<Object>(Object *resource);
|
||||
|
||||
template<class T>
|
||||
T *Object::findParent() {
|
||||
if (getType() == T::TYPE) {
|
||||
return cast<T>(this);
|
||||
} else if (!_parent) {
|
||||
return nullptr;
|
||||
} else {
|
||||
return _parent->findParent<T>();
|
||||
}
|
||||
}
|
||||
|
||||
template<>
|
||||
Object *Object::findParent();
|
||||
|
||||
template <class T>
|
||||
Common::Array<T *> Object::listChildren(int subType) const {
|
||||
Common::Array<T *> list;
|
||||
|
||||
for (uint i = 0; i < _children.size(); i++) {
|
||||
if (_children[i]->getType() == T::TYPE
|
||||
&& (_children[i]->getSubType() == subType || subType == -1)) {
|
||||
// Found a matching child
|
||||
list.push_back(Object::cast<T>(_children[i]));
|
||||
}
|
||||
}
|
||||
|
||||
return list;
|
||||
}
|
||||
|
||||
template<class T>
|
||||
Common::Array<T *> Object::listChildrenRecursive(int subType) {
|
||||
Common::Array<T *> list;
|
||||
|
||||
for (uint i = 0; i < _children.size(); i++) {
|
||||
if (_children[i]->getType() == T::TYPE
|
||||
&& (_children[i]->getSubType() == subType || subType == -1)) {
|
||||
// Found a matching child
|
||||
list.push_back(Object::cast<T>(_children[i]));
|
||||
}
|
||||
|
||||
// Look for matching resources in the child's children
|
||||
list.push_back(_children[i]->listChildrenRecursive<T>(subType));
|
||||
}
|
||||
|
||||
return list;
|
||||
}
|
||||
|
||||
template<>
|
||||
Common::Array<Object *> Object::listChildren<Object>(int subType) const;
|
||||
|
||||
template<class T>
|
||||
T *Object::findChild(bool mustBeUnique) const {
|
||||
return findChildWithSubtype<T>(-1, mustBeUnique);
|
||||
}
|
||||
|
||||
template <class T>
|
||||
T *Object::findChildWithSubtype(int subType, bool mustBeUnique) const {
|
||||
Common::Array<T *> list = listChildren<T>(subType);
|
||||
|
||||
if (list.empty()) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if (list.size() > 1 && mustBeUnique) {
|
||||
error("Several children resources matching criteria type = %s, subtype = %d", Type(T::TYPE).getName(), subType);
|
||||
}
|
||||
|
||||
return list.front();
|
||||
}
|
||||
|
||||
template <class T>
|
||||
T *Object::findChildWithIndex(uint16 index, int subType) const {
|
||||
return Object::cast<T>(findChildWithIndex(T::TYPE, index, subType));
|
||||
}
|
||||
|
||||
template <class T>
|
||||
T *Object::findChildWithOrder(uint16 order, int subType) const {
|
||||
return Object::cast<T>(findChildWithOrder(T::TYPE, order, subType));
|
||||
}
|
||||
|
||||
template<class T>
|
||||
T *Object::findChildWithName(const Common::String &name, int subType) const {
|
||||
return Object::cast<T>(findChildWithName(T::TYPE, name, subType));
|
||||
}
|
||||
|
||||
} // End of namespace Resources
|
||||
} // End of namespace Stark
|
||||
|
||||
#endif // STARK_RESOURCES_RESOURCE_H
|
||||
221
engines/stark/resources/path.cpp
Normal file
221
engines/stark/resources/path.cpp
Normal file
@@ -0,0 +1,221 @@
|
||||
/* 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 "engines/stark/resources/path.h"
|
||||
|
||||
#include "engines/stark/formats/xrc.h"
|
||||
|
||||
#include "engines/stark/resources/floor.h"
|
||||
|
||||
#include "engines/stark/services/global.h"
|
||||
#include "engines/stark/services/services.h"
|
||||
|
||||
namespace Stark {
|
||||
namespace Resources {
|
||||
|
||||
Object *Path::construct(Object *parent, byte subType, uint16 index, const Common::String &name) {
|
||||
switch (subType) {
|
||||
case kPath2D:
|
||||
return new Path2D(parent, subType, index, name);
|
||||
case kPath3D:
|
||||
return new Path3D(parent, subType, index, name);
|
||||
default:
|
||||
error("Unknown path subtype %d", subType);
|
||||
}
|
||||
}
|
||||
|
||||
Path::~Path() {
|
||||
}
|
||||
|
||||
Path::Path(Object *parent, byte subType, uint16 index, const Common::String &name) :
|
||||
Object(parent, subType, index, name),
|
||||
_field_30(0) {
|
||||
_type = TYPE;
|
||||
}
|
||||
|
||||
void Path::readData(Formats::XRCReadStream *stream) {
|
||||
_field_30 = stream->readUint32LE();
|
||||
}
|
||||
|
||||
void Path::printData() {
|
||||
debug("field_30: %d", _field_30);
|
||||
}
|
||||
|
||||
float Path::getEdgeLength(uint edgeIndex) const {
|
||||
Math::Vector3d edgeStart = getVertexPosition(edgeIndex);
|
||||
Math::Vector3d edgeEnd = getVertexPosition(edgeIndex + 1);
|
||||
|
||||
return edgeStart.getDistanceTo(edgeEnd);
|
||||
}
|
||||
|
||||
float Path::getWeightedEdgeLength(uint edgeIndex) const {
|
||||
float length = getEdgeLength(edgeIndex);
|
||||
float startWeight = getVertexWeight(edgeIndex);
|
||||
float endWeight = getVertexWeight(edgeIndex + 1);
|
||||
|
||||
return 2000.0 * length / (startWeight + endWeight);
|
||||
}
|
||||
|
||||
Math::Vector3d Path::getWeightedPositionInEdge(uint edgeIndex, float positionInEdge) {
|
||||
float edgeLength = getEdgeLength(edgeIndex);
|
||||
float weightedEdgeLength = getWeightedEdgeLength(edgeIndex);
|
||||
|
||||
float startWeight = getVertexWeight(edgeIndex);
|
||||
float endWeight = getVertexWeight(edgeIndex + 1);
|
||||
|
||||
float weightedEdgePosition = ((endWeight - startWeight) / (2 * weightedEdgeLength) * positionInEdge + startWeight) * 0.001
|
||||
* positionInEdge / edgeLength;
|
||||
|
||||
Math::Vector3d edgeStart = getVertexPosition(edgeIndex);
|
||||
Math::Vector3d edgeEnd = getVertexPosition(edgeIndex + 1);
|
||||
|
||||
return edgeEnd * weightedEdgePosition + edgeStart * (1.0 - weightedEdgePosition);
|
||||
}
|
||||
|
||||
float Path::getSortKey() const {
|
||||
return 0;
|
||||
}
|
||||
|
||||
Math::Vector3d Path::getEdgeDirection(uint edgeIndex) const {
|
||||
return Math::Vector3d();
|
||||
}
|
||||
|
||||
|
||||
Path2D::Path2D(Object *parent, byte subType, uint16 index, const Common::String &name) :
|
||||
Path(parent, subType, index, name) {
|
||||
}
|
||||
|
||||
void Path2D::readData(Formats::XRCReadStream *stream) {
|
||||
Path::readData(stream);
|
||||
|
||||
uint32 vertexCount = stream->readUint32LE();
|
||||
for (uint i = 0; i < vertexCount; i++) {
|
||||
Vertex vertex;
|
||||
vertex.weight = stream->readFloatLE();
|
||||
vertex.position = stream->readPoint();
|
||||
|
||||
_vertices.push_back(vertex);
|
||||
}
|
||||
|
||||
stream->readUint32LE(); // Unused in the original
|
||||
}
|
||||
|
||||
void Path2D::printData() {
|
||||
Path::printData();
|
||||
|
||||
for (uint i = 0; i < _vertices.size(); i++) {
|
||||
debug("vertex[%d]: (x %d, y %d), weight: %f", i,
|
||||
_vertices[i].position.x, _vertices[i].position.y, _vertices[i].weight);
|
||||
}
|
||||
}
|
||||
|
||||
Path2D::~Path2D() {
|
||||
}
|
||||
|
||||
uint Path2D::getEdgeCount() const {
|
||||
return _vertices.size() - 1;
|
||||
}
|
||||
|
||||
Math::Vector3d Path2D::getVertexPosition(uint vertexIndex) const {
|
||||
Common::Point point = _vertices[vertexIndex].position;
|
||||
return Math::Vector3d(point.x, point.y, 0.0);
|
||||
}
|
||||
|
||||
float Path2D::getVertexWeight(uint vertexIndex) const {
|
||||
return _vertices[vertexIndex].weight;
|
||||
}
|
||||
|
||||
Path3D::Path3D(Object *parent, byte subType, uint16 index, const Common::String &name) :
|
||||
Path(parent, subType, index, name),
|
||||
_sortKey(0) {
|
||||
}
|
||||
|
||||
void Path3D::readData(Formats::XRCReadStream *stream) {
|
||||
Path::readData(stream);
|
||||
|
||||
uint32 vertexCount = stream->readUint32LE();
|
||||
for (uint i = 0; i < vertexCount; i++) {
|
||||
Vertex vertex;
|
||||
vertex.weight = stream->readFloatLE();
|
||||
vertex.position = stream->readVector3();
|
||||
|
||||
_vertices.push_back(vertex);
|
||||
}
|
||||
|
||||
_sortKey = stream->readFloatLE();
|
||||
}
|
||||
|
||||
void Path3D::printData() {
|
||||
Path::printData();
|
||||
|
||||
for (uint i = 0; i < _vertices.size(); i++) {
|
||||
debug("vertex[%d]: (x %f, y %f, z %f), weight: %f", i,
|
||||
_vertices[i].position.x(), _vertices[i].position.y(), _vertices[i].position.z(), _vertices[i].weight);
|
||||
}
|
||||
|
||||
debug("sortKey: %f", _sortKey);
|
||||
}
|
||||
|
||||
Path3D::~Path3D() {
|
||||
}
|
||||
|
||||
uint Path3D::getEdgeCount() const {
|
||||
return _vertices.size() - 1;
|
||||
}
|
||||
|
||||
Math::Vector3d Path3D::getVertexPosition(uint vertexIndex) const {
|
||||
return _vertices[vertexIndex].position;
|
||||
}
|
||||
|
||||
float Path3D::getVertexWeight(uint vertexIndex) const {
|
||||
return _vertices[vertexIndex].weight;
|
||||
}
|
||||
|
||||
float Path3D::getSortKey() const {
|
||||
return _sortKey;
|
||||
}
|
||||
|
||||
Math::Vector3d Path3D::getEdgeDirection(uint edgeIndex) const {
|
||||
Math::Vector3d direction = getVertexPosition(edgeIndex) - getVertexPosition(edgeIndex + 1);
|
||||
direction.normalize();
|
||||
return direction;
|
||||
}
|
||||
|
||||
Math::Vector3d Path3D::getVertexPosition3D(uint vertexIndex, int32 *faceIndex) {
|
||||
Math::Vector3d vertex = getVertexPosition(vertexIndex);
|
||||
|
||||
Floor *floor = StarkGlobal->getCurrent()->getFloor();
|
||||
if (floor) {
|
||||
int32 face = floor->findFaceContainingPoint(vertex);
|
||||
if (face >= 0) {
|
||||
floor->computePointHeightInFace(vertex, face);
|
||||
}
|
||||
|
||||
if (faceIndex) {
|
||||
*faceIndex = face;
|
||||
}
|
||||
}
|
||||
|
||||
return vertex;
|
||||
}
|
||||
|
||||
} // End of namespace Resources
|
||||
} // End of namespace Stark
|
||||
161
engines/stark/resources/path.h
Normal file
161
engines/stark/resources/path.h
Normal file
@@ -0,0 +1,161 @@
|
||||
/* 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/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef STARK_RESOURCES_PATH_H
|
||||
#define STARK_RESOURCES_PATH_H
|
||||
|
||||
#include "common/rect.h"
|
||||
#include "math/vector3d.h"
|
||||
#include "common/str.h"
|
||||
|
||||
#include "engines/stark/resources/object.h"
|
||||
|
||||
namespace Stark {
|
||||
|
||||
namespace Formats {
|
||||
class XRCReadStream;
|
||||
}
|
||||
|
||||
namespace Resources {
|
||||
|
||||
/**
|
||||
* A path can be followed by an item in a location
|
||||
*
|
||||
* Path are made of a list of vertices. Two consecutive vertices delimit an edge.
|
||||
* Each vertex has a weight. A higher weight means a higher movement speed.
|
||||
*/
|
||||
class Path : public Object {
|
||||
public:
|
||||
static const Type::ResourceType TYPE = Type::kPath;
|
||||
|
||||
enum SubType {
|
||||
kPath2D = 1,
|
||||
kPath3D = 2
|
||||
};
|
||||
|
||||
/** Path factory */
|
||||
static Object *construct(Object *parent, byte subType, uint16 index, const Common::String &name);
|
||||
|
||||
Path(Object *parent, byte subType, uint16 index, const Common::String &name);
|
||||
virtual ~Path();
|
||||
|
||||
// Resource API
|
||||
virtual void readData(Formats::XRCReadStream *stream) override;
|
||||
|
||||
/** Get the edge count in the path */
|
||||
virtual uint getEdgeCount() const = 0;
|
||||
|
||||
/**
|
||||
* Get a unit vector pointing in the direction of an edge
|
||||
*
|
||||
* Only valid for 3D paths
|
||||
*/
|
||||
virtual Math::Vector3d getEdgeDirection(uint edgeIndex) const;
|
||||
|
||||
/** Get the sort key to be used by the item following the path */
|
||||
virtual float getSortKey() const;
|
||||
|
||||
/** Get an edge's length */
|
||||
float getWeightedEdgeLength(uint edgeIndex) const;
|
||||
|
||||
/** Get the scene position from a position in an edge */
|
||||
Math::Vector3d getWeightedPositionInEdge(uint edgeIndex, float positionInEdge);
|
||||
|
||||
protected:
|
||||
void printData() override;
|
||||
float getEdgeLength(uint edgeIndex) const;
|
||||
virtual float getVertexWeight(uint vertexIndex) const = 0;
|
||||
virtual Math::Vector3d getVertexPosition(uint vertexIndex) const = 0;
|
||||
|
||||
uint32 _field_30;
|
||||
|
||||
};
|
||||
|
||||
/**
|
||||
* A 2D path for 2D items
|
||||
*/
|
||||
class Path2D : public Path {
|
||||
public:
|
||||
Path2D(Object *parent, byte subType, uint16 index, const Common::String &name);
|
||||
virtual ~Path2D();
|
||||
|
||||
struct Vertex {
|
||||
float weight;
|
||||
Common::Point position;
|
||||
};
|
||||
|
||||
// Resource API
|
||||
void readData(Formats::XRCReadStream *stream) override;
|
||||
|
||||
// Path API
|
||||
uint getEdgeCount() const override;
|
||||
|
||||
protected:
|
||||
float getVertexWeight(uint vertexIndex) const override;
|
||||
Math::Vector3d getVertexPosition(uint vertexIndex) const override;
|
||||
|
||||
private:
|
||||
// Resource API
|
||||
void printData() override;
|
||||
|
||||
Common::Array<Vertex> _vertices;
|
||||
};
|
||||
|
||||
/**
|
||||
* A 3D path for 3D items
|
||||
*/
|
||||
class Path3D : public Path {
|
||||
public:
|
||||
Path3D(Object *parent, byte subType, uint16 index, const Common::String &name);
|
||||
virtual ~Path3D();
|
||||
|
||||
struct Vertex {
|
||||
float weight;
|
||||
Math::Vector3d position;
|
||||
};
|
||||
|
||||
// Resource API
|
||||
void readData(Formats::XRCReadStream *stream) override;
|
||||
|
||||
// Path API
|
||||
uint getEdgeCount() const override;
|
||||
float getSortKey() const override;
|
||||
Math::Vector3d getEdgeDirection(uint edgeIndex) const override;
|
||||
|
||||
/** Get the full position in world coordinates of one of the vertices of the path */
|
||||
Math::Vector3d getVertexPosition3D(uint vertexIndex, int32 *faceIndex);
|
||||
|
||||
protected:
|
||||
float getVertexWeight(uint vertexIndex) const override;
|
||||
Math::Vector3d getVertexPosition(uint vertexIndex) const override;
|
||||
|
||||
private:
|
||||
// Resource API
|
||||
void printData() override;
|
||||
|
||||
Common::Array<Vertex> _vertices;
|
||||
float _sortKey;
|
||||
};
|
||||
|
||||
} // End of namespace Resources
|
||||
} // End of namespace Stark
|
||||
|
||||
#endif // STARK_RESOURCES_PATH_H
|
||||
187
engines/stark/resources/pattable.cpp
Normal file
187
engines/stark/resources/pattable.cpp
Normal file
@@ -0,0 +1,187 @@
|
||||
/* 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 "engines/stark/resources/pattable.h"
|
||||
#include "engines/stark/resources/item.h"
|
||||
#include "engines/stark/resources/script.h"
|
||||
#include "engines/stark/resources/string.h"
|
||||
|
||||
#include "engines/stark/services/stateprovider.h"
|
||||
|
||||
#include "engines/stark/formats/xrc.h"
|
||||
|
||||
namespace Stark {
|
||||
namespace Resources {
|
||||
|
||||
PATTable::~PATTable() {
|
||||
}
|
||||
|
||||
PATTable::PATTable(Object *parent, byte subType, uint16 index, const Common::String &name) :
|
||||
Object(parent, subType, index, name),
|
||||
_defaultAction(-1),
|
||||
_tooltipOverrideIndex(-1) {
|
||||
_type = TYPE;
|
||||
}
|
||||
|
||||
void PATTable::readData(Formats::XRCReadStream *stream) {
|
||||
uint32 entryCount = stream->readUint32LE();
|
||||
for (uint i = 0; i < entryCount; i++) {
|
||||
Entry entry;
|
||||
|
||||
entry._actionType = stream->readSint32LE();
|
||||
entry._scriptIndex = stream->readSint32LE();
|
||||
entry._script = nullptr;
|
||||
|
||||
_ownEntries.push_back(entry);
|
||||
}
|
||||
|
||||
_defaultAction = stream->readSint32LE();
|
||||
}
|
||||
|
||||
void PATTable::printData() {
|
||||
for (uint i = 0; i < _ownEntries.size(); i++) {
|
||||
debug("entry[%d].actionType: %d", i, _ownEntries[i]._actionType);
|
||||
debug("entry[%d].scriptIndex: %d", i, _ownEntries[i]._scriptIndex);
|
||||
}
|
||||
debug("defaultAction: %d", _defaultAction);
|
||||
}
|
||||
|
||||
void PATTable::onAllLoaded() {
|
||||
Object::onAllLoaded();
|
||||
|
||||
_itemEntries.clear();
|
||||
addOwnEntriesToItemEntries();
|
||||
}
|
||||
|
||||
void PATTable::onEnterLocation() {
|
||||
Object::onEnterLocation();
|
||||
|
||||
_itemEntries.clear();
|
||||
|
||||
// Add our own entries to the list of available actions
|
||||
addOwnEntriesToItemEntries();
|
||||
|
||||
// If the PAT's owning item has a template, find it
|
||||
ItemTemplate *itemTemplate = findItemTemplate();
|
||||
|
||||
// Add the item template actions to the list of available actions
|
||||
if (itemTemplate) {
|
||||
PATTable *templatePAT = itemTemplate->findChild<PATTable>();
|
||||
|
||||
Common::Array<Entry> templateEntries = templatePAT->listItemEntries();
|
||||
for (uint i = 0; i < templateEntries.size(); i++) {
|
||||
if (!_itemEntries.contains(templateEntries[i]._actionType)) {
|
||||
_itemEntries[templateEntries[i]._actionType] = templateEntries[i];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void PATTable::saveLoad(ResourceSerializer *serializer) {
|
||||
serializer->syncAsSint32LE(_tooltipOverrideIndex);
|
||||
|
||||
if (serializer->isLoading() && _tooltipOverrideIndex >= 0) {
|
||||
String *string = findChildWithIndex<String>(_tooltipOverrideIndex);
|
||||
setTooltip(string);
|
||||
}
|
||||
}
|
||||
|
||||
ItemTemplate *PATTable::findItemTemplate() {
|
||||
Item *parent = findParent<Item>();
|
||||
|
||||
ItemTemplate *itemTemplate = nullptr;
|
||||
if (parent->getSubType() == Item::kItemModel) {
|
||||
ModelItem *item = Object::cast<ModelItem>(parent);
|
||||
itemTemplate = item->getItemTemplate();
|
||||
|
||||
} else if (parent->getSubType() == Item::kItemLevelTemplate) {
|
||||
LevelItemTemplate *item = Object::cast<LevelItemTemplate>(parent);
|
||||
itemTemplate = item->getItemTemplate();
|
||||
}
|
||||
|
||||
return itemTemplate;
|
||||
}
|
||||
|
||||
void PATTable::addOwnEntriesToItemEntries() {
|
||||
for (uint i = 0; i < _ownEntries.size(); i++) {
|
||||
if (_ownEntries[i]._scriptIndex != -1) {
|
||||
Entry entry = _ownEntries[i];
|
||||
entry._script = findChildWithIndex<Script>(_ownEntries[i]._scriptIndex);
|
||||
_itemEntries[entry._actionType] = entry;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Common::Array<PATTable::Entry> PATTable::listItemEntries() const {
|
||||
Common::Array<PATTable::Entry> entries;
|
||||
|
||||
for (EntryMap::const_iterator it = _itemEntries.begin(); it != _itemEntries.end(); it++) {
|
||||
entries.push_back(it->_value);
|
||||
}
|
||||
|
||||
return entries;
|
||||
}
|
||||
|
||||
ActionArray PATTable::listPossibleActions() const {
|
||||
ActionArray actions;
|
||||
|
||||
for (EntryMap::const_iterator it = _itemEntries.begin(); it != _itemEntries.end(); it++) {
|
||||
// Check the script can be launched
|
||||
if (it->_value._script->shouldExecute(Script::kCallModePlayerAction)) {
|
||||
actions.push_back(it->_key);
|
||||
}
|
||||
}
|
||||
|
||||
return actions;
|
||||
}
|
||||
|
||||
bool PATTable::canPerformAction(uint32 action) const {
|
||||
if (_itemEntries.contains(action)) {
|
||||
return _itemEntries[action]._script->shouldExecute(Script::kCallModePlayerAction);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
int32 PATTable::getDefaultAction() const {
|
||||
if (_defaultAction != -1 && canPerformAction(_defaultAction)) {
|
||||
return _defaultAction;
|
||||
} else {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
bool PATTable::runScriptForAction(uint32 action) {
|
||||
if (_itemEntries.contains(action)) {
|
||||
_itemEntries[action]._script->execute(Script::kCallModePlayerAction);
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void PATTable::setTooltip(String *string) {
|
||||
_name = string->getName();
|
||||
_tooltipOverrideIndex = string->getIndex();
|
||||
}
|
||||
|
||||
} // End of namespace Resources
|
||||
} // End of namespace Stark
|
||||
101
engines/stark/resources/pattable.h
Normal file
101
engines/stark/resources/pattable.h
Normal file
@@ -0,0 +1,101 @@
|
||||
/* 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/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef STARK_RESOURCES_PAT_TABLE_H
|
||||
#define STARK_RESOURCES_PAT_TABLE_H
|
||||
|
||||
#include "common/str.h"
|
||||
#include "common/hashmap.h"
|
||||
|
||||
#include "engines/stark/resources/object.h"
|
||||
|
||||
namespace Stark {
|
||||
|
||||
namespace Formats {
|
||||
class XRCReadStream;
|
||||
}
|
||||
|
||||
namespace Resources {
|
||||
|
||||
class Script;
|
||||
class String;
|
||||
class ItemTemplate;
|
||||
|
||||
typedef Common::Array<uint32> ActionArray;
|
||||
|
||||
class PATTable : public Object {
|
||||
public:
|
||||
static const Type::ResourceType TYPE = Type::kPATTable;
|
||||
|
||||
enum ActionType {
|
||||
kActionUse = 1,
|
||||
kActionLook = 2,
|
||||
kActionTalk = 3,
|
||||
kActionExit = 7
|
||||
};
|
||||
|
||||
PATTable(Object *parent, byte subType, uint16 index, const Common::String &name);
|
||||
virtual ~PATTable();
|
||||
|
||||
// Resource API
|
||||
void readData(Formats::XRCReadStream *stream) override;
|
||||
void onAllLoaded() override;
|
||||
void onEnterLocation() override;
|
||||
void saveLoad(ResourceSerializer *serializer) override;
|
||||
|
||||
ActionArray listPossibleActions() const;
|
||||
|
||||
bool runScriptForAction(uint32 action);
|
||||
|
||||
bool canPerformAction(uint32 action) const;
|
||||
|
||||
/** If a default action is available, only it can be executed */
|
||||
int32 getDefaultAction() const;
|
||||
|
||||
/** Replace the PAT tooltip with the name of a string resource */
|
||||
void setTooltip(String *string);
|
||||
|
||||
protected:
|
||||
struct Entry {
|
||||
uint32 _actionType;
|
||||
int32 _scriptIndex;
|
||||
Script *_script;
|
||||
};
|
||||
|
||||
typedef Common::HashMap<uint32, Entry> EntryMap;
|
||||
|
||||
void addOwnEntriesToItemEntries();
|
||||
Common::Array<Entry> listItemEntries() const;
|
||||
ItemTemplate *findItemTemplate();
|
||||
|
||||
|
||||
void printData() override;
|
||||
|
||||
Common::Array<Entry> _ownEntries;
|
||||
EntryMap _itemEntries;
|
||||
int32 _defaultAction;
|
||||
int32 _tooltipOverrideIndex;
|
||||
};
|
||||
|
||||
} // End of namespace Resources
|
||||
} // End of namespace Stark
|
||||
|
||||
#endif // STARK_RESOURCES_PAT_TABLE_H
|
||||
41
engines/stark/resources/root.cpp
Normal file
41
engines/stark/resources/root.cpp
Normal file
@@ -0,0 +1,41 @@
|
||||
/* 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 "engines/stark/resources/root.h"
|
||||
|
||||
#include "engines/stark/formats/xrc.h"
|
||||
|
||||
namespace Stark {
|
||||
namespace Resources {
|
||||
|
||||
Root::~Root() {
|
||||
}
|
||||
|
||||
Root::Root(Object *parent, byte subType, uint16 index, const Common::String &name) :
|
||||
Object(parent, subType, index, name) {
|
||||
_type = TYPE;
|
||||
}
|
||||
|
||||
void Root::printData() {
|
||||
}
|
||||
|
||||
} // End of namespace Resources
|
||||
} // End of namespace Stark
|
||||
56
engines/stark/resources/root.h
Normal file
56
engines/stark/resources/root.h
Normal file
@@ -0,0 +1,56 @@
|
||||
/* 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/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef STARK_RESOURCES_ROOT_H
|
||||
#define STARK_RESOURCES_ROOT_H
|
||||
|
||||
#include "common/str.h"
|
||||
|
||||
#include "engines/stark/resources/object.h"
|
||||
|
||||
namespace Stark {
|
||||
|
||||
namespace Formats {
|
||||
class XRCReadStream;
|
||||
}
|
||||
|
||||
namespace Resources {
|
||||
|
||||
/**
|
||||
* The top level element of the game resource tree.
|
||||
*
|
||||
* Contains all the levels.
|
||||
*/
|
||||
class Root : public Object {
|
||||
public:
|
||||
static const Type::ResourceType TYPE = Type::kRoot;
|
||||
|
||||
Root(Object *parent, byte subType, uint16 index, const Common::String &name);
|
||||
virtual ~Root();
|
||||
|
||||
protected:
|
||||
void printData() override;
|
||||
};
|
||||
|
||||
} // End of namespace Resources
|
||||
} // End of namespace Stark
|
||||
|
||||
#endif // STARK_RESOURCES_ROOT_H
|
||||
445
engines/stark/resources/script.cpp
Normal file
445
engines/stark/resources/script.cpp
Normal file
@@ -0,0 +1,445 @@
|
||||
/* 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 "engines/stark/resources/script.h"
|
||||
|
||||
#include "engines/stark/formats/xrc.h"
|
||||
|
||||
#include "engines/stark/resources/anim.h"
|
||||
#include "engines/stark/resources/command.h"
|
||||
#include "engines/stark/resources/item.h"
|
||||
#include "engines/stark/resources/scroll.h"
|
||||
#include "engines/stark/resources/sound.h"
|
||||
#include "engines/stark/resources/speech.h"
|
||||
|
||||
#include "engines/stark/services/dialogplayer.h"
|
||||
#include "engines/stark/services/global.h"
|
||||
#include "engines/stark/services/services.h"
|
||||
#include "engines/stark/services/stateprovider.h"
|
||||
#include "engines/stark/services/userinterface.h"
|
||||
|
||||
#include "engines/stark/tools/decompiler.h"
|
||||
|
||||
namespace Stark {
|
||||
namespace Resources {
|
||||
|
||||
Script::~Script() {
|
||||
}
|
||||
|
||||
Script::Script(Object *parent, byte subType, uint16 index, const Common::String &name) :
|
||||
Object(parent, subType, index, name),
|
||||
_scriptType(0),
|
||||
_runEvent(0),
|
||||
_minChapter(0),
|
||||
_maxChapter(999),
|
||||
_shouldResetGameSpeed(false),
|
||||
_enabled(false),
|
||||
_nextCommand(nullptr),
|
||||
_pauseTimeLeft(-1),
|
||||
_suspendingResource(nullptr),
|
||||
_resumeStatus(kResumeSuspend) {
|
||||
_type = TYPE;
|
||||
}
|
||||
|
||||
void Script::readData(Formats::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() {
|
||||
Object::onAllLoaded();
|
||||
reset();
|
||||
}
|
||||
|
||||
void Script::onGameLoop() {
|
||||
Object::onGameLoop();
|
||||
execute(kCallModeGameLoop);
|
||||
}
|
||||
|
||||
void Script::reset() {
|
||||
if (_suspendingResource && _suspendingResource->getType() == Type::kItem) {
|
||||
Item *item = _suspendingResource->cast<Item>(_suspendingResource);
|
||||
item->setMovement(nullptr);
|
||||
}
|
||||
|
||||
_suspendingResource = nullptr;
|
||||
_resumeStatus = kResumeSuspend;
|
||||
_pauseTimeLeft = -1;
|
||||
|
||||
_nextCommand = getBeginCommand();
|
||||
}
|
||||
|
||||
bool Script::isOnBegin() {
|
||||
return _nextCommand && _nextCommand->getSubType() == Command::kCommandBegin;
|
||||
}
|
||||
|
||||
bool Script::isOnEnd() {
|
||||
return _nextCommand && _nextCommand->getSubType() == Command::kCommandEnd;
|
||||
}
|
||||
|
||||
Command *Script::getBeginCommand() {
|
||||
return findChildWithSubtype<Command>(Command::kCommandBegin, false);
|
||||
}
|
||||
|
||||
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());
|
||||
}
|
||||
}
|
||||
|
||||
void Script::enable(bool value) {
|
||||
if (_scriptType == kScriptTypeOnGameEvent || _scriptType == kScriptTypeOnPlayerAction) {
|
||||
_enabled = value;
|
||||
}
|
||||
}
|
||||
|
||||
bool Script::shouldExecute(uint32 callMode) {
|
||||
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 = StarkGlobal->getCurrentChapter();
|
||||
if (currentChapter < _minChapter || currentChapter >= _maxChapter) {
|
||||
return false; // Wrong chapter
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Script::isSuspended() {
|
||||
return _pauseTimeLeft >= 0 || _suspendingResource;
|
||||
}
|
||||
|
||||
Object *Script::getSuspendingResource() const {
|
||||
return _suspendingResource;
|
||||
}
|
||||
|
||||
void Script::updateSuspended() {
|
||||
if (_pauseTimeLeft >= 0) {
|
||||
// Decrease the remaining pause time
|
||||
_pauseTimeLeft -= StarkGlobal->getMillisecondsPerGameloop();
|
||||
} else {
|
||||
_pauseTimeLeft = -1;
|
||||
}
|
||||
|
||||
if (_nextCommand->getSubType() == Command::kScriptPauseSkippable
|
||||
&& (StarkUserInterface->wasInteractionDenied() || _pauseTimeLeft < 0)) {
|
||||
StarkUserInterface->setInteractive(true);
|
||||
_pauseTimeLeft = -1;
|
||||
}
|
||||
|
||||
bool commandChanged = false;
|
||||
|
||||
if (_suspendingResource) {
|
||||
// Check if the suspending resource is still active
|
||||
switch (_suspendingResource->getType().get()) {
|
||||
case Type::kDialog: {
|
||||
if (!StarkDialogPlayer->isRunning()) {
|
||||
// Resume the script execution if the dialog is complete
|
||||
_suspendingResource = nullptr;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case Type::kFMV: {
|
||||
// Scripts are not running during an FMV, if we are here, then it has stopped playing
|
||||
_suspendingResource = nullptr;
|
||||
break;
|
||||
}
|
||||
case Type::kSoundItem: {
|
||||
Sound *soundItem = Object::cast<Sound>(_suspendingResource);
|
||||
if (!soundItem->isPlaying()) {
|
||||
// Resume the script execution once the sound has stopped playing
|
||||
_suspendingResource = nullptr;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case Type::kSpeech: {
|
||||
Speech *speech = Object::cast<Speech>(_suspendingResource);
|
||||
if (!StarkDialogPlayer->isSpeechReady(speech) && !speech->isPlaying()) {
|
||||
// Resume the script execution once the speech has stopped playing
|
||||
_suspendingResource = nullptr;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case Type::kScroll: {
|
||||
Scroll *scroll = Object::cast<Scroll>(_suspendingResource);
|
||||
if (!scroll->isActive()) {
|
||||
// Resume the script execution once the scroll target position is reached
|
||||
_suspendingResource = nullptr;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case Type::kItem: {
|
||||
if (_nextCommand->getSubType() == Command::kWalkTo) {
|
||||
if (_resumeStatus == kResumeComplete) {
|
||||
// Resume the script execution once the item has stopped its movement
|
||||
_suspendingResource = nullptr;
|
||||
_nextCommand = _nextCommand->nextCommandIf(false);
|
||||
commandChanged = true;
|
||||
} else if (_resumeStatus == kResumeAbort) {
|
||||
// Resume the script execution once the item has stopped its movement
|
||||
_suspendingResource = nullptr;
|
||||
_nextCommand = _nextCommand->nextCommandIf(true);
|
||||
commandChanged = true;
|
||||
}
|
||||
} else {
|
||||
if (_resumeStatus != kResumeSuspend) {
|
||||
// Resume the script execution once the item has stopped its movement
|
||||
_suspendingResource = nullptr;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
case Type::kAnim: {
|
||||
Anim *anim = Object::cast<Anim>(_suspendingResource);
|
||||
if (anim->isDone()) {
|
||||
anim->resetItem();
|
||||
// Resume the script execution once the animation is complete
|
||||
_suspendingResource = nullptr;
|
||||
}
|
||||
break;
|
||||
}
|
||||
default:
|
||||
error("Unhandled suspending resource type %s", _suspendingResource->getType().getName());
|
||||
}
|
||||
}
|
||||
|
||||
if (_nextCommand->getSubType() == Command::kItemSetActivity && !_suspendingResource) {
|
||||
_nextCommand->resumeItemSetActivity();
|
||||
}
|
||||
|
||||
if (!isSuspended() && _shouldResetGameSpeed) {
|
||||
StarkGlobal->setNormalSpeed();
|
||||
}
|
||||
|
||||
if (!isSuspended() && !commandChanged) {
|
||||
// Resume to the next command
|
||||
goToNextCommand();
|
||||
}
|
||||
}
|
||||
|
||||
void Script::stop() {
|
||||
reset();
|
||||
_enabled = false;
|
||||
_returnObjects.clear();
|
||||
}
|
||||
|
||||
void Script::pause(int32 msecs) {
|
||||
_pauseTimeLeft = msecs;
|
||||
}
|
||||
|
||||
void Script::suspend(Object *cause) {
|
||||
_suspendingResource = cause;
|
||||
_resumeStatus = kResumeSuspend;
|
||||
}
|
||||
|
||||
void Script::setResumeStatus(ResumeStatus status) {
|
||||
_resumeStatus = status;
|
||||
}
|
||||
|
||||
void Script::goToNextCommand() {
|
||||
_nextCommand = _nextCommand->nextCommand();
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
if (!_nextCommand) {
|
||||
break; // No next command, stop here
|
||||
}
|
||||
|
||||
if (isOnEnd()) {
|
||||
break; // Reached the end of the script
|
||||
}
|
||||
|
||||
_nextCommand = _nextCommand->execute(callMode, this);
|
||||
|
||||
executedCommands++;
|
||||
|
||||
if (executedCommands > 50) {
|
||||
break; // Too many consecutive commands
|
||||
}
|
||||
}
|
||||
|
||||
if (isOnEnd() || !_nextCommand) {
|
||||
// Reset ended scripts so they can be started again
|
||||
reset();
|
||||
|
||||
// Check if we should return to some caller script
|
||||
if (!_returnObjects.empty()) {
|
||||
Object *callerObject = _returnObjects.back();
|
||||
_returnObjects.pop_back();
|
||||
|
||||
// Resume execution of the caller object
|
||||
resumeCallerExecution(callerObject);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Script::resumeCallerExecution(Object *callerObject) {
|
||||
switch (callerObject->getType().get()) {
|
||||
case Type::kCommand: {
|
||||
Command *callerCommand = Object::cast<Command>(callerObject);
|
||||
_nextCommand = callerCommand->nextCommand();
|
||||
break;
|
||||
}
|
||||
case Type::kDialog: {
|
||||
Dialog *callerDialog = Object::cast<Dialog>(callerObject);
|
||||
StarkDialogPlayer->resume(callerDialog);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
error("Unhandled caller object type %s", callerObject->getType().getName());
|
||||
}
|
||||
}
|
||||
|
||||
void Script::addReturnObject(Object *object) {
|
||||
_returnObjects.push_back(object);
|
||||
}
|
||||
|
||||
void Script::print(uint depth) {
|
||||
printDescription(depth);
|
||||
printData();
|
||||
|
||||
// Print anything that is not a command
|
||||
for (uint i = 0; i < _children.size(); i++) {
|
||||
if (_children[i]->getType() != Type::kCommand) {
|
||||
_children[i]->print(depth + 1);
|
||||
}
|
||||
}
|
||||
|
||||
Tools::Decompiler *decompiler = new Tools::Decompiler(this);
|
||||
|
||||
// Print the decompiled output
|
||||
printWithDepth(depth + 1, "Decompiled output");
|
||||
if (decompiler->getError() == "") {
|
||||
decompiler->printDecompiled();
|
||||
} else {
|
||||
debug("Decompilation failure: %s", decompiler->getError().c_str());
|
||||
}
|
||||
|
||||
delete decompiler;
|
||||
}
|
||||
|
||||
void Script::printData() {
|
||||
debug("scriptType: %d", _scriptType);
|
||||
debug("runEvent: %d", _runEvent);
|
||||
debug("minChapter: %d", _minChapter);
|
||||
debug("maxChapter: %d", _maxChapter);
|
||||
debug("shouldResetGameSpeed: %d", _shouldResetGameSpeed);
|
||||
}
|
||||
|
||||
void Script::saveLoad(ResourceSerializer *serializer) {
|
||||
serializer->syncAsSint32LE(_enabled);
|
||||
}
|
||||
|
||||
void Script::saveLoadCurrent(ResourceSerializer *serializer) {
|
||||
bool isStarted = !isOnBegin();
|
||||
serializer->syncAsUint32LE(isStarted);
|
||||
|
||||
if (isStarted) {
|
||||
serializer->syncAsResourceReference(&_nextCommand);
|
||||
|
||||
serializer->syncArraySize(_returnObjects);
|
||||
for (uint i = 0; i < _returnObjects.size(); i++) {
|
||||
serializer->syncAsResourceReference(&_returnObjects[i]);
|
||||
}
|
||||
|
||||
serializer->syncAsSint32LE(_pauseTimeLeft);
|
||||
serializer->syncAsResourceReference(&_suspendingResource);
|
||||
serializer->syncAsSint32LE(_resumeStatus);
|
||||
}
|
||||
}
|
||||
|
||||
} // End of namespace Resources
|
||||
} // End of namespace Stark
|
||||
180
engines/stark/resources/script.h
Normal file
180
engines/stark/resources/script.h
Normal file
@@ -0,0 +1,180 @@
|
||||
/* 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/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef STARK_RESOURCES_SCRIPT_H
|
||||
#define STARK_RESOURCES_SCRIPT_H
|
||||
|
||||
#include "common/str.h"
|
||||
|
||||
#include "engines/stark/resources/object.h"
|
||||
|
||||
namespace Stark {
|
||||
|
||||
namespace Formats {
|
||||
class XRCReadStream;
|
||||
}
|
||||
|
||||
namespace Resources {
|
||||
|
||||
class Command;
|
||||
|
||||
/**
|
||||
* A script resource
|
||||
*
|
||||
* Scripts are made of a collection of Command resources. Commands
|
||||
* return the next command to be executed, allowing for branches.
|
||||
*/
|
||||
class Script : public Object {
|
||||
public:
|
||||
static const Type::ResourceType TYPE = Type::kScript;
|
||||
|
||||
enum SubType {
|
||||
kSubTypeGameEvent = 4,
|
||||
kSubTypePlayerAction = 5,
|
||||
kSubTypeDialog = 6
|
||||
};
|
||||
|
||||
enum ScriptType {
|
||||
kScriptTypeOnGameEvent = 0,
|
||||
kScriptTypePassiveDialog = 1,
|
||||
kScriptTypeOnPlayerAction = 2,
|
||||
kScriptType3 = 3,
|
||||
kScriptType4 = 4
|
||||
};
|
||||
|
||||
enum GameEvent {
|
||||
kGameEventOnGameLoop = 0,
|
||||
kGameEventOnEnterLocation = 1,
|
||||
kGameEventOnExitLocation = 2
|
||||
};
|
||||
|
||||
/**
|
||||
* Script call modes.
|
||||
*
|
||||
* Most script types are only meaningful for a call mode.
|
||||
* The shouldExecute method checks the consistency between
|
||||
* the script type and the call mode.
|
||||
*/
|
||||
enum CallMode {
|
||||
kCallModeGameLoop = 1,
|
||||
kCallModeExitLocation = 2,
|
||||
kCallModeEnterLocation = 3,
|
||||
kCallModePlayerAction = 4,
|
||||
kCallModeDialogCreateSelections = 5,
|
||||
kCallModeDialogAnswer = 6
|
||||
};
|
||||
|
||||
enum ResumeStatus {
|
||||
kResumeComplete,
|
||||
kResumeAbort,
|
||||
kResumeSuspend
|
||||
};
|
||||
|
||||
Script(Object *parent, byte subType, uint16 index, const Common::String &name);
|
||||
virtual ~Script();
|
||||
|
||||
// Resource API
|
||||
void readData(Formats::XRCReadStream *stream) override;
|
||||
void saveLoad(ResourceSerializer *serializer) override;
|
||||
void saveLoadCurrent(ResourceSerializer *serializer) override;
|
||||
void onAllLoaded() override;
|
||||
void onGameLoop() override;
|
||||
|
||||
/** Reset the script so that it can be executed again from the beginning */
|
||||
void reset();
|
||||
|
||||
/** Is the script enabled? */
|
||||
bool isEnabled();
|
||||
|
||||
/** Enable the script */
|
||||
void enable(bool value);
|
||||
|
||||
/** Disable and reset the script */
|
||||
void stop();
|
||||
|
||||
/** Is the script on its Begin command? */
|
||||
bool isOnBegin();
|
||||
|
||||
/** Has the script ended? */
|
||||
bool isOnEnd();
|
||||
|
||||
/** Get the script's startup command */
|
||||
Command *getBeginCommand();
|
||||
|
||||
/** Attempt to run the script using the specified call mode */
|
||||
void execute(uint32 callMode);
|
||||
|
||||
/** Pause the script for the specified time */
|
||||
void pause(int32 msecs);
|
||||
|
||||
/** Suspend the script while the specified resource is running */
|
||||
void suspend(Object *cause);
|
||||
|
||||
/** Is the script paused, or waiting for a resource to complete? */
|
||||
bool isSuspended();
|
||||
|
||||
/** Get the resource the script is waiting to complete, if any */
|
||||
Object *getSuspendingResource() const;
|
||||
|
||||
/** Returns true if the script is enabled and valid for this call mode */
|
||||
bool shouldExecute(uint32 callMode);
|
||||
|
||||
/** Step the script to the next command, overriding all checks */
|
||||
void goToNextCommand();
|
||||
|
||||
/**
|
||||
* Add an object to the return list.
|
||||
*
|
||||
* The script will resume execution of this object once it reaches an End opcode
|
||||
*/
|
||||
void addReturnObject(Object *object);
|
||||
|
||||
/** Set the outcome of a suspension (completion or abortion) */
|
||||
void setResumeStatus(ResumeStatus status);
|
||||
|
||||
protected:
|
||||
void print(uint depth) override;
|
||||
void printData() override;
|
||||
|
||||
void updateSuspended();
|
||||
|
||||
void resumeCallerExecution(Object *callerObject);
|
||||
|
||||
uint32 _scriptType;
|
||||
uint32 _runEvent;
|
||||
uint32 _minChapter;
|
||||
uint32 _maxChapter;
|
||||
bool _shouldResetGameSpeed;
|
||||
|
||||
bool _enabled;
|
||||
Command *_nextCommand;
|
||||
|
||||
int32 _pauseTimeLeft;
|
||||
Object *_suspendingResource;
|
||||
ResumeStatus _resumeStatus;
|
||||
|
||||
Common::Array<Object *> _returnObjects;
|
||||
};
|
||||
|
||||
} // End of namespace Resources
|
||||
} // End of namespace Stark
|
||||
|
||||
#endif // STARK_RESOURCES_SCRIPT_H
|
||||
100
engines/stark/resources/scroll.cpp
Normal file
100
engines/stark/resources/scroll.cpp
Normal file
@@ -0,0 +1,100 @@
|
||||
/* 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 "engines/stark/resources/scroll.h"
|
||||
|
||||
#include "engines/stark/formats/xrc.h"
|
||||
#include "engines/stark/resources/location.h"
|
||||
#include "engines/stark/services/stateprovider.h"
|
||||
|
||||
namespace Stark {
|
||||
namespace Resources {
|
||||
|
||||
Scroll::~Scroll() {
|
||||
}
|
||||
|
||||
Scroll::Scroll(Object *parent, byte subType, uint16 index, const Common::String &name) :
|
||||
Object(parent, subType, index, name),
|
||||
_coordinate(0),
|
||||
_field_30(0),
|
||||
_field_34(0),
|
||||
_bookmarkIndex(0),
|
||||
_active(false) {
|
||||
_type = TYPE;
|
||||
}
|
||||
|
||||
void Scroll::applyToLocationImmediate() {
|
||||
Location *location = findParent<Location>();
|
||||
location->scrollToCoordinateImmediate(_coordinate);
|
||||
}
|
||||
|
||||
void Scroll::start() {
|
||||
_active = true;
|
||||
|
||||
Location *location = findParent<Location>();
|
||||
location->setHasActiveScroll();
|
||||
}
|
||||
|
||||
void Scroll::stop() {
|
||||
_active = false;
|
||||
}
|
||||
|
||||
bool Scroll::isActive() {
|
||||
return _active;
|
||||
}
|
||||
|
||||
void Scroll::onGameLoop() {
|
||||
Object::onGameLoop();
|
||||
|
||||
if (_active) {
|
||||
Location *location = findParent<Location>();
|
||||
bool complete = location->scrollToCoordinateSmooth(_coordinate);
|
||||
if (complete) {
|
||||
_active = false;
|
||||
location->stopAllScrolls();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Scroll::readData(Formats::XRCReadStream *stream) {
|
||||
_coordinate = stream->readUint32LE();
|
||||
_field_30 = stream->readUint32LE();
|
||||
_field_34 = stream->readUint32LE();
|
||||
_bookmarkIndex = stream->readUint32LE();
|
||||
}
|
||||
|
||||
void Scroll::saveLoadCurrent(ResourceSerializer *serializer) {
|
||||
serializer->syncAsUint32LE(_active);
|
||||
|
||||
if (serializer->isLoading() && _active) {
|
||||
start();
|
||||
}
|
||||
}
|
||||
|
||||
void Scroll::printData() {
|
||||
debug("coordinate: %d", _coordinate);
|
||||
debug("field_30: %d", _field_30);
|
||||
debug("field_34: %d", _field_34);
|
||||
debug("bookmarkIndex: %d", _bookmarkIndex);
|
||||
}
|
||||
|
||||
} // End of namespace Resources
|
||||
} // End of namespace Stark
|
||||
78
engines/stark/resources/scroll.h
Normal file
78
engines/stark/resources/scroll.h
Normal file
@@ -0,0 +1,78 @@
|
||||
/* 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/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef STARK_RESOURCES_SCROLL_H
|
||||
#define STARK_RESOURCES_SCROLL_H
|
||||
|
||||
#include "common/str.h"
|
||||
|
||||
#include "engines/stark/resources/object.h"
|
||||
|
||||
namespace Stark {
|
||||
|
||||
namespace Formats {
|
||||
class XRCReadStream;
|
||||
}
|
||||
|
||||
namespace Resources {
|
||||
|
||||
/**
|
||||
* Scroll position for a location
|
||||
*/
|
||||
class Scroll : public Object {
|
||||
public:
|
||||
static const Type::ResourceType TYPE = Type::kScroll;
|
||||
|
||||
Scroll(Object *parent, byte subType, uint16 index, const Common::String &name);
|
||||
virtual ~Scroll();
|
||||
|
||||
// Resource API
|
||||
void readData(Formats::XRCReadStream *stream) override;
|
||||
void onGameLoop() override;
|
||||
void saveLoadCurrent(ResourceSerializer *serializer) override;
|
||||
|
||||
/** Start scrolling the location to this position */
|
||||
void start();
|
||||
|
||||
/** Stop scrolling the location from this object */
|
||||
void stop();
|
||||
|
||||
/** Is this scroll currently running? */
|
||||
bool isActive();
|
||||
|
||||
/** Scroll the location to this position, with immediate effect */
|
||||
void applyToLocationImmediate();
|
||||
|
||||
protected:
|
||||
void printData() override;
|
||||
|
||||
uint32 _coordinate;
|
||||
uint32 _field_30;
|
||||
uint32 _field_34;
|
||||
uint32 _bookmarkIndex;
|
||||
|
||||
bool _active;
|
||||
};
|
||||
|
||||
} // End of namespace Resources
|
||||
} // End of namespace Stark
|
||||
|
||||
#endif // STARK_RESOURCES_SCROLL_H
|
||||
280
engines/stark/resources/sound.cpp
Normal file
280
engines/stark/resources/sound.cpp
Normal file
@@ -0,0 +1,280 @@
|
||||
/* 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 "engines/stark/resources/sound.h"
|
||||
|
||||
#include "audio/decoders/vorbis.h"
|
||||
|
||||
#include "common/system.h"
|
||||
|
||||
#include "engines/stark/formats/iss.h"
|
||||
#include "engines/stark/formats/xrc.h"
|
||||
#include "engines/stark/resources/location.h"
|
||||
#include "engines/stark/services/archiveloader.h"
|
||||
#include "engines/stark/services/global.h"
|
||||
#include "engines/stark/services/services.h"
|
||||
#include "engines/stark/services/stateprovider.h"
|
||||
|
||||
namespace Stark {
|
||||
namespace Resources {
|
||||
|
||||
Sound::~Sound() {
|
||||
}
|
||||
|
||||
Sound::Sound(Object *parent, byte subType, uint16 index, const Common::String &name) :
|
||||
Object(parent, subType, index, name),
|
||||
_enabled(0),
|
||||
_looping(false),
|
||||
_field_64(0),
|
||||
_loopIndefinitely(false),
|
||||
_loadFromFile(true),
|
||||
_maxDuration(0),
|
||||
_stockSoundType(0),
|
||||
_field_6C(0),
|
||||
_soundType(0),
|
||||
_pan(0),
|
||||
_volume(0),
|
||||
_fadeDurationRemaining(0),
|
||||
_fadeTargetVolume(0.0),
|
||||
_fadeTargetPan(0.0),
|
||||
_shouldStopOnDestroy(true) {
|
||||
_type = TYPE;
|
||||
}
|
||||
|
||||
Audio::RewindableAudioStream *Sound::makeAudioStream() {
|
||||
Common::SeekableReadStream *stream = nullptr;
|
||||
Audio::RewindableAudioStream *audioStream = nullptr;
|
||||
|
||||
// First try the .iss / isn files
|
||||
if (_loadFromFile) {
|
||||
stream = StarkArchiveLoader->getExternalFile(_filename, _archiveName);
|
||||
} else {
|
||||
stream = StarkArchiveLoader->getFile(_filename, _archiveName);
|
||||
}
|
||||
|
||||
if (stream) {
|
||||
audioStream = Formats::makeISSStream(stream, DisposeAfterUse::YES);
|
||||
}
|
||||
|
||||
if (!audioStream) {
|
||||
// The 2 CD version uses Ogg Vorbis
|
||||
Common::Path filename = _filename;
|
||||
Common::String baseName(filename.baseName());
|
||||
if (baseName.hasSuffix(".iss") || baseName.hasSuffix(".isn") || baseName.hasSuffix(".ssn")) {
|
||||
baseName = Common::String(baseName.c_str(), baseName.size() - 4) + ".ovs";
|
||||
filename = _filename.getParent().appendComponent(baseName);
|
||||
}
|
||||
|
||||
stream = StarkArchiveLoader->getExternalFile(filename, _archiveName);
|
||||
if (stream) {
|
||||
#ifdef USE_VORBIS
|
||||
audioStream = Audio::makeVorbisStream(stream, DisposeAfterUse::YES);
|
||||
#else
|
||||
warning("Cannot decode sound '%s', Vorbis support is not compiled in", filename.toString().c_str());
|
||||
delete stream;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
if (!audioStream) {
|
||||
warning("Unable to load sound '%s'", _filename.toString().c_str());
|
||||
}
|
||||
|
||||
return audioStream;
|
||||
}
|
||||
|
||||
Audio::Mixer::SoundType Sound::getMixerSoundType() {
|
||||
switch (_soundType) {
|
||||
case kSoundTypeVoice:
|
||||
return Audio::Mixer::kSpeechSoundType;
|
||||
case kSoundTypeEffect:
|
||||
return Audio::Mixer::kSFXSoundType;
|
||||
case kSoundTypeMusic:
|
||||
return Audio::Mixer::kMusicSoundType;
|
||||
default:
|
||||
error("Unknown sound type '%d'", _soundType);
|
||||
}
|
||||
}
|
||||
|
||||
void Sound::play() {
|
||||
if (isPlaying()) {
|
||||
return;
|
||||
}
|
||||
|
||||
Audio::RewindableAudioStream *rewindableStream = makeAudioStream();
|
||||
|
||||
if (!rewindableStream) {
|
||||
return;
|
||||
}
|
||||
|
||||
Audio::AudioStream *playStream;
|
||||
if (_looping) {
|
||||
playStream = Audio::makeLoopingAudioStream(rewindableStream, 0);
|
||||
} else {
|
||||
playStream = rewindableStream;
|
||||
}
|
||||
|
||||
g_system->getMixer()->playStream(getMixerSoundType(), &_handle, playStream, -1,
|
||||
_volume * Audio::Mixer::kMaxChannelVolume, _pan * 127);
|
||||
}
|
||||
|
||||
bool Sound::isPlaying() {
|
||||
return g_system->getMixer()->isSoundHandleActive(_handle);
|
||||
}
|
||||
|
||||
void Sound::stop() {
|
||||
g_system->getMixer()->stopHandle(_handle);
|
||||
_handle = Audio::SoundHandle();
|
||||
}
|
||||
|
||||
void Sound::onPreDestroy() {
|
||||
Object::onPreDestroy();
|
||||
|
||||
if (_shouldStopOnDestroy) {
|
||||
stop();
|
||||
}
|
||||
}
|
||||
|
||||
void Sound::readData(Formats::XRCReadStream *stream) {
|
||||
_filename = stream->readString();
|
||||
_enabled = stream->readUint32LE();
|
||||
_looping = stream->readBool();
|
||||
_field_64 = stream->readUint32LE();
|
||||
_loopIndefinitely = stream->readBool();
|
||||
_maxDuration = stream->readUint32LE();
|
||||
_loadFromFile = stream->readBool(); // Used only in the 4CD version
|
||||
_stockSoundType = stream->readUint32LE();
|
||||
_soundName = stream->readString();
|
||||
_field_6C = stream->readUint32LE();
|
||||
_soundType = stream->readUint32LE();
|
||||
_pan = stream->readFloatLE();
|
||||
_volume = stream->readFloatLE();
|
||||
_archiveName = stream->getArchiveName();
|
||||
}
|
||||
|
||||
void Sound::printData() {
|
||||
debug("filename: %s", _filename.toString().c_str());
|
||||
debug("enabled: %d", _enabled);
|
||||
debug("looping: %d", _looping);
|
||||
debug("field_64: %d", _field_64);
|
||||
debug("loopIndefinitely: %d", _loopIndefinitely);
|
||||
debug("maxDuration: %d", _maxDuration);
|
||||
debug("loadFromFile: %d", _loadFromFile);
|
||||
debug("stockSoundType: %d", _stockSoundType);
|
||||
debug("soundName: %s", _soundName.c_str());
|
||||
debug("field_6C: %d", _field_6C);
|
||||
debug("soundType: %d", _soundType);
|
||||
debug("pan: %f", _pan);
|
||||
debug("volume: %f", _volume);
|
||||
}
|
||||
|
||||
void Sound::onGameLoop() {
|
||||
Object::onGameLoop();
|
||||
|
||||
if (_subType == kSoundBackground && !isPlaying()) {
|
||||
Location *location = StarkGlobal->getCurrent()->getLocation();
|
||||
if (location->getName() != "Amongst Stalls" || StarkGlobal->getCurrentChapter() < 100) {
|
||||
play();
|
||||
}
|
||||
}
|
||||
|
||||
if (_looping && !_loopIndefinitely) {
|
||||
// Automatically stop after the maximum run time has been reached
|
||||
uint32 elapsedTime = g_system->getMixer()->getSoundElapsedTime(_handle);
|
||||
if (elapsedTime > _maxDuration) {
|
||||
stop();
|
||||
}
|
||||
}
|
||||
|
||||
if (_fadeDurationRemaining > 0 && isPlaying()) {
|
||||
_volume += (_fadeTargetVolume - _volume) * StarkGlobal->getMillisecondsPerGameloop() / (float) _fadeDurationRemaining;
|
||||
_pan += (_fadeTargetPan - _pan) * StarkGlobal->getMillisecondsPerGameloop() / (float) _fadeDurationRemaining;
|
||||
|
||||
_fadeDurationRemaining -= StarkGlobal->getMillisecondsPerGameloop();
|
||||
|
||||
if (_fadeDurationRemaining <= 0) {
|
||||
_fadeDurationRemaining = 0;
|
||||
|
||||
_volume = _fadeTargetVolume;
|
||||
_pan = _fadeTargetPan;
|
||||
}
|
||||
|
||||
g_system->getMixer()->setChannelVolume(_handle, _volume * Audio::Mixer::kMaxChannelVolume);
|
||||
g_system->getMixer()->setChannelBalance(_handle, _pan * 127);
|
||||
}
|
||||
}
|
||||
|
||||
uint32 Sound::getStockSoundType() const {
|
||||
return _stockSoundType;
|
||||
}
|
||||
|
||||
void Sound::changeVolumePan(int32 volume, int32 pan, int32 duration) {
|
||||
if (isPlaying()) {
|
||||
_fadeDurationRemaining = duration;
|
||||
|
||||
if (_fadeDurationRemaining > 0) {
|
||||
_fadeTargetVolume = volume / 100.0f;
|
||||
_fadeTargetPan = pan / 100.0f;
|
||||
} else {
|
||||
_volume = volume / 100.0f;
|
||||
_pan = pan / 100.0f;
|
||||
|
||||
g_system->getMixer()->setChannelVolume(_handle, _volume * Audio::Mixer::kMaxChannelVolume);
|
||||
g_system->getMixer()->setChannelBalance(_handle, _pan * 127);
|
||||
}
|
||||
} else {
|
||||
if (_fadeDurationRemaining == 0) {
|
||||
_volume = volume / 100.0f;
|
||||
_pan = pan / 100.0f;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Sound::saveLoadCurrent(ResourceSerializer *serializer) {
|
||||
bool playing = isPlaying();
|
||||
serializer->syncAsUint32LE(playing);
|
||||
|
||||
if (_subType != kSoundBackground && playing) {
|
||||
uint32 elapsed = g_system->getMixer()->getSoundElapsedTime(_handle);
|
||||
serializer->syncAsUint32LE(elapsed);
|
||||
serializer->syncAsFloat(_volume);
|
||||
serializer->syncAsFloat(_pan);
|
||||
serializer->syncAsUint32LE(_fadeDurationRemaining);
|
||||
serializer->syncAsFloat(_fadeTargetVolume);
|
||||
serializer->syncAsFloat(_fadeTargetPan);
|
||||
|
||||
if (serializer->isLoading()) {
|
||||
play();
|
||||
// TODO: Seek to the "elapsed" position
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Sound::onEnginePause(bool pause) {
|
||||
g_system->getMixer()->pauseHandle(_handle, pause);
|
||||
}
|
||||
|
||||
void Sound::setStopOnDestroy(bool stopOnDestroy) {
|
||||
_shouldStopOnDestroy = stopOnDestroy;
|
||||
}
|
||||
|
||||
} // End of namespace Resources
|
||||
} // End of namespace Stark
|
||||
128
engines/stark/resources/sound.h
Normal file
128
engines/stark/resources/sound.h
Normal file
@@ -0,0 +1,128 @@
|
||||
/* 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/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef STARK_RESOURCES_SOUND_H
|
||||
#define STARK_RESOURCES_SOUND_H
|
||||
|
||||
#include "audio/mixer.h"
|
||||
|
||||
#include "common/path.h"
|
||||
#include "common/str.h"
|
||||
|
||||
#include "engines/stark/resources/object.h"
|
||||
|
||||
namespace Audio {
|
||||
class RewindableAudioStream;
|
||||
}
|
||||
|
||||
namespace Stark {
|
||||
|
||||
namespace Formats {
|
||||
class XRCReadStream;
|
||||
}
|
||||
|
||||
namespace Resources {
|
||||
|
||||
/**
|
||||
* A sound resource
|
||||
*/
|
||||
class Sound : public Object {
|
||||
public:
|
||||
static const Type::ResourceType TYPE = Type::kSoundItem;
|
||||
|
||||
enum SubType {
|
||||
kSoundBackground = 3,
|
||||
kSoundStock = 5
|
||||
};
|
||||
|
||||
enum SoundType {
|
||||
kSoundTypeVoice = 0,
|
||||
kSoundTypeEffect = 1,
|
||||
kSoundTypeMusic = 2
|
||||
};
|
||||
|
||||
Sound(Object *parent, byte subType, uint16 index, const Common::String &name);
|
||||
virtual ~Sound();
|
||||
|
||||
// Resource API
|
||||
void readData(Formats::XRCReadStream *stream) override;
|
||||
void onPreDestroy() override;
|
||||
void onGameLoop() override;
|
||||
void saveLoadCurrent(ResourceSerializer *serializer) override;
|
||||
void onEnginePause(bool pause) override;
|
||||
|
||||
/** Start playing the sound */
|
||||
void play();
|
||||
|
||||
/** Is the sound playing */
|
||||
bool isPlaying();
|
||||
|
||||
/** Stop the sound */
|
||||
void stop();
|
||||
|
||||
/** Get the type for stock sounds */
|
||||
uint32 getStockSoundType() const;
|
||||
|
||||
/** Fade the sound's current volume and pan to the specified target over duration milliseconds */
|
||||
void changeVolumePan(int32 volume, int32 pan, int32 duration);
|
||||
|
||||
/** Set whether to loop or not */
|
||||
void setLooping(bool looping) { _looping = looping; }
|
||||
|
||||
/**
|
||||
* In the menus, we don't want sounds to be cut when changing screens.
|
||||
* The actual sounds need to outlive the entity. This flag allows to do so.
|
||||
*/
|
||||
void setStopOnDestroy(bool stopOnDestroy);
|
||||
|
||||
protected:
|
||||
void printData() override;
|
||||
|
||||
Audio::RewindableAudioStream *makeAudioStream();
|
||||
Audio::Mixer::SoundType getMixerSoundType();
|
||||
|
||||
Common::Path _filename;
|
||||
Common::Path _archiveName;
|
||||
uint32 _enabled;
|
||||
bool _looping;
|
||||
uint32 _field_64;
|
||||
bool _loopIndefinitely;
|
||||
uint32 _maxDuration;
|
||||
bool _loadFromFile;
|
||||
uint32 _stockSoundType;
|
||||
Common::String _soundName;
|
||||
uint32 _field_6C;
|
||||
uint32 _soundType;
|
||||
float _pan;
|
||||
float _volume;
|
||||
bool _shouldStopOnDestroy;
|
||||
|
||||
int32 _fadeDurationRemaining;
|
||||
float _fadeTargetVolume;
|
||||
float _fadeTargetPan;
|
||||
|
||||
Audio::SoundHandle _handle;
|
||||
};
|
||||
|
||||
} // End of namespace Resources
|
||||
} // End of namespace Stark
|
||||
|
||||
#endif // STARK_RESOURCES_SOUND_H
|
||||
247
engines/stark/resources/speech.cpp
Normal file
247
engines/stark/resources/speech.cpp
Normal file
@@ -0,0 +1,247 @@
|
||||
/* 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 "engines/stark/resources/speech.h"
|
||||
|
||||
#include "engines/stark/formats/xrc.h"
|
||||
|
||||
#include "engines/stark/services/services.h"
|
||||
#include "engines/stark/services/settings.h"
|
||||
#include "engines/stark/services/dialogplayer.h"
|
||||
#include "engines/stark/services/global.h"
|
||||
#include "engines/stark/services/stateprovider.h"
|
||||
|
||||
#include "engines/stark/resources/anim.h"
|
||||
#include "engines/stark/resources/item.h"
|
||||
#include "engines/stark/resources/level.h"
|
||||
#include "engines/stark/resources/lipsync.h"
|
||||
#include "engines/stark/resources/location.h"
|
||||
#include "engines/stark/resources/sound.h"
|
||||
|
||||
namespace Stark {
|
||||
namespace Resources {
|
||||
|
||||
Speech::~Speech() {
|
||||
}
|
||||
|
||||
Speech::Speech(Object *parent, byte subType, uint16 index, const Common::String &name) :
|
||||
Object(parent, subType, index, name),
|
||||
_character(0),
|
||||
_soundResource(nullptr),
|
||||
_playTalkAnim(true),
|
||||
_removeTalkAnimWhenComplete(true),
|
||||
_lipSync(nullptr),
|
||||
_waitTimeRemaining(-1) {
|
||||
_type = TYPE;
|
||||
}
|
||||
|
||||
Common::String Speech::getPhrase() const {
|
||||
return _phrase;
|
||||
}
|
||||
|
||||
void Speech::playSound() {
|
||||
StarkGlobal->setNormalSpeed();
|
||||
|
||||
if (_playTalkAnim) {
|
||||
setCharacterTalkAnim();
|
||||
}
|
||||
|
||||
stopOtherSpeechesFromSameCharacter();
|
||||
|
||||
_soundResource = findChild<Sound>();
|
||||
_soundResource->play();
|
||||
}
|
||||
|
||||
void Speech::setCharacterTalkAnim() {
|
||||
ItemVisual *characterItem = getCharacterItem();
|
||||
if (characterItem) {
|
||||
characterItem->setAnimActivity(Anim::kActorActivityTalk);
|
||||
|
||||
_lipSync = findChild<LipSync>();
|
||||
if (_lipSync) {
|
||||
_lipSync->setItem(characterItem, _playTalkAnim);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Speech::removeCharacterTalkAnim() const {
|
||||
ItemVisual *characterItem = getCharacterItem();
|
||||
if (characterItem && characterItem->getAnimActivity() == Anim::kActorActivityTalk) {
|
||||
characterItem->setAnimActivity(Anim::kActorActivityIdle);
|
||||
}
|
||||
}
|
||||
|
||||
ItemVisual *Speech::getCharacterItem() const {
|
||||
Current *current = StarkGlobal->getCurrent();
|
||||
if (!current) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
Location *location = current->getLocation();
|
||||
if (!location) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return location->getCharacterItem(_character);
|
||||
}
|
||||
|
||||
int32 Speech::getCharacterId() {
|
||||
return _character;
|
||||
}
|
||||
|
||||
bool Speech::isPlaying() {
|
||||
return _soundResource || _waitTimeRemaining > 0;
|
||||
}
|
||||
|
||||
void Speech::stop() {
|
||||
if (_soundResource) {
|
||||
_soundResource->stop();
|
||||
_soundResource = nullptr;
|
||||
}
|
||||
|
||||
_waitTimeRemaining = -1;
|
||||
|
||||
if (_lipSync) {
|
||||
_lipSync->reset();
|
||||
}
|
||||
|
||||
if (_removeTalkAnimWhenComplete) {
|
||||
removeCharacterTalkAnim();
|
||||
}
|
||||
|
||||
_removeTalkAnimWhenComplete = true;
|
||||
_playTalkAnim = true;
|
||||
}
|
||||
|
||||
bool Speech::characterIsApril() const {
|
||||
int32 aprilCharacterIndex = StarkGlobal->getApril()->getCharacterIndex();
|
||||
return _character == aprilCharacterIndex;
|
||||
}
|
||||
|
||||
int32 Speech::getPauseAfterSpeechDuration() const {
|
||||
if (_phrase.hasSuffix("...")) {
|
||||
return 1400;
|
||||
} else if (_phrase.hasSuffix("--")) {
|
||||
return 0;
|
||||
} else {
|
||||
return 1000;
|
||||
}
|
||||
}
|
||||
|
||||
void Speech::readData(Formats::XRCReadStream *stream) {
|
||||
Object::readData(stream);
|
||||
|
||||
_phrase = stream->readString();
|
||||
_character = stream->readSint32LE();
|
||||
|
||||
// bug fix for #12967 (STARK: Cortez says "no", but subtitles say "si")
|
||||
if (StarkSettings->getLanguage() == Common::EN_ANY
|
||||
&& _character == 1 // Cortez
|
||||
&& getIndex() == 1
|
||||
&& getSubType() == 0
|
||||
&& getName().equals("Cortez_Laying low #1")) {
|
||||
_phrase = "Nyo! So it was a good thing I didn't stick my head out the door to look for you, then, no?";
|
||||
}
|
||||
|
||||
// For debug purposes
|
||||
//printData();
|
||||
}
|
||||
|
||||
void Speech::onGameLoop() {
|
||||
Object::onGameLoop();
|
||||
|
||||
if (_soundResource && !_soundResource->isPlaying()) {
|
||||
_soundResource->stop();
|
||||
_soundResource = nullptr;
|
||||
_waitTimeRemaining = getPauseAfterSpeechDuration();
|
||||
}
|
||||
|
||||
if (_waitTimeRemaining >= 0) {
|
||||
_waitTimeRemaining -= StarkGlobal->getMillisecondsPerGameloop();
|
||||
|
||||
if (StarkGlobal->isFastForward()) {
|
||||
_waitTimeRemaining = -1;
|
||||
}
|
||||
|
||||
if (_waitTimeRemaining <= 0) {
|
||||
stop();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Speech::onExitLocation() {
|
||||
stop();
|
||||
}
|
||||
|
||||
void Speech::onPreDestroy() {
|
||||
stop();
|
||||
}
|
||||
|
||||
void Speech::printData() {
|
||||
Object::printData();
|
||||
|
||||
debug("phrase: %s", _phrase.c_str());
|
||||
debug("character: %d", _character);
|
||||
}
|
||||
|
||||
void Speech::setPlayTalkAnim(bool playTalkAnim) {
|
||||
_playTalkAnim = playTalkAnim;
|
||||
}
|
||||
|
||||
void Speech::stopOtherSpeechesFromSameCharacter() {
|
||||
Level *globalLevel = StarkGlobal->getLevel();
|
||||
Level *currentLevel = StarkGlobal->getCurrent()->getLevel();
|
||||
Location *currentLocation = StarkGlobal->getCurrent()->getLocation();
|
||||
|
||||
Common::Array<Speech *> globalLevelSpeeches = globalLevel->listChildrenRecursive<Speech>();
|
||||
Common::Array<Speech *> currentLevelSpeeches = currentLevel->listChildrenRecursive<Speech>();
|
||||
Common::Array<Speech *> currentLocationSpeeches = currentLocation->listChildrenRecursive<Speech>();
|
||||
|
||||
Common::Array<Speech *> speeches;
|
||||
speeches.push_back(globalLevelSpeeches);
|
||||
speeches.push_back(currentLevelSpeeches);
|
||||
speeches.push_back(currentLocationSpeeches);
|
||||
|
||||
for (uint i = 0; i < speeches.size(); i++) {
|
||||
Speech *speech = speeches[i];
|
||||
if (speech->_character == _character && speech->isPlaying()) {
|
||||
speech->stop();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Speech::saveLoadCurrent(ResourceSerializer *serializer) {
|
||||
bool playing = isPlaying();
|
||||
serializer->syncAsUint32LE(playing);
|
||||
|
||||
if (playing) {
|
||||
serializer->syncAsUint32LE(_removeTalkAnimWhenComplete);
|
||||
serializer->syncAsResourceReference(&_soundResource);
|
||||
serializer->syncAsResourceReference(&_lipSync);
|
||||
|
||||
if (serializer->isLoading()) {
|
||||
StarkDialogPlayer->playSingle(this);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} // End of namespace Resources
|
||||
} // End of namespace Stark
|
||||
106
engines/stark/resources/speech.h
Normal file
106
engines/stark/resources/speech.h
Normal file
@@ -0,0 +1,106 @@
|
||||
/* 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/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef STARK_RESOURCES_SPEECH_H
|
||||
#define STARK_RESOURCES_SPEECH_H
|
||||
|
||||
#include "common/str.h"
|
||||
|
||||
#include "engines/stark/resources/object.h"
|
||||
|
||||
namespace Stark {
|
||||
|
||||
namespace Formats {
|
||||
class XRCReadStream;
|
||||
}
|
||||
|
||||
namespace Resources {
|
||||
|
||||
class ItemVisual;
|
||||
class LipSync;
|
||||
class Sound;
|
||||
|
||||
/**
|
||||
* Speech resource
|
||||
*
|
||||
* Speech resources are used to define dialog lines.
|
||||
* A Speech resource contains text for a character and references
|
||||
* a Sound resource for the dubbing.
|
||||
*/
|
||||
class Speech : public Object {
|
||||
public:
|
||||
static const Type::ResourceType TYPE = Type::kSpeech;
|
||||
|
||||
Speech(Object *parent, byte subType, uint16 index, const Common::String &name);
|
||||
virtual ~Speech();
|
||||
|
||||
// Resource API
|
||||
void readData(Formats::XRCReadStream *stream) override;
|
||||
void onGameLoop() override;
|
||||
void onExitLocation() override;
|
||||
void onPreDestroy() override;
|
||||
void saveLoadCurrent(ResourceSerializer *serializer) override;
|
||||
|
||||
/** Obtain the text associated to the speech line */
|
||||
Common::String getPhrase() const;
|
||||
|
||||
/** Play the voice over */
|
||||
void playSound();
|
||||
|
||||
/** Return true if the speech is playing */
|
||||
bool isPlaying();
|
||||
|
||||
/** Stop the speech if it is playing */
|
||||
void stop();
|
||||
|
||||
/** Is the character saying the line April ? */
|
||||
bool characterIsApril() const;
|
||||
|
||||
/** Should the character change to the talk anim while this is playing? */
|
||||
void setPlayTalkAnim(bool playTalkAnim);
|
||||
|
||||
/** Get the character's id - index in the KnowledgeSet */
|
||||
int32 getCharacterId();
|
||||
|
||||
protected:
|
||||
void printData() override;
|
||||
|
||||
void setCharacterTalkAnim();
|
||||
void removeCharacterTalkAnim() const;
|
||||
ItemVisual *getCharacterItem() const;
|
||||
void stopOtherSpeechesFromSameCharacter();
|
||||
|
||||
int32 getPauseAfterSpeechDuration() const;
|
||||
|
||||
Common::String _phrase;
|
||||
int32 _character;
|
||||
bool _playTalkAnim;
|
||||
bool _removeTalkAnimWhenComplete;
|
||||
|
||||
Sound *_soundResource;
|
||||
LipSync *_lipSync;
|
||||
int32 _waitTimeRemaining;
|
||||
};
|
||||
|
||||
} // End of namespace Resources
|
||||
} // End of namespace Stark
|
||||
|
||||
#endif // STARK_RESOURCES_SPEECH_H
|
||||
41
engines/stark/resources/string.cpp
Normal file
41
engines/stark/resources/string.cpp
Normal file
@@ -0,0 +1,41 @@
|
||||
/* 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 "engines/stark/resources/string.h"
|
||||
|
||||
#include "engines/stark/formats/xrc.h"
|
||||
|
||||
namespace Stark {
|
||||
namespace Resources {
|
||||
|
||||
String::~String() {
|
||||
}
|
||||
|
||||
String::String(Object *parent, byte subType, uint16 index, const Common::String &name) :
|
||||
Object(parent, subType, index, name) {
|
||||
_type = TYPE;
|
||||
}
|
||||
|
||||
void String::printData() {
|
||||
}
|
||||
|
||||
} // End of namespace Resources
|
||||
} // End of namespace Stark
|
||||
57
engines/stark/resources/string.h
Normal file
57
engines/stark/resources/string.h
Normal file
@@ -0,0 +1,57 @@
|
||||
/* 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/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef STARK_RESOURCES_STRING_H
|
||||
#define STARK_RESOURCES_STRING_H
|
||||
|
||||
#include "common/str.h"
|
||||
|
||||
#include "engines/stark/resources/object.h"
|
||||
|
||||
namespace Stark {
|
||||
|
||||
namespace Formats {
|
||||
class XRCReadStream;
|
||||
}
|
||||
|
||||
namespace Resources {
|
||||
|
||||
/**
|
||||
* A character string resource.
|
||||
*
|
||||
* String resources are used by scripts to change the title
|
||||
* of items.
|
||||
*/
|
||||
class String : public Object {
|
||||
public:
|
||||
static const Type::ResourceType TYPE = Type::kString;
|
||||
|
||||
String(Object *parent, byte subType, uint16 index, const Common::String &name);
|
||||
~String() override;
|
||||
|
||||
protected:
|
||||
void printData() override;
|
||||
};
|
||||
|
||||
} // End of namespace Resources
|
||||
} // End of namespace Stark
|
||||
|
||||
#endif // STARK_RESOURCES_STRING_H
|
||||
202
engines/stark/resources/textureset.cpp
Normal file
202
engines/stark/resources/textureset.cpp
Normal file
@@ -0,0 +1,202 @@
|
||||
/* 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 "engines/stark/resources/textureset.h"
|
||||
|
||||
#include "engines/stark/debug.h"
|
||||
|
||||
#include "engines/stark/formats/dds.h"
|
||||
#include "engines/stark/formats/tm.h"
|
||||
#include "engines/stark/formats/xrc.h"
|
||||
|
||||
#include "engines/stark/gfx/driver.h"
|
||||
#include "engines/stark/gfx/texture.h"
|
||||
|
||||
#include "engines/stark/services/archiveloader.h"
|
||||
#include "engines/stark/services/services.h"
|
||||
#include "engines/stark/services/settings.h"
|
||||
|
||||
#include "common/file.h"
|
||||
#include "common/compression/unzip.h"
|
||||
#include "image/png.h"
|
||||
|
||||
namespace Stark {
|
||||
namespace Resources {
|
||||
|
||||
TextureSet::~TextureSet() {
|
||||
delete _textureSet;
|
||||
}
|
||||
|
||||
TextureSet::TextureSet(Object *parent, byte subType, uint16 index, const Common::String &name) :
|
||||
Object(parent, subType, index, name),
|
||||
_textureSet(nullptr) {
|
||||
_type = TYPE;
|
||||
}
|
||||
|
||||
Gfx::TextureSet *TextureSet::getTexture() {
|
||||
return _textureSet;
|
||||
}
|
||||
|
||||
void TextureSet::readData(Formats::XRCReadStream *stream) {
|
||||
_filename = Common::Path(stream->readString());
|
||||
_archiveName = stream->getArchiveName();
|
||||
}
|
||||
|
||||
void TextureSet::onPostRead() {
|
||||
if (StarkSettings->isAssetsModEnabled() && StarkGfx->supportsModdedAssets()) {
|
||||
_textureSet = readOverrideDdsArchive();
|
||||
}
|
||||
|
||||
if (!_textureSet) {
|
||||
ArchiveReadStream *stream = StarkArchiveLoader->getFile(_filename, _archiveName);
|
||||
|
||||
_textureSet = Formats::TextureSetReader::read(stream);
|
||||
|
||||
delete stream;
|
||||
}
|
||||
}
|
||||
|
||||
static Common::String stripExtension(const Common::String &filename) {
|
||||
if (filename.hasSuffixIgnoreCase(".bmp")) {
|
||||
return Common::String(filename.c_str(), filename.size() - 4);
|
||||
}
|
||||
return filename;
|
||||
}
|
||||
|
||||
void TextureSet::extractArchive() {
|
||||
ArchiveReadStream *stream = StarkArchiveLoader->getFile(_filename, _archiveName);
|
||||
Formats::BiffArchive *archive = Formats::TextureSetReader::readArchive(stream);
|
||||
|
||||
Common::Array<Formats::Texture *> textures = archive->listObjectsRecursive<Formats::Texture>();
|
||||
for (uint i = 0; i < textures.size(); i++) {
|
||||
Common::Path filename(Common::String::format(
|
||||
"dump/%s/%s.png",
|
||||
_filename.baseName().c_str(),
|
||||
stripExtension(textures[i]->getName()).c_str()));
|
||||
|
||||
if (Common::File::exists(filename)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
Common::DumpFile out;
|
||||
if (!out.open(filename, true)) {
|
||||
warning("Unable to open file '%s' for writing", filename.toString().c_str());
|
||||
return;
|
||||
}
|
||||
|
||||
Graphics::Surface *surface = textures[i]->getSurface();
|
||||
|
||||
Image::writePNG(out, *surface);
|
||||
|
||||
out.close();
|
||||
|
||||
surface->free();
|
||||
delete surface;
|
||||
}
|
||||
|
||||
delete archive;
|
||||
delete stream;
|
||||
}
|
||||
|
||||
Gfx::TextureSet *TextureSet::readOverrideDdsArchive() {
|
||||
Common::Path archiveName = _filename.append(".zip");
|
||||
|
||||
debugC(kDebugModding, "Attempting to load %s", archiveName.toString().c_str());
|
||||
|
||||
Common::Archive *archive = Common::makeZipArchive(archiveName);
|
||||
if (!archive) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
Common::ArchiveMemberList files;
|
||||
archive->listMatchingMembers(files, "*.dds");
|
||||
if (files.empty()) {
|
||||
warning("No DDS files found in archive %s", archiveName.toString().c_str());
|
||||
delete archive;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
uint loadedCount = 0;
|
||||
Gfx::TextureSet *textureSet = new Gfx::TextureSet();
|
||||
|
||||
for (Common::ArchiveMemberList::const_iterator it = files.begin(); it != files.end(); it++) {
|
||||
const Common::String &name = (*it)->getName();
|
||||
|
||||
debugC(kDebugModding, "Attempting to load texture %s", name.c_str());
|
||||
|
||||
Common::SeekableReadStream *ddsStream = (*it)->createReadStream();
|
||||
if (!ddsStream) {
|
||||
warning("Unable to open %s for reading in %s", (*it)->getName().c_str(), archiveName.toString().c_str());
|
||||
continue;
|
||||
}
|
||||
|
||||
Formats::DDS dds;
|
||||
if (!dds.load(*ddsStream, name + " in " + archiveName.toString('/'))) {
|
||||
delete ddsStream;
|
||||
continue;
|
||||
}
|
||||
|
||||
const Formats::DDS::MipMaps &mipmaps = dds.getMipMaps();
|
||||
if (mipmaps.empty()) {
|
||||
warning("No mipmaps in %s", name.c_str());
|
||||
delete ddsStream;
|
||||
continue;
|
||||
}
|
||||
|
||||
Gfx::Texture *texture = StarkGfx->createTexture();
|
||||
texture->setLevelCount(mipmaps.size());
|
||||
for (uint i = 0; i < mipmaps.size(); i++) {
|
||||
texture->addLevel(i, &mipmaps[i]);
|
||||
}
|
||||
|
||||
// Remove the .dds extension, add .bmp to match the names
|
||||
// used by the models.
|
||||
Common::String textureName = Common::String(name.c_str(), name.size() - 4);
|
||||
|
||||
// Fix for loading one of Emma's textures in mods caused by inconsistent zip filename encoding
|
||||
// The original game uses a 1 byte character (\xe6 which is ae in CP1252)
|
||||
// \x91 is ae in CP437 and CP850 which is used by some compression utilities
|
||||
// \xc3\xa6 is the UTF-8 2-byte representation
|
||||
// Both get converted to the game's original encoding here
|
||||
if (textureName == "pupp\x91r" || textureName == "pupp\xc3\xa6r") {
|
||||
textureName = "pupp\xe6r";
|
||||
}
|
||||
|
||||
textureSet->addTexture(textureName + ".bmp", texture);
|
||||
|
||||
delete ddsStream;
|
||||
|
||||
loadedCount++;
|
||||
}
|
||||
|
||||
debugC(kDebugModding, "Loaded %d textures from %s", loadedCount, archiveName.toString().c_str());
|
||||
|
||||
delete archive;
|
||||
|
||||
return textureSet;
|
||||
}
|
||||
|
||||
void TextureSet::printData() {
|
||||
debug("filename: %s", _filename.toString().c_str());
|
||||
}
|
||||
|
||||
} // End of namespace Resources
|
||||
} // End of namespace Stark
|
||||
82
engines/stark/resources/textureset.h
Normal file
82
engines/stark/resources/textureset.h
Normal file
@@ -0,0 +1,82 @@
|
||||
/* 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/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef STARK_RESOURCES_TEXTURE_SET_H
|
||||
#define STARK_RESOURCES_TEXTURE_SET_H
|
||||
|
||||
#include "common/path.h"
|
||||
#include "common/str.h"
|
||||
|
||||
#include "engines/stark/resources/object.h"
|
||||
|
||||
namespace Stark {
|
||||
|
||||
namespace Gfx {
|
||||
class TextureSet;
|
||||
}
|
||||
|
||||
namespace Formats {
|
||||
class XRCReadStream;
|
||||
}
|
||||
|
||||
namespace Resources {
|
||||
|
||||
/**
|
||||
* A texture resource
|
||||
*
|
||||
* Used by items to provide textures to meshes
|
||||
*/
|
||||
class TextureSet : public Object {
|
||||
public:
|
||||
static const Type::ResourceType TYPE = Type::kTextureSet;
|
||||
|
||||
enum SubType {
|
||||
kTextureNormal = 1,
|
||||
kTextureFace = 2
|
||||
};
|
||||
|
||||
TextureSet(Object *parent, byte subType, uint16 index, const Common::String &name);
|
||||
~TextureSet() override;
|
||||
|
||||
// Resource API
|
||||
void readData(Formats::XRCReadStream *stream) override;
|
||||
void onPostRead() override;
|
||||
|
||||
/** Obtain the texture to be rendered */
|
||||
Gfx::TextureSet *getTexture();
|
||||
|
||||
/** Extract the texture set archive to the dump directory relative to the current directory */
|
||||
void extractArchive();
|
||||
|
||||
protected:
|
||||
void printData() override;
|
||||
Gfx::TextureSet *readOverrideDdsArchive();
|
||||
|
||||
Common::Path _filename;
|
||||
Common::Path _archiveName;
|
||||
|
||||
Gfx::TextureSet *_textureSet;
|
||||
};
|
||||
|
||||
} // End of namespace Resources
|
||||
} // End of namespace Stark
|
||||
|
||||
#endif // STARK_RESOURCES_TEXTURE_SET_H
|
||||
Reference in New Issue
Block a user