mirror of
https://github.com/TES3MP/openmw-tes3mp.git
synced 2025-02-02 01:45:31 +00:00
Restore animation text key handling
This commit is contained in:
parent
9b8e2e9db3
commit
2235d2978b
9 changed files with 178 additions and 7 deletions
|
@ -648,6 +648,8 @@ CharacterController::CharacterController(const MWWorld::Ptr &ptr, MWRender::Anim
|
||||||
if(!mAnimation)
|
if(!mAnimation)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
mAnimation->setTextKeyListener(this);
|
||||||
|
|
||||||
const MWWorld::Class &cls = mPtr.getClass();
|
const MWWorld::Class &cls = mPtr.getClass();
|
||||||
if(cls.isActor())
|
if(cls.isActor())
|
||||||
{
|
{
|
||||||
|
@ -698,8 +700,147 @@ CharacterController::CharacterController(const MWWorld::Ptr &ptr, MWRender::Anim
|
||||||
|
|
||||||
CharacterController::~CharacterController()
|
CharacterController::~CharacterController()
|
||||||
{
|
{
|
||||||
|
if (mAnimation)
|
||||||
|
mAnimation->setTextKeyListener(NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void split(const std::string &s, char delim, std::vector<std::string> &elems) {
|
||||||
|
std::stringstream ss(s);
|
||||||
|
std::string item;
|
||||||
|
while (std::getline(ss, item, delim)) {
|
||||||
|
elems.push_back(item);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void CharacterController::handleTextKey(const std::string &groupname, const std::multimap<float, std::string>::const_iterator &key, const std::multimap<float, std::string> &map)
|
||||||
|
{
|
||||||
|
const std::string &evt = key->second;
|
||||||
|
|
||||||
|
if(evt.compare(0, 7, "sound: ") == 0)
|
||||||
|
{
|
||||||
|
MWBase::SoundManager *sndMgr = MWBase::Environment::get().getSoundManager();
|
||||||
|
sndMgr->playSound3D(mPtr, evt.substr(7), 1.0f, 1.0f);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if(evt.compare(0, 10, "soundgen: ") == 0)
|
||||||
|
{
|
||||||
|
std::string soundgen = evt.substr(10);
|
||||||
|
|
||||||
|
// The event can optionally contain volume and pitch modifiers
|
||||||
|
float volume=1.f, pitch=1.f;
|
||||||
|
if (soundgen.find(" ") != std::string::npos)
|
||||||
|
{
|
||||||
|
std::vector<std::string> tokens;
|
||||||
|
split(soundgen, ' ', tokens);
|
||||||
|
soundgen = tokens[0];
|
||||||
|
if (tokens.size() >= 2)
|
||||||
|
volume = Ogre::StringConverter::parseReal(tokens[1]);
|
||||||
|
if (tokens.size() >= 3)
|
||||||
|
pitch = Ogre::StringConverter::parseReal(tokens[2]);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string sound = mPtr.getClass().getSoundIdFromSndGen(mPtr, soundgen);
|
||||||
|
if(!sound.empty())
|
||||||
|
{
|
||||||
|
MWBase::SoundManager *sndMgr = MWBase::Environment::get().getSoundManager();
|
||||||
|
MWBase::SoundManager::PlayType type = MWBase::SoundManager::Play_TypeSfx;
|
||||||
|
if(evt.compare(10, evt.size()-10, "left") == 0 || evt.compare(10, evt.size()-10, "right") == 0 || evt.compare(10, evt.size()-10, "land") == 0)
|
||||||
|
type = MWBase::SoundManager::Play_TypeFoot;
|
||||||
|
sndMgr->playSound3D(mPtr, sound, volume, pitch, type);
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(evt.compare(0, groupname.size(), groupname) != 0 ||
|
||||||
|
evt.compare(groupname.size(), 2, ": ") != 0)
|
||||||
|
{
|
||||||
|
// Not ours, skip it
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
size_t off = groupname.size()+2;
|
||||||
|
size_t len = evt.size() - off;
|
||||||
|
|
||||||
|
if(evt.compare(off, len, "equip attach") == 0)
|
||||||
|
mAnimation->showWeapons(true);
|
||||||
|
else if(evt.compare(off, len, "unequip detach") == 0)
|
||||||
|
mAnimation->showWeapons(false);
|
||||||
|
else if(evt.compare(off, len, "chop hit") == 0)
|
||||||
|
mPtr.getClass().hit(mPtr, ESM::Weapon::AT_Chop);
|
||||||
|
else if(evt.compare(off, len, "slash hit") == 0)
|
||||||
|
mPtr.getClass().hit(mPtr, ESM::Weapon::AT_Slash);
|
||||||
|
else if(evt.compare(off, len, "thrust hit") == 0)
|
||||||
|
mPtr.getClass().hit(mPtr, ESM::Weapon::AT_Thrust);
|
||||||
|
else if(evt.compare(off, len, "hit") == 0)
|
||||||
|
{
|
||||||
|
if (groupname == "attack1")
|
||||||
|
mPtr.getClass().hit(mPtr, ESM::Weapon::AT_Chop);
|
||||||
|
else if (groupname == "attack2")
|
||||||
|
mPtr.getClass().hit(mPtr, ESM::Weapon::AT_Slash);
|
||||||
|
else if (groupname == "attack3")
|
||||||
|
mPtr.getClass().hit(mPtr, ESM::Weapon::AT_Thrust);
|
||||||
|
else
|
||||||
|
mPtr.getClass().hit(mPtr);
|
||||||
|
}
|
||||||
|
else if (!groupname.empty() && groupname.compare(0, groupname.size()-1, "attack") == 0
|
||||||
|
&& evt.compare(off, len, "start") == 0)
|
||||||
|
{
|
||||||
|
std::multimap<float, std::string>::const_iterator hitKey = key;
|
||||||
|
|
||||||
|
// Not all animations have a hit key defined. If there is none, the hit happens with the start key.
|
||||||
|
bool hasHitKey = false;
|
||||||
|
while (hitKey != map.end())
|
||||||
|
{
|
||||||
|
if (hitKey->second == groupname + ": hit")
|
||||||
|
{
|
||||||
|
hasHitKey = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (hitKey->second == groupname + ": stop")
|
||||||
|
break;
|
||||||
|
++hitKey;
|
||||||
|
}
|
||||||
|
if (!hasHitKey)
|
||||||
|
{
|
||||||
|
if (groupname == "attack1")
|
||||||
|
mPtr.getClass().hit(mPtr, ESM::Weapon::AT_Chop);
|
||||||
|
else if (groupname == "attack2")
|
||||||
|
mPtr.getClass().hit(mPtr, ESM::Weapon::AT_Slash);
|
||||||
|
else if (groupname == "attack3")
|
||||||
|
mPtr.getClass().hit(mPtr, ESM::Weapon::AT_Thrust);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (evt.compare(off, len, "shoot attach") == 0)
|
||||||
|
mAnimation->attachArrow();
|
||||||
|
else if (evt.compare(off, len, "shoot release") == 0)
|
||||||
|
{;}//mAnimation->releaseArrow();
|
||||||
|
else if (evt.compare(off, len, "shoot follow attach") == 0)
|
||||||
|
mAnimation->attachArrow();
|
||||||
|
|
||||||
|
else if (groupname == "spellcast" && evt.substr(evt.size()-7, 7) == "release")
|
||||||
|
{
|
||||||
|
// Make sure this key is actually for the RangeType we are casting. The flame atronach has
|
||||||
|
// the same animation for all range types, so there are 3 "release" keys on the same time, one for each range type.
|
||||||
|
// FIXME: compare with mCurrentWeapon instead
|
||||||
|
const std::string& spellid = mPtr.getClass().getCreatureStats(mPtr).getSpells().getSelectedSpell();
|
||||||
|
const ESM::Spell* spell = MWBase::Environment::get().getWorld()->getStore().get<ESM::Spell>().find(spellid);
|
||||||
|
const ESM::ENAMstruct &effectentry = spell->mEffects.mList.at(0);
|
||||||
|
int range = 0;
|
||||||
|
if (evt.compare(off, len, "self release") == 0)
|
||||||
|
range = 0;
|
||||||
|
else if (evt.compare(off, len, "touch release") == 0)
|
||||||
|
range = 1;
|
||||||
|
else if (evt.compare(off, len, "target release") == 0)
|
||||||
|
range = 2;
|
||||||
|
if (effectentry.mRange == range)
|
||||||
|
{
|
||||||
|
MWBase::Environment::get().getWorld()->castSpell(mPtr);
|
||||||
|
}
|
||||||
|
std::cout << "current attack: " << mCurrentWeapon << std::endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
else if (groupname == "shield" && evt.compare(off, len, "block hit") == 0)
|
||||||
|
mPtr.getClass().block(mPtr);
|
||||||
|
}
|
||||||
|
|
||||||
void CharacterController::updatePtr(const MWWorld::Ptr &ptr)
|
void CharacterController::updatePtr(const MWWorld::Ptr &ptr)
|
||||||
{
|
{
|
||||||
|
|
|
@ -7,6 +7,8 @@
|
||||||
|
|
||||||
#include "../mwworld/ptr.hpp"
|
#include "../mwworld/ptr.hpp"
|
||||||
|
|
||||||
|
#include "../mwrender/animation.hpp"
|
||||||
|
|
||||||
namespace MWWorld
|
namespace MWWorld
|
||||||
{
|
{
|
||||||
class ContainerStoreIterator;
|
class ContainerStoreIterator;
|
||||||
|
@ -134,7 +136,7 @@ enum JumpingState {
|
||||||
JumpState_Landing
|
JumpState_Landing
|
||||||
};
|
};
|
||||||
|
|
||||||
class CharacterController
|
class CharacterController : public MWRender::Animation::TextKeyListener
|
||||||
{
|
{
|
||||||
MWWorld::Ptr mPtr;
|
MWWorld::Ptr mPtr;
|
||||||
MWRender::Animation *mAnimation;
|
MWRender::Animation *mAnimation;
|
||||||
|
@ -205,6 +207,9 @@ public:
|
||||||
CharacterController(const MWWorld::Ptr &ptr, MWRender::Animation *anim);
|
CharacterController(const MWWorld::Ptr &ptr, MWRender::Animation *anim);
|
||||||
virtual ~CharacterController();
|
virtual ~CharacterController();
|
||||||
|
|
||||||
|
virtual void handleTextKey(const std::string &groupname, const std::multimap<float, std::string>::const_iterator &key,
|
||||||
|
const std::multimap<float, std::string>& map);
|
||||||
|
|
||||||
// Be careful when to call this, see comment in Actors
|
// Be careful when to call this, see comment in Actors
|
||||||
void updateContinuousVfx();
|
void updateContinuousVfx();
|
||||||
|
|
||||||
|
|
|
@ -238,6 +238,7 @@ namespace MWRender
|
||||||
, mInsert(parentNode)
|
, mInsert(parentNode)
|
||||||
, mResourceSystem(resourceSystem)
|
, mResourceSystem(resourceSystem)
|
||||||
, mAccumulate(1.f, 1.f, 0.f)
|
, mAccumulate(1.f, 1.f, 0.f)
|
||||||
|
, mTextKeyListener(NULL)
|
||||||
{
|
{
|
||||||
for(size_t i = 0;i < sNumGroups;i++)
|
for(size_t i = 0;i < sNumGroups;i++)
|
||||||
mAnimationTimePtr[i].reset(new AnimationTime(this));
|
mAnimationTimePtr[i].reset(new AnimationTime(this));
|
||||||
|
@ -426,7 +427,8 @@ namespace MWRender
|
||||||
else if(evt.compare(off, len, "loop stop") == 0)
|
else if(evt.compare(off, len, "loop stop") == 0)
|
||||||
state.mLoopStopTime = key->first;
|
state.mLoopStopTime = key->first;
|
||||||
|
|
||||||
// TODO: forward to listener?
|
if (mTextKeyListener)
|
||||||
|
mTextKeyListener->handleTextKey(groupname, key, map);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Animation::play(const std::string &groupname, int priority, int groups, bool autodisable, float speedmult,
|
void Animation::play(const std::string &groupname, int priority, int groups, bool autodisable, float speedmult,
|
||||||
|
@ -590,6 +592,11 @@ namespace MWRender
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Animation::setTextKeyListener(Animation::TextKeyListener *listener)
|
||||||
|
{
|
||||||
|
mTextKeyListener = listener;
|
||||||
|
}
|
||||||
|
|
||||||
void Animation::resetActiveGroups()
|
void Animation::resetActiveGroups()
|
||||||
{
|
{
|
||||||
// remove all previous external controllers from the scene graph
|
// remove all previous external controllers from the scene graph
|
||||||
|
|
|
@ -54,6 +54,15 @@ public:
|
||||||
Group_All = Group_LowerBody | Group_UpperBody
|
Group_All = Group_LowerBody | Group_UpperBody
|
||||||
};
|
};
|
||||||
|
|
||||||
|
class TextKeyListener
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
virtual void handleTextKey(const std::string &groupname, const std::multimap<float, std::string>::const_iterator &key,
|
||||||
|
const std::multimap<float, std::string>& map) = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
void setTextKeyListener(TextKeyListener* listener);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
/* This is the number of *discrete* groups. */
|
/* This is the number of *discrete* groups. */
|
||||||
static const size_t sNumGroups = 4;
|
static const size_t sNumGroups = 4;
|
||||||
|
@ -203,6 +212,8 @@ protected:
|
||||||
|
|
||||||
std::vector<EffectParams> mEffects;
|
std::vector<EffectParams> mEffects;
|
||||||
|
|
||||||
|
TextKeyListener* mTextKeyListener;
|
||||||
|
|
||||||
/* Sets the appropriate animations on the bone groups based on priority.
|
/* Sets the appropriate animations on the bone groups based on priority.
|
||||||
*/
|
*/
|
||||||
void resetActiveGroups();
|
void resetActiveGroups();
|
||||||
|
|
|
@ -158,7 +158,7 @@ void Objects::insertNPC(const MWWorld::Ptr &ptr)
|
||||||
mObjects.insert(std::make_pair(ptr, anim.release()));
|
mObjects.insert(std::make_pair(ptr, anim.release()));
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Objects::deleteObject (const MWWorld::Ptr& ptr)
|
bool Objects::removeObject (const MWWorld::Ptr& ptr)
|
||||||
{
|
{
|
||||||
if(!ptr.getRefData().getBaseNode())
|
if(!ptr.getRefData().getBaseNode())
|
||||||
return true;
|
return true;
|
||||||
|
|
|
@ -66,7 +66,7 @@ public:
|
||||||
//Ogre::AxisAlignedBox getDimensions(MWWorld::CellStore*);
|
//Ogre::AxisAlignedBox getDimensions(MWWorld::CellStore*);
|
||||||
///< get a bounding box that encloses all objects in the specified cell
|
///< get a bounding box that encloses all objects in the specified cell
|
||||||
|
|
||||||
bool deleteObject (const MWWorld::Ptr& ptr);
|
bool removeObject (const MWWorld::Ptr& ptr);
|
||||||
///< \return found?
|
///< \return found?
|
||||||
|
|
||||||
void removeCell(const MWWorld::CellStore* store);
|
void removeCell(const MWWorld::CellStore* store);
|
||||||
|
|
|
@ -285,6 +285,11 @@ namespace MWRender
|
||||||
ptr.getRefData().getBaseNode()->setScale(scale);
|
ptr.getRefData().getBaseNode()->setScale(scale);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void RenderingManager::removeObject(const MWWorld::Ptr &ptr)
|
||||||
|
{
|
||||||
|
mObjects->removeObject(ptr);
|
||||||
|
}
|
||||||
|
|
||||||
void RenderingManager::updatePtr(const MWWorld::Ptr &old, const MWWorld::Ptr &updated)
|
void RenderingManager::updatePtr(const MWWorld::Ptr &old, const MWWorld::Ptr &updated)
|
||||||
{
|
{
|
||||||
mObjects->updatePtr(old, updated);
|
mObjects->updatePtr(old, updated);
|
||||||
|
|
|
@ -71,6 +71,8 @@ namespace MWRender
|
||||||
void moveObject(const MWWorld::Ptr& ptr, const osg::Vec3f& pos);
|
void moveObject(const MWWorld::Ptr& ptr, const osg::Vec3f& pos);
|
||||||
void scaleObject(const MWWorld::Ptr& ptr, const osg::Vec3f& scale);
|
void scaleObject(const MWWorld::Ptr& ptr, const osg::Vec3f& scale);
|
||||||
|
|
||||||
|
void removeObject(const MWWorld::Ptr& ptr);
|
||||||
|
|
||||||
void setSkyEnabled(bool enabled);
|
void setSkyEnabled(bool enabled);
|
||||||
|
|
||||||
bool toggleRenderMode(RenderMode mode);
|
bool toggleRenderMode(RenderMode mode);
|
||||||
|
|
|
@ -210,12 +210,12 @@ namespace MWWorld
|
||||||
mPhysics->removeHeightField ((*iter)->getCell()->getGridX(), (*iter)->getCell()->getGridY());
|
mPhysics->removeHeightField ((*iter)->getCell()->getGridX(), (*iter)->getCell()->getGridY());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
MWBase::Environment::get().getMechanicsManager()->drop (*iter);
|
||||||
|
|
||||||
mRendering.removeCell(*iter);
|
mRendering.removeCell(*iter);
|
||||||
|
|
||||||
MWBase::Environment::get().getWorld()->getLocalScripts().clearCell (*iter);
|
MWBase::Environment::get().getWorld()->getLocalScripts().clearCell (*iter);
|
||||||
|
|
||||||
MWBase::Environment::get().getMechanicsManager()->drop (*iter);
|
|
||||||
|
|
||||||
MWBase::Environment::get().getSoundManager()->stopSound (*iter);
|
MWBase::Environment::get().getSoundManager()->stopSound (*iter);
|
||||||
mActiveCells.erase(*iter);
|
mActiveCells.erase(*iter);
|
||||||
}
|
}
|
||||||
|
@ -563,7 +563,7 @@ namespace MWWorld
|
||||||
MWBase::Environment::get().getMechanicsManager()->remove (ptr);
|
MWBase::Environment::get().getMechanicsManager()->remove (ptr);
|
||||||
MWBase::Environment::get().getSoundManager()->stopSound3D (ptr);
|
MWBase::Environment::get().getSoundManager()->stopSound3D (ptr);
|
||||||
mPhysics->remove(ptr);
|
mPhysics->remove(ptr);
|
||||||
//mRendering.removeObject (ptr);
|
mRendering.removeObject (ptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Scene::isCellActive(const CellStore &cell)
|
bool Scene::isCellActive(const CellStore &cell)
|
||||||
|
|
Loading…
Reference in a new issue