npc.cpp 8.54 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/inventorystore.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::InventoryStore mInventoryStore;
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
            if (!ref->base->faction.empty())
            {
56 57
                if(ref->base->npdt52.gold != -10)
                {
58
                    data->mNpcStats.mFactionRank[ref->base->faction] = (int)ref->base->npdt52.rank;
59 60 61
                }
                else
                {
62
                    data->mNpcStats.mFactionRank[ref->base->faction] = (int)ref->base->npdt12.rank;
63
                }
64 65
            }

66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89
            if(ref->base->npdt52.gold != -10)
            {
                for (int i=0; i<27; ++i)
                    data->mNpcStats.mSkill[i].setBase (ref->base->npdt52.skills[i]);

                // 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;
            }
            else
            {
                //TODO: do something with npdt12 maybe:p
            }
90

91 92
            // \todo add initial container content

93
            // store
94 95 96 97
            ptr.getRefData().setCustomData (data.release());
        }
    }

Marc Zinnschlag's avatar
Marc Zinnschlag committed
98 99 100 101 102 103 104 105
    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
106
    void Npc::insertObjectRendering (const MWWorld::Ptr& ptr, MWRender::RenderingInterface& renderingInterface) const
107
    {
Jason Hooks's avatar
Jason Hooks committed
108 109 110
		
			
        renderingInterface.getActors().insertNPC(ptr, getInventoryStore(ptr));
Jason Hooks's avatar
Jason Hooks committed
111
		
Jason Hooks's avatar
Jason Hooks committed
112
    }
Jason Hooks's avatar
Jason Hooks committed
113

Jason Hooks's avatar
Jason Hooks committed
114 115
    void Npc::insertObject(const MWWorld::Ptr& ptr, MWWorld::PhysicsSystem& physics, MWWorld::Environment& environment) const
    {
Jason Hooks's avatar
Jason Hooks committed
116

Marc Zinnschlag's avatar
Marc Zinnschlag committed
117

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

Jason Hooks's avatar
Jason Hooks committed
121

Jason Hooks's avatar
Jason Hooks committed
122
        assert (ref->base != NULL);
123 124 125 126
		 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
127

128 129 130
        std::string smodel = "meshes\\base_anim.nif";
		if(beast)
			smodel = "meshes\\base_animkna.nif";
Jason Hooks's avatar
Jason Hooks committed
131
		physics.insertActorPhysics(ptr, smodel);
132

133

134
    }
135

136 137 138 139 140 141 142 143 144 145
    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
146 147 148 149 150 151 152 153
    std::string Npc::getName (const MWWorld::Ptr& ptr) const
    {
        ESMS::LiveCellRef<ESM::NPC, MWWorld::RefData> *ref =
            ptr.get<ESM::NPC>();

        return ref->base->name;
    }

154
    MWMechanics::CreatureStats& Npc::getCreatureStats (const MWWorld::Ptr& ptr) const
155
    {
156
        ensureCustomData (ptr);
157

158
        return dynamic_cast<CustomData&> (*ptr.getRefData().getCustomData()).mCreatureStats;
159 160
    }

Marc Zinnschlag's avatar
Marc Zinnschlag committed
161 162
    MWMechanics::NpcStats& Npc::getNpcStats (const MWWorld::Ptr& ptr) const
    {
163
        ensureCustomData (ptr);
Marc Zinnschlag's avatar
Marc Zinnschlag committed
164

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

168 169 170 171
    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));
172
    }
Marc Zinnschlag's avatar
Marc Zinnschlag committed
173

174
    MWWorld::ContainerStore& Npc::getContainerStore (const MWWorld::Ptr& ptr)
175
        const
Marc Zinnschlag's avatar
Marc Zinnschlag committed
176
    {
177
        ensureCustomData (ptr);
Marc Zinnschlag's avatar
Marc Zinnschlag committed
178

179 180 181 182 183 184 185 186 187
        return dynamic_cast<CustomData&> (*ptr.getRefData().getCustomData()).mInventoryStore;
    }

    MWWorld::InventoryStore& Npc::getInventoryStore (const MWWorld::Ptr& ptr)
        const
    {
        ensureCustomData (ptr);

        return dynamic_cast<CustomData&> (*ptr.getRefData().getCustomData()).mInventoryStore;
Marc Zinnschlag's avatar
Marc Zinnschlag committed
188 189
    }

190 191 192 193 194 195 196 197
    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
198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227
    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:

228 229
                stats.mRun = set;
                break;
Marc Zinnschlag's avatar
Marc Zinnschlag committed
230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250

            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:

251 252 253 254
                if (!ignoreForce && stats.mForceRun)
                    return true;

                return stats.mRun;
Marc Zinnschlag's avatar
Marc Zinnschlag committed
255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275

            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
    }

276 277
    MWMechanics::Movement& Npc::getMovementSettings (const MWWorld::Ptr& ptr) const
    {
278
        ensureCustomData (ptr);
279

280
        return dynamic_cast<CustomData&> (*ptr.getRefData().getCustomData()).mMovement;
281 282 283 284 285 286
    }

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

287 288
        vector.x = - getMovementSettings (ptr).mLeftRight * 200;
        vector.y = getMovementSettings (ptr).mForwardBackward * 200;
289

290 291
        if (getStance (ptr, Run, false))
            vector *= 2;
292 293 294 295

        return vector;
    }

296 297 298
    void Npc::registerSelf()
    {
        boost::shared_ptr<Class> instance (new Npc);
299
        std::cout << "class npc:" << typeid (ESM::NPC).name();
300 301 302
        registerClass (typeid (ESM::NPC).name(), instance);
    }
}