diff --git a/apps/openmw/mwmechanics/aicombat.cpp b/apps/openmw/mwmechanics/aicombat.cpp index a3e7cb6a26..38bd9ed4b5 100644 --- a/apps/openmw/mwmechanics/aicombat.cpp +++ b/apps/openmw/mwmechanics/aicombat.cpp @@ -703,7 +703,7 @@ std::string chooseBestAttack(const ESM::Weapon* weapon) attackType = "chop"; } else - MWMechanics::CharacterController::setAttackTypeRandomly(attackType); + attackType = MWMechanics::CharacterController::getRandomAttackType(); return attackType; } diff --git a/apps/openmw/mwmechanics/character.cpp b/apps/openmw/mwmechanics/character.cpp index 209229efc5..471ec7b5f4 100644 --- a/apps/openmw/mwmechanics/character.cpp +++ b/apps/openmw/mwmechanics/character.cpp @@ -385,7 +385,7 @@ void CharacterController::refreshJumpAnims(const std::string& weapShortGroup, Ju } } -bool CharacterController::onOpen() +bool CharacterController::onOpen() const { if (mPtr.getType() == ESM::Container::sRecordId) { @@ -406,7 +406,7 @@ bool CharacterController::onOpen() return true; } -void CharacterController::onClose() +void CharacterController::onClose() const { if (mPtr.getType() == ESM::Container::sRecordId) { @@ -445,7 +445,7 @@ std::string CharacterController::getWeaponAnimation(int weaponType) const return weaponGroup; } -std::string CharacterController::fallbackShortWeaponGroup(const std::string& baseGroupName, MWRender::Animation::BlendMask* blendMask) +std::string CharacterController::fallbackShortWeaponGroup(const std::string& baseGroupName, MWRender::Animation::BlendMask* blendMask) const { bool isRealWeapon = mWeaponType != ESM::Weapon::HandToHand && mWeaponType != ESM::Weapon::Spell && mWeaponType != ESM::Weapon::None; if (!isRealWeapon) @@ -561,7 +561,7 @@ void CharacterController::refreshMovementAnims(const std::string& weapShortGroup std::string::size_type runpos = movementAnimName.find("run"); if (runpos != std::string::npos) { - movementAnimName.replace(runpos, runpos+3, "walk"); + movementAnimName.replace(runpos, 3, "walk"); if (!mAnimation->hasAnimation(movementAnimName)) movementAnimName.clear(); } @@ -842,28 +842,7 @@ std::string CharacterController::chooseRandomAttackAnimation() const CharacterController::CharacterController(const MWWorld::Ptr &ptr, MWRender::Animation *anim) : mPtr(ptr) - , mWeapon(MWWorld::Ptr()) , mAnimation(anim) - , mIdleState(CharState_None) - , mMovementState(CharState_None) - , mMovementAnimSpeed(0.f) - , mAdjustMovementAnimSpeed(false) - , mHasMovedInXY(false) - , mMovementAnimationControlled(true) - , mDeathState(CharState_None) - , mFloatToSurface(true) - , mHitState(CharState_None) - , mUpperBodyState(UpperCharState_Nothing) - , mJumpState(JumpState_None) - , mWeaponType(ESM::Weapon::None) - , mAttackStrength(0.f) - , mSkipAnim(false) - , mSecondsOfSwimming(0) - , mSecondsOfRunning(0) - , mTurnAnimationThreshold(0) - , mCastingManualSpell(false) - , mTimeUntilWake(0.f) - , mIsMovingBackward(false) { if(!mAnimation) return; @@ -949,9 +928,9 @@ CharacterController::~CharacterController() } } -void CharacterController::handleTextKey(const std::string &groupname, SceneUtil::TextKeyMap::ConstIterator key, const SceneUtil::TextKeyMap& map) +void CharacterController::handleTextKey(std::string_view groupname, SceneUtil::TextKeyMap::ConstIterator key, const SceneUtil::TextKeyMap& map) { - const std::string &evt = key->second; + std::string_view evt = key->second; if(evt.compare(0, 7, "sound: ") == 0) { @@ -963,7 +942,7 @@ void CharacterController::handleTextKey(const std::string &groupname, SceneUtil: auto& charClass = mPtr.getClass(); if(evt.compare(0, 10, "soundgen: ") == 0) { - std::string soundgen = evt.substr(10); + std::string soundgen = std::string(evt.substr(10)); // The event can optionally contain volume and pitch modifiers float volume=1.f, pitch=1.f; @@ -1043,16 +1022,18 @@ void CharacterController::handleTextKey(const std::string &groupname, SceneUtil: { std::multimap::const_iterator hitKey = key; + std::string hitKeyName = std::string(groupname) + ": hit"; + std::string stopKeyName = std::string(groupname) + ": stop"; // 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") + if (hitKey->second == hitKeyName) { hasHitKey = true; break; } - if (hitKey->second == groupname + ": stop") + if (hitKey->second == stopKeyName) break; ++hitKey; } @@ -1093,7 +1074,7 @@ void CharacterController::updatePtr(const MWWorld::Ptr &ptr) mPtr = ptr; } -void CharacterController::updateIdleStormState(bool inwater) +void CharacterController::updateIdleStormState(bool inwater) const { if (!mAnimation->hasAnimation("idlestorm") || mUpperBodyState != UpperCharState_Nothing || inwater) { @@ -1548,12 +1529,12 @@ bool CharacterController::updateState(CharacterState idle) else { // There is no "best attack" for Hand-to-Hand - setAttackTypeRandomly(mAttackType); + mAttackType = getRandomAttackType(); } } else { - setAttackTypeBasedOnMovement(); + mAttackType = getMovementBasedAttackType(); } } // else if (mPtr != getPlayer()) use mAttackType set by AiCombat @@ -2382,7 +2363,7 @@ void CharacterController::update(float duration) mAnimation->enableHeadAnimation(cls.isActor() && !cls.getCreatureStats(mPtr).isDead()); } -void CharacterController::persistAnimationState() +void CharacterController::persistAnimationState() const { ESM::AnimationState& state = mPtr.getRefData().getAnimationState(); @@ -2518,18 +2499,18 @@ void CharacterController::skipAnim() mSkipAnim = true; } -bool CharacterController::isPersistentAnimPlaying() +bool CharacterController::isPersistentAnimPlaying() const { if (!mAnimQueue.empty()) { - AnimationQueueEntry& first = mAnimQueue.front(); + const AnimationQueueEntry& first = mAnimQueue.front(); return first.mPersist && isAnimPlaying(first.mGroup); } return false; } -bool CharacterController::isAnimPlaying(const std::string &groupName) +bool CharacterController::isAnimPlaying(const std::string &groupName) const { if(mAnimation == nullptr) return false; @@ -2542,9 +2523,15 @@ void CharacterController::clearAnimQueue(bool clearPersistAnims) if ((!isPersistentAnimPlaying() || clearPersistAnims) && !mAnimQueue.empty()) mAnimation->disable(mAnimQueue.front().mGroup); + if (clearPersistAnims) + { + mAnimQueue.clear(); + return; + } + for (AnimationQueue::iterator it = mAnimQueue.begin(); it != mAnimQueue.end();) { - if (clearPersistAnims || !it->mPersist) + if (!it->mPersist) it = mAnimQueue.erase(it); else ++it; @@ -2610,7 +2597,7 @@ void CharacterController::resurrect() mWeaponType = ESM::Weapon::None; } -void CharacterController::updateContinuousVfx() +void CharacterController::updateContinuousVfx() const { // Keeping track of when to stop a continuous VFX seems to be very difficult to do inside the spells code, // as it's extremely spread out (ActiveSpells, Spells, InventoryStore effects, etc...) so we do it here. @@ -2627,7 +2614,7 @@ void CharacterController::updateContinuousVfx() } } -void CharacterController::updateMagicEffects() +void CharacterController::updateMagicEffects() const { if (!mPtr.getClass().isActor()) return; @@ -2643,7 +2630,7 @@ void CharacterController::updateMagicEffects() mAnimation->setVampire(vampire); } -void CharacterController::setVisibility(float visibility) +void CharacterController::setVisibility(float visibility) const { // We should take actor's invisibility in account if (mPtr.getClass().isActor()) @@ -2669,18 +2656,17 @@ void CharacterController::setVisibility(float visibility) mAnimation->setAlpha(visibility); } -void CharacterController::setAttackTypeBasedOnMovement() +std::string CharacterController::getMovementBasedAttackType() const { float *move = mPtr.getClass().getMovementSettings(mPtr).mPosition; if (std::abs(move[1]) > std::abs(move[0]) + 0.2f) // forward-backward - mAttackType = "thrust"; - else if (std::abs(move[0]) > std::abs(move[1]) + 0.2f) // sideway - mAttackType = "slash"; - else - mAttackType = "chop"; + return "thrust"; + if (std::abs(move[0]) > std::abs(move[1]) + 0.2f) // sideway + return "slash"; + return "chop"; } -bool CharacterController::isRandomAttackAnimation(const std::string& group) const +bool CharacterController::isRandomAttackAnimation(std::string_view group) { return (group == "attack1" || group == "swimattack1" || group == "attack2" || group == "swimattack2" || @@ -2774,16 +2760,15 @@ void CharacterController::setAIAttackType(const std::string& attackType) mAttackType = attackType; } -void CharacterController::setAttackTypeRandomly(std::string& attackType) +std::string CharacterController::getRandomAttackType() { MWBase::World* world = MWBase::Environment::get().getWorld(); float random = Misc::Rng::rollProbability(world->getPrng()); if (random >= 2/3.f) - attackType = "thrust"; - else if (random >= 1/3.f) - attackType = "slash"; - else - attackType = "chop"; + return "thrust"; + if (random >= 1/3.f) + return "slash"; + return "chop"; } bool CharacterController::readyToPrepareAttack() const @@ -2805,12 +2790,12 @@ float CharacterController::getAttackStrength() const return mAttackStrength; } -bool CharacterController::getAttackingOrSpell() +bool CharacterController::getAttackingOrSpell() const { return mPtr.getClass().getCreatureStats(mPtr).getAttackingOrSpell(); } -void CharacterController::setActive(int active) +void CharacterController::setActive(int active) const { mAnimation->setActive(active); } @@ -2820,7 +2805,7 @@ void CharacterController::setHeadTrackTarget(const MWWorld::ConstPtr &target) mHeadTrackTarget = target; } -void CharacterController::playSwishSound(float attackStrength) +void CharacterController::playSwishSound(float attackStrength) const { MWBase::SoundManager *sndMgr = MWBase::Environment::get().getSoundManager(); diff --git a/apps/openmw/mwmechanics/character.hpp b/apps/openmw/mwmechanics/character.hpp index 38f7a48a2b..ac53dd4d45 100644 --- a/apps/openmw/mwmechanics/character.hpp +++ b/apps/openmw/mwmechanics/character.hpp @@ -149,53 +149,53 @@ class CharacterController : public MWRender::Animation::TextKeyListener typedef std::deque AnimationQueue; AnimationQueue mAnimQueue; - CharacterState mIdleState; + CharacterState mIdleState{CharState_None}; std::string mCurrentIdle; - CharacterState mMovementState; + CharacterState mMovementState{CharState_None}; std::string mCurrentMovement; - float mMovementAnimSpeed; - bool mAdjustMovementAnimSpeed; - bool mHasMovedInXY; - bool mMovementAnimationControlled; + float mMovementAnimSpeed{0.f}; + bool mAdjustMovementAnimSpeed{false}; + bool mHasMovedInXY{false}; + bool mMovementAnimationControlled{true}; - CharacterState mDeathState; + CharacterState mDeathState{CharState_None}; std::string mCurrentDeath; - bool mFloatToSurface; + bool mFloatToSurface{true}; - CharacterState mHitState; + CharacterState mHitState{CharState_None}; std::string mCurrentHit; - UpperBodyCharacterState mUpperBodyState; + UpperBodyCharacterState mUpperBodyState{UpperCharState_Nothing}; - JumpingState mJumpState; + JumpingState mJumpState{JumpState_None}; std::string mCurrentJump; - int mWeaponType; + int mWeaponType{ESM::Weapon::None}; std::string mCurrentWeapon; - float mAttackStrength; + float mAttackStrength{0.f}; - bool mSkipAnim; + bool mSkipAnim{false}; // counted for skill increase - float mSecondsOfSwimming; - float mSecondsOfRunning; + float mSecondsOfSwimming{0.f}; + float mSecondsOfRunning{0.f}; MWWorld::ConstPtr mHeadTrackTarget; - float mTurnAnimationThreshold; // how long to continue playing turning animation after actor stopped turning + float mTurnAnimationThreshold{0.f}; // how long to continue playing turning animation after actor stopped turning std::string mAttackType; // slash, chop or thrust - bool mCastingManualSpell; + bool mCastingManualSpell{false}; - float mTimeUntilWake; + float mTimeUntilWake{0.f}; - bool mIsMovingBackward; + bool mIsMovingBackward{false}; osg::Vec2f mSmoothedSpeed; - void setAttackTypeBasedOnMovement(); + std::string getMovementBasedAttackType() const; void refreshCurrentAnims(CharacterState idle, CharacterState movement, JumpingState jump, bool force=false); void refreshHitRecoilAnims(CharacterState& idle); @@ -206,18 +206,18 @@ class CharacterController : public MWRender::Animation::TextKeyListener void clearAnimQueue(bool clearPersistAnims = false); bool updateState(CharacterState idle); - void updateIdleStormState(bool inwater); + void updateIdleStormState(bool inwater) const; std::string chooseRandomAttackAnimation() const; - bool isRandomAttackAnimation(const std::string& group) const; + static bool isRandomAttackAnimation(std::string_view group); - bool isPersistentAnimPlaying(); + bool isPersistentAnimPlaying() const; void updateAnimQueue(); void updateHeadTracking(float duration); - void updateMagicEffects(); + void updateMagicEffects() const; void playDeath(float startpoint, CharacterState death); CharacterState chooseRandomDeathState() const; @@ -229,11 +229,11 @@ class CharacterController : public MWRender::Animation::TextKeyListener bool updateCarriedLeftVisible(int weaptype) const; - std::string fallbackShortWeaponGroup(const std::string& baseGroupName, MWRender::Animation::BlendMask* blendMask = nullptr); + std::string fallbackShortWeaponGroup(const std::string& baseGroupName, MWRender::Animation::BlendMask* blendMask = nullptr) const; std::string getWeaponAnimation(int weaponType) const; - bool getAttackingOrSpell(); + bool getAttackingOrSpell() const; void setAttackingOrSpell(bool attackingOrSpell); @@ -246,24 +246,24 @@ public: const MWWorld::Ptr& getPtr() const { return mPtr; } - void handleTextKey(const std::string &groupname, SceneUtil::TextKeyMap::ConstIterator key, const SceneUtil::TextKeyMap& map) override; + void handleTextKey(std::string_view groupname, SceneUtil::TextKeyMap::ConstIterator key, const SceneUtil::TextKeyMap& map) override; // Be careful when to call this, see comment in Actors - void updateContinuousVfx(); + void updateContinuousVfx() const; void updatePtr(const MWWorld::Ptr &ptr); void update(float duration); - bool onOpen(); - void onClose(); + bool onOpen() const; + void onClose() const; - void persistAnimationState(); + void persistAnimationState() const; void unpersistAnimationState(); bool playGroup(const std::string &groupname, int mode, int count, bool persist=false); void skipAnim(); - bool isAnimPlaying(const std::string &groupName); + bool isAnimPlaying(const std::string &groupName) const; enum KillResult { @@ -291,10 +291,10 @@ public: bool isTurning() const; bool isAttackingOrSpell() const; - void setVisibility(float visibility); + void setVisibility(float visibility) const; void castSpell(const std::string& spellId, bool manualSpell=false); void setAIAttackType(const std::string& attackType); - static void setAttackTypeRandomly(std::string& attackType); + static std::string getRandomAttackType(); bool readyToPrepareAttack() const; bool readyToStartAttack() const; @@ -302,12 +302,12 @@ public: float getAttackStrength() const; /// @see Animation::setActive - void setActive(int active); + void setActive(int active) const; /// Make this character turn its head towards \a target. To turn off head tracking, pass an empty Ptr. void setHeadTrackTarget(const MWWorld::ConstPtr& target); - void playSwishSound(float attackStrength); + void playSwishSound(float attackStrength) const; }; } diff --git a/apps/openmw/mwrender/animation.hpp b/apps/openmw/mwrender/animation.hpp index 1bad0f8d95..ed1ddb78d2 100644 --- a/apps/openmw/mwrender/animation.hpp +++ b/apps/openmw/mwrender/animation.hpp @@ -149,7 +149,7 @@ public: class TextKeyListener { public: - virtual void handleTextKey(const std::string &groupname, SceneUtil::TextKeyMap::ConstIterator key, + virtual void handleTextKey(std::string_view groupname, SceneUtil::TextKeyMap::ConstIterator key, const SceneUtil::TextKeyMap& map) = 0; virtual ~TextKeyListener() = default;