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"
Marc Zinnschlag's avatar
Marc Zinnschlag committed
20
#include "../mwworld/customdata.hpp"
21

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

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

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

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

43
namespace MWClass
44
{
45 46 47 48 49 50 51 52
    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>();

53
            // NPC stats
54 55 56 57 58 59 60 61 62 63
            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]);

64 65 66 67 68 69 70 71 72 73 74 75 76 77 78
            // 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;

79 80
            // \todo add initial container content

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

Marc Zinnschlag's avatar
Marc Zinnschlag committed
86 87 88 89 90 91 92 93
    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
94
    void Npc::insertObjectRendering (const MWWorld::Ptr& ptr, MWRender::RenderingInterface& renderingInterface) const
95
    {
Jason Hooks's avatar
Jason Hooks committed
96
        renderingInterface.getActors().insertNPC(ptr);
Jason Hooks's avatar
Jason Hooks committed
97
    }
Jason Hooks's avatar
Jason Hooks committed
98

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

Marc Zinnschlag's avatar
Marc Zinnschlag committed
102

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

Jason Hooks's avatar
Jason Hooks committed
106

Jason Hooks's avatar
Jason Hooks committed
107
        assert (ref->base != NULL);
108 109 110 111
		 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
112

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

118

119
    }
120

121 122 123 124 125 126 127 128 129 130
    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
131 132 133 134 135 136 137 138
    std::string Npc::getName (const MWWorld::Ptr& ptr) const
    {
        ESMS::LiveCellRef<ESM::NPC, MWWorld::RefData> *ref =
            ptr.get<ESM::NPC>();

        return ref->base->name;
    }

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

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

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

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

153 154 155 156
    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));
157
    }
Marc Zinnschlag's avatar
Marc Zinnschlag committed
158

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

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

167 168 169 170 171 172 173 174
    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
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 204
    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:

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

            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:

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

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

            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
    }

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

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

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

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

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

        return vector;
    }

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

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