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