1 #ifndef GAME_RENDER_NPCANIMATION_H 2 #define GAME_RENDER_NPCANIMATION_H 3 4 #include "animation.hpp" 5 6 #include "../mwworld/inventorystore.hpp" 7 8 #include "actoranimation.hpp" 9 #include "weaponanimation.hpp" 10 11 #include <array> 12 13 namespace ESM 14 { 15 struct NPC; 16 struct BodyPart; 17 } 18 19 namespace MWSound 20 { 21 class Sound; 22 } 23 24 namespace MWRender 25 { 26 27 class NeckController; 28 class HeadAnimationTime; 29 30 class NpcAnimation : public ActorAnimation, public WeaponAnimation, public MWWorld::InventoryStoreListener 31 { 32 public: 33 void equipmentChanged() override; 34 void permanentEffectAdded(const ESM::MagicEffect *magicEffect, bool isNew) override; 35 36 public: 37 typedef std::map<ESM::PartReferenceType,std::string> PartBoneMap; 38 39 enum ViewMode { 40 VM_Normal, 41 VM_FirstPerson, 42 VM_HeadOnly 43 }; 44 45 private: 46 static const PartBoneMap sPartList; 47 48 // Bounded Parts 49 PartHolderPtr mObjectParts[ESM::PRT_Count]; 50 std::array<MWSound::Sound*, ESM::PRT_Count> mSounds; 51 52 const ESM::NPC *mNpc; 53 std::string mHeadModel; 54 std::string mHairModel; 55 ViewMode mViewMode; 56 bool mShowWeapons; 57 bool mShowCarriedLeft; 58 59 enum NpcType 60 { 61 Type_Normal, 62 Type_Werewolf, 63 Type_Vampire 64 }; 65 NpcType mNpcType; 66 67 int mPartslots[ESM::PRT_Count]; //Each part slot is taken by clothing, armor, or is empty 68 int mPartPriorities[ESM::PRT_Count]; 69 70 osg::Vec3f mFirstPersonOffset; 71 // Field of view to use when rendering first person meshes 72 float mFirstPersonFieldOfView; 73 74 std::shared_ptr<HeadAnimationTime> mHeadAnimationTime; 75 std::shared_ptr<WeaponAnimationTime> mWeaponAnimationTime; 76 77 bool mSoundsDisabled; 78 79 bool mAccurateAiming; 80 float mAimingFactor; 81 82 void updateNpcBase(); 83 84 NpcType getNpcType() const; 85 86 PartHolderPtr insertBoundedPart(const std::string &model, const std::string &bonename, 87 const std::string &bonefilter, bool enchantedGlow, osg::Vec4f* glowColor=nullptr); 88 89 void removeIndividualPart(ESM::PartReferenceType type); 90 void reserveIndividualPart(ESM::PartReferenceType type, int group, int priority); 91 92 bool addOrReplaceIndividualPart(ESM::PartReferenceType type, int group, int priority, const std::string &mesh, 93 bool enchantedGlow=false, osg::Vec4f* glowColor=nullptr); 94 void removePartGroup(int group); 95 void addPartGroup(int group, int priority, const std::vector<ESM::PartReference> &parts, 96 bool enchantedGlow=false, osg::Vec4f* glowColor=nullptr); 97 98 void setRenderBin(); 99 100 osg::ref_ptr<NeckController> mFirstPersonNeckController; 101 102 static bool isFirstPersonPart(const ESM::BodyPart* bodypart); 103 static bool isFemalePart(const ESM::BodyPart* bodypart); 104 static NpcType getNpcType(const MWWorld::Ptr& ptr); 105 106 protected: 107 void addControllers() override; 108 bool isArrowAttached() const override; 109 std::string getShieldMesh(MWWorld::ConstPtr shield) const override; 110 111 public: 112 /** 113 * @param ptr 114 * @param disableListener Don't listen for equipment changes and magic effects. InventoryStore only supports 115 * one listener at a time, so you shouldn't do this if creating several NpcAnimations 116 * for the same Ptr, eg preview dolls for the player. 117 * Those need to be manually rendered anyway. 118 * @param disableSounds Same as \a disableListener but for playing items sounds 119 * @param viewMode 120 */ 121 NpcAnimation(const MWWorld::Ptr& ptr, osg::ref_ptr<osg::Group> parentNode, Resource::ResourceSystem* resourceSystem, 122 bool disableSounds = false, ViewMode viewMode=VM_Normal, float firstPersonFieldOfView=55.f); 123 virtual ~NpcAnimation(); 124 125 void enableHeadAnimation(bool enable) override; 126 127 /// 1: the first person meshes follow the camera's rotation completely 128 /// 0: the first person meshes follow the camera with a reduced factor, so you can look down at your own hands 129 void setAccurateAiming(bool enabled) override; 130 131 void setWeaponGroup(const std::string& group, bool relativeDuration) override; 132 133 osg::Vec3f runAnimation(float timepassed) override; 134 135 /// A relative factor (0-1) that decides if and how much the skeleton should be pitched 136 /// to indicate the facing orientation of the character. setPitchFactor(float factor)137 void setPitchFactor(float factor) override { mPitchFactor = factor; } 138 139 void showWeapons(bool showWeapon) override; 140 getCarriedLeftShown() const141 bool getCarriedLeftShown() const override { return mShowCarriedLeft; } 142 void showCarriedLeft(bool show) override; 143 144 void attachArrow() override; 145 void detachArrow() override; 146 void releaseArrow(float attackStrength) override; 147 148 osg::Group* getArrowBone() override; 149 osg::Node* getWeaponNode() override; 150 Resource::ResourceSystem* getResourceSystem() override; 151 152 // WeaponAnimation showWeapon(bool show)153 void showWeapon(bool show) override { showWeapons(show); } 154 155 void setViewMode(ViewMode viewMode); 156 157 void updateParts(); 158 159 /// Rebuilds the NPC, updating their root model, animation sources, and equipment. 160 void rebuild(); 161 162 /// Get the inventory slot that the given node path leads into, or -1 if not found. 163 int getSlot(const osg::NodePath& path) const; 164 165 void setVampire(bool vampire) override; 166 167 /// Set a translation offset (in object root space) to apply to meshes when in first person mode. 168 void setFirstPersonOffset(const osg::Vec3f& offset); 169 170 void updatePtr(const MWWorld::Ptr& updated) override; 171 172 /// Get a list of body parts that may be used by an NPC of given race and gender. 173 /// @note This is a fixed size list, one list item for each ESM::PartReferenceType, may contain nullptr body parts. 174 static const std::vector<const ESM::BodyPart*>& getBodyParts(const std::string& raceId, bool female, bool firstperson, bool werewolf); 175 }; 176 177 } 178 179 #endif 180