1 /*
2  * OpenMW - The completely unofficial reimplementation of Morrowind
3  *
4  * This file (character.cpp) is part of the OpenMW package.
5  *
6  * OpenMW is distributed as free software: you can redistribute it
7  * and/or modify it under the terms of the GNU General Public License
8  * version 3, as published by the Free Software Foundation.
9  *
10  * This program is distributed in the hope that it will be useful, but
11  * WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13  * General Public License for more details.
14  *
15  * You should have received a copy of the GNU General Public License
16  * version 3 along with this program. If not, see
17  * https://www.gnu.org/licenses/ .
18  */
19 
20 #include "character.hpp"
21 
22 #include <iostream>
23 
24 #include <components/misc/mathutil.hpp>
25 #include <components/misc/rng.hpp>
26 
27 #include <components/settings/settings.hpp>
28 
29 #include <components/sceneutil/positionattitudetransform.hpp>
30 
31 #include "../mwrender/animation.hpp"
32 
33 #include "../mwbase/environment.hpp"
34 #include "../mwbase/mechanicsmanager.hpp"
35 #include "../mwbase/world.hpp"
36 #include "../mwbase/soundmanager.hpp"
37 #include "../mwbase/windowmanager.hpp"
38 
39 #include "../mwworld/class.hpp"
40 #include "../mwworld/inventorystore.hpp"
41 #include "../mwworld/esmstore.hpp"
42 #include "../mwworld/player.hpp"
43 
44 #include "aicombataction.hpp"
45 #include "movement.hpp"
46 #include "npcstats.hpp"
47 #include "creaturestats.hpp"
48 #include "security.hpp"
49 #include "actorutil.hpp"
50 #include "spellcasting.hpp"
51 
52 namespace
53 {
54 
getBestAttack(const ESM::Weapon * weapon)55 std::string getBestAttack (const ESM::Weapon* weapon)
56 {
57     int slash = (weapon->mData.mSlash[0] + weapon->mData.mSlash[1])/2;
58     int chop = (weapon->mData.mChop[0] + weapon->mData.mChop[1])/2;
59     int thrust = (weapon->mData.mThrust[0] + weapon->mData.mThrust[1])/2;
60     if (slash == chop && slash == thrust)
61         return "slash";
62     else if (thrust >= chop && thrust >= slash)
63         return "thrust";
64     else if (slash >= chop && slash >= thrust)
65         return "slash";
66     else
67         return "chop";
68 }
69 
70 // Converts a movement Run state to its equivalent Walk state.
runStateToWalkState(MWMechanics::CharacterState state)71 MWMechanics::CharacterState runStateToWalkState (MWMechanics::CharacterState state)
72 {
73     using namespace MWMechanics;
74     CharacterState ret = state;
75     switch (state)
76     {
77         case CharState_RunForward:
78             ret = CharState_WalkForward;
79             break;
80         case CharState_RunBack:
81             ret = CharState_WalkBack;
82             break;
83         case CharState_RunLeft:
84             ret = CharState_WalkLeft;
85             break;
86         case CharState_RunRight:
87             ret = CharState_WalkRight;
88             break;
89         case CharState_SwimRunForward:
90             ret = CharState_SwimWalkForward;
91             break;
92         case CharState_SwimRunBack:
93             ret = CharState_SwimWalkBack;
94             break;
95         case CharState_SwimRunLeft:
96             ret = CharState_SwimWalkLeft;
97             break;
98         case CharState_SwimRunRight:
99             ret = CharState_SwimWalkRight;
100             break;
101         default:
102             break;
103     }
104     return ret;
105 }
106 
getFallDamage(const MWWorld::Ptr & ptr,float fallHeight)107 float getFallDamage(const MWWorld::Ptr& ptr, float fallHeight)
108 {
109     MWBase::World *world = MWBase::Environment::get().getWorld();
110     const MWWorld::Store<ESM::GameSetting> &store = world->getStore().get<ESM::GameSetting>();
111 
112     const float fallDistanceMin = store.find("fFallDamageDistanceMin")->mValue.getFloat();
113 
114     if (fallHeight >= fallDistanceMin)
115     {
116         const float acrobaticsSkill = static_cast<float>(ptr.getClass().getSkill(ptr, ESM::Skill::Acrobatics));
117         const float jumpSpellBonus = ptr.getClass().getCreatureStats(ptr).getMagicEffects().get(ESM::MagicEffect::Jump).getMagnitude();
118         const float fallAcroBase = store.find("fFallAcroBase")->mValue.getFloat();
119         const float fallAcroMult = store.find("fFallAcroMult")->mValue.getFloat();
120         const float fallDistanceBase = store.find("fFallDistanceBase")->mValue.getFloat();
121         const float fallDistanceMult = store.find("fFallDistanceMult")->mValue.getFloat();
122 
123         float x = fallHeight - fallDistanceMin;
124         x -= (1.5f * acrobaticsSkill) + jumpSpellBonus;
125         x = std::max(0.0f, x);
126 
127         float a = fallAcroBase + fallAcroMult * (100 - acrobaticsSkill);
128         x = fallDistanceBase + fallDistanceMult * x;
129         x *= a;
130 
131         return x;
132     }
133     return 0.f;
134 }
135 
136 }
137 
138 namespace MWMechanics
139 {
140 
141 struct StateInfo {
142     CharacterState state;
143     const char groupname[32];
144 };
145 
146 static const StateInfo sMovementList[] = {
147     { CharState_WalkForward, "walkforward" },
148     { CharState_WalkBack, "walkback" },
149     { CharState_WalkLeft, "walkleft" },
150     { CharState_WalkRight, "walkright" },
151 
152     { CharState_SwimWalkForward, "swimwalkforward" },
153     { CharState_SwimWalkBack, "swimwalkback" },
154     { CharState_SwimWalkLeft, "swimwalkleft" },
155     { CharState_SwimWalkRight, "swimwalkright" },
156 
157     { CharState_RunForward, "runforward" },
158     { CharState_RunBack, "runback" },
159     { CharState_RunLeft, "runleft" },
160     { CharState_RunRight, "runright" },
161 
162     { CharState_SwimRunForward, "swimrunforward" },
163     { CharState_SwimRunBack, "swimrunback" },
164     { CharState_SwimRunLeft, "swimrunleft" },
165     { CharState_SwimRunRight, "swimrunright" },
166 
167     { CharState_SneakForward, "sneakforward" },
168     { CharState_SneakBack, "sneakback" },
169     { CharState_SneakLeft, "sneakleft" },
170     { CharState_SneakRight, "sneakright" },
171 
172     { CharState_Jump, "jump" },
173 
174     { CharState_TurnLeft, "turnleft" },
175     { CharState_TurnRight, "turnright" },
176     { CharState_SwimTurnLeft, "swimturnleft" },
177     { CharState_SwimTurnRight, "swimturnright" },
178 };
179 static const StateInfo *sMovementListEnd = &sMovementList[sizeof(sMovementList)/sizeof(sMovementList[0])];
180 
181 
182 class FindCharState {
183     CharacterState state;
184 
185 public:
FindCharState(CharacterState _state)186     FindCharState(CharacterState _state) : state(_state) { }
187 
operator ()(const StateInfo & info) const188     bool operator()(const StateInfo &info) const
189     { return info.state == state; }
190 };
191 
192 
chooseRandomGroup(const std::string & prefix,int * num) const193 std::string CharacterController::chooseRandomGroup (const std::string& prefix, int* num) const
194 {
195     int numAnims=0;
196     while (mAnimation->hasAnimation(prefix + std::to_string(numAnims+1)))
197         ++numAnims;
198 
199     int roll = Misc::Rng::rollDice(numAnims) + 1; // [1, numAnims]
200     if (num)
201         *num = roll;
202     return prefix + std::to_string(roll);
203 }
204 
refreshHitRecoilAnims(CharacterState & idle)205 void CharacterController::refreshHitRecoilAnims(CharacterState& idle)
206 {
207     bool recovery = mPtr.getClass().getCreatureStats(mPtr).getHitRecovery();
208     bool knockdown = mPtr.getClass().getCreatureStats(mPtr).getKnockedDown();
209     bool block = mPtr.getClass().getCreatureStats(mPtr).getBlock();
210     bool isSwimming = MWBase::Environment::get().getWorld()->isSwimming(mPtr);
211     if(mHitState == CharState_None)
212     {
213         if ((mPtr.getClass().getCreatureStats(mPtr).getFatigue().getCurrent() < 0
214                 || mPtr.getClass().getCreatureStats(mPtr).getFatigue().getBase() == 0))
215         {
216             mTimeUntilWake = Misc::Rng::rollClosedProbability() * 2 + 1; // Wake up after 1 to 3 seconds
217             if (isSwimming && mAnimation->hasAnimation("swimknockout"))
218             {
219                 mHitState = CharState_SwimKnockOut;
220                 mCurrentHit = "swimknockout";
221                 mAnimation->play(mCurrentHit, Priority_Knockdown, MWRender::Animation::BlendMask_All, false, 1, "start", "stop", 0.0f, ~0ul);
222             }
223             else if (!isSwimming && mAnimation->hasAnimation("knockout"))
224             {
225                 mHitState = CharState_KnockOut;
226                 mCurrentHit = "knockout";
227                 mAnimation->play(mCurrentHit, Priority_Knockdown, MWRender::Animation::BlendMask_All, false, 1, "start", "stop", 0.0f, ~0ul);
228             }
229             else
230             {
231                 // Knockout animations are missing. Fall back to idle animation, so target actor still can be killed via HtH.
232                 mCurrentHit.erase();
233             }
234 
235             mPtr.getClass().getCreatureStats(mPtr).setKnockedDown(true);
236         }
237         else if (knockdown)
238         {
239             if (isSwimming && mAnimation->hasAnimation("swimknockdown"))
240             {
241                 mHitState = CharState_SwimKnockDown;
242                 mCurrentHit = "swimknockdown";
243                 mAnimation->play(mCurrentHit, Priority_Knockdown, MWRender::Animation::BlendMask_All, true, 1, "start", "stop", 0.0f, 0);
244             }
245             else if (!isSwimming && mAnimation->hasAnimation("knockdown"))
246             {
247                 mHitState = CharState_KnockDown;
248                 mCurrentHit = "knockdown";
249                 mAnimation->play(mCurrentHit, Priority_Knockdown, MWRender::Animation::BlendMask_All, true, 1, "start", "stop", 0.0f, 0);
250             }
251             else
252             {
253                 // Knockdown animation is missing. Cancel knockdown state.
254                 mPtr.getClass().getCreatureStats(mPtr).setKnockedDown(false);
255             }
256         }
257         else if (recovery)
258         {
259             std::string anim = chooseRandomGroup("swimhit");
260             if (isSwimming && mAnimation->hasAnimation(anim))
261             {
262                 mHitState = CharState_SwimHit;
263                 mCurrentHit = anim;
264                 mAnimation->play(mCurrentHit, Priority_Hit, MWRender::Animation::BlendMask_All, true, 1, "start", "stop", 0.0f, 0);
265             }
266             else
267             {
268                 anim = chooseRandomGroup("hit");
269                 if (mAnimation->hasAnimation(anim))
270                 {
271                     mHitState = CharState_Hit;
272                     mCurrentHit = anim;
273                     mAnimation->play(mCurrentHit, Priority_Hit, MWRender::Animation::BlendMask_All, true, 1, "start", "stop", 0.0f, 0);
274                 }
275             }
276         }
277         else if (block && mAnimation->hasAnimation("shield"))
278         {
279             mHitState = CharState_Block;
280             mCurrentHit = "shield";
281             MWRender::Animation::AnimPriority priorityBlock (Priority_Hit);
282             priorityBlock[MWRender::Animation::BoneGroup_LeftArm] = Priority_Block;
283             priorityBlock[MWRender::Animation::BoneGroup_LowerBody] = Priority_WeaponLowerBody;
284             mAnimation->play(mCurrentHit, priorityBlock, MWRender::Animation::BlendMask_All, true, 1, "block start", "block stop", 0.0f, 0);
285         }
286 
287         // Cancel upper body animations
288         if (isKnockedOut() || isKnockedDown())
289         {
290             if (mUpperBodyState > UpperCharState_WeapEquiped)
291             {
292                 mAnimation->disable(mCurrentWeapon);
293                 mUpperBodyState = UpperCharState_WeapEquiped;
294                 if (mWeaponType > ESM::Weapon::None)
295                     mAnimation->showWeapons(true);
296             }
297             else if (mUpperBodyState > UpperCharState_Nothing && mUpperBodyState < UpperCharState_WeapEquiped)
298             {
299                 mAnimation->disable(mCurrentWeapon);
300                 mUpperBodyState = UpperCharState_Nothing;
301             }
302         }
303         if (mHitState != CharState_None)
304             idle = CharState_None;
305     }
306     else if(!mAnimation->isPlaying(mCurrentHit))
307     {
308         mCurrentHit.erase();
309         if (knockdown)
310             mPtr.getClass().getCreatureStats(mPtr).setKnockedDown(false);
311         if (recovery)
312             mPtr.getClass().getCreatureStats(mPtr).setHitRecovery(false);
313         if (block)
314             mPtr.getClass().getCreatureStats(mPtr).setBlock(false);
315         mHitState = CharState_None;
316     }
317     else if (isKnockedOut() && mPtr.getClass().getCreatureStats(mPtr).getFatigue().getCurrent() > 0
318             && mTimeUntilWake <= 0)
319     {
320         mHitState = isSwimming ? CharState_SwimKnockDown : CharState_KnockDown;
321         mAnimation->disable(mCurrentHit);
322         mAnimation->play(mCurrentHit, Priority_Knockdown, MWRender::Animation::BlendMask_All, true, 1, "loop stop", "stop", 0.0f, 0);
323     }
324 }
325 
refreshJumpAnims(const std::string & weapShortGroup,JumpingState jump,CharacterState & idle,bool force)326 void CharacterController::refreshJumpAnims(const std::string& weapShortGroup, JumpingState jump, CharacterState& idle, bool force)
327 {
328     if (!force && jump == mJumpState && idle == CharState_None)
329         return;
330 
331     std::string jumpAnimName;
332     MWRender::Animation::BlendMask jumpmask = MWRender::Animation::BlendMask_All;
333     if (jump != JumpState_None)
334     {
335         jumpAnimName = "jump";
336         if(!weapShortGroup.empty())
337         {
338             jumpAnimName += weapShortGroup;
339             if(!mAnimation->hasAnimation(jumpAnimName))
340             {
341                 jumpAnimName = fallbackShortWeaponGroup("jump", &jumpmask);
342 
343                 // If we apply jump only for lower body, do not reset idle animations.
344                 // For upper body there will be idle animation.
345                 if (jumpmask == MWRender::Animation::BlendMask_LowerBody && idle == CharState_None)
346                     idle = CharState_Idle;
347             }
348         }
349     }
350 
351     if (!force && jump == mJumpState)
352         return;
353 
354     bool startAtLoop = (jump == mJumpState);
355     mJumpState = jump;
356 
357     if (!mCurrentJump.empty())
358     {
359         mAnimation->disable(mCurrentJump);
360         mCurrentJump.clear();
361     }
362 
363     if(mJumpState == JumpState_InAir)
364     {
365         if (mAnimation->hasAnimation(jumpAnimName))
366         {
367             mAnimation->play(jumpAnimName, Priority_Jump, jumpmask, false,
368                          1.0f, startAtLoop ? "loop start" : "start", "stop", 0.f, ~0ul);
369             mCurrentJump = jumpAnimName;
370         }
371     }
372     else if (mJumpState == JumpState_Landing)
373     {
374         if (mAnimation->hasAnimation(jumpAnimName))
375         {
376             mAnimation->play(jumpAnimName, Priority_Jump, jumpmask, true,
377                          1.0f, "loop stop", "stop", 0.0f, 0);
378             mCurrentJump = jumpAnimName;
379         }
380     }
381 }
382 
onOpen()383 bool CharacterController::onOpen()
384 {
385     if (mPtr.getTypeName() == typeid(ESM::Container).name())
386     {
387         if (!mAnimation->hasAnimation("containeropen"))
388             return true;
389 
390         if (mAnimation->isPlaying("containeropen"))
391             return false;
392 
393         if (mAnimation->isPlaying("containerclose"))
394             return false;
395 
396         mAnimation->play("containeropen", Priority_Persistent, MWRender::Animation::BlendMask_All, false, 1.0f, "start", "stop", 0.f, 0);
397         if (mAnimation->isPlaying("containeropen"))
398             return false;
399     }
400 
401     return true;
402 }
403 
onClose()404 void CharacterController::onClose()
405 {
406     if (mPtr.getTypeName() == typeid(ESM::Container).name())
407     {
408         if (!mAnimation->hasAnimation("containerclose"))
409             return;
410 
411         float complete, startPoint = 0.f;
412         bool animPlaying = mAnimation->getInfo("containeropen", &complete);
413         if (animPlaying)
414             startPoint = 1.f - complete;
415 
416         mAnimation->play("containerclose", Priority_Persistent, MWRender::Animation::BlendMask_All, false, 1.0f, "start", "stop", startPoint, 0);
417     }
418 }
419 
getWeaponAnimation(int weaponType) const420 std::string CharacterController::getWeaponAnimation(int weaponType) const
421 {
422     std::string weaponGroup = getWeaponType(weaponType)->mLongGroup;
423     bool isRealWeapon = weaponType != ESM::Weapon::HandToHand && weaponType != ESM::Weapon::Spell && weaponType != ESM::Weapon::None;
424     if (isRealWeapon && !mAnimation->hasAnimation(weaponGroup))
425     {
426         static const std::string oneHandFallback = getWeaponType(ESM::Weapon::LongBladeOneHand)->mLongGroup;
427         static const std::string twoHandFallback = getWeaponType(ESM::Weapon::LongBladeTwoHand)->mLongGroup;
428 
429         const ESM::WeaponType* weapInfo = getWeaponType(weaponType);
430 
431         // For real two-handed melee weapons use 2h swords animations as fallback, otherwise use the 1h ones
432         if (weapInfo->mFlags & ESM::WeaponType::TwoHanded && weapInfo->mWeaponClass == ESM::WeaponType::Melee)
433             weaponGroup = twoHandFallback;
434         else if (isRealWeapon)
435             weaponGroup = oneHandFallback;
436     }
437 
438     return weaponGroup;
439 }
440 
fallbackShortWeaponGroup(const std::string & baseGroupName,MWRender::Animation::BlendMask * blendMask)441 std::string CharacterController::fallbackShortWeaponGroup(const std::string& baseGroupName, MWRender::Animation::BlendMask* blendMask)
442 {
443     bool isRealWeapon = mWeaponType != ESM::Weapon::HandToHand && mWeaponType != ESM::Weapon::Spell && mWeaponType != ESM::Weapon::None;
444     if (!isRealWeapon)
445     {
446         if (blendMask != nullptr)
447             *blendMask = MWRender::Animation::BlendMask_LowerBody;
448 
449         return baseGroupName;
450     }
451 
452     static const std::string oneHandFallback = getWeaponType(ESM::Weapon::LongBladeOneHand)->mShortGroup;
453     static const std::string twoHandFallback = getWeaponType(ESM::Weapon::LongBladeTwoHand)->mShortGroup;
454 
455     std::string groupName = baseGroupName;
456     const ESM::WeaponType* weapInfo = getWeaponType(mWeaponType);
457 
458     // For real two-handed melee weapons use 2h swords animations as fallback, otherwise use the 1h ones
459     if (weapInfo->mFlags & ESM::WeaponType::TwoHanded && weapInfo->mWeaponClass == ESM::WeaponType::Melee)
460         groupName += twoHandFallback;
461     else
462         groupName += oneHandFallback;
463 
464     // Special case for crossbows - we shouls apply 1h animations a fallback only for lower body
465     if (mWeaponType == ESM::Weapon::MarksmanCrossbow && blendMask != nullptr)
466         *blendMask = MWRender::Animation::BlendMask_LowerBody;
467 
468     if (!mAnimation->hasAnimation(groupName))
469     {
470         groupName = baseGroupName;
471         if (blendMask != nullptr)
472             *blendMask = MWRender::Animation::BlendMask_LowerBody;
473     }
474 
475     return groupName;
476 }
477 
refreshMovementAnims(const std::string & weapShortGroup,CharacterState movement,CharacterState & idle,bool force)478 void CharacterController::refreshMovementAnims(const std::string& weapShortGroup, CharacterState movement, CharacterState& idle, bool force)
479 {
480     if (movement == mMovementState && idle == mIdleState && !force)
481         return;
482 
483     // Reset idle if we actually play movement animations excepts of these cases:
484     // 1. When we play turning animations
485     // 2. When we use a fallback animation for lower body since movement animation for given weapon is missing (e.g. for crossbows and spellcasting)
486     bool resetIdle = (movement != CharState_None && !isTurning());
487 
488     std::string movementAnimName;
489     MWRender::Animation::BlendMask movemask;
490     const StateInfo *movestate;
491 
492     movemask = MWRender::Animation::BlendMask_All;
493     movestate = std::find_if(sMovementList, sMovementListEnd, FindCharState(movement));
494     if(movestate != sMovementListEnd)
495     {
496         movementAnimName = movestate->groupname;
497         if(!weapShortGroup.empty())
498         {
499             std::string::size_type swimpos = movementAnimName.find("swim");
500             if (swimpos == std::string::npos)
501             {
502                 if (mWeaponType == ESM::Weapon::Spell && (movement == CharState_TurnLeft || movement == CharState_TurnRight)) // Spellcasting stance turning is a special case
503                     movementAnimName = weapShortGroup + movementAnimName;
504                 else
505                     movementAnimName += weapShortGroup;
506             }
507 
508             if(!mAnimation->hasAnimation(movementAnimName))
509             {
510                 movementAnimName = movestate->groupname;
511                 if (swimpos == std::string::npos)
512                 {
513                     movementAnimName = fallbackShortWeaponGroup(movementAnimName, &movemask);
514 
515                     // If we apply movement only for lower body, do not reset idle animations.
516                     // For upper body there will be idle animation.
517                     if (movemask == MWRender::Animation::BlendMask_LowerBody && idle == CharState_None)
518                         idle = CharState_Idle;
519 
520                     if (movemask == MWRender::Animation::BlendMask_LowerBody)
521                         resetIdle = false;
522                 }
523             }
524         }
525     }
526 
527     if(force || movement != mMovementState)
528     {
529         mMovementState = movement;
530         if(movestate != sMovementListEnd)
531         {
532             if(!mAnimation->hasAnimation(movementAnimName))
533             {
534                 std::string::size_type swimpos = movementAnimName.find("swim");
535                 if (swimpos != std::string::npos)
536                 {
537                     movementAnimName.erase(swimpos, 4);
538                     if (!weapShortGroup.empty())
539                     {
540                         std::string weapMovementAnimName = movementAnimName + weapShortGroup;
541                         if(mAnimation->hasAnimation(weapMovementAnimName))
542                             movementAnimName = weapMovementAnimName;
543                         else
544                         {
545                             movementAnimName = fallbackShortWeaponGroup(movementAnimName, &movemask);
546                             if (movemask == MWRender::Animation::BlendMask_LowerBody)
547                                 resetIdle = false;
548                         }
549                     }
550                 }
551 
552                 if (swimpos == std::string::npos || !mAnimation->hasAnimation(movementAnimName))
553                 {
554                     std::string::size_type runpos = movementAnimName.find("run");
555                     if (runpos != std::string::npos)
556                     {
557                         movementAnimName.replace(runpos, runpos+3, "walk");
558                         if (!mAnimation->hasAnimation(movementAnimName))
559                             movementAnimName.clear();
560                     }
561                     else
562                         movementAnimName.clear();
563                 }
564             }
565         }
566 
567         // If we're playing the same animation, start it from the point it ended
568         float startpoint = 0.f;
569         if (!mCurrentMovement.empty() && movementAnimName == mCurrentMovement)
570             mAnimation->getInfo(mCurrentMovement, &startpoint);
571 
572         mMovementAnimationControlled = true;
573 
574         mAnimation->disable(mCurrentMovement);
575 
576         if (!mAnimation->hasAnimation(movementAnimName))
577             movementAnimName.clear();
578 
579         mCurrentMovement = movementAnimName;
580         if(!mCurrentMovement.empty())
581         {
582             if (resetIdle)
583             {
584                 mAnimation->disable(mCurrentIdle);
585                 mIdleState = CharState_None;
586                 idle = CharState_None;
587             }
588 
589             // For non-flying creatures, MW uses the Walk animation to calculate the animation velocity
590             // even if we are running. This must be replicated, otherwise the observed speed would differ drastically.
591             std::string anim = mCurrentMovement;
592             mAdjustMovementAnimSpeed = true;
593             if (mPtr.getClass().getTypeName() == typeid(ESM::Creature).name()
594                     && !(mPtr.get<ESM::Creature>()->mBase->mFlags & ESM::Creature::Flies))
595             {
596                 CharacterState walkState = runStateToWalkState(mMovementState);
597                 const StateInfo *stateinfo = std::find_if(sMovementList, sMovementListEnd, FindCharState(walkState));
598                 anim = stateinfo->groupname;
599 
600                 mMovementAnimSpeed = mAnimation->getVelocity(anim);
601                 if (mMovementAnimSpeed <= 1.0f)
602                 {
603                     // Another bug: when using a fallback animation (e.g. RunForward as fallback to SwimRunForward),
604                     // then the equivalent Walk animation will not use a fallback, and if that animation doesn't exist
605                     // we will play without any scaling.
606                     // Makes the speed attribute of most water creatures totally useless.
607                     // And again, this can not be fixed without patching game data.
608                     mAdjustMovementAnimSpeed = false;
609                     mMovementAnimSpeed = 1.f;
610                 }
611             }
612             else
613             {
614                 mMovementAnimSpeed = mAnimation->getVelocity(anim);
615 
616                 if (mMovementAnimSpeed <= 1.0f)
617                 {
618                     // The first person anims don't have any velocity to calculate a speed multiplier from.
619                     // We use the third person velocities instead.
620                     // FIXME: should be pulled from the actual animation, but it is not presently loaded.
621                     bool sneaking = mMovementState == CharState_SneakForward || mMovementState == CharState_SneakBack
622                                  || mMovementState == CharState_SneakLeft    || mMovementState == CharState_SneakRight;
623                     mMovementAnimSpeed = (sneaking ? 33.5452f : (isRunning() ? 222.857f : 154.064f));
624                     mMovementAnimationControlled = false;
625                 }
626             }
627 
628             mAnimation->play(mCurrentMovement, Priority_Movement, movemask, false,
629                              1.f, "start", "stop", startpoint, ~0ul, true);
630         }
631         else
632             mMovementState = CharState_None;
633     }
634 }
635 
refreshIdleAnims(const std::string & weapShortGroup,CharacterState idle,bool force)636 void CharacterController::refreshIdleAnims(const std::string& weapShortGroup, CharacterState idle, bool force)
637 {
638     // FIXME: if one of the below states is close to their last animation frame (i.e. will be disabled in the coming update),
639     // the idle animation should be displayed
640     if (((mUpperBodyState != UpperCharState_Nothing && mUpperBodyState != UpperCharState_WeapEquiped)
641             || (mMovementState != CharState_None && !isTurning())
642             || mHitState != CharState_None)
643             && !mPtr.getClass().isBipedal(mPtr))
644         idle = CharState_None;
645 
646     if(force || idle != mIdleState || (!mAnimation->isPlaying(mCurrentIdle) && mAnimQueue.empty()))
647     {
648         mIdleState = idle;
649         size_t numLoops = ~0ul;
650 
651         std::string idleGroup;
652         MWRender::Animation::AnimPriority idlePriority (Priority_Default);
653         // Only play "idleswim" or "idlesneak" if they exist. Otherwise, fallback to
654         // "idle"+weapon or "idle".
655         if(mIdleState == CharState_IdleSwim && mAnimation->hasAnimation("idleswim"))
656         {
657             idleGroup = "idleswim";
658             idlePriority = Priority_SwimIdle;
659         }
660         else if(mIdleState == CharState_IdleSneak && mAnimation->hasAnimation("idlesneak"))
661         {
662             idleGroup = "idlesneak";
663             idlePriority[MWRender::Animation::BoneGroup_LowerBody] = Priority_SneakIdleLowerBody;
664         }
665         else if(mIdleState != CharState_None)
666         {
667             idleGroup = "idle";
668             if(!weapShortGroup.empty())
669             {
670                 idleGroup += weapShortGroup;
671                 if(!mAnimation->hasAnimation(idleGroup))
672                 {
673                     idleGroup = fallbackShortWeaponGroup("idle");
674                 }
675 
676                 // play until the Loop Stop key 2 to 5 times, then play until the Stop key
677                 // this replicates original engine behavior for the "Idle1h" 1st-person animation
678                 numLoops = 1 + Misc::Rng::rollDice(4);
679             }
680         }
681 
682         // There is no need to restart anim if the new and old anims are the same.
683         // Just update a number of loops.
684         float startPoint = 0;
685         if (!mCurrentIdle.empty() && mCurrentIdle == idleGroup)
686         {
687             mAnimation->getInfo(mCurrentIdle, &startPoint);
688         }
689 
690         if(!mCurrentIdle.empty())
691             mAnimation->disable(mCurrentIdle);
692 
693         mCurrentIdle = idleGroup;
694         if(!mCurrentIdle.empty())
695             mAnimation->play(mCurrentIdle, idlePriority, MWRender::Animation::BlendMask_All, false,
696                              1.0f, "start", "stop", startPoint, numLoops, true);
697     }
698 }
699 
refreshCurrentAnims(CharacterState idle,CharacterState movement,JumpingState jump,bool force)700 void CharacterController::refreshCurrentAnims(CharacterState idle, CharacterState movement, JumpingState jump, bool force)
701 {
702     // If the current animation is persistent, do not touch it
703     if (isPersistentAnimPlaying())
704         return;
705 
706     if (mPtr.getClass().isActor())
707         refreshHitRecoilAnims(idle);
708 
709     std::string weap;
710     if (mPtr.getClass().hasInventoryStore(mPtr))
711         weap = getWeaponType(mWeaponType)->mShortGroup;
712 
713     refreshJumpAnims(weap, jump, idle, force);
714     refreshMovementAnims(weap, movement, idle, force);
715 
716     // idle handled last as it can depend on the other states
717     refreshIdleAnims(weap, idle, force);
718 }
719 
playDeath(float startpoint,CharacterState death)720 void CharacterController::playDeath(float startpoint, CharacterState death)
721 {
722     // Make sure the character was swimming upon death for forward-compatibility
723     const bool wasSwimming = MWBase::Environment::get().getWorld()->isSwimming(mPtr);
724 
725     switch (death)
726     {
727     case CharState_SwimDeath:
728         mCurrentDeath = "swimdeath";
729         break;
730     case CharState_SwimDeathKnockDown:
731         mCurrentDeath = (wasSwimming ? "swimdeathknockdown" : "deathknockdown");
732         break;
733     case CharState_SwimDeathKnockOut:
734         mCurrentDeath = (wasSwimming ? "swimdeathknockout" : "deathknockout");
735         break;
736     case CharState_DeathKnockDown:
737         mCurrentDeath = "deathknockdown";
738         break;
739     case CharState_DeathKnockOut:
740         mCurrentDeath = "deathknockout";
741         break;
742     default:
743         mCurrentDeath = "death" + std::to_string(death - CharState_Death1 + 1);
744     }
745     mDeathState = death;
746 
747     mPtr.getClass().getCreatureStats(mPtr).setDeathAnimation(mDeathState - CharState_Death1);
748 
749     // For dead actors, refreshCurrentAnims is no longer called, so we need to disable the movement state manually.
750     // Note that these animations wouldn't actually be visible (due to the Death animation's priority being higher).
751     // However, they could still trigger text keys, such as Hit events, or sounds.
752     mMovementState = CharState_None;
753     mAnimation->disable(mCurrentMovement);
754     mCurrentMovement = "";
755     mUpperBodyState = UpperCharState_Nothing;
756     mAnimation->disable(mCurrentWeapon);
757     mCurrentWeapon = "";
758     mHitState = CharState_None;
759     mAnimation->disable(mCurrentHit);
760     mCurrentHit = "";
761     mIdleState = CharState_None;
762     mAnimation->disable(mCurrentIdle);
763     mCurrentIdle = "";
764     mJumpState = JumpState_None;
765     mAnimation->disable(mCurrentJump);
766     mCurrentJump = "";
767     mMovementAnimationControlled = true;
768 
769     mAnimation->play(mCurrentDeath, Priority_Death, MWRender::Animation::BlendMask_All,
770                     false, 1.0f, "start", "stop", startpoint, 0);
771 }
772 
chooseRandomDeathState() const773 CharacterState CharacterController::chooseRandomDeathState() const
774 {
775     int selected=0;
776     chooseRandomGroup("death", &selected);
777     return static_cast<CharacterState>(CharState_Death1 + (selected-1));
778 }
779 
playRandomDeath(float startpoint)780 void CharacterController::playRandomDeath(float startpoint)
781 {
782     if (mPtr == getPlayer())
783     {
784         // The first-person animations do not include death, so we need to
785         // force-switch to third person before playing the death animation.
786         MWBase::Environment::get().getWorld()->useDeathCamera();
787     }
788 
789     if(mHitState == CharState_SwimKnockDown && mAnimation->hasAnimation("swimdeathknockdown"))
790     {
791         mDeathState = CharState_SwimDeathKnockDown;
792     }
793     else if(mHitState == CharState_SwimKnockOut && mAnimation->hasAnimation("swimdeathknockout"))
794     {
795         mDeathState = CharState_SwimDeathKnockOut;
796     }
797     else if(MWBase::Environment::get().getWorld()->isSwimming(mPtr) && mAnimation->hasAnimation("swimdeath"))
798     {
799         mDeathState = CharState_SwimDeath;
800     }
801     else if (mHitState == CharState_KnockDown && mAnimation->hasAnimation("deathknockdown"))
802     {
803         mDeathState = CharState_DeathKnockDown;
804     }
805     else if (mHitState == CharState_KnockOut && mAnimation->hasAnimation("deathknockout"))
806     {
807         mDeathState = CharState_DeathKnockOut;
808     }
809     else
810     {
811         mDeathState = chooseRandomDeathState();
812     }
813 
814     // Do not interrupt scripted animation by death
815     if (isPersistentAnimPlaying())
816         return;
817 
818     playDeath(startpoint, mDeathState);
819 }
820 
chooseRandomAttackAnimation() const821 std::string CharacterController::chooseRandomAttackAnimation() const
822 {
823     std::string result;
824     bool isSwimming = MWBase::Environment::get().getWorld()->isSwimming(mPtr);
825 
826     if (isSwimming)
827         result = chooseRandomGroup("swimattack");
828 
829     if (!isSwimming || !mAnimation->hasAnimation(result))
830         result = chooseRandomGroup("attack");
831 
832     return result;
833 }
834 
CharacterController(const MWWorld::Ptr & ptr,MWRender::Animation * anim)835 CharacterController::CharacterController(const MWWorld::Ptr &ptr, MWRender::Animation *anim)
836     : mPtr(ptr)
837     , mWeapon(MWWorld::Ptr())
838     , mAnimation(anim)
839     , mIdleState(CharState_None)
840     , mMovementState(CharState_None)
841     , mMovementAnimSpeed(0.f)
842     , mAdjustMovementAnimSpeed(false)
843     , mHasMovedInXY(false)
844     , mMovementAnimationControlled(true)
845     , mDeathState(CharState_None)
846     , mFloatToSurface(true)
847     , mHitState(CharState_None)
848     , mUpperBodyState(UpperCharState_Nothing)
849     , mJumpState(JumpState_None)
850     , mWeaponType(ESM::Weapon::None)
851     , mAttackStrength(0.f)
852     , mSkipAnim(false)
853     , mSecondsOfSwimming(0)
854     , mSecondsOfRunning(0)
855     , mTurnAnimationThreshold(0)
856     , mAttackingOrSpell(false)
857     , mCastingManualSpell(false)
858     , mTimeUntilWake(0.f)
859     , mIsMovingBackward(false)
860 {
861     if(!mAnimation)
862         return;
863 
864     mAnimation->setTextKeyListener(this);
865 
866     const MWWorld::Class &cls = mPtr.getClass();
867     if(cls.isActor())
868     {
869         /* Accumulate along X/Y only for now, until we can figure out how we should
870          * handle knockout and death which moves the character down. */
871         mAnimation->setAccumulation(osg::Vec3f(1.0f, 1.0f, 0.0f));
872 
873         if (cls.hasInventoryStore(mPtr))
874         {
875             getActiveWeapon(mPtr, &mWeaponType);
876             if (mWeaponType != ESM::Weapon::None)
877             {
878                 mUpperBodyState = UpperCharState_WeapEquiped;
879                 mCurrentWeapon = getWeaponAnimation(mWeaponType);
880             }
881 
882             if(mWeaponType != ESM::Weapon::None && mWeaponType != ESM::Weapon::Spell && mWeaponType != ESM::Weapon::HandToHand)
883             {
884                 mAnimation->showWeapons(true);
885                 // Note: controllers for ranged weapon should use time for beginning of animation to play shooting properly,
886                 // for other weapons they should use absolute time. Some mods rely on this behaviour (to rotate throwing projectiles, for example)
887                 ESM::WeaponType::Class weaponClass = getWeaponType(mWeaponType)->mWeaponClass;
888                 bool useRelativeDuration = weaponClass == ESM::WeaponType::Ranged;
889                 mAnimation->setWeaponGroup(mCurrentWeapon, useRelativeDuration);
890             }
891 
892             mAnimation->showCarriedLeft(updateCarriedLeftVisible(mWeaponType));
893         }
894 
895         if(!cls.getCreatureStats(mPtr).isDead())
896         {
897             mIdleState = CharState_Idle;
898             if (cls.getCreatureStats(mPtr).getFallHeight() > 0)
899                 mJumpState = JumpState_InAir;
900         }
901         else
902         {
903             const MWMechanics::CreatureStats& cStats = mPtr.getClass().getCreatureStats(mPtr);
904             if (cStats.isDeathAnimationFinished())
905             {
906                 // Set the death state, but don't play it yet
907                 // We will play it in the first frame, but only if no script set the skipAnim flag
908                 signed char deathanim = cStats.getDeathAnimation();
909                 if (deathanim == -1)
910                     mDeathState = chooseRandomDeathState();
911                 else
912                     mDeathState = static_cast<CharacterState>(CharState_Death1 + deathanim);
913 
914                 mFloatToSurface = false;
915             }
916             // else: nothing to do, will detect death in the next frame and start playing death animation
917         }
918     }
919     else
920     {
921         /* Don't accumulate with non-actors. */
922         mAnimation->setAccumulation(osg::Vec3f(0.f, 0.f, 0.f));
923 
924         mIdleState = CharState_Idle;
925     }
926 
927     // Do not update animation status for dead actors
928     if(mDeathState == CharState_None && (!cls.isActor() || !cls.getCreatureStats(mPtr).isDead()))
929         refreshCurrentAnims(mIdleState, mMovementState, mJumpState, true);
930 
931     mAnimation->runAnimation(0.f);
932 
933     unpersistAnimationState();
934 }
935 
~CharacterController()936 CharacterController::~CharacterController()
937 {
938     if (mAnimation)
939     {
940         persistAnimationState();
941         mAnimation->setTextKeyListener(nullptr);
942     }
943 }
944 
split(const std::string & s,char delim,std::vector<std::string> & elems)945 void split(const std::string &s, char delim, std::vector<std::string> &elems) {
946     std::stringstream ss(s);
947     std::string item;
948     while (std::getline(ss, item, delim)) {
949         elems.push_back(item);
950     }
951 }
952 
handleTextKey(const std::string & groupname,SceneUtil::TextKeyMap::ConstIterator key,const SceneUtil::TextKeyMap & map)953 void CharacterController::handleTextKey(const std::string &groupname, SceneUtil::TextKeyMap::ConstIterator key, const SceneUtil::TextKeyMap& map)
954 {
955     const std::string &evt = key->second;
956 
957     if(evt.compare(0, 7, "sound: ") == 0)
958     {
959         MWBase::SoundManager *sndMgr = MWBase::Environment::get().getSoundManager();
960         sndMgr->playSound3D(mPtr, evt.substr(7), 1.0f, 1.0f);
961         return;
962     }
963     if(evt.compare(0, 10, "soundgen: ") == 0)
964     {
965         std::string soundgen = evt.substr(10);
966 
967         // The event can optionally contain volume and pitch modifiers
968         float volume=1.f, pitch=1.f;
969         if (soundgen.find(' ') != std::string::npos)
970         {
971             std::vector<std::string> tokens;
972             split(soundgen, ' ', tokens);
973             soundgen = tokens[0];
974             if (tokens.size() >= 2)
975             {
976                 std::stringstream stream;
977                 stream << tokens[1];
978                 stream >> volume;
979             }
980             if (tokens.size() >= 3)
981             {
982                 std::stringstream stream;
983                 stream << tokens[2];
984                 stream >> pitch;
985             }
986         }
987 
988         std::string sound = mPtr.getClass().getSoundIdFromSndGen(mPtr, soundgen);
989         if(!sound.empty())
990         {
991             MWBase::SoundManager *sndMgr = MWBase::Environment::get().getSoundManager();
992             // NB: landing sound is not played for NPCs here
993             if(soundgen == "left" || soundgen == "right" || soundgen == "land")
994             {
995                 sndMgr->playSound3D(mPtr, sound, volume, pitch, MWSound::Type::Foot,
996                                     MWSound::PlayMode::NoPlayerLocal);
997             }
998             else
999             {
1000                 sndMgr->playSound3D(mPtr, sound, volume, pitch);
1001             }
1002         }
1003         return;
1004     }
1005 
1006     if(evt.compare(0, groupname.size(), groupname) != 0 ||
1007        evt.compare(groupname.size(), 2, ": ") != 0)
1008     {
1009         // Not ours, skip it
1010         return;
1011     }
1012     size_t off = groupname.size()+2;
1013     size_t len = evt.size() - off;
1014 
1015     if(groupname == "shield" && evt.compare(off, len, "equip attach") == 0)
1016         mAnimation->showCarriedLeft(true);
1017     else if(groupname == "shield" && evt.compare(off, len, "unequip detach") == 0)
1018         mAnimation->showCarriedLeft(false);
1019     else if(evt.compare(off, len, "equip attach") == 0)
1020         mAnimation->showWeapons(true);
1021     else if(evt.compare(off, len, "unequip detach") == 0)
1022         mAnimation->showWeapons(false);
1023     else if(evt.compare(off, len, "chop hit") == 0)
1024         mPtr.getClass().hit(mPtr, mAttackStrength, ESM::Weapon::AT_Chop);
1025     else if(evt.compare(off, len, "slash hit") == 0)
1026         mPtr.getClass().hit(mPtr, mAttackStrength, ESM::Weapon::AT_Slash);
1027     else if(evt.compare(off, len, "thrust hit") == 0)
1028         mPtr.getClass().hit(mPtr, mAttackStrength, ESM::Weapon::AT_Thrust);
1029     else if(evt.compare(off, len, "hit") == 0)
1030     {
1031         if (groupname == "attack1" || groupname == "swimattack1")
1032             mPtr.getClass().hit(mPtr, mAttackStrength, ESM::Weapon::AT_Chop);
1033         else if (groupname == "attack2" || groupname == "swimattack2")
1034             mPtr.getClass().hit(mPtr, mAttackStrength, ESM::Weapon::AT_Slash);
1035         else if (groupname == "attack3" || groupname == "swimattack3")
1036             mPtr.getClass().hit(mPtr, mAttackStrength, ESM::Weapon::AT_Thrust);
1037         else
1038             mPtr.getClass().hit(mPtr, mAttackStrength);
1039     }
1040     else if (!groupname.empty()
1041              && (groupname.compare(0, groupname.size()-1, "attack") == 0 || groupname.compare(0, groupname.size()-1, "swimattack") == 0)
1042              && evt.compare(off, len, "start") == 0)
1043     {
1044         std::multimap<float, std::string>::const_iterator hitKey = key;
1045 
1046         // Not all animations have a hit key defined. If there is none, the hit happens with the start key.
1047         bool hasHitKey = false;
1048         while (hitKey != map.end())
1049         {
1050             if (hitKey->second == groupname + ": hit")
1051             {
1052                 hasHitKey = true;
1053                 break;
1054             }
1055             if (hitKey->second == groupname + ": stop")
1056                 break;
1057             ++hitKey;
1058         }
1059         if (!hasHitKey)
1060         {
1061             if (groupname == "attack1" || groupname == "swimattack1")
1062                 mPtr.getClass().hit(mPtr, mAttackStrength, ESM::Weapon::AT_Chop);
1063             else if (groupname == "attack2" || groupname == "swimattack2")
1064                 mPtr.getClass().hit(mPtr, mAttackStrength, ESM::Weapon::AT_Slash);
1065             else if (groupname == "attack3" || groupname == "swimattack3")
1066                 mPtr.getClass().hit(mPtr, mAttackStrength, ESM::Weapon::AT_Thrust);
1067         }
1068     }
1069     else if (evt.compare(off, len, "shoot attach") == 0)
1070         mAnimation->attachArrow();
1071     else if (evt.compare(off, len, "shoot release") == 0)
1072         mAnimation->releaseArrow(mAttackStrength);
1073     else if (evt.compare(off, len, "shoot follow attach") == 0)
1074         mAnimation->attachArrow();
1075 
1076     else if (groupname == "spellcast" && evt.substr(evt.size()-7, 7) == "release"
1077              // Make sure this key is actually for the RangeType we are casting. The flame atronach has
1078              // the same animation for all range types, so there are 3 "release" keys on the same time, one for each range type.
1079              && evt.compare(off, len, mAttackType + " release") == 0)
1080     {
1081         MWBase::Environment::get().getWorld()->castSpell(mPtr, mCastingManualSpell);
1082         mCastingManualSpell = false;
1083     }
1084 
1085     else if (groupname == "shield" && evt.compare(off, len, "block hit") == 0)
1086         mPtr.getClass().block(mPtr);
1087     else if (groupname == "containeropen" && evt.compare(off, len, "loot") == 0)
1088         MWBase::Environment::get().getWindowManager()->pushGuiMode(MWGui::GM_Container, mPtr);
1089 }
1090 
updatePtr(const MWWorld::Ptr & ptr)1091 void CharacterController::updatePtr(const MWWorld::Ptr &ptr)
1092 {
1093     mPtr = ptr;
1094 }
1095 
updateIdleStormState(bool inwater)1096 void CharacterController::updateIdleStormState(bool inwater)
1097 {
1098     if (!mAnimation->hasAnimation("idlestorm") || mUpperBodyState != UpperCharState_Nothing || inwater)
1099     {
1100         mAnimation->disable("idlestorm");
1101         return;
1102     }
1103 
1104     if (MWBase::Environment::get().getWorld()->isInStorm())
1105     {
1106         osg::Vec3f stormDirection = MWBase::Environment::get().getWorld()->getStormDirection();
1107         osg::Vec3f characterDirection = mPtr.getRefData().getBaseNode()->getAttitude() * osg::Vec3f(0,1,0);
1108         stormDirection.normalize();
1109         characterDirection.normalize();
1110         if (stormDirection * characterDirection < -0.5f)
1111         {
1112             if (!mAnimation->isPlaying("idlestorm"))
1113             {
1114                 int mask = MWRender::Animation::BlendMask_Torso | MWRender::Animation::BlendMask_RightArm;
1115                 mAnimation->play("idlestorm", Priority_Storm, mask, true, 1.0f, "start", "stop", 0.0f, ~0ul);
1116             }
1117             else
1118             {
1119                 mAnimation->setLoopingEnabled("idlestorm", true);
1120             }
1121             return;
1122         }
1123     }
1124 
1125     if (mAnimation->isPlaying("idlestorm"))
1126     {
1127         mAnimation->setLoopingEnabled("idlestorm", false);
1128     }
1129 }
1130 
updateCreatureState()1131 bool CharacterController::updateCreatureState()
1132 {
1133     const MWWorld::Class &cls = mPtr.getClass();
1134     CreatureStats &stats = cls.getCreatureStats(mPtr);
1135 
1136     int weapType = ESM::Weapon::None;
1137     if(stats.getDrawState() == DrawState_Weapon)
1138         weapType = ESM::Weapon::HandToHand;
1139     else if (stats.getDrawState() == DrawState_Spell)
1140         weapType = ESM::Weapon::Spell;
1141 
1142     if (weapType != mWeaponType)
1143     {
1144         mWeaponType = weapType;
1145         if (mAnimation->isPlaying(mCurrentWeapon))
1146             mAnimation->disable(mCurrentWeapon);
1147     }
1148 
1149     if(mAttackingOrSpell)
1150     {
1151         if(mUpperBodyState == UpperCharState_Nothing && mHitState == CharState_None)
1152         {
1153             MWBase::Environment::get().getWorld()->breakInvisibility(mPtr);
1154 
1155             std::string startKey = "start";
1156             std::string stopKey = "stop";
1157             if (weapType == ESM::Weapon::Spell)
1158             {
1159                 const std::string spellid = stats.getSpells().getSelectedSpell();
1160                 bool canCast = mCastingManualSpell || MWBase::Environment::get().getWorld()->startSpellCast(mPtr);
1161 
1162                 if (!spellid.empty() && canCast)
1163                 {
1164                     MWMechanics::CastSpell cast(mPtr, nullptr, false, mCastingManualSpell);
1165                     cast.playSpellCastingEffects(spellid, false);
1166 
1167                     if (!mAnimation->hasAnimation("spellcast"))
1168                     {
1169                         MWBase::Environment::get().getWorld()->castSpell(mPtr, mCastingManualSpell); // No "release" text key to use, so cast immediately
1170                         mCastingManualSpell = false;
1171                     }
1172                     else
1173                     {
1174                         const ESM::Spell *spell = MWBase::Environment::get().getWorld()->getStore().get<ESM::Spell>().find(spellid);
1175                         const ESM::ENAMstruct &effectentry = spell->mEffects.mList.at(0);
1176 
1177                         switch(effectentry.mRange)
1178                         {
1179                             case 0: mAttackType = "self"; break;
1180                             case 1: mAttackType = "touch"; break;
1181                             case 2: mAttackType = "target"; break;
1182                         }
1183 
1184                         startKey = mAttackType + " " + startKey;
1185                         stopKey = mAttackType + " " + stopKey;
1186                         mCurrentWeapon = "spellcast";
1187                     }
1188                 }
1189                 else
1190                     mCurrentWeapon = "";
1191             }
1192 
1193             if (weapType != ESM::Weapon::Spell || !mAnimation->hasAnimation("spellcast")) // Not all creatures have a dedicated spellcast animation
1194             {
1195                 mCurrentWeapon = chooseRandomAttackAnimation();
1196             }
1197 
1198             if (!mCurrentWeapon.empty())
1199             {
1200                 mAnimation->play(mCurrentWeapon, Priority_Weapon,
1201                                  MWRender::Animation::BlendMask_All, true,
1202                                  1, startKey, stopKey,
1203                                  0.0f, 0);
1204                 mUpperBodyState = UpperCharState_StartToMinAttack;
1205 
1206                 mAttackStrength = std::min(1.f, 0.1f + Misc::Rng::rollClosedProbability());
1207 
1208                 if (weapType == ESM::Weapon::HandToHand)
1209                     playSwishSound(0.0f);
1210             }
1211         }
1212 
1213         mAttackingOrSpell = false;
1214     }
1215 
1216     bool animPlaying = mAnimation->getInfo(mCurrentWeapon);
1217     if (!animPlaying)
1218         mUpperBodyState = UpperCharState_Nothing;
1219     return false;
1220 }
1221 
updateCarriedLeftVisible(const int weaptype) const1222 bool CharacterController::updateCarriedLeftVisible(const int weaptype) const
1223 {
1224     // Shields/torches shouldn't be visible during any operation involving two hands
1225     // There seems to be no text keys for this purpose, except maybe for "[un]equip start/stop",
1226     // but they are also present in weapon drawing animation.
1227     return mAnimation->updateCarriedLeftVisible(weaptype);
1228 }
1229 
updateWeaponState(CharacterState & idle)1230 bool CharacterController::updateWeaponState(CharacterState& idle)
1231 {
1232     const MWWorld::Class &cls = mPtr.getClass();
1233     CreatureStats &stats = cls.getCreatureStats(mPtr);
1234     int weaptype = ESM::Weapon::None;
1235     if(stats.getDrawState() == DrawState_Weapon)
1236         weaptype = ESM::Weapon::HandToHand;
1237     else if (stats.getDrawState() == DrawState_Spell)
1238         weaptype = ESM::Weapon::Spell;
1239 
1240     const bool isWerewolf = cls.isNpc() && cls.getNpcStats(mPtr).isWerewolf();
1241 
1242     std::string upSoundId;
1243     std::string downSoundId;
1244     bool weaponChanged = false;
1245     if (mPtr.getClass().hasInventoryStore(mPtr))
1246     {
1247         MWWorld::InventoryStore &inv = cls.getInventoryStore(mPtr);
1248         MWWorld::ContainerStoreIterator weapon = getActiveWeapon(mPtr, &weaptype);
1249         if(stats.getDrawState() == DrawState_Spell)
1250             weapon = inv.getSlot(MWWorld::InventoryStore::Slot_CarriedRight);
1251 
1252         if(weapon != inv.end() && mWeaponType != ESM::Weapon::HandToHand && weaptype != ESM::Weapon::HandToHand && weaptype != ESM::Weapon::Spell && weaptype != ESM::Weapon::None)
1253             upSoundId = weapon->getClass().getUpSoundId(*weapon);
1254 
1255         if(weapon != inv.end() && mWeaponType != ESM::Weapon::HandToHand && mWeaponType != ESM::Weapon::Spell && mWeaponType != ESM::Weapon::None)
1256             downSoundId = weapon->getClass().getDownSoundId(*weapon);
1257 
1258         // weapon->HtH switch: weapon is empty already, so we need to take sound from previous weapon
1259         if(weapon == inv.end() && !mWeapon.isEmpty() && weaptype == ESM::Weapon::HandToHand && mWeaponType != ESM::Weapon::Spell)
1260             downSoundId = mWeapon.getClass().getDownSoundId(mWeapon);
1261 
1262         MWWorld::Ptr newWeapon = weapon != inv.end() ? *weapon : MWWorld::Ptr();
1263 
1264         if (mWeapon != newWeapon)
1265         {
1266             mWeapon = newWeapon;
1267             weaponChanged = true;
1268         }
1269     }
1270 
1271     // For biped actors, blend weapon animations with lower body animations with higher priority
1272     MWRender::Animation::AnimPriority priorityWeapon(Priority_Weapon);
1273     if (mPtr.getClass().isBipedal(mPtr))
1274         priorityWeapon[MWRender::Animation::BoneGroup_LowerBody] = Priority_WeaponLowerBody;
1275 
1276     bool forcestateupdate = false;
1277 
1278     // We should not play equipping animation and sound during weapon->weapon transition
1279     bool isStillWeapon = weaptype != ESM::Weapon::HandToHand && weaptype != ESM::Weapon::Spell && weaptype != ESM::Weapon::None &&
1280                             mWeaponType != ESM::Weapon::HandToHand && mWeaponType != ESM::Weapon::Spell && mWeaponType != ESM::Weapon::None;
1281 
1282     // If the current weapon type was changed in the middle of attack (e.g. by Equip console command or when bound spell expires),
1283     // we should force actor to the "weapon equipped" state, interrupt attack and update animations.
1284     if (isStillWeapon && mWeaponType != weaptype && mUpperBodyState > UpperCharState_WeapEquiped)
1285     {
1286         forcestateupdate = true;
1287         mUpperBodyState = UpperCharState_WeapEquiped;
1288         mAttackingOrSpell = false;
1289         mAnimation->disable(mCurrentWeapon);
1290         mAnimation->showWeapons(true);
1291         if (mPtr == getPlayer())
1292             MWBase::Environment::get().getWorld()->getPlayer().setAttackingOrSpell(false);
1293     }
1294 
1295     if(!isKnockedOut() && !isKnockedDown() && !isRecovery())
1296     {
1297         std::string weapgroup;
1298         if ((!isWerewolf || mWeaponType != ESM::Weapon::Spell)
1299             && weaptype != mWeaponType
1300             && mUpperBodyState != UpperCharState_UnEquipingWeap
1301             && !isStillWeapon)
1302         {
1303             // We can not play un-equip animation if weapon changed since last update
1304             if (!weaponChanged)
1305             {
1306                 // Note: we do not disable unequipping animation automatically to avoid body desync
1307                 weapgroup = getWeaponAnimation(mWeaponType);
1308                 int unequipMask = MWRender::Animation::BlendMask_All;
1309                 bool useShieldAnims = mAnimation->useShieldAnimations();
1310                 if (useShieldAnims && mWeaponType != ESM::Weapon::HandToHand && mWeaponType != ESM::Weapon::Spell && !(mWeaponType == ESM::Weapon::None && weaptype == ESM::Weapon::Spell))
1311                 {
1312                     unequipMask = unequipMask |~MWRender::Animation::BlendMask_LeftArm;
1313                     mAnimation->play("shield", Priority_Block,
1314                                 MWRender::Animation::BlendMask_LeftArm, true,
1315                                 1.0f, "unequip start", "unequip stop", 0.0f, 0);
1316                 }
1317                 else if (mWeaponType == ESM::Weapon::HandToHand)
1318                     mAnimation->showCarriedLeft(false);
1319 
1320                 mAnimation->play(weapgroup, priorityWeapon, unequipMask, false,
1321                                 1.0f, "unequip start", "unequip stop", 0.0f, 0);
1322                 mUpperBodyState = UpperCharState_UnEquipingWeap;
1323 
1324                 mAnimation->detachArrow();
1325 
1326                 // If we do not have the "unequip detach" key, hide weapon manually.
1327                 if (mAnimation->getTextKeyTime(weapgroup+": unequip detach") < 0)
1328                     mAnimation->showWeapons(false);
1329             }
1330 
1331             if(!downSoundId.empty())
1332             {
1333                 MWBase::SoundManager *sndMgr = MWBase::Environment::get().getSoundManager();
1334                 sndMgr->playSound3D(mPtr, downSoundId, 1.0f, 1.0f);
1335             }
1336         }
1337 
1338         float complete;
1339         bool animPlaying = mAnimation->getInfo(mCurrentWeapon, &complete);
1340         if (!animPlaying || complete >= 1.0f)
1341         {
1342             // Weapon is changed, no current animation (e.g. unequipping or attack).
1343             // Start equipping animation now.
1344             if (weaptype != mWeaponType)
1345             {
1346                 forcestateupdate = true;
1347                 bool useShieldAnims = mAnimation->useShieldAnimations();
1348                 if (!useShieldAnims)
1349                     mAnimation->showCarriedLeft(updateCarriedLeftVisible(weaptype));
1350 
1351                 weapgroup = getWeaponAnimation(weaptype);
1352 
1353                 // Note: controllers for ranged weapon should use time for beginning of animation to play shooting properly,
1354                 // for other weapons they should use absolute time. Some mods rely on this behaviour (to rotate throwing projectiles, for example)
1355                 ESM::WeaponType::Class weaponClass = getWeaponType(weaptype)->mWeaponClass;
1356                 bool useRelativeDuration = weaponClass == ESM::WeaponType::Ranged;
1357                 mAnimation->setWeaponGroup(weapgroup, useRelativeDuration);
1358 
1359                 if (!isStillWeapon)
1360                 {
1361                     mAnimation->disable(mCurrentWeapon);
1362                     if (weaptype != ESM::Weapon::None)
1363                     {
1364                         mAnimation->showWeapons(false);
1365                         int equipMask = MWRender::Animation::BlendMask_All;
1366                         if (useShieldAnims && weaptype != ESM::Weapon::Spell)
1367                         {
1368                             equipMask = equipMask |~MWRender::Animation::BlendMask_LeftArm;
1369                             mAnimation->play("shield", Priority_Block,
1370                                         MWRender::Animation::BlendMask_LeftArm, true,
1371                                         1.0f, "equip start", "equip stop", 0.0f, 0);
1372                         }
1373 
1374                         mAnimation->play(weapgroup, priorityWeapon, equipMask, true,
1375                                         1.0f, "equip start", "equip stop", 0.0f, 0);
1376                         mUpperBodyState = UpperCharState_EquipingWeap;
1377 
1378                         // If we do not have the "equip attach" key, show weapon manually.
1379                         if (weaptype != ESM::Weapon::Spell)
1380                         {
1381                             if (mAnimation->getTextKeyTime(weapgroup+": equip attach") < 0)
1382                                 mAnimation->showWeapons(true);
1383                         }
1384                     }
1385                 }
1386 
1387                 if(isWerewolf)
1388                 {
1389                     const MWWorld::ESMStore &store = MWBase::Environment::get().getWorld()->getStore();
1390                     const ESM::Sound *sound = store.get<ESM::Sound>().searchRandom("WolfEquip");
1391                     if(sound)
1392                     {
1393                         MWBase::SoundManager *sndMgr = MWBase::Environment::get().getSoundManager();
1394                         sndMgr->playSound3D(mPtr, sound->mId, 1.0f, 1.0f);
1395                     }
1396                 }
1397 
1398                 mWeaponType = weaptype;
1399                 mCurrentWeapon = getWeaponAnimation(mWeaponType);
1400 
1401                 if(!upSoundId.empty() && !isStillWeapon)
1402                 {
1403                     MWBase::SoundManager *sndMgr = MWBase::Environment::get().getSoundManager();
1404                     sndMgr->playSound3D(mPtr, upSoundId, 1.0f, 1.0f);
1405                 }
1406             }
1407 
1408             // Make sure that we disabled unequipping animation
1409             if (mUpperBodyState == UpperCharState_UnEquipingWeap)
1410             {
1411                 mUpperBodyState = UpperCharState_Nothing;
1412                 mAnimation->disable(mCurrentWeapon);
1413                 mWeaponType = ESM::Weapon::None;
1414                 mCurrentWeapon = getWeaponAnimation(mWeaponType);
1415             }
1416         }
1417     }
1418 
1419     if(isWerewolf)
1420     {
1421         MWBase::SoundManager *sndMgr = MWBase::Environment::get().getSoundManager();
1422         if(cls.getCreatureStats(mPtr).getStance(MWMechanics::CreatureStats::Stance_Run)
1423             && mHasMovedInXY
1424             && !MWBase::Environment::get().getWorld()->isSwimming(mPtr)
1425             && mWeaponType == ESM::Weapon::None)
1426         {
1427             if(!sndMgr->getSoundPlaying(mPtr, "WolfRun"))
1428                 sndMgr->playSound3D(mPtr, "WolfRun", 1.0f, 1.0f, MWSound::Type::Sfx,
1429                                     MWSound::PlayMode::Loop);
1430         }
1431         else
1432             sndMgr->stopSound3D(mPtr, "WolfRun");
1433     }
1434 
1435     // Cancel attack if we no longer have ammunition
1436     bool ammunition = true;
1437     bool isWeapon = false;
1438     float weapSpeed = 1.f;
1439     if (mPtr.getClass().hasInventoryStore(mPtr))
1440     {
1441         MWWorld::InventoryStore &inv = cls.getInventoryStore(mPtr);
1442         MWWorld::ConstContainerStoreIterator weapon = getActiveWeapon(mPtr, &weaptype);
1443         isWeapon = (weapon != inv.end() && weapon->getTypeName() == typeid(ESM::Weapon).name());
1444         if (isWeapon)
1445         {
1446             weapSpeed = weapon->get<ESM::Weapon>()->mBase->mData.mSpeed;
1447             MWWorld::ConstContainerStoreIterator ammo = inv.getSlot(MWWorld::InventoryStore::Slot_Ammunition);
1448             int ammotype = getWeaponType(weapon->get<ESM::Weapon>()->mBase->mData.mType)->mAmmoType;
1449             if (ammotype != ESM::Weapon::None && (ammo == inv.end() || ammo->get<ESM::Weapon>()->mBase->mData.mType != ammotype))
1450                 ammunition = false;
1451         }
1452 
1453         if (!ammunition && mUpperBodyState > UpperCharState_WeapEquiped)
1454         {
1455             mAnimation->disable(mCurrentWeapon);
1456             mUpperBodyState = UpperCharState_WeapEquiped;
1457         }
1458     }
1459 
1460     // Combat for actors with persistent animations obviously will be buggy
1461     if (isPersistentAnimPlaying())
1462         return forcestateupdate;
1463 
1464     float complete;
1465     bool animPlaying;
1466     ESM::WeaponType::Class weapclass = getWeaponType(mWeaponType)->mWeaponClass;
1467     if(mAttackingOrSpell)
1468     {
1469         MWWorld::Ptr player = getPlayer();
1470 
1471         bool resetIdle = ammunition;
1472         if(mUpperBodyState == UpperCharState_WeapEquiped && (mHitState == CharState_None || mHitState == CharState_Block))
1473         {
1474             MWBase::Environment::get().getWorld()->breakInvisibility(mPtr);
1475             mAttackStrength = 0;
1476 
1477             // Randomize attacks for non-bipedal creatures with Weapon flag
1478             if (mPtr.getClass().getTypeName() == typeid(ESM::Creature).name() &&
1479                 !mPtr.getClass().isBipedal(mPtr) &&
1480                 (!mAnimation->hasAnimation(mCurrentWeapon) || isRandomAttackAnimation(mCurrentWeapon)))
1481             {
1482                 mCurrentWeapon = chooseRandomAttackAnimation();
1483             }
1484 
1485             if(mWeaponType == ESM::Weapon::Spell)
1486             {
1487                 // Unset casting flag, otherwise pressing the mouse button down would
1488                 // continue casting every frame if there is no animation
1489                 mAttackingOrSpell = false;
1490                 if (mPtr == player)
1491                 {
1492                     MWBase::Environment::get().getWorld()->getPlayer().setAttackingOrSpell(false);
1493 
1494                     // For the player, set the spell we want to cast
1495                     // This has to be done at the start of the casting animation,
1496                     // *not* when selecting a spell in the GUI (otherwise you could change the spell mid-animation)
1497                     std::string selectedSpell = MWBase::Environment::get().getWindowManager()->getSelectedSpell();
1498                     stats.getSpells().setSelectedSpell(selectedSpell);
1499                 }
1500                 std::string spellid = stats.getSpells().getSelectedSpell();
1501                 bool isMagicItem = false;
1502                 bool canCast = mCastingManualSpell || MWBase::Environment::get().getWorld()->startSpellCast(mPtr);
1503 
1504                 if (spellid.empty())
1505                 {
1506                     if (mPtr.getClass().hasInventoryStore(mPtr))
1507                     {
1508                         MWWorld::InventoryStore& inv = mPtr.getClass().getInventoryStore(mPtr);
1509                         if (inv.getSelectedEnchantItem() != inv.end())
1510                         {
1511                             const MWWorld::Ptr& enchantItem = *inv.getSelectedEnchantItem();
1512                             spellid = enchantItem.getClass().getEnchantment(enchantItem);
1513                             isMagicItem = true;
1514                         }
1515                     }
1516                 }
1517 
1518                 static const bool useCastingAnimations = Settings::Manager::getBool("use magic item animations", "Game");
1519                 if (isMagicItem && !useCastingAnimations)
1520                 {
1521                     // Enchanted items by default do not use casting animations
1522                     MWBase::Environment::get().getWorld()->castSpell(mPtr);
1523                     resetIdle = false;
1524                 }
1525                 else if(!spellid.empty() && canCast)
1526                 {
1527                     MWMechanics::CastSpell cast(mPtr, nullptr, false, mCastingManualSpell);
1528                     cast.playSpellCastingEffects(spellid, isMagicItem);
1529 
1530                     std::vector<ESM::ENAMstruct> effects;
1531                     const MWWorld::ESMStore &store = MWBase::Environment::get().getWorld()->getStore();
1532                     if (isMagicItem)
1533                     {
1534                         const ESM::Enchantment *enchantment = store.get<ESM::Enchantment>().find(spellid);
1535                         effects = enchantment->mEffects.mList;
1536                     }
1537                     else
1538                     {
1539                         const ESM::Spell *spell = store.get<ESM::Spell>().find(spellid);
1540                         effects = spell->mEffects.mList;
1541                     }
1542 
1543                     const ESM::MagicEffect *effect = store.get<ESM::MagicEffect>().find(effects.back().mEffectID); // use last effect of list for color of VFX_Hands
1544 
1545                     const ESM::Static* castStatic = MWBase::Environment::get().getWorld()->getStore().get<ESM::Static>().find ("VFX_Hands");
1546 
1547                     for (size_t iter = 0; iter < effects.size(); ++iter) // play hands vfx for each effect
1548                     {
1549                         if (mAnimation->getNode("Bip01 L Hand"))
1550                             mAnimation->addEffect("meshes\\" + castStatic->mModel, -1, false, "Bip01 L Hand", effect->mParticle);
1551 
1552                         if (mAnimation->getNode("Bip01 R Hand"))
1553                             mAnimation->addEffect("meshes\\" + castStatic->mModel, -1, false, "Bip01 R Hand", effect->mParticle);
1554                     }
1555 
1556                     const ESM::ENAMstruct &firstEffect = effects.at(0); // first effect used for casting animation
1557 
1558                     std::string startKey;
1559                     std::string stopKey;
1560                     if (isRandomAttackAnimation(mCurrentWeapon))
1561                     {
1562                         startKey = "start";
1563                         stopKey = "stop";
1564                         MWBase::Environment::get().getWorld()->castSpell(mPtr, mCastingManualSpell); // No "release" text key to use, so cast immediately
1565                         mCastingManualSpell = false;
1566                     }
1567                     else
1568                     {
1569                         switch(firstEffect.mRange)
1570                         {
1571                             case 0: mAttackType = "self"; break;
1572                             case 1: mAttackType = "touch"; break;
1573                             case 2: mAttackType = "target"; break;
1574                         }
1575 
1576                         startKey = mAttackType+" start";
1577                         stopKey = mAttackType+" stop";
1578                     }
1579 
1580                     mAnimation->play(mCurrentWeapon, priorityWeapon,
1581                                      MWRender::Animation::BlendMask_All, true,
1582                                      1, startKey, stopKey,
1583                                      0.0f, 0);
1584                     mUpperBodyState = UpperCharState_CastingSpell;
1585                 }
1586                 else
1587                 {
1588                     resetIdle = false;
1589                 }
1590             }
1591             else if(mWeaponType == ESM::Weapon::PickProbe)
1592             {
1593                 MWWorld::ContainerStoreIterator weapon = mPtr.getClass().getInventoryStore(mPtr).getSlot(MWWorld::InventoryStore::Slot_CarriedRight);
1594                 MWWorld::Ptr item = *weapon;
1595                 // TODO: this will only work for the player, and needs to be fixed if NPCs should ever use lockpicks/probes.
1596                 MWWorld::Ptr target = MWBase::Environment::get().getWorld()->getFacedObject();
1597                 std::string resultMessage, resultSound;
1598 
1599                 if(!target.isEmpty())
1600                 {
1601                     if(item.getTypeName() == typeid(ESM::Lockpick).name())
1602                         Security(mPtr).pickLock(target, item, resultMessage, resultSound);
1603                     else if(item.getTypeName() == typeid(ESM::Probe).name())
1604                         Security(mPtr).probeTrap(target, item, resultMessage, resultSound);
1605                 }
1606                 mAnimation->play(mCurrentWeapon, priorityWeapon,
1607                                  MWRender::Animation::BlendMask_All, true,
1608                                  1.0f, "start", "stop", 0.0, 0);
1609                 mUpperBodyState = UpperCharState_FollowStartToFollowStop;
1610 
1611                 if(!resultMessage.empty())
1612                     MWBase::Environment::get().getWindowManager()->messageBox(resultMessage);
1613                 if(!resultSound.empty())
1614                     MWBase::Environment::get().getSoundManager()->playSound3D(target, resultSound,
1615                                                                               1.0f, 1.0f);
1616             }
1617             else if (ammunition)
1618             {
1619                 std::string startKey;
1620                 std::string stopKey;
1621 
1622                 if(weapclass == ESM::WeaponType::Ranged || weapclass == ESM::WeaponType::Thrown)
1623                 {
1624                     mAttackType = "shoot";
1625                     startKey = mAttackType+" start";
1626                     stopKey = mAttackType+" min attack";
1627                 }
1628                 else if (isRandomAttackAnimation(mCurrentWeapon))
1629                 {
1630                     startKey = "start";
1631                     stopKey = "stop";
1632                 }
1633                 else
1634                 {
1635                     if(mPtr == getPlayer())
1636                     {
1637                         if (Settings::Manager::getBool("best attack", "Game"))
1638                         {
1639                             if (isWeapon)
1640                             {
1641                                 MWWorld::ConstContainerStoreIterator weapon = mPtr.getClass().getInventoryStore(mPtr).getSlot(MWWorld::InventoryStore::Slot_CarriedRight);
1642                                 mAttackType = getBestAttack(weapon->get<ESM::Weapon>()->mBase);
1643                             }
1644                             else
1645                             {
1646                                 // There is no "best attack" for Hand-to-Hand
1647                                 setAttackTypeRandomly(mAttackType);
1648                             }
1649                         }
1650                         else
1651                         {
1652                             setAttackTypeBasedOnMovement();
1653                         }
1654                     }
1655                     // else if (mPtr != getPlayer()) use mAttackType set by AiCombat
1656                     startKey = mAttackType+" start";
1657                     stopKey = mAttackType+" min attack";
1658                 }
1659 
1660                 mAnimation->play(mCurrentWeapon, priorityWeapon,
1661                                  MWRender::Animation::BlendMask_All, false,
1662                                  weapSpeed, startKey, stopKey,
1663                                  0.0f, 0);
1664                 mUpperBodyState = UpperCharState_StartToMinAttack;
1665             }
1666         }
1667 
1668         // We should not break swim and sneak animations
1669         if (resetIdle &&
1670             idle != CharState_IdleSneak && idle != CharState_IdleSwim &&
1671             mIdleState != CharState_IdleSneak && mIdleState != CharState_IdleSwim)
1672         {
1673             mAnimation->disable(mCurrentIdle);
1674             mIdleState = CharState_None;
1675         }
1676 
1677         animPlaying = mAnimation->getInfo(mCurrentWeapon, &complete);
1678         if(mUpperBodyState == UpperCharState_MinAttackToMaxAttack && !isKnockedDown())
1679             mAttackStrength = complete;
1680     }
1681     else
1682     {
1683         animPlaying = mAnimation->getInfo(mCurrentWeapon, &complete);
1684         if(mUpperBodyState == UpperCharState_MinAttackToMaxAttack && !isKnockedDown())
1685         {
1686             float attackStrength = complete;
1687             float minAttackTime = mAnimation->getTextKeyTime(mCurrentWeapon+": "+mAttackType+" "+"min attack");
1688             float maxAttackTime = mAnimation->getTextKeyTime(mCurrentWeapon+": "+mAttackType+" "+"max attack");
1689             if (minAttackTime == maxAttackTime)
1690             {
1691                 // most creatures don't actually have an attack wind-up animation, so use a uniform random value
1692                 // (even some creatures that can use weapons don't have a wind-up animation either, e.g. Rieklings)
1693                 // Note: vanilla MW uses a random value for *all* non-player actors, but we probably don't need to go that far.
1694                 attackStrength = std::min(1.f, 0.1f + Misc::Rng::rollClosedProbability());
1695             }
1696 
1697             if(weapclass != ESM::WeaponType::Ranged && weapclass != ESM::WeaponType::Thrown)
1698             {
1699                 MWBase::SoundManager *sndMgr = MWBase::Environment::get().getSoundManager();
1700 
1701                 if(isWerewolf)
1702                 {
1703                     const MWWorld::ESMStore &store = MWBase::Environment::get().getWorld()->getStore();
1704                     const ESM::Sound *sound = store.get<ESM::Sound>().searchRandom("WolfSwing");
1705                     if(sound)
1706                         sndMgr->playSound3D(mPtr, sound->mId, 1.0f, 1.0f);
1707                 }
1708                 else
1709                 {
1710                     playSwishSound(attackStrength);
1711                 }
1712             }
1713             mAttackStrength = attackStrength;
1714 
1715             mAnimation->disable(mCurrentWeapon);
1716             mAnimation->play(mCurrentWeapon, priorityWeapon,
1717                              MWRender::Animation::BlendMask_All, false,
1718                              weapSpeed, mAttackType+" max attack", mAttackType+" min hit",
1719                              1.0f-complete, 0);
1720 
1721             complete = 0.f;
1722             mUpperBodyState = UpperCharState_MaxAttackToMinHit;
1723         }
1724         else if (isKnockedDown())
1725         {
1726             if (mUpperBodyState > UpperCharState_WeapEquiped)
1727             {
1728                 mUpperBodyState = UpperCharState_WeapEquiped;
1729                 if (mWeaponType > ESM::Weapon::None)
1730                     mAnimation->showWeapons(true);
1731             }
1732             mAnimation->disable(mCurrentWeapon);
1733         }
1734     }
1735 
1736     mAnimation->setPitchFactor(0.f);
1737     if (weapclass == ESM::WeaponType::Ranged || weapclass == ESM::WeaponType::Thrown)
1738     {
1739         switch (mUpperBodyState)
1740         {
1741         case UpperCharState_StartToMinAttack:
1742             mAnimation->setPitchFactor(complete);
1743             break;
1744         case UpperCharState_MinAttackToMaxAttack:
1745         case UpperCharState_MaxAttackToMinHit:
1746         case UpperCharState_MinHitToHit:
1747             mAnimation->setPitchFactor(1.f);
1748             break;
1749         case UpperCharState_FollowStartToFollowStop:
1750             if (animPlaying)
1751             {
1752                 // technically we do not need a pitch for crossbow reload animation,
1753                 // but we should avoid abrupt repositioning
1754                 if (mWeaponType == ESM::Weapon::MarksmanCrossbow)
1755                     mAnimation->setPitchFactor(std::max(0.f, 1.f-complete*10.f));
1756                 else
1757                     mAnimation->setPitchFactor(1.f-complete);
1758             }
1759             break;
1760         default:
1761             break;
1762         }
1763     }
1764 
1765     if(!animPlaying)
1766     {
1767         if(mUpperBodyState == UpperCharState_EquipingWeap ||
1768            mUpperBodyState == UpperCharState_FollowStartToFollowStop ||
1769            mUpperBodyState == UpperCharState_CastingSpell)
1770         {
1771             if (ammunition && mWeaponType == ESM::Weapon::MarksmanCrossbow)
1772                 mAnimation->attachArrow();
1773 
1774             mUpperBodyState = UpperCharState_WeapEquiped;
1775         }
1776         else if(mUpperBodyState == UpperCharState_UnEquipingWeap)
1777             mUpperBodyState = UpperCharState_Nothing;
1778     }
1779     else if(complete >= 1.0f && !isRandomAttackAnimation(mCurrentWeapon))
1780     {
1781         std::string start, stop;
1782         switch(mUpperBodyState)
1783         {
1784             case UpperCharState_MinAttackToMaxAttack:
1785                 //hack to avoid body pos desync when jumping/sneaking in 'max attack' state
1786                 if(!mAnimation->isPlaying(mCurrentWeapon))
1787                     mAnimation->play(mCurrentWeapon, priorityWeapon,
1788                         MWRender::Animation::BlendMask_All, false,
1789                         0, mAttackType+" min attack", mAttackType+" max attack", 0.999f, 0);
1790                 break;
1791             case UpperCharState_StartToMinAttack:
1792             case UpperCharState_MaxAttackToMinHit:
1793             {
1794                 if (mUpperBodyState == UpperCharState_StartToMinAttack)
1795                 {
1796                     // If actor is already stopped preparing attack, do not play the "min attack -> max attack" part.
1797                     // Happens if the player did not hold the attack button.
1798                     // Note: if the "min attack"->"max attack" is a stub, "play" it anyway. Attack strength will be random.
1799                     float minAttackTime = mAnimation->getTextKeyTime(mCurrentWeapon+": "+mAttackType+" "+"min attack");
1800                     float maxAttackTime = mAnimation->getTextKeyTime(mCurrentWeapon+": "+mAttackType+" "+"max attack");
1801                     if (mAttackingOrSpell || minAttackTime == maxAttackTime)
1802                     {
1803                         start = mAttackType+" min attack";
1804                         stop = mAttackType+" max attack";
1805                         mUpperBodyState = UpperCharState_MinAttackToMaxAttack;
1806                         break;
1807                     }
1808 
1809                     if(weapclass != ESM::WeaponType::Ranged && weapclass != ESM::WeaponType::Thrown)
1810                         playSwishSound(0.0f);
1811                 }
1812 
1813                 if(mAttackType == "shoot")
1814                 {
1815                     start = mAttackType+" min hit";
1816                     stop = mAttackType+" release";
1817                 }
1818                 else
1819                 {
1820                     start = mAttackType+" min hit";
1821                     stop = mAttackType+" hit";
1822                 }
1823                 mUpperBodyState = UpperCharState_MinHitToHit;
1824                 break;
1825             }
1826             case UpperCharState_MinHitToHit:
1827                 if(mAttackType == "shoot")
1828                 {
1829                     start = mAttackType+" follow start";
1830                     stop = mAttackType+" follow stop";
1831                 }
1832                 else
1833                 {
1834                     float str = mAttackStrength;
1835                     start = mAttackType+((str < 0.5f) ? " small follow start"
1836                                                                   : (str < 1.0f) ? " medium follow start"
1837                                                                                  : " large follow start");
1838                     stop = mAttackType+((str < 0.5f) ? " small follow stop"
1839                                                                  : (str < 1.0f) ? " medium follow stop"
1840                                                                                 : " large follow stop");
1841                 }
1842                 mUpperBodyState = UpperCharState_FollowStartToFollowStop;
1843                 break;
1844             default:
1845                 break;
1846         }
1847 
1848         // Note: apply crossbow reload animation only for upper body
1849         // since blending with movement animations can give weird result.
1850         if(!start.empty())
1851         {
1852             int mask = MWRender::Animation::BlendMask_All;
1853             if (mWeaponType == ESM::Weapon::MarksmanCrossbow)
1854                 mask = MWRender::Animation::BlendMask_UpperBody;
1855 
1856             mAnimation->disable(mCurrentWeapon);
1857             if (mUpperBodyState == UpperCharState_FollowStartToFollowStop)
1858                 mAnimation->play(mCurrentWeapon, priorityWeapon,
1859                                  mask, true,
1860                                  weapSpeed, start, stop, 0.0f, 0);
1861             else
1862                 mAnimation->play(mCurrentWeapon, priorityWeapon,
1863                                  mask, false,
1864                                  weapSpeed, start, stop, 0.0f, 0);
1865         }
1866     }
1867     else if(complete >= 1.0f && isRandomAttackAnimation(mCurrentWeapon))
1868     {
1869         mAnimation->disable(mCurrentWeapon);
1870         mUpperBodyState = UpperCharState_WeapEquiped;
1871     }
1872 
1873     if (mPtr.getClass().hasInventoryStore(mPtr))
1874     {
1875         const MWWorld::InventoryStore& inv = mPtr.getClass().getInventoryStore(mPtr);
1876         MWWorld::ConstContainerStoreIterator torch = inv.getSlot(MWWorld::InventoryStore::Slot_CarriedLeft);
1877         if(torch != inv.end() && torch->getTypeName() == typeid(ESM::Light).name()
1878                 && updateCarriedLeftVisible(mWeaponType))
1879         {
1880             if (mAnimation->isPlaying("shield"))
1881                 mAnimation->disable("shield");
1882 
1883             mAnimation->play("torch", Priority_Torch, MWRender::Animation::BlendMask_LeftArm,
1884                 false, 1.0f, "start", "stop", 0.0f, (~(size_t)0), true);
1885         }
1886         else if (mAnimation->isPlaying("torch"))
1887         {
1888             mAnimation->disable("torch");
1889         }
1890     }
1891 
1892     mAnimation->setAccurateAiming(mUpperBodyState > UpperCharState_WeapEquiped);
1893 
1894     return forcestateupdate;
1895 }
1896 
updateAnimQueue()1897 void CharacterController::updateAnimQueue()
1898 {
1899     if(mAnimQueue.size() > 1)
1900     {
1901         if(mAnimation->isPlaying(mAnimQueue.front().mGroup) == false)
1902         {
1903             mAnimation->disable(mAnimQueue.front().mGroup);
1904             mAnimQueue.pop_front();
1905 
1906             bool loopfallback = (mAnimQueue.front().mGroup.compare(0,4,"idle") == 0);
1907             mAnimation->play(mAnimQueue.front().mGroup, Priority_Default,
1908                              MWRender::Animation::BlendMask_All, false,
1909                              1.0f, "start", "stop", 0.0f, mAnimQueue.front().mLoopCount, loopfallback);
1910         }
1911     }
1912 
1913     if(!mAnimQueue.empty())
1914         mAnimation->setLoopingEnabled(mAnimQueue.front().mGroup, mAnimQueue.size() <= 1);
1915 }
1916 
update(float duration)1917 void CharacterController::update(float duration)
1918 {
1919     MWBase::World *world = MWBase::Environment::get().getWorld();
1920     const MWWorld::Class &cls = mPtr.getClass();
1921     osg::Vec3f movement(0.f, 0.f, 0.f);
1922     float speed = 0.f;
1923 
1924     updateMagicEffects();
1925 
1926     if (isKnockedOut())
1927         mTimeUntilWake -= duration;
1928 
1929     bool isPlayer = mPtr == MWMechanics::getPlayer();
1930     bool isFirstPersonPlayer = isPlayer && MWBase::Environment::get().getWorld()->isFirstPerson();
1931     bool godmode = isPlayer && MWBase::Environment::get().getWorld()->getGodModeState();
1932 
1933     float scale = mPtr.getCellRef().getScale();
1934 
1935     static const bool normalizeSpeed = Settings::Manager::getBool("normalise race speed", "Game");
1936     if (!normalizeSpeed && mPtr.getClass().isNpc())
1937     {
1938         const ESM::NPC* npc = mPtr.get<ESM::NPC>()->mBase;
1939         const ESM::Race* race = world->getStore().get<ESM::Race>().find(npc->mRace);
1940         float weight = npc->isMale() ? race->mData.mWeight.mMale : race->mData.mWeight.mFemale;
1941         scale *= weight;
1942     }
1943 
1944     if(!cls.isActor())
1945         updateAnimQueue();
1946     else if(!cls.getCreatureStats(mPtr).isDead())
1947     {
1948         bool onground = world->isOnGround(mPtr);
1949         bool incapacitated = ((!godmode && cls.getCreatureStats(mPtr).isParalyzed()) || cls.getCreatureStats(mPtr).getKnockedDown());
1950         bool inwater = world->isSwimming(mPtr);
1951         bool flying = world->isFlying(mPtr);
1952         bool solid = world->isActorCollisionEnabled(mPtr);
1953         // Can't run and sneak while flying (see speed formula in Npc/Creature::getSpeed)
1954         bool sneak = cls.getCreatureStats(mPtr).getStance(MWMechanics::CreatureStats::Stance_Sneak) && !flying;
1955         bool isrunning = cls.getCreatureStats(mPtr).getStance(MWMechanics::CreatureStats::Stance_Run) && !flying;
1956         CreatureStats &stats = cls.getCreatureStats(mPtr);
1957         Movement& movementSettings = cls.getMovementSettings(mPtr);
1958 
1959         //Force Jump Logic
1960 
1961         bool isMoving = (std::abs(movementSettings.mPosition[0]) > .5 || std::abs(movementSettings.mPosition[1]) > .5);
1962         if(!inwater && !flying && solid)
1963         {
1964             //Force Jump
1965             if(stats.getMovementFlag(MWMechanics::CreatureStats::Flag_ForceJump))
1966                 movementSettings.mPosition[2] = onground ? 1 : 0;
1967             //Force Move Jump, only jump if they're otherwise moving
1968             if(stats.getMovementFlag(MWMechanics::CreatureStats::Flag_ForceMoveJump) && isMoving)
1969                 movementSettings.mPosition[2] = onground ? 1 : 0;
1970         }
1971 
1972         osg::Vec3f rot = cls.getRotationVector(mPtr);
1973         osg::Vec3f vec(movementSettings.asVec3());
1974         movementSettings.mSpeedFactor = std::min(vec.length(), 1.f);
1975         vec.normalize();
1976 
1977         // TODO: Move this check to mwinput.
1978         // Joystick analogue movement.
1979         // Due to the half way split between walking/running, we multiply speed by 2 while walking, unless a keyboard was used.
1980         if (isPlayer && !isrunning && !sneak && !flying && movementSettings.mSpeedFactor <= 0.5f)
1981             movementSettings.mSpeedFactor *= 2.f;
1982 
1983         static const bool smoothMovement = Settings::Manager::getBool("smooth movement", "Game");
1984         if (smoothMovement)
1985         {
1986             static const float playerTurningCoef = 1.0 / std::max(0.01f, Settings::Manager::getFloat("smooth movement player turning delay", "Game"));
1987             float angle = mPtr.getRefData().getPosition().rot[2];
1988             osg::Vec2f targetSpeed = Misc::rotateVec2f(osg::Vec2f(vec.x(), vec.y()), -angle) * movementSettings.mSpeedFactor;
1989             osg::Vec2f delta = targetSpeed - mSmoothedSpeed;
1990             float speedDelta = movementSettings.mSpeedFactor - mSmoothedSpeed.length();
1991             float deltaLen = delta.length();
1992 
1993             float maxDelta;
1994             if (isFirstPersonPlayer)
1995                 maxDelta = 1;
1996             else if (std::abs(speedDelta) < deltaLen / 2)
1997                 // Turning is smooth for player and less smooth for NPCs (otherwise NPC can miss a path point).
1998                 maxDelta = duration * (isPlayer ? playerTurningCoef : 6.f);
1999             else if (isPlayer && speedDelta < -deltaLen / 2)
2000                 // As soon as controls are released, mwinput switches player from running to walking.
2001                 // So stopping should be instant for player, otherwise it causes a small twitch.
2002                 maxDelta = 1;
2003             else // In all other cases speeding up and stopping are smooth.
2004                 maxDelta = duration * 3.f;
2005 
2006             if (deltaLen > maxDelta)
2007                 delta *= maxDelta / deltaLen;
2008             mSmoothedSpeed += delta;
2009 
2010             osg::Vec2f newSpeed = Misc::rotateVec2f(mSmoothedSpeed, angle);
2011             movementSettings.mSpeedFactor = newSpeed.normalize();
2012             vec.x() = newSpeed.x();
2013             vec.y() = newSpeed.y();
2014 
2015             const float eps = 0.001f;
2016             if (movementSettings.mSpeedFactor < eps)
2017             {
2018                 movementSettings.mSpeedFactor = 0;
2019                 vec.x() = 0;
2020                 vec.y() = 1;
2021             }
2022             else if ((vec.y() < 0) != mIsMovingBackward)
2023             {
2024                 if (targetSpeed.length() < eps || (movementSettings.mPosition[1] < 0) == mIsMovingBackward)
2025                     vec.y() = mIsMovingBackward ? -eps : eps;
2026             }
2027             vec.normalize();
2028         }
2029 
2030         float effectiveRotation = rot.z();
2031         bool canMove = cls.getMaxSpeed(mPtr) > 0;
2032         static const bool turnToMovementDirection = Settings::Manager::getBool("turn to movement direction", "Game");
2033         if (!turnToMovementDirection || isFirstPersonPlayer)
2034         {
2035             movementSettings.mIsStrafing = std::abs(vec.x()) > std::abs(vec.y()) * 2;
2036             stats.setSideMovementAngle(0);
2037         }
2038         else if (canMove)
2039         {
2040             float targetMovementAngle = vec.y() >= 0 ? std::atan2(-vec.x(), vec.y()) : std::atan2(vec.x(), -vec.y());
2041             movementSettings.mIsStrafing = (stats.getDrawState() != MWMechanics::DrawState_Nothing || inwater)
2042                                            && std::abs(targetMovementAngle) > osg::DegreesToRadians(60.0f);
2043             if (movementSettings.mIsStrafing)
2044                 targetMovementAngle = 0;
2045             float delta = targetMovementAngle - stats.getSideMovementAngle();
2046             float cosDelta = cosf(delta);
2047 
2048             if ((vec.y() < 0) == mIsMovingBackward)
2049                 movementSettings.mSpeedFactor *= std::min(std::max(cosDelta, 0.f) + 0.3f, 1.f); // slow down when turn
2050             if (std::abs(delta) < osg::DegreesToRadians(20.0f))
2051                 mIsMovingBackward = vec.y() < 0;
2052 
2053             float maxDelta = osg::PI * duration * (2.5f - cosDelta);
2054             delta = osg::clampBetween(delta, -maxDelta, maxDelta);
2055             stats.setSideMovementAngle(stats.getSideMovementAngle() + delta);
2056             effectiveRotation += delta;
2057         }
2058 
2059         mAnimation->setLegsYawRadians(stats.getSideMovementAngle());
2060         if (stats.getDrawState() == MWMechanics::DrawState_Nothing || inwater)
2061             mAnimation->setUpperBodyYawRadians(stats.getSideMovementAngle() / 2);
2062         else
2063             mAnimation->setUpperBodyYawRadians(stats.getSideMovementAngle() / 4);
2064         if (smoothMovement && !isPlayer && !inwater)
2065             mAnimation->setUpperBodyYawRadians(mAnimation->getUpperBodyYawRadians() + mAnimation->getHeadYaw() / 2);
2066 
2067         speed = cls.getCurrentSpeed(mPtr);
2068         vec.x() *= speed;
2069         vec.y() *= speed;
2070 
2071         if(mHitState != CharState_None && mJumpState == JumpState_None)
2072             vec = osg::Vec3f();
2073 
2074         CharacterState movestate = CharState_None;
2075         CharacterState idlestate = CharState_SpecialIdle;
2076         JumpingState jumpstate = JumpState_None;
2077 
2078         bool forcestateupdate = false;
2079 
2080         mHasMovedInXY = std::abs(vec.x())+std::abs(vec.y()) > 0.0f;
2081         isrunning = isrunning && mHasMovedInXY;
2082 
2083         // advance athletics
2084         if(mHasMovedInXY && isPlayer)
2085         {
2086             if(inwater)
2087             {
2088                 mSecondsOfSwimming += duration;
2089                 while(mSecondsOfSwimming > 1)
2090                 {
2091                     cls.skillUsageSucceeded(mPtr, ESM::Skill::Athletics, 1);
2092                     mSecondsOfSwimming -= 1;
2093                 }
2094             }
2095             else if(isrunning && !sneak)
2096             {
2097                 mSecondsOfRunning += duration;
2098                 while(mSecondsOfRunning > 1)
2099                 {
2100                     cls.skillUsageSucceeded(mPtr, ESM::Skill::Athletics, 0);
2101                     mSecondsOfRunning -= 1;
2102                 }
2103             }
2104         }
2105 
2106         // reduce fatigue
2107         const MWWorld::Store<ESM::GameSetting> &gmst = world->getStore().get<ESM::GameSetting>();
2108         float fatigueLoss = 0;
2109         static const float fFatigueRunBase = gmst.find("fFatigueRunBase")->mValue.getFloat();
2110         static const float fFatigueRunMult = gmst.find("fFatigueRunMult")->mValue.getFloat();
2111         static const float fFatigueSwimWalkBase = gmst.find("fFatigueSwimWalkBase")->mValue.getFloat();
2112         static const float fFatigueSwimRunBase = gmst.find("fFatigueSwimRunBase")->mValue.getFloat();
2113         static const float fFatigueSwimWalkMult = gmst.find("fFatigueSwimWalkMult")->mValue.getFloat();
2114         static const float fFatigueSwimRunMult = gmst.find("fFatigueSwimRunMult")->mValue.getFloat();
2115         static const float fFatigueSneakBase = gmst.find("fFatigueSneakBase")->mValue.getFloat();
2116         static const float fFatigueSneakMult = gmst.find("fFatigueSneakMult")->mValue.getFloat();
2117 
2118         if (cls.getEncumbrance(mPtr) <= cls.getCapacity(mPtr))
2119         {
2120             const float encumbrance = cls.getNormalizedEncumbrance(mPtr);
2121             if (sneak)
2122                 fatigueLoss = fFatigueSneakBase + encumbrance * fFatigueSneakMult;
2123             else
2124             {
2125                 if (inwater)
2126                 {
2127                     if (!isrunning)
2128                         fatigueLoss = fFatigueSwimWalkBase + encumbrance * fFatigueSwimWalkMult;
2129                     else
2130                         fatigueLoss = fFatigueSwimRunBase + encumbrance * fFatigueSwimRunMult;
2131                 }
2132                 else if (isrunning)
2133                     fatigueLoss = fFatigueRunBase + encumbrance * fFatigueRunMult;
2134             }
2135         }
2136         fatigueLoss *= duration;
2137         fatigueLoss *= movementSettings.mSpeedFactor;
2138         DynamicStat<float> fatigue = cls.getCreatureStats(mPtr).getFatigue();
2139 
2140         if (!godmode)
2141         {
2142             fatigue.setCurrent(fatigue.getCurrent() - fatigueLoss, fatigue.getCurrent() < 0);
2143             cls.getCreatureStats(mPtr).setFatigue(fatigue);
2144         }
2145 
2146         float z = cls.getJump(mPtr);
2147         if(sneak || inwater || flying || incapacitated || !solid || z <= 0)
2148             vec.z() = 0.0f;
2149 
2150         bool inJump = true;
2151         bool playLandingSound = false;
2152         if(!onground && !flying && !inwater && solid)
2153         {
2154             // In the air (either getting up —ascending part of jump— or falling).
2155 
2156             forcestateupdate = (mJumpState != JumpState_InAir);
2157             jumpstate = JumpState_InAir;
2158 
2159             static const float fJumpMoveBase = gmst.find("fJumpMoveBase")->mValue.getFloat();
2160             static const float fJumpMoveMult = gmst.find("fJumpMoveMult")->mValue.getFloat();
2161             float factor = fJumpMoveBase + fJumpMoveMult * mPtr.getClass().getSkill(mPtr, ESM::Skill::Acrobatics)/100.f;
2162             factor = std::min(1.f, factor);
2163             vec.x() *= factor;
2164             vec.y() *= factor;
2165             vec.z()  = 0.0f;
2166         }
2167         else if(vec.z() > 0.0f && mJumpState != JumpState_InAir)
2168         {
2169             // Started a jump.
2170             if (z > 0)
2171             {
2172                 if(vec.x() == 0 && vec.y() == 0)
2173                     vec = osg::Vec3f(0.0f, 0.0f, z);
2174                 else
2175                 {
2176                     osg::Vec3f lat (vec.x(), vec.y(), 0.0f);
2177                     lat.normalize();
2178                     vec = osg::Vec3f(lat.x(), lat.y(), 1.0f) * z * 0.707f;
2179                 }
2180             }
2181         }
2182         else if(mJumpState == JumpState_InAir && !inwater && !flying && solid)
2183         {
2184             forcestateupdate = true;
2185             jumpstate = JumpState_Landing;
2186             vec.z() = 0.0f;
2187 
2188             // We should reset idle animation during landing
2189             mAnimation->disable(mCurrentIdle);
2190 
2191             float height = cls.getCreatureStats(mPtr).land(isPlayer);
2192             float healthLost = getFallDamage(mPtr, height);
2193 
2194             if (healthLost > 0.0f)
2195             {
2196                 const float fatigueTerm = cls.getCreatureStats(mPtr).getFatigueTerm();
2197 
2198                 // inflict fall damages
2199                 if (!godmode)
2200                 {
2201                     float realHealthLost = static_cast<float>(healthLost * (1.0f - 0.25f * fatigueTerm));
2202                     cls.onHit(mPtr, realHealthLost, true, MWWorld::Ptr(), MWWorld::Ptr(), osg::Vec3f(), true);
2203                 }
2204 
2205                 const float acrobaticsSkill = cls.getSkill(mPtr, ESM::Skill::Acrobatics);
2206                 if (healthLost > (acrobaticsSkill * fatigueTerm))
2207                 {
2208                     if (!godmode)
2209                         cls.getCreatureStats(mPtr).setKnockedDown(true);
2210                 }
2211                 else
2212                 {
2213                     // report acrobatics progression
2214                     if (isPlayer)
2215                         cls.skillUsageSucceeded(mPtr, ESM::Skill::Acrobatics, 1);
2216                 }
2217             }
2218 
2219             if (mPtr.getClass().isNpc())
2220                 playLandingSound = true;
2221         }
2222         else
2223         {
2224             if(mPtr.getClass().isNpc() && mJumpState == JumpState_InAir && !flying && solid)
2225                 playLandingSound = true;
2226 
2227             jumpstate = mAnimation->isPlaying(mCurrentJump) ? JumpState_Landing : JumpState_None;
2228 
2229             vec.x() *= scale;
2230             vec.y() *= scale;
2231             vec.z() = 0.0f;
2232 
2233             inJump = false;
2234 
2235             if (movementSettings.mIsStrafing)
2236             {
2237                 if(vec.x() > 0.0f)
2238                     movestate = (inwater ? (isrunning ? CharState_SwimRunRight : CharState_SwimWalkRight)
2239                                          : (sneak ? CharState_SneakRight
2240                                                   : (isrunning ? CharState_RunRight : CharState_WalkRight)));
2241                 else if(vec.x() < 0.0f)
2242                     movestate = (inwater ? (isrunning ? CharState_SwimRunLeft : CharState_SwimWalkLeft)
2243                                          : (sneak ? CharState_SneakLeft
2244                                                   : (isrunning ? CharState_RunLeft : CharState_WalkLeft)));
2245             }
2246             else if (vec.length2() > 0.0f)
2247             {
2248                 if (vec.y() >= 0.0f)
2249                     movestate = (inwater ? (isrunning ? CharState_SwimRunForward : CharState_SwimWalkForward)
2250                                          : (sneak ? CharState_SneakForward
2251                                                   : (isrunning ? CharState_RunForward : CharState_WalkForward)));
2252                 else
2253                     movestate = (inwater ? (isrunning ? CharState_SwimRunBack : CharState_SwimWalkBack)
2254                                          : (sneak ? CharState_SneakBack
2255                                                   : (isrunning ? CharState_RunBack : CharState_WalkBack)));
2256             }
2257             else
2258             {
2259                 // Do not play turning animation for player if rotation speed is very slow.
2260                 // Actual threshold should take framerate in account.
2261                 float rotationThreshold = (isPlayer ? 0.015f : 0.001f) * 60 * duration;
2262 
2263                 // It seems only bipedal actors use turning animations.
2264                 // Also do not use turning animations in the first-person view and when sneaking.
2265                 if (!sneak && jumpstate == JumpState_None && !isFirstPersonPlayer && mPtr.getClass().isBipedal(mPtr))
2266                 {
2267                     if(effectiveRotation > rotationThreshold)
2268                         movestate = inwater ? CharState_SwimTurnRight : CharState_TurnRight;
2269                     else if(effectiveRotation < -rotationThreshold)
2270                         movestate = inwater ? CharState_SwimTurnLeft : CharState_TurnLeft;
2271                 }
2272             }
2273         }
2274 
2275         if (playLandingSound)
2276         {
2277             MWBase::SoundManager *sndMgr = MWBase::Environment::get().getSoundManager();
2278             std::string sound;
2279             osg::Vec3f pos(mPtr.getRefData().getPosition().asVec3());
2280             if (world->isUnderwater(mPtr.getCell(), pos) || world->isWalkingOnWater(mPtr))
2281                 sound = "DefaultLandWater";
2282             else if (onground)
2283                 sound = "DefaultLand";
2284 
2285             if (!sound.empty())
2286                 sndMgr->playSound3D(mPtr, sound, 1.f, 1.f, MWSound::Type::Foot, MWSound::PlayMode::NoPlayerLocal);
2287         }
2288 
2289         if (turnToMovementDirection && !isFirstPersonPlayer &&
2290             (movestate == CharState_SwimRunForward || movestate == CharState_SwimWalkForward ||
2291              movestate == CharState_SwimRunBack || movestate == CharState_SwimWalkBack))
2292         {
2293             float swimmingPitch = mAnimation->getBodyPitchRadians();
2294             float targetSwimmingPitch = -mPtr.getRefData().getPosition().rot[0];
2295             float maxSwimPitchDelta = 3.0f * duration;
2296             swimmingPitch += osg::clampBetween(targetSwimmingPitch - swimmingPitch, -maxSwimPitchDelta, maxSwimPitchDelta);
2297             mAnimation->setBodyPitchRadians(swimmingPitch);
2298         }
2299         else
2300             mAnimation->setBodyPitchRadians(0);
2301 
2302         static const bool swimUpwardCorrection = Settings::Manager::getBool("swim upward correction", "Game");
2303         if (inwater && isPlayer && !isFirstPersonPlayer && swimUpwardCorrection)
2304         {
2305             static const float swimUpwardCoef = Settings::Manager::getFloat("swim upward coef", "Game");
2306             static const float swimForwardCoef = sqrtf(1.0f - swimUpwardCoef * swimUpwardCoef);
2307             vec.z() = std::abs(vec.y()) * swimUpwardCoef;
2308             vec.y() *= swimForwardCoef;
2309         }
2310 
2311         // Player can not use smooth turning as NPCs, so we play turning animation a bit to avoid jittering
2312         if (isPlayer)
2313         {
2314             float threshold = mCurrentMovement.find("swim") == std::string::npos ? 0.4f : 0.8f;
2315             float complete;
2316             bool animPlaying = mAnimation->getInfo(mCurrentMovement, &complete);
2317             if (movestate == CharState_None && jumpstate == JumpState_None && isTurning())
2318             {
2319                 if (animPlaying && complete < threshold)
2320                     movestate = mMovementState;
2321             }
2322         }
2323         else
2324         {
2325             if (mPtr.getClass().isBipedal(mPtr))
2326             {
2327                 if (mTurnAnimationThreshold > 0)
2328                     mTurnAnimationThreshold -= duration;
2329 
2330                 if (movestate == CharState_TurnRight || movestate == CharState_TurnLeft ||
2331                     movestate == CharState_SwimTurnRight || movestate == CharState_SwimTurnLeft)
2332                 {
2333                     mTurnAnimationThreshold = 0.05f;
2334                 }
2335                 else if (movestate == CharState_None && isTurning()
2336                         && mTurnAnimationThreshold > 0)
2337                 {
2338                     movestate = mMovementState;
2339                 }
2340             }
2341         }
2342 
2343         if(movestate != CharState_None && !isTurning())
2344             clearAnimQueue();
2345 
2346         if(mAnimQueue.empty() || inwater || (sneak && mIdleState != CharState_SpecialIdle))
2347         {
2348             if (inwater)
2349                 idlestate = CharState_IdleSwim;
2350             else if (sneak && !inJump)
2351                 idlestate = CharState_IdleSneak;
2352             else
2353                 idlestate = CharState_Idle;
2354         }
2355         else
2356             updateAnimQueue();
2357 
2358         if (!mSkipAnim)
2359         {
2360             // bipedal means hand-to-hand could be used (which is handled in updateWeaponState). an existing InventoryStore means an actual weapon could be used.
2361             if(cls.isBipedal(mPtr) || cls.hasInventoryStore(mPtr))
2362                 forcestateupdate = updateWeaponState(idlestate) || forcestateupdate;
2363             else
2364                 forcestateupdate = updateCreatureState() || forcestateupdate;
2365 
2366             refreshCurrentAnims(idlestate, movestate, jumpstate, forcestateupdate);
2367             updateIdleStormState(inwater);
2368         }
2369 
2370         if (inJump)
2371             mMovementAnimationControlled = false;
2372 
2373         if (isTurning())
2374         {
2375             // Adjust animation speed from 1.0 to 1.5 multiplier
2376             if (duration > 0)
2377             {
2378                 float turnSpeed = std::min(1.5f, std::abs(rot.z()) / duration / static_cast<float>(osg::PI));
2379                 mAnimation->adjustSpeedMult(mCurrentMovement, std::max(turnSpeed, 1.0f));
2380             }
2381         }
2382         else if (mMovementState != CharState_None && mAdjustMovementAnimSpeed)
2383         {
2384             // Vanilla caps the played animation speed.
2385             const float maxSpeedMult = 10.f;
2386             const float speedMult = speed / mMovementAnimSpeed;
2387             mAnimation->adjustSpeedMult(mCurrentMovement, std::min(maxSpeedMult, speedMult));
2388             // Make sure the actual speed is the "expected" speed even though the animation is slower
2389             scale *= std::max(1.f, speedMult / maxSpeedMult);
2390         }
2391 
2392         if (!mSkipAnim)
2393         {
2394             if(!isKnockedDown() && !isKnockedOut())
2395             {
2396                 if (rot != osg::Vec3f())
2397                     world->rotateObject(mPtr, rot.x(), rot.y(), rot.z(), true);
2398             }
2399             else //avoid z-rotating for knockdown
2400             {
2401                 if (rot.x() != 0 && rot.y() != 0)
2402                     world->rotateObject(mPtr, rot.x(), rot.y(), 0.0f, true);
2403             }
2404 
2405             if (!mMovementAnimationControlled)
2406                 world->queueMovement(mPtr, vec);
2407         }
2408 
2409         movement = vec;
2410         movementSettings.mPosition[0] = movementSettings.mPosition[1] = 0;
2411         if (movement.z() == 0.f)
2412             movementSettings.mPosition[2] = 0;
2413         // Can't reset jump state (mPosition[2]) here in full; we don't know for sure whether the PhysicSystem will actually handle it in this frame
2414         // due to the fixed minimum timestep used for the physics update. It will be reset in PhysicSystem::move once the jump is handled.
2415 
2416         if (!mSkipAnim)
2417             updateHeadTracking(duration);
2418     }
2419     else if(cls.getCreatureStats(mPtr).isDead())
2420     {
2421         // initial start of death animation for actors that started the game as dead
2422         // not done in constructor since we need to give scripts a chance to set the mSkipAnim flag
2423         if (!mSkipAnim && mDeathState != CharState_None && mCurrentDeath.empty())
2424         {
2425             // Fast-forward death animation to end for persisting corpses or corpses after end of death animation
2426             if (cls.isPersistent(mPtr) || cls.getCreatureStats(mPtr).isDeathAnimationFinished())
2427                 playDeath(1.f, mDeathState);
2428         }
2429     }
2430 
2431     bool isPersist = isPersistentAnimPlaying();
2432     osg::Vec3f moved = mAnimation->runAnimation(mSkipAnim && !isPersist ? 0.f : duration);
2433     if(duration > 0.0f)
2434         moved /= duration;
2435     else
2436         moved = osg::Vec3f(0.f, 0.f, 0.f);
2437 
2438     moved.x() *= scale;
2439     moved.y() *= scale;
2440 
2441     // Ensure we're moving in generally the right direction...
2442     if (speed > 0.f && moved != osg::Vec3f())
2443     {
2444         float l = moved.length();
2445         if (std::abs(movement.x() - moved.x()) > std::abs(moved.x()) / 2 ||
2446             std::abs(movement.y() - moved.y()) > std::abs(moved.y()) / 2 ||
2447             std::abs(movement.z() - moved.z()) > std::abs(moved.z()) / 2)
2448         {
2449             moved = movement;
2450             // For some creatures getSpeed doesn't work, so we adjust speed to the animation.
2451             // TODO: Fix Creature::getSpeed.
2452             float newLength = moved.length();
2453             if (newLength > 0 && !cls.isNpc())
2454                 moved *= (l / newLength);
2455         }
2456     }
2457 
2458     if (mFloatToSurface && cls.isActor())
2459     {
2460         if (cls.getCreatureStats(mPtr).isDead()
2461             || (!godmode && cls.getCreatureStats(mPtr).getMagicEffects().get(ESM::MagicEffect::Paralyze).getModifier() > 0))
2462         {
2463             moved.z() = 1.0;
2464         }
2465     }
2466 
2467     // Update movement
2468     if(mMovementAnimationControlled && mPtr.getClass().isActor())
2469         world->queueMovement(mPtr, moved);
2470 
2471     mSkipAnim = false;
2472 
2473     mAnimation->enableHeadAnimation(cls.isActor() && !cls.getCreatureStats(mPtr).isDead());
2474 }
2475 
persistAnimationState()2476 void CharacterController::persistAnimationState()
2477 {
2478     ESM::AnimationState& state = mPtr.getRefData().getAnimationState();
2479 
2480     state.mScriptedAnims.clear();
2481     for (AnimationQueue::const_iterator iter = mAnimQueue.begin(); iter != mAnimQueue.end(); ++iter)
2482     {
2483         if (!iter->mPersist)
2484             continue;
2485 
2486         ESM::AnimationState::ScriptedAnimation anim;
2487         anim.mGroup = iter->mGroup;
2488 
2489         if (iter == mAnimQueue.begin())
2490         {
2491             anim.mLoopCount = mAnimation->getCurrentLoopCount(anim.mGroup);
2492             float complete;
2493             mAnimation->getInfo(anim.mGroup, &complete, nullptr);
2494             anim.mTime = complete;
2495         }
2496         else
2497         {
2498             anim.mLoopCount = iter->mLoopCount;
2499             anim.mTime = 0.f;
2500         }
2501 
2502         state.mScriptedAnims.push_back(anim);
2503     }
2504 }
2505 
unpersistAnimationState()2506 void CharacterController::unpersistAnimationState()
2507 {
2508     const ESM::AnimationState& state = mPtr.getRefData().getAnimationState();
2509 
2510     if (!state.mScriptedAnims.empty())
2511     {
2512         clearAnimQueue();
2513         for (ESM::AnimationState::ScriptedAnimations::const_iterator iter = state.mScriptedAnims.begin(); iter != state.mScriptedAnims.end(); ++iter)
2514         {
2515             AnimationQueueEntry entry;
2516             entry.mGroup = iter->mGroup;
2517             entry.mLoopCount = iter->mLoopCount;
2518             entry.mPersist = true;
2519 
2520             mAnimQueue.push_back(entry);
2521         }
2522 
2523         const ESM::AnimationState::ScriptedAnimation& anim = state.mScriptedAnims.front();
2524         float complete = anim.mTime;
2525         if (anim.mAbsolute)
2526         {
2527             float start = mAnimation->getTextKeyTime(anim.mGroup+": start");
2528             float stop = mAnimation->getTextKeyTime(anim.mGroup+": stop");
2529             float time = std::max(start, std::min(stop, anim.mTime));
2530             complete = (time - start) / (stop - start);
2531         }
2532 
2533         mAnimation->disable(mCurrentIdle);
2534         mCurrentIdle.clear();
2535         mIdleState = CharState_SpecialIdle;
2536 
2537         bool loopfallback = (mAnimQueue.front().mGroup.compare(0,4,"idle") == 0);
2538         mAnimation->play(anim.mGroup,
2539                          Priority_Persistent, MWRender::Animation::BlendMask_All, false, 1.0f,
2540                          "start", "stop", complete, anim.mLoopCount, loopfallback);
2541     }
2542 }
2543 
playGroup(const std::string & groupname,int mode,int count,bool persist)2544 bool CharacterController::playGroup(const std::string &groupname, int mode, int count, bool persist)
2545 {
2546     if(!mAnimation || !mAnimation->hasAnimation(groupname))
2547         return false;
2548 
2549     // We should not interrupt persistent animations by non-persistent ones
2550     if (isPersistentAnimPlaying() && !persist)
2551         return false;
2552 
2553     // If this animation is a looped animation (has a "loop start" key) that is already playing
2554     // and has not yet reached the end of the loop, allow it to continue animating with its existing loop count
2555     // and remove any other animations that were queued.
2556     // This emulates observed behavior from the original allows the script "OutsideBanner" to animate banners correctly.
2557     if (!mAnimQueue.empty() && mAnimQueue.front().mGroup == groupname &&
2558         mAnimation->getTextKeyTime(mAnimQueue.front().mGroup + ": loop start") >= 0 &&
2559         mAnimation->isPlaying(groupname))
2560     {
2561         float endOfLoop = mAnimation->getTextKeyTime(mAnimQueue.front().mGroup+": loop stop");
2562 
2563         if (endOfLoop < 0) // if no Loop Stop key was found, use the Stop key
2564             endOfLoop = mAnimation->getTextKeyTime(mAnimQueue.front().mGroup+": stop");
2565 
2566         if (endOfLoop > 0 && (mAnimation->getCurrentTime(mAnimQueue.front().mGroup) < endOfLoop))
2567         {
2568             mAnimQueue.resize(1);
2569             return true;
2570         }
2571     }
2572 
2573     count = std::max(count, 1);
2574 
2575     AnimationQueueEntry entry;
2576     entry.mGroup = groupname;
2577     entry.mLoopCount = count-1;
2578     entry.mPersist = persist;
2579 
2580     if(mode != 0 || mAnimQueue.empty() || !isAnimPlaying(mAnimQueue.front().mGroup))
2581     {
2582         clearAnimQueue(persist);
2583 
2584         mAnimation->disable(mCurrentIdle);
2585         mCurrentIdle.clear();
2586 
2587         mIdleState = CharState_SpecialIdle;
2588         bool loopfallback = (entry.mGroup.compare(0,4,"idle") == 0);
2589         mAnimation->play(groupname, persist && groupname != "idle" ? Priority_Persistent : Priority_Default,
2590                             MWRender::Animation::BlendMask_All, false, 1.0f,
2591                             ((mode==2) ? "loop start" : "start"), "stop", 0.0f, count-1, loopfallback);
2592     }
2593     else
2594     {
2595         mAnimQueue.resize(1);
2596     }
2597 
2598     // "PlayGroup idle" is a special case, used to remove to stop scripted animations playing
2599     if (groupname == "idle")
2600         entry.mPersist = false;
2601 
2602     mAnimQueue.push_back(entry);
2603 
2604     return true;
2605 }
2606 
skipAnim()2607 void CharacterController::skipAnim()
2608 {
2609     mSkipAnim = true;
2610 }
2611 
isPersistentAnimPlaying()2612 bool CharacterController::isPersistentAnimPlaying()
2613 {
2614     if (!mAnimQueue.empty())
2615     {
2616         AnimationQueueEntry& first = mAnimQueue.front();
2617         return first.mPersist && isAnimPlaying(first.mGroup);
2618     }
2619 
2620     return false;
2621 }
2622 
isAnimPlaying(const std::string & groupName)2623 bool CharacterController::isAnimPlaying(const std::string &groupName)
2624 {
2625     if(mAnimation == nullptr)
2626         return false;
2627     return mAnimation->isPlaying(groupName);
2628 }
2629 
clearAnimQueue(bool clearPersistAnims)2630 void CharacterController::clearAnimQueue(bool clearPersistAnims)
2631 {
2632     // Do not interrupt scripted animations, if we want to keep them
2633     if ((!isPersistentAnimPlaying() || clearPersistAnims) && !mAnimQueue.empty())
2634         mAnimation->disable(mAnimQueue.front().mGroup);
2635 
2636     for (AnimationQueue::iterator it = mAnimQueue.begin(); it != mAnimQueue.end();)
2637     {
2638         if (clearPersistAnims || !it->mPersist)
2639             it = mAnimQueue.erase(it);
2640         else
2641             ++it;
2642     }
2643 }
2644 
forceStateUpdate()2645 void CharacterController::forceStateUpdate()
2646 {
2647     if(!mAnimation)
2648         return;
2649     clearAnimQueue();
2650 
2651     // Make sure we canceled the current attack or spellcasting,
2652     // because we disabled attack animations anyway.
2653     mCastingManualSpell = false;
2654     mAttackingOrSpell = false;
2655     if (mUpperBodyState != UpperCharState_Nothing)
2656         mUpperBodyState = UpperCharState_WeapEquiped;
2657 
2658     refreshCurrentAnims(mIdleState, mMovementState, mJumpState, true);
2659 
2660     if(mDeathState != CharState_None)
2661     {
2662         playRandomDeath();
2663     }
2664 
2665     mAnimation->runAnimation(0.f);
2666 }
2667 
kill()2668 CharacterController::KillResult CharacterController::kill()
2669 {
2670     if (mDeathState == CharState_None)
2671     {
2672         playRandomDeath();
2673 
2674         mAnimation->disable(mCurrentIdle);
2675 
2676         mIdleState = CharState_None;
2677         mCurrentIdle.clear();
2678         return Result_DeathAnimStarted;
2679     }
2680 
2681     MWMechanics::CreatureStats& cStats = mPtr.getClass().getCreatureStats(mPtr);
2682     if (isAnimPlaying(mCurrentDeath))
2683         return Result_DeathAnimPlaying;
2684     if (!cStats.isDeathAnimationFinished())
2685     {
2686         cStats.setDeathAnimationFinished(true);
2687         return Result_DeathAnimJustFinished;
2688     }
2689     return Result_DeathAnimFinished;
2690 }
2691 
resurrect()2692 void CharacterController::resurrect()
2693 {
2694     if(mDeathState == CharState_None)
2695         return;
2696 
2697     if(mAnimation)
2698         mAnimation->disable(mCurrentDeath);
2699     mCurrentDeath.clear();
2700     mDeathState = CharState_None;
2701     mWeaponType = ESM::Weapon::None;
2702 }
2703 
updateContinuousVfx()2704 void CharacterController::updateContinuousVfx()
2705 {
2706     // Keeping track of when to stop a continuous VFX seems to be very difficult to do inside the spells code,
2707     // as it's extremely spread out (ActiveSpells, Spells, InventoryStore effects, etc...) so we do it here.
2708 
2709     // Stop any effects that are no longer active
2710     std::vector<int> effects;
2711     mAnimation->getLoopingEffects(effects);
2712 
2713     for (int effectId : effects)
2714     {
2715         if (mPtr.getClass().getCreatureStats(mPtr).isDeathAnimationFinished()
2716             || mPtr.getClass().getCreatureStats(mPtr).getMagicEffects().get(MWMechanics::EffectKey(effectId)).getMagnitude() <= 0)
2717             mAnimation->removeEffect(effectId);
2718     }
2719 }
2720 
updateMagicEffects()2721 void CharacterController::updateMagicEffects()
2722 {
2723     if (!mPtr.getClass().isActor())
2724         return;
2725 
2726     float light = mPtr.getClass().getCreatureStats(mPtr).getMagicEffects().get(ESM::MagicEffect::Light).getMagnitude();
2727     mAnimation->setLightEffect(light);
2728 
2729     // If you're dead you don't care about whether you've started/stopped being a vampire or not
2730     if (mPtr.getClass().getCreatureStats(mPtr).isDead())
2731         return;
2732 
2733     bool vampire = mPtr.getClass().getCreatureStats(mPtr).getMagicEffects().get(ESM::MagicEffect::Vampirism).getMagnitude() > 0.0f;
2734     mAnimation->setVampire(vampire);
2735 }
2736 
setVisibility(float visibility)2737 void CharacterController::setVisibility(float visibility)
2738 {
2739     // We should take actor's invisibility in account
2740     if (mPtr.getClass().isActor())
2741     {
2742         float alpha = 1.f;
2743         if (mPtr.getClass().getCreatureStats(mPtr).getMagicEffects().get(ESM::MagicEffect::Invisibility).getModifier()) // Ignore base magnitude (see bug #3555).
2744         {
2745             if (mPtr == getPlayer())
2746                 alpha = 0.25f;
2747             else
2748                 alpha = 0.05f;
2749         }
2750         float chameleon = mPtr.getClass().getCreatureStats(mPtr).getMagicEffects().get(ESM::MagicEffect::Chameleon).getMagnitude();
2751         if (chameleon)
2752         {
2753             alpha *= std::min(0.75f, std::max(0.25f, (100.f - chameleon)/100.f));
2754         }
2755 
2756         visibility = std::min(visibility, alpha);
2757     }
2758 
2759     // TODO: implement a dithering shader rather than just change object transparency.
2760     mAnimation->setAlpha(visibility);
2761 }
2762 
setAttackTypeBasedOnMovement()2763 void CharacterController::setAttackTypeBasedOnMovement()
2764 {
2765     float *move = mPtr.getClass().getMovementSettings(mPtr).mPosition;
2766     if (std::abs(move[1]) > std::abs(move[0]) + 0.2f) // forward-backward
2767         mAttackType = "thrust";
2768     else if (std::abs(move[0]) > std::abs(move[1]) + 0.2f) // sideway
2769         mAttackType = "slash";
2770     else
2771         mAttackType = "chop";
2772 }
2773 
isRandomAttackAnimation(const std::string & group) const2774 bool CharacterController::isRandomAttackAnimation(const std::string& group) const
2775 {
2776     return (group == "attack1" || group == "swimattack1" ||
2777             group == "attack2" || group == "swimattack2" ||
2778             group == "attack3" || group == "swimattack3");
2779 }
2780 
isAttackPreparing() const2781 bool CharacterController::isAttackPreparing() const
2782 {
2783     return mUpperBodyState == UpperCharState_StartToMinAttack ||
2784             mUpperBodyState == UpperCharState_MinAttackToMaxAttack;
2785 }
2786 
isCastingSpell() const2787 bool CharacterController::isCastingSpell() const
2788 {
2789     return mCastingManualSpell || mUpperBodyState == UpperCharState_CastingSpell;
2790 }
2791 
isReadyToBlock() const2792 bool CharacterController::isReadyToBlock() const
2793 {
2794     return updateCarriedLeftVisible(mWeaponType);
2795 }
2796 
isKnockedDown() const2797 bool CharacterController::isKnockedDown() const
2798 {
2799     return mHitState == CharState_KnockDown ||
2800             mHitState == CharState_SwimKnockDown;
2801 }
2802 
isKnockedOut() const2803 bool CharacterController::isKnockedOut() const
2804 {
2805     return mHitState == CharState_KnockOut ||
2806             mHitState == CharState_SwimKnockOut;
2807 }
2808 
isTurning() const2809 bool CharacterController::isTurning() const
2810 {
2811     return mMovementState == CharState_TurnLeft ||
2812             mMovementState == CharState_TurnRight ||
2813             mMovementState == CharState_SwimTurnLeft ||
2814             mMovementState == CharState_SwimTurnRight;
2815 }
2816 
isRecovery() const2817 bool CharacterController::isRecovery() const
2818 {
2819     return mHitState == CharState_Hit ||
2820             mHitState == CharState_SwimHit;
2821 }
2822 
isAttackingOrSpell() const2823 bool CharacterController::isAttackingOrSpell() const
2824 {
2825     return mUpperBodyState != UpperCharState_Nothing &&
2826             mUpperBodyState != UpperCharState_WeapEquiped;
2827 }
2828 
isSneaking() const2829 bool CharacterController::isSneaking() const
2830 {
2831     return mIdleState == CharState_IdleSneak ||
2832             mMovementState == CharState_SneakForward ||
2833             mMovementState == CharState_SneakBack ||
2834             mMovementState == CharState_SneakLeft ||
2835             mMovementState == CharState_SneakRight;
2836 }
2837 
isRunning() const2838 bool CharacterController::isRunning() const
2839 {
2840     return mMovementState == CharState_RunForward ||
2841             mMovementState == CharState_RunBack ||
2842             mMovementState == CharState_RunLeft ||
2843             mMovementState == CharState_RunRight ||
2844             mMovementState == CharState_SwimRunForward ||
2845             mMovementState == CharState_SwimRunBack ||
2846             mMovementState == CharState_SwimRunLeft ||
2847             mMovementState == CharState_SwimRunRight;
2848 }
2849 
setAttackingOrSpell(bool attackingOrSpell)2850 void CharacterController::setAttackingOrSpell(bool attackingOrSpell)
2851 {
2852     mAttackingOrSpell = attackingOrSpell;
2853 }
2854 
castSpell(const std::string spellId,bool manualSpell)2855 void CharacterController::castSpell(const std::string spellId, bool manualSpell)
2856 {
2857     mAttackingOrSpell = true;
2858     mCastingManualSpell = manualSpell;
2859     ActionSpell action = ActionSpell(spellId);
2860     action.prepare(mPtr);
2861 }
2862 
setAIAttackType(const std::string & attackType)2863 void CharacterController::setAIAttackType(const std::string& attackType)
2864 {
2865     mAttackType = attackType;
2866 }
2867 
setAttackTypeRandomly(std::string & attackType)2868 void CharacterController::setAttackTypeRandomly(std::string& attackType)
2869 {
2870     float random = Misc::Rng::rollProbability();
2871     if (random >= 2/3.f)
2872         attackType = "thrust";
2873     else if (random >= 1/3.f)
2874         attackType = "slash";
2875     else
2876         attackType = "chop";
2877 }
2878 
readyToPrepareAttack() const2879 bool CharacterController::readyToPrepareAttack() const
2880 {
2881     return (mHitState == CharState_None || mHitState == CharState_Block)
2882             && mUpperBodyState <= UpperCharState_WeapEquiped;
2883 }
2884 
readyToStartAttack() const2885 bool CharacterController::readyToStartAttack() const
2886 {
2887     if (mHitState != CharState_None && mHitState != CharState_Block)
2888         return false;
2889 
2890     if (mPtr.getClass().hasInventoryStore(mPtr) || mPtr.getClass().isBipedal(mPtr))
2891         return mUpperBodyState == UpperCharState_WeapEquiped;
2892     else
2893         return mUpperBodyState == UpperCharState_Nothing;
2894 }
2895 
getAttackStrength() const2896 float CharacterController::getAttackStrength() const
2897 {
2898     return mAttackStrength;
2899 }
2900 
setActive(int active)2901 void CharacterController::setActive(int active)
2902 {
2903     mAnimation->setActive(active);
2904 }
2905 
setHeadTrackTarget(const MWWorld::ConstPtr & target)2906 void CharacterController::setHeadTrackTarget(const MWWorld::ConstPtr &target)
2907 {
2908     mHeadTrackTarget = target;
2909 }
2910 
playSwishSound(float attackStrength)2911 void CharacterController::playSwishSound(float attackStrength)
2912 {
2913     MWBase::SoundManager *sndMgr = MWBase::Environment::get().getSoundManager();
2914 
2915     std::string sound = "Weapon Swish";
2916     if(attackStrength < 0.5f)
2917         sndMgr->playSound3D(mPtr, sound, 1.0f, 0.8f); //Weak attack
2918     else if(attackStrength < 1.0f)
2919         sndMgr->playSound3D(mPtr, sound, 1.0f, 1.0f); //Medium attack
2920     else
2921         sndMgr->playSound3D(mPtr, sound, 1.0f, 1.2f); //Strong attack
2922 }
2923 
updateHeadTracking(float duration)2924 void CharacterController::updateHeadTracking(float duration)
2925 {
2926     const osg::Node* head = mAnimation->getNode("Bip01 Head");
2927     if (!head)
2928         return;
2929 
2930     double zAngleRadians = 0.f;
2931     double xAngleRadians = 0.f;
2932 
2933     if (!mHeadTrackTarget.isEmpty())
2934     {
2935         osg::NodePathList nodepaths = head->getParentalNodePaths();
2936         if (nodepaths.empty())
2937             return;
2938         osg::Matrixf mat = osg::computeLocalToWorld(nodepaths[0]);
2939         osg::Vec3f headPos = mat.getTrans();
2940 
2941         osg::Vec3f direction;
2942         if (const MWRender::Animation* anim = MWBase::Environment::get().getWorld()->getAnimation(mHeadTrackTarget))
2943         {
2944             const osg::Node* node = anim->getNode("Head");
2945             if (node == nullptr)
2946                 node = anim->getNode("Bip01 Head");
2947             if (node != nullptr)
2948             {
2949                 nodepaths = node->getParentalNodePaths();
2950                 if (!nodepaths.empty())
2951                     direction = osg::computeLocalToWorld(nodepaths[0]).getTrans() - headPos;
2952             }
2953             else
2954                 // no head node to look at, fall back to look at center of collision box
2955                 direction = MWBase::Environment::get().getWorld()->aimToTarget(mPtr, mHeadTrackTarget, false);
2956         }
2957         direction.normalize();
2958 
2959         if (!mPtr.getRefData().getBaseNode())
2960             return;
2961         const osg::Vec3f actorDirection = mPtr.getRefData().getBaseNode()->getAttitude() * osg::Vec3f(0,1,0);
2962 
2963         zAngleRadians = std::atan2(actorDirection.x(), actorDirection.y()) - std::atan2(direction.x(), direction.y());
2964         zAngleRadians = Misc::normalizeAngle(zAngleRadians - mAnimation->getHeadYaw()) + mAnimation->getHeadYaw();
2965         zAngleRadians *= (1 - direction.z() * direction.z());
2966         xAngleRadians = std::asin(direction.z());
2967     }
2968 
2969     const double xLimit = osg::DegreesToRadians(40.0);
2970     const double zLimit = osg::DegreesToRadians(30.0);
2971     double zLimitOffset = mAnimation->getUpperBodyYawRadians();
2972     xAngleRadians = osg::clampBetween(xAngleRadians, -xLimit, xLimit);
2973     zAngleRadians = osg::clampBetween(zAngleRadians, -zLimit + zLimitOffset, zLimit + zLimitOffset);
2974 
2975     float factor = duration*5;
2976     factor = std::min(factor, 1.f);
2977     xAngleRadians = (1.f-factor) * mAnimation->getHeadPitch() + factor * xAngleRadians;
2978     zAngleRadians = (1.f-factor) * mAnimation->getHeadYaw() + factor * zAngleRadians;
2979 
2980     mAnimation->setHeadPitch(xAngleRadians);
2981     mAnimation->setHeadYaw(zAngleRadians);
2982 }
2983 
2984 }
2985