mirror of
https://github.com/libretro/scummvm.git
synced 2025-05-13 17:46:22 +00:00
STARK: Implement animation triggered sounds
Mainly used for footstep sounds
This commit is contained in:
parent
bd262446fa
commit
368d71cfd5
@ -26,6 +26,7 @@
|
|||||||
#include "engines/stark/resources/anim.h"
|
#include "engines/stark/resources/anim.h"
|
||||||
#include "engines/stark/resources/animhierarchy.h"
|
#include "engines/stark/resources/animhierarchy.h"
|
||||||
#include "engines/stark/resources/animscript.h"
|
#include "engines/stark/resources/animscript.h"
|
||||||
|
#include "engines/stark/resources/animsoundtrigger.h"
|
||||||
#include "engines/stark/resources/bonesmesh.h"
|
#include "engines/stark/resources/bonesmesh.h"
|
||||||
#include "engines/stark/resources/bookmark.h"
|
#include "engines/stark/resources/bookmark.h"
|
||||||
#include "engines/stark/resources/camera.h"
|
#include "engines/stark/resources/camera.h"
|
||||||
@ -275,6 +276,9 @@ Resources::Object *XRCReader::createResource(XRCReadStream *stream, Resources::O
|
|||||||
case Resources::Type::kLipSync:
|
case Resources::Type::kLipSync:
|
||||||
resource = new Resources::LipSync(parent, subType, index, name);
|
resource = new Resources::LipSync(parent, subType, index, name);
|
||||||
break;
|
break;
|
||||||
|
case Resources::Type::kAnimSoundTrigger:
|
||||||
|
resource = new Resources::AnimSoundTrigger(parent, subType, index, name);
|
||||||
|
break;
|
||||||
case Resources::Type::kString:
|
case Resources::Type::kString:
|
||||||
resource = new Resources::String(parent, subType, index, name);
|
resource = new Resources::String(parent, subType, index, name);
|
||||||
break;
|
break;
|
||||||
|
@ -31,6 +31,7 @@ MODULE_OBJS := \
|
|||||||
resources/anim.o \
|
resources/anim.o \
|
||||||
resources/animhierarchy.o \
|
resources/animhierarchy.o \
|
||||||
resources/animscript.o \
|
resources/animscript.o \
|
||||||
|
resources/animsoundtrigger.o \
|
||||||
resources/bonesmesh.o \
|
resources/bonesmesh.o \
|
||||||
resources/bookmark.o \
|
resources/bookmark.o \
|
||||||
resources/camera.o \
|
resources/camera.o \
|
||||||
|
@ -514,6 +514,15 @@ uint32 AnimSkeleton::getDuration() const {
|
|||||||
return _totalTime;
|
return _totalTime;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
uint32 AnimSkeleton::getCurrentTime() const {
|
||||||
|
return _currentTime;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32 AnimSkeleton::getRemainingTime() const {
|
||||||
|
int32 remainingTime = _totalTime - _currentTime;
|
||||||
|
return CLIP<int32>(remainingTime, 0, _totalTime);
|
||||||
|
}
|
||||||
|
|
||||||
void AnimSkeleton::playAsAction(ItemVisual *item) {
|
void AnimSkeleton::playAsAction(ItemVisual *item) {
|
||||||
_actionItem = item;
|
_actionItem = item;
|
||||||
|
|
||||||
|
@ -260,6 +260,12 @@ public:
|
|||||||
bool isAtTime(uint32 time) const override;
|
bool isAtTime(uint32 time) const override;
|
||||||
uint32 getMovementSpeed() const override;
|
uint32 getMovementSpeed() const override;
|
||||||
|
|
||||||
|
/** Get the position in the animation loop in milliseconds */
|
||||||
|
uint32 getCurrentTime() const;
|
||||||
|
|
||||||
|
/** Get the duration in milliseconds before the animation loops ends */
|
||||||
|
uint32 getRemainingTime() const;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
void printData() override;
|
void printData() override;
|
||||||
|
|
||||||
|
101
engines/stark/resources/animsoundtrigger.cpp
Normal file
101
engines/stark/resources/animsoundtrigger.cpp
Normal file
@ -0,0 +1,101 @@
|
|||||||
|
/* ResidualVM - A 3D game interpreter
|
||||||
|
*
|
||||||
|
* ResidualVM is the legal property of its developers, whose names
|
||||||
|
* are too numerous to list here. Please refer to the AUTHORS
|
||||||
|
* file distributed with this source distribution.
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU General Public License
|
||||||
|
* as published by the Free Software Foundation; either version 2
|
||||||
|
* of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "engines/stark/resources/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) {
|
||||||
|
// TODO: If the location has a 3D layer set the source position of the sound to the item position
|
||||||
|
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
|
74
engines/stark/resources/animsoundtrigger.h
Normal file
74
engines/stark/resources/animsoundtrigger.h
Normal file
@ -0,0 +1,74 @@
|
|||||||
|
/* ResidualVM - A 3D game interpreter
|
||||||
|
*
|
||||||
|
* ResidualVM is the legal property of its developers, whose names
|
||||||
|
* are too numerous to list here. Please refer to the AUTHORS
|
||||||
|
* file distributed with this source distribution.
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU General Public License
|
||||||
|
* as published by the Free Software Foundation; either version 2
|
||||||
|
* of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#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
|
@ -39,7 +39,8 @@ public:
|
|||||||
static const Type::ResourceType TYPE = Type::kContainer;
|
static const Type::ResourceType TYPE = Type::kContainer;
|
||||||
|
|
||||||
enum SubType {
|
enum SubType {
|
||||||
kSounds = 5
|
kSounds = 5,
|
||||||
|
kStockSounds = 8
|
||||||
};
|
};
|
||||||
|
|
||||||
Container(Object *parent, byte subType, uint16 index, const Common::String &name);
|
Container(Object *parent, byte subType, uint16 index, const Common::String &name);
|
||||||
|
@ -27,9 +27,12 @@
|
|||||||
|
|
||||||
#include "engines/stark/movement/movement.h"
|
#include "engines/stark/movement/movement.h"
|
||||||
|
|
||||||
|
#include "engines/stark/resources/container.h"
|
||||||
#include "engines/stark/resources/item.h"
|
#include "engines/stark/resources/item.h"
|
||||||
#include "engines/stark/resources/layer.h"
|
#include "engines/stark/resources/layer.h"
|
||||||
|
#include "engines/stark/resources/level.h"
|
||||||
#include "engines/stark/resources/scroll.h"
|
#include "engines/stark/resources/scroll.h"
|
||||||
|
#include "engines/stark/resources/sound.h"
|
||||||
|
|
||||||
#include "engines/stark/scene.h"
|
#include "engines/stark/scene.h"
|
||||||
#include "engines/stark/services/services.h"
|
#include "engines/stark/services/services.h"
|
||||||
@ -335,5 +338,37 @@ void Location::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;
|
||||||
|
}
|
||||||
|
|
||||||
} // End of namespace Resources
|
} // End of namespace Resources
|
||||||
} // End of namespace Stark
|
} // End of namespace Stark
|
||||||
|
@ -41,6 +41,7 @@ namespace Resources {
|
|||||||
class ItemVisual;
|
class ItemVisual;
|
||||||
class Layer;
|
class Layer;
|
||||||
class ModelItem;
|
class ModelItem;
|
||||||
|
class Sound;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A location is a scene of the game
|
* A location is a scene of the game
|
||||||
@ -115,6 +116,9 @@ public:
|
|||||||
/** Reset animation blending for all the items in the location */
|
/** Reset animation blending for all the items in the location */
|
||||||
void resetAnimationBlending();
|
void resetAnimationBlending();
|
||||||
|
|
||||||
|
/** Find a stock sound by its type in the location, the level, or the global level */
|
||||||
|
Sound *findStockSound(uint32 stockSoundType) const;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
void printData() override;
|
void printData() override;
|
||||||
|
|
||||||
@ -125,6 +129,8 @@ private:
|
|||||||
uint getScrollStepFollow();
|
uint getScrollStepFollow();
|
||||||
Common::Point getScrollPointFromCoordinate(uint32 coordinate) const;
|
Common::Point getScrollPointFromCoordinate(uint32 coordinate) const;
|
||||||
|
|
||||||
|
Sound *findStockSound(const Object *parent, uint32 stockSoundType) const;
|
||||||
|
|
||||||
Common::Array<Layer *> _layers;
|
Common::Array<Layer *> _layers;
|
||||||
Layer *_currentLayer;
|
Layer *_currentLayer;
|
||||||
|
|
||||||
|
@ -78,7 +78,7 @@ const char *Type::getName() const {
|
|||||||
{ Type::kScroll, "Scroll" },
|
{ Type::kScroll, "Scroll" },
|
||||||
{ Type::kFMV, "FMV" },
|
{ Type::kFMV, "FMV" },
|
||||||
{ Type::kLipSync, "LipSynch" },
|
{ Type::kLipSync, "LipSynch" },
|
||||||
{ Type::kAnimScriptBonesTrigger, "AnimScriptBonesTrigger" },
|
{ Type::kAnimSoundTrigger, "AnimSoundTrigger" },
|
||||||
{ Type::kString, "String" },
|
{ Type::kString, "String" },
|
||||||
{ Type::kTextureSet, "TextureSet" }
|
{ Type::kTextureSet, "TextureSet" }
|
||||||
};
|
};
|
||||||
@ -235,7 +235,7 @@ Object *Object::cast<Object>(Object *resource) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
template<>
|
template<>
|
||||||
Common::Array<Object *> Object::listChildren<Object>(int subType) {
|
Common::Array<Object *> Object::listChildren<Object>(int subType) const {
|
||||||
assert(subType == -1);
|
assert(subType == -1);
|
||||||
|
|
||||||
Common::Array<Object *> list;
|
Common::Array<Object *> list;
|
||||||
|
@ -71,7 +71,7 @@ public:
|
|||||||
kScroll = 33,
|
kScroll = 33,
|
||||||
kFMV = 34,
|
kFMV = 34,
|
||||||
kLipSync = 35,
|
kLipSync = 35,
|
||||||
kAnimScriptBonesTrigger = 36,
|
kAnimSoundTrigger = 36,
|
||||||
kString = 37,
|
kString = 37,
|
||||||
kTextureSet = 38
|
kTextureSet = 38
|
||||||
};
|
};
|
||||||
@ -233,7 +233,7 @@ public:
|
|||||||
|
|
||||||
/** Find a child matching the template parameter type and the specified subtype */
|
/** Find a child matching the template parameter type and the specified subtype */
|
||||||
template<class T>
|
template<class T>
|
||||||
T *findChildWithSubtype(int subType, bool mustBeUnique = true);
|
T *findChildWithSubtype(int subType, bool mustBeUnique = true) const;
|
||||||
|
|
||||||
/** Find a child matching the template parameter type and the specified index */
|
/** Find a child matching the template parameter type and the specified index */
|
||||||
template<class T>
|
template<class T>
|
||||||
@ -245,7 +245,7 @@ public:
|
|||||||
|
|
||||||
/** List children matching the template parameter type and the specified subtype */
|
/** List children matching the template parameter type and the specified subtype */
|
||||||
template<class T>
|
template<class T>
|
||||||
Common::Array<T *> listChildren(int subType = -1);
|
Common::Array<T *> listChildren(int subType = -1) const;
|
||||||
|
|
||||||
/** List children recursively matching the template parameter type and the specified subtype */
|
/** List children recursively matching the template parameter type and the specified subtype */
|
||||||
template<class T>
|
template<class T>
|
||||||
@ -320,7 +320,7 @@ template<>
|
|||||||
Object *Object::findParent();
|
Object *Object::findParent();
|
||||||
|
|
||||||
template <class T>
|
template <class T>
|
||||||
Common::Array<T *> Object::listChildren(int subType) {
|
Common::Array<T *> Object::listChildren(int subType) const {
|
||||||
Common::Array<T *> list;
|
Common::Array<T *> list;
|
||||||
|
|
||||||
for (uint i = 0; i < _children.size(); i++) {
|
for (uint i = 0; i < _children.size(); i++) {
|
||||||
@ -353,7 +353,7 @@ Common::Array<T *> Object::listChildrenRecursive(int subType) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
template<>
|
template<>
|
||||||
Common::Array<Object *> Object::listChildren<Object>(int subType);
|
Common::Array<Object *> Object::listChildren<Object>(int subType) const;
|
||||||
|
|
||||||
template<class T>
|
template<class T>
|
||||||
T *Object::findChild(bool mustBeUnique) {
|
T *Object::findChild(bool mustBeUnique) {
|
||||||
@ -361,7 +361,7 @@ T *Object::findChild(bool mustBeUnique) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
template <class T>
|
template <class T>
|
||||||
T *Object::findChildWithSubtype(int subType, bool mustBeUnique) {
|
T *Object::findChildWithSubtype(int subType, bool mustBeUnique) const {
|
||||||
Common::Array<T *> list = listChildren<T>(subType);
|
Common::Array<T *> list = listChildren<T>(subType);
|
||||||
|
|
||||||
if (list.empty()) {
|
if (list.empty()) {
|
||||||
|
@ -181,5 +181,9 @@ void Sound::onGameLoop() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
uint32 Sound::getStockSoundType() const {
|
||||||
|
return _stockSoundType;
|
||||||
|
}
|
||||||
} // End of namespace Resources
|
} // End of namespace Resources
|
||||||
} // End of namespace Stark
|
} // End of namespace Stark
|
||||||
|
@ -48,6 +48,10 @@ class Sound : public Object {
|
|||||||
public:
|
public:
|
||||||
static const Type::ResourceType TYPE = Type::kSoundItem;
|
static const Type::ResourceType TYPE = Type::kSoundItem;
|
||||||
|
|
||||||
|
enum SubType {
|
||||||
|
kSoundStock = 5
|
||||||
|
};
|
||||||
|
|
||||||
enum SoundType {
|
enum SoundType {
|
||||||
kSoundTypeVoice = 0,
|
kSoundTypeVoice = 0,
|
||||||
kSoundTypeEffect = 1,
|
kSoundTypeEffect = 1,
|
||||||
@ -71,6 +75,9 @@ public:
|
|||||||
/** Stop the sound */
|
/** Stop the sound */
|
||||||
void stop();
|
void stop();
|
||||||
|
|
||||||
|
/** Get the type for stock sounds */
|
||||||
|
uint32 getStockSoundType() const;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
void printData() override;
|
void printData() override;
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user