mirror of
https://github.com/TES3MP/openmw-tes3mp.git
synced 2025-02-01 19:45:33 +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)
|
||||
return;
|
||||
|
||||
mAnimation->setTextKeyListener(this);
|
||||
|
||||
const MWWorld::Class &cls = mPtr.getClass();
|
||||
if(cls.isActor())
|
||||
{
|
||||
|
@ -698,8 +700,147 @@ CharacterController::CharacterController(const MWWorld::Ptr &ptr, MWRender::Anim
|
|||
|
||||
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)
|
||||
{
|
||||
|
|
|
@ -7,6 +7,8 @@
|
|||
|
||||
#include "../mwworld/ptr.hpp"
|
||||
|
||||
#include "../mwrender/animation.hpp"
|
||||
|
||||
namespace MWWorld
|
||||
{
|
||||
class ContainerStoreIterator;
|
||||
|
@ -134,7 +136,7 @@ enum JumpingState {
|
|||
JumpState_Landing
|
||||
};
|
||||
|
||||
class CharacterController
|
||||
class CharacterController : public MWRender::Animation::TextKeyListener
|
||||
{
|
||||
MWWorld::Ptr mPtr;
|
||||
MWRender::Animation *mAnimation;
|
||||
|
@ -205,6 +207,9 @@ public:
|
|||
CharacterController(const MWWorld::Ptr &ptr, MWRender::Animation *anim);
|
||||
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
|
||||
void updateContinuousVfx();
|
||||
|
||||
|
|
|
@ -238,6 +238,7 @@ namespace MWRender
|
|||
, mInsert(parentNode)
|
||||
, mResourceSystem(resourceSystem)
|
||||
, mAccumulate(1.f, 1.f, 0.f)
|
||||
, mTextKeyListener(NULL)
|
||||
{
|
||||
for(size_t i = 0;i < sNumGroups;i++)
|
||||
mAnimationTimePtr[i].reset(new AnimationTime(this));
|
||||
|
@ -426,7 +427,8 @@ namespace MWRender
|
|||
else if(evt.compare(off, len, "loop stop") == 0)
|
||||
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,
|
||||
|
@ -590,6 +592,11 @@ namespace MWRender
|
|||
return true;
|
||||
}
|
||||
|
||||
void Animation::setTextKeyListener(Animation::TextKeyListener *listener)
|
||||
{
|
||||
mTextKeyListener = listener;
|
||||
}
|
||||
|
||||
void Animation::resetActiveGroups()
|
||||
{
|
||||
// remove all previous external controllers from the scene graph
|
||||
|
|
|
@ -54,6 +54,15 @@ public:
|
|||
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:
|
||||
/* This is the number of *discrete* groups. */
|
||||
static const size_t sNumGroups = 4;
|
||||
|
@ -203,6 +212,8 @@ protected:
|
|||
|
||||
std::vector<EffectParams> mEffects;
|
||||
|
||||
TextKeyListener* mTextKeyListener;
|
||||
|
||||
/* Sets the appropriate animations on the bone groups based on priority.
|
||||
*/
|
||||
void resetActiveGroups();
|
||||
|
|
|
@ -158,7 +158,7 @@ void Objects::insertNPC(const MWWorld::Ptr &ptr)
|
|||
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())
|
||||
return true;
|
||||
|
|
|
@ -66,7 +66,7 @@ public:
|
|||
//Ogre::AxisAlignedBox getDimensions(MWWorld::CellStore*);
|
||||
///< 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?
|
||||
|
||||
void removeCell(const MWWorld::CellStore* store);
|
||||
|
|
|
@ -285,6 +285,11 @@ namespace MWRender
|
|||
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)
|
||||
{
|
||||
mObjects->updatePtr(old, updated);
|
||||
|
|
|
@ -71,6 +71,8 @@ namespace MWRender
|
|||
void moveObject(const MWWorld::Ptr& ptr, const osg::Vec3f& pos);
|
||||
void scaleObject(const MWWorld::Ptr& ptr, const osg::Vec3f& scale);
|
||||
|
||||
void removeObject(const MWWorld::Ptr& ptr);
|
||||
|
||||
void setSkyEnabled(bool enabled);
|
||||
|
||||
bool toggleRenderMode(RenderMode mode);
|
||||
|
|
|
@ -210,12 +210,12 @@ namespace MWWorld
|
|||
mPhysics->removeHeightField ((*iter)->getCell()->getGridX(), (*iter)->getCell()->getGridY());
|
||||
}
|
||||
|
||||
MWBase::Environment::get().getMechanicsManager()->drop (*iter);
|
||||
|
||||
mRendering.removeCell(*iter);
|
||||
|
||||
MWBase::Environment::get().getWorld()->getLocalScripts().clearCell (*iter);
|
||||
|
||||
MWBase::Environment::get().getMechanicsManager()->drop (*iter);
|
||||
|
||||
MWBase::Environment::get().getSoundManager()->stopSound (*iter);
|
||||
mActiveCells.erase(*iter);
|
||||
}
|
||||
|
@ -563,7 +563,7 @@ namespace MWWorld
|
|||
MWBase::Environment::get().getMechanicsManager()->remove (ptr);
|
||||
MWBase::Environment::get().getSoundManager()->stopSound3D (ptr);
|
||||
mPhysics->remove(ptr);
|
||||
//mRendering.removeObject (ptr);
|
||||
mRendering.removeObject (ptr);
|
||||
}
|
||||
|
||||
bool Scene::isCellActive(const CellStore &cell)
|
||||
|
|
Loading…
Reference in a new issue