npc.cpp 7.85 KB
Newer Older
1 2 3

#include "npc.hpp"

4 5
#include <memory>

6 7
#include <OgreSceneNode.h>

8 9
#include <components/esm/loadnpc.hpp>

Marc Zinnschlag's avatar
Marc Zinnschlag committed
10
#include "../mwmechanics/creaturestats.hpp"
Marc Zinnschlag's avatar
Marc Zinnschlag committed
11
#include "../mwmechanics/npcstats.hpp"
12 13
#include "../mwmechanics/movement.hpp"
#include "../mwmechanics/mechanicsmanager.hpp"
Marc Zinnschlag's avatar
Marc Zinnschlag committed
14

15
#include "../mwworld/ptr.hpp"
16
#include "../mwworld/actiontalk.hpp"
17 18
#include "../mwworld/environment.hpp"
#include "../mwworld/world.hpp"
19
#include "../mwworld/containerstore.hpp"
20

Marc Zinnschlag's avatar
Marc Zinnschlag committed
21
namespace
22 23 24
{
    const Ogre::Radian kOgrePi (Ogre::Math::PI);
    const Ogre::Radian kOgrePiOverTwo (Ogre::Math::PI / Ogre::Real(2.0));
25 26 27 28

    struct CustomData : public MWWorld::CustomData
    {
        MWMechanics::NpcStats mNpcStats;
29
        MWMechanics::CreatureStats mCreatureStats;
30
        MWMechanics::Movement mMovement;
31
        MWWorld::ContainerStore<MWWorld::RefData> mContainerStore;
32 33 34 35 36 37 38 39

        virtual MWWorld::CustomData *clone() const;
    };

    MWWorld::CustomData *CustomData::clone() const
    {
        return new CustomData (*this);
    }
40 41
}

