npc.cpp 8.26 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 58 59 60 61 62 63
                if(ref->base->npdt52.gold != -10)
                {
                    data->mNpcStats.mFactionRank[ref->base->faction] = ref->base->npdt52.rank;
                }
                else
                {
                    data->mNpcStats.mFactionRank[ref->base->faction] = ref->base->npdt52.rank;
                }
64 65 66 67 68
            }

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

69 70 71 72 73 74 75 76 77 78 79 80 81 82 83
            // 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;

84 85
            // \todo add initial container content

86
            // store
87 88 89 90
            ptr.getRefData().setCustomData (data.release());
        }
    }

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

Jason Hooks's avatar
Jason Hooks committed
104 105
    void Npc::insertObject(const MWWorld::Ptr& ptr, MWWorld::PhysicsSystem& physics, MWWorld::Environment& environment) const
    {
Jason Hooks's avatar
Jason Hooks committed
106

Marc Zinnschlag's avatar
Marc Zinnschlag committed
107

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

Jason Hooks's avatar
Jason Hooks committed
111

Jason Hooks's avatar
Jason Hooks committed
112
        assert (ref->base != NULL);
113 114 115 116
		 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
117

118 119 120
        std::string smodel = "meshes\\base_anim.nif";
		if(beast)
			smodel = "meshes\\base_animkna.nif";
Jason Hooks's avatar
Jason Hooks committed
121
		physics.insertActorPhysics(ptr, smodel);
122

123

124
    }
125

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

        return ref->base->name;
    }

144
    MWMechanics::CreatureStats& Npc::getCreatureStats (const MWWorld::Ptr& ptr) const
145
    {
146
        ensureCustomData (ptr);
147

148
        return dynamic_cast<CustomData&> (*ptr.getRefData().getCustomData()).mCreatureStats;
149 150
    }

Marc Zinnschlag's avatar
Marc Zinnschlag committed
151 152
    MWMechanics::NpcStats& Npc::getNpcStats (const MWWorld::Ptr& ptr) const
    {
153
        ensureCustomData (ptr);
Marc Zinnschlag's avatar
Marc Zinnschlag committed
154

155
        return dynamic_cast<CustomData&> (*ptr.getRefData().getCustomData()).mNpcStats;
Marc Zinnschlag's avatar
Marc Zinnschlag committed
156 157
    }

158 159 160 161
    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));
162
    }
Marc Zinnschlag's avatar
Marc Zinnschlag committed
163

164
    MWWorld::ContainerStore& Npc::getContainerStore (const MWWorld::Ptr& ptr)
165
        const
Marc Zinnschlag's avatar
Marc Zinnschlag committed
166
    {
167
        ensureCustomData (ptr);
Marc Zinnschlag's avatar
Marc Zinnschlag committed
168

169 170 171 172 173 174 175 176 177
        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
178 179
    }

180 181 182 183 184 185 186 187
    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
188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217
    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:

218 219
                stats.mRun = set;
                break;
Marc Zinnschlag's avatar
Marc Zinnschlag committed
220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240

            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:

241 242 243 244
                if (!ignoreForce && stats.mForceRun)
                    return true;

                return stats.mRun;
Marc Zinnschlag's avatar
Marc Zinnschlag committed
245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265

            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
    }

266 267
    MWMechanics::Movement& Npc::getMovementSettings (const MWWorld::Ptr& ptr) const
    {
268
        ensureCustomData (ptr);
269

270
        return dynamic_cast<CustomData&> (*ptr.getRefData().getCustomData()).mMovement;
271 272 273 274 275 276
    }

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

277 278
        vector.x = - getMovementSettings (ptr).mLeftRight * 200;
        vector.y = getMovementSettings (ptr).mForwardBackward * 200;
279

280 281
        if (getStance (ptr, Run, false))
            vector *= 2;
282 283 284 285

        return vector;
    }

286 287 288
    void Npc::registerSelf()
    {
        boost::shared_ptr<Class> instance (new Npc);
289
        std::cout << "class npc:" << typeid (ESM::NPC).name();
290 291 292
        registerClass (typeid (ESM::NPC).name(), instance);
    }
}