mirror of
				https://github.com/OpenMW/openmw.git
				synced 2025-10-31 20:56:39 +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