42
namespace MWClass
43
{
44 45 46 47 48 49 50 51
    void Npc::ensureCustomData (const MWWorld::Ptr& ptr) const
    {
        if (!ptr.getRefData().getCustomData())
        {
            std::auto_ptr<CustomData> data (new CustomData);

            ESMS::LiveCellRef<ESM::NPC, MWWorld::RefData> *ref = ptr.get<ESM::NPC>();

52
            // NPC stats
53 54 55 56 57 58 59 60 61 62
            if (!ref->base->faction.empty())
            {
                // TODO research how initial rank is stored. The information in loadnpc.hpp are at
                // best very unclear.
                data->mNpcStats.mFactionRank[ref->base->faction] = 0;
            }

            for (int i=0; i<27; ++i)
                data->mNpcStats.mSkill[i].setBase (ref->base->npdt52.skills[i]);

63 64 65 66 67 68 69 70 71 72 73 74 75 76 77
            // creature stats
            data->mCreatureStats.mAttributes[0].set (ref->base->npdt52.strength);
            data->mCreatureStats.mAttributes[1].set (ref->base->npdt52.intelligence);
            data->mCreatureStats.mAttributes[2].set (ref->base->npdt52.willpower);
            data->mCreatureStats.mAttributes[3].set (ref->base->npdt52.agility);
            data->mCreatureStats.mAttributes[4].set (ref->base->npdt52.speed);
            data->mCreatureStats.mAttributes[5].set (ref->base->npdt52.endurance);
            data->mCreatureStats.mAttributes[6].set (ref->base->npdt52.personality);
            data->mCreatureStats.mAttributes[7].set (ref->base->npdt52.luck);
            data->mCreatureStats.mDynamic[0].set (ref->base->npdt52.health);
            data->mCreatureStats.mDynamic[1].set (ref->base->npdt52.mana);
            data->mCreatureStats.mDynamic[2].set (ref->base->npdt52.fatigue);

            data->mCreatureStats.mLevel = ref->base->npdt52.level;

78 79
            // \todo add initial container content

80
            // store
81 82 83 84
            ptr.getRefData().setCustomData (data.release());
        }
    }

Marc Zinnschlag's avatar
Marc Zinnschlag committed
85 86 87 88 89 90 91 92
    std::string Npc::getId (const MWWorld::Ptr& ptr) const
    {
        ESMS::LiveCellRef<ESM::NPC, MWWorld::RefData> *ref =
            ptr.get<ESM::NPC>();

        return ref->base->mId;
    }

Jason Hooks's avatar
Jason Hooks committed
93
    void Npc::insertObjectRendering (const MWWorld::Ptr& ptr, MWRender::RenderingInterface& renderingInterface) const
94
    {
Jason Hooks's avatar
Jason Hooks committed
95
        renderingInterface.getActors().insertNPC(ptr);
Jason Hooks's avatar
Jason Hooks committed
96
    }
Jason Hooks's avatar
Jason Hooks committed
97

Jason Hooks's avatar
Jason Hooks committed
98 99
    void Npc::insertObject(const MWWorld::Ptr& ptr, MWWorld::PhysicsSystem& physics, MWWorld::Environment& environment) const
    {
Jason Hooks's avatar
Jason Hooks committed
100

Marc Zinnschlag's avatar
Marc Zinnschlag committed
101

Jason Hooks's avatar
Jason Hooks committed
102 103
        ESMS::LiveCellRef<ESM::NPC, MWWorld::RefData> *ref =
            ptr.get<ESM::NPC>();
Marc Zinnschlag's avatar
Marc Zinnschlag committed
104

Jason Hooks's avatar
Jason Hooks committed
105

Jason Hooks's avatar
Jason Hooks committed
106
        assert (ref->base != NULL);
107 108 109 110
		 std::string headID = ref->base->head;
		 std::string bodyRaceID = headID.substr(0, headID.find_last_of("head_") - 4);
		 bool beast = bodyRaceID == "b_n_khajiit_m_" || bodyRaceID == "b_n_khajiit_f_" || bodyRaceID == "b_n_argonian_m_" || bodyRaceID == "b_n_argonian_f_";

Marc Zinnschlag's avatar
Marc Zinnschlag committed
111

112 113 114
        std::string smodel = "meshes\\base_anim.nif";
		if(beast)
			smodel = "meshes\\base_animkna.nif";
Jason Hooks's avatar
Jason Hooks committed
115
		physics.insertActorPhysics(ptr, smodel);
116

117

118
    }
119

120 121 122 123 124 125 126 127 128 129
    void Npc::enable (const MWWorld::Ptr& ptr, MWWorld::Environment& environment) const
    {
        environment.mMechanicsManager->addActor (ptr);
    }

    void Npc::disable (const MWWorld::Ptr& ptr, MWWorld::Environment& environment) const
    {
        environment.mMechanicsManager->removeActor (ptr);
    }

Marc Zinnschlag's avatar
Marc Zinnschlag committed
130 131 132 133 134 135 136 137
    std::string Npc::getName (const MWWorld::Ptr& ptr) const
    {
        ESMS::LiveCellRef<ESM::NPC, MWWorld::RefData> *ref =
            ptr.get<ESM::NPC>();

        return ref->base->name;
    }

138
    MWMechanics::CreatureStats& Npc::getCreatureStats (const MWWorld::Ptr& ptr) const
139
    {
140
        ensureCustomData (ptr);
141

142
        return dynamic_cast<CustomData&> (*ptr.getRefData().getCustomData()).mCreatureStats;
143 144
    }

Marc Zinnschlag's avatar
Marc Zinnschlag committed
145 146
    MWMechanics::NpcStats& Npc::getNpcStats (const MWWorld::Ptr& ptr) const
    {
147
        ensureCustomData (ptr);
Marc Zinnschlag's avatar
Marc Zinnschlag committed
148

149
        return dynamic_cast<CustomData&> (*ptr.getRefData().getCustomData()).mNpcStats;
Marc Zinnschlag's avatar
Marc Zinnschlag committed
150 151
    }

152 153 154 155
    boost::shared_ptr<MWWorld::Action> Npc::activate (const MWWorld::Ptr& ptr,
        const MWWorld::Ptr& actor, const MWWorld::Environment& environment) const
    {
        return boost::shared_ptr<MWWorld::Action> (new MWWorld::ActionTalk (ptr));
156
    }
Marc Zinnschlag's avatar
Marc Zinnschlag committed
157

158 159
    MWWorld::ContainerStore<MWWorld::RefData>& Npc::getContainerStore (const MWWorld::Ptr& ptr)
        const
Marc Zinnschlag's avatar
Marc Zinnschlag committed
160
    {
161
        ensureCustomData (ptr);
Marc Zinnschlag's avatar
Marc Zinnschlag committed
162

163
        return dynamic_cast<CustomData&> (*ptr.getRefData().getCustomData()).mContainerStore;
Marc Zinnschlag's avatar
Marc Zinnschlag committed
164 165
    }

166 167 168 169 170 171 172 173
    std::string Npc::getScript (const MWWorld::Ptr& ptr) const
    {
        ESMS::LiveCellRef<ESM::NPC, MWWorld::RefData> *ref =
            ptr.get<ESM::NPC>();

        return ref->base->script;
    }

Marc Zinnschlag's avatar
Marc Zinnschlag committed
174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203
    void Npc::setForceStance (const MWWorld::Ptr& ptr, Stance stance, bool force) const
    {
        MWMechanics::NpcStats& stats = getNpcStats (ptr);

        switch (stance)
        {
            case Run:

                stats.mForceRun = force;
                break;

            case Sneak:

                stats.mForceSneak = force;
                break;

            case Combat:

                throw std::runtime_error ("combat stance not enforcable for NPCs");
        }
    }

    void Npc::setStance (const MWWorld::Ptr& ptr, Stance stance, bool set) const
    {
        MWMechanics::NpcStats& stats = getNpcStats (ptr);

        switch (stance)
        {
            case Run:

204 205
                stats.mRun = set;
                break;
Marc Zinnschlag's avatar
Marc Zinnschlag committed
206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226

            case Sneak:

                stats.mSneak = set;
                break;

            case Combat:

                stats.mCombat = set;
                break;
        }
    }

    bool Npc::getStance (const MWWorld::Ptr& ptr, Stance stance, bool ignoreForce) const
    {
        MWMechanics::NpcStats& stats = getNpcStats (ptr);

        switch (stance)
        {
            case Run:

227 228 229 230
                if (!ignoreForce && stats.mForceRun)
                    return true;

                return stats.mRun;
Marc Zinnschlag's avatar
Marc Zinnschlag committed
231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251

            case Sneak:

                if (!ignoreForce && stats.mForceSneak)
                    return true;

                return stats.mSneak;

            case Combat:

                return stats.mCombat;
        }

        return false;
    }

    float Npc::getSpeed (const MWWorld::Ptr& ptr) const
    {
        return getStance (ptr, Run) ? 600 : 300; // TODO calculate these values from stats
    }

252 253
    MWMechanics::Movement& Npc::getMovementSettings (const MWWorld::Ptr& ptr) const
    {
254
        ensureCustomData (ptr);
255

256
        return dynamic_cast<CustomData&> (*ptr.getRefData().getCustomData()).mMovement;
257 258 259 260 261 262
    }

    Ogre::Vector3 Npc::getMovementVector (const MWWorld::Ptr& ptr) const
    {
        Ogre::Vector3 vector (0, 0, 0);

263 264
        vector.x = - getMovementSettings (ptr).mLeftRight * 200;
        vector.y = getMovementSettings (ptr).mForwardBackward * 200;
265

266 267
        if (getStance (ptr, Run, false))
            vector *= 2;
268 269 270 271

        return vector;
    }

272 273 274 275 276 277 278
    void Npc::registerSelf()
    {
        boost::shared_ptr<Class> instance (new Npc);

        registerClass (typeid (ESM::NPC).name(), instance);
    }
}