npc.cpp 17.7 KB
Newer Older
1 2 3 4 5

#include "npc.hpp"

#include <components/esm/loadnpc.hpp>

Marc Zinnschlag's avatar
Marc Zinnschlag committed
6
#include "../mwmechanics/creaturestats.hpp"
Marc Zinnschlag's avatar
Marc Zinnschlag committed
7
#include "../mwmechanics/npcstats.hpp"
Marc Zinnschlag's avatar
Marc Zinnschlag committed
8

9
#include "../mwworld/ptr.hpp"
10
#include "../mwworld/actiontalk.hpp"
11 12 13 14
#include "../mwworld/environment.hpp"
#include "../mwworld/world.hpp"

#include "../mwrender/cellimp.hpp"
15

16
#include "../mwmechanics/mechanicsmanager.hpp"
Jason Hooks's avatar
Jason Hooks committed
17
#include <OgreSceneNode.h>
18

19 20 21 22 23 24
namespace 
{
    const Ogre::Radian kOgrePi (Ogre::Math::PI);
    const Ogre::Radian kOgrePiOverTwo (Ogre::Math::PI / Ogre::Real(2.0));
}

25
namespace MWClass
26
{
Marc Zinnschlag's avatar
Marc Zinnschlag committed
27 28 29 30 31 32 33 34
    std::string Npc::getId (const MWWorld::Ptr& ptr) const
    {
        ESMS::LiveCellRef<ESM::NPC, MWWorld::RefData> *ref =
            ptr.get<ESM::NPC>();

        return ref->base->mId;
    }

35 36 37
    void Npc::insertObj (const MWWorld::Ptr& ptr, MWRender::CellRenderImp& cellRender,
        MWWorld::Environment& environment) const
    {
38
        //Ogre::SceneNode *chest;
39 40
        ESMS::LiveCellRef<ESM::NPC, MWWorld::RefData> *ref =
            ptr.get<ESM::NPC>();
41 42 43
        
        //Store scenenodes by npc's name + bodypart [0]  ,  npc's name + bodypart    [1]
        //Ex.                 Fargothchest               ,  Fargothneck
44 45 46

        assert (ref->base != NULL);

47
        std::string hairID = ref->base->hair;
48
        std::string headID = ref->base->head;
49 50
        std::string npcName = ref->base->name;
        //std::cout << "NPC: " << npcName << "\n";
51 52 53 54 55 56

        //get the part of the bodypart id which describes the race and the gender
        std::string bodyRaceID = headID.substr(0, headID.find_last_of("head_") - 4);
        std::string headModel = "meshes\\" +
            environment.mWorld->getStore().bodyParts.find(headID)->model;

57
        std::string hairModel = "meshes\\" +
Jason Hooks's avatar
Jason Hooks committed
58
            environment.mWorld->getStore().bodyParts.find(hairID)->model;
59

Jason Hooks's avatar
Jason Hooks committed
60 61
        MWRender::Rendering rendering (cellRender, ref->ref);
        
62 63 64 65 66 67

        //TODO: define consts for each bodypart e.g. chest, foot, wrist... and put the parts in the
        // right place
        const ESM::BodyPart *bodyPart =
            environment.mWorld->getStore().bodyParts.search (bodyRaceID + "chest");

68 69 70 71 72 73 74 75 76 77 78 79 80 81 82
        //bodyPart->model->
        Ogre::Vector3 pos = Ogre::Vector3( 20, 20, 20);
        Ogre::Vector3 axis = Ogre::Vector3( 0, 0, 1);
        Ogre::Radian angle = Ogre::Radian(0);
        
        std::string addresses[6] = {"", "", "", "","", ""};
        std::string addresses2[6] = {"", "", "", "", "", ""};
        std::string upperleft[5] = {"", "", "", "", ""};
        std::string upperright[5] = {"", "", "", "", ""};
        std::string neckandup[5] = {"", "", "","",""};
        std::string empty[6] = {"", "", "", "","", ""};
        int numbers = 0;
        int uppernumbers = 0;
        int neckNumbers = 0;
        
Jason Hooks's avatar
Jason Hooks committed
83
        if (bodyPart){
84
        
Jason Hooks's avatar
Jason Hooks committed
85
           cellRender.insertMesh("meshes\\" + bodyPart->model, pos, axis, angle, npcName + "chest", addresses, numbers, true);   //2 0
86 87 88 89 90 91 92 93
           addresses2[numbers] = npcName + "chest";
           addresses[numbers++] = npcName + "chest";
           upperleft[uppernumbers] = npcName + "chest";
           upperright[uppernumbers++] = npcName + "chest";
           neckandup[neckNumbers++] = npcName + "chest";
        }
           //std::cout << "GETTING NPC PART";
        //Orgre::SceneNode test = cellRender.getNpcPart();
Jason Hooks's avatar
Jason Hooks committed
94

95 96 97 98 99 100 101 102 103 104 105 106 107
        const ESM::BodyPart *upperleg = environment.mWorld->getStore().bodyParts.search (bodyRaceID + "upper leg");
        const ESM::BodyPart *groin = environment.mWorld->getStore().bodyParts.search (bodyRaceID + "groin");
        const ESM::BodyPart *arm = environment.mWorld->getStore().bodyParts.search (bodyRaceID + "upper arm");
        const ESM::BodyPart *neck = environment.mWorld->getStore().bodyParts.search (bodyRaceID + "neck");
        const ESM::BodyPart *knee = environment.mWorld->getStore().bodyParts.search (bodyRaceID + "knee");
        const ESM::BodyPart *ankle = environment.mWorld->getStore().bodyParts.search (bodyRaceID + "ankle");
        const ESM::BodyPart *foot = environment.mWorld->getStore().bodyParts.search (bodyRaceID + "foot");
        const ESM::BodyPart *feet = environment.mWorld->getStore().bodyParts.search (bodyRaceID + "feet");
        const ESM::BodyPart *tail = environment.mWorld->getStore().bodyParts.search (bodyRaceID + "tail");
        const ESM::BodyPart *wrist = environment.mWorld->getStore().bodyParts.search (bodyRaceID + "wrist");
        const ESM::BodyPart *forearm = environment.mWorld->getStore().bodyParts.search (bodyRaceID + "forearm");
        const ESM::BodyPart *hand = environment.mWorld->getStore().bodyParts.search (bodyRaceID + "hand.1st");
        const ESM::BodyPart *hands = environment.mWorld->getStore().bodyParts.search (bodyRaceID + "hands.1st");
Jason Hooks's avatar
Jason Hooks committed
108 109


110
        //std::cout << "RACE" << bodyRaceID << "\n";
Jason Hooks's avatar
Jason Hooks committed
111

112 113 114
        Ogre::Vector3 pos2 = Ogre::Vector3( 0, .5, 75);
        std::string upperarmpath[2] = {npcName + "chest", npcName + "upper arm"};
        
Jason Hooks's avatar
Jason Hooks committed
115
        if (groin){
116
            cellRender.insertMesh("meshes\\" + groin->model, pos2, axis, kOgrePi, npcName + "groin", addresses, numbers);
117 118 119 120
            addresses2[numbers] = npcName + "groin";
            addresses[numbers++] = npcName + "groin";
        }
        if (tail) {
121
            cellRender.insertMesh("tail\\" + tail->model, Ogre::Vector3(0 , 0, -76), axis, kOgrePi, npcName + "tail", addresses, numbers, "tail");
122 123 124 125 126
            //std::cout << "TAIL\n";
        }
        
        //addresses[1] = npcName + "groin";
        if(upperleg){
127
        cellRender.insertMesh ("meshes\\" + upperleg->model, Ogre::Vector3( 6, 0, -16), axis, kOgrePi, npcName + "upper leg", addresses, numbers); //-18
128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157
        cellRender.insertMesh ("meshes\\" + upperleg->model, Ogre::Vector3( -6, 0, -16), axis, Ogre::Radian(0), npcName + "upper leg2", addresses2, numbers);
        addresses2[numbers] = npcName + "upper leg2";
        addresses[numbers++] = npcName + "upper leg";
        cellRender.scaleMesh(Ogre::Vector3(1, -1, 1), addresses, numbers);
        }
        if(knee)
        {
            cellRender.insertMesh ("meshes\\" + knee->model, Ogre::Vector3( 0, -1, -23), axis, Ogre::Radian(0), npcName + "knee", addresses, numbers);
        //cellRender.rotateMesh(Ogre::Vector3(0, 1, 0), Ogre::Radian (1), npcName + "upper arm");
        cellRender.insertMesh ("meshes\\" + knee->model, Ogre::Vector3( 0, -1, -23), axis, Ogre::Radian(0), npcName + "knee2", addresses2, numbers);
        
            addresses2[numbers] = npcName + "knee2";
            addresses[numbers++] = npcName + "knee";
        }
        if(ankle){
            
            cellRender.insertMesh ("meshes\\" + ankle->model, Ogre::Vector3( 0, 0, -20), axis, Ogre::Radian(0), npcName + "ankle", addresses, numbers);   //-1
            cellRender.insertMesh ("meshes\\" + ankle->model, Ogre::Vector3( 0,0, -20), axis, Ogre::Radian(0), npcName + "ankle2", addresses2, numbers); //-1
            
            addresses2[numbers] = npcName + "ankle2";
            addresses[numbers++] = npcName + "ankle";
        }
        if(foot){
            if(bodyRaceID.compare("b_n_khajiit_m_") == 0)
            {
                feet = foot;
            }
            else
            {
                cellRender.insertMesh ("meshes\\" + foot->model, Ogre::Vector3( 0, -4, -15), axis, Ogre::Radian(0), npcName + "foot", addresses, numbers);
Jason Hooks's avatar
Jason Hooks committed
158

159 160 161 162 163 164 165 166
                cellRender.insertMesh ("meshes\\" + foot->model, Ogre::Vector3( 0, -4, -15), axis, Ogre::Radian(0), npcName + "foot2", addresses2, numbers);
                addresses2[numbers] = npcName + "foot2";
                addresses[numbers++] = npcName + "foot";
            }
            //cellRender.scaleMesh(Ogre::Vector3(1, -1, 1), addresses, numbers);
        }
        if(feet){
            
167
            cellRender.insertMesh ("foot\\" + feet->model, Ogre::Vector3( 7, 4, -16), axis, kOgrePi, npcName + "foot", addresses, numbers);        //9, 0, -14
Jason Hooks's avatar
Jason Hooks committed
168

169
            cellRender.insertMesh ("foot\\" + feet->model, Ogre::Vector3( 7, 4, -16), axis, kOgrePi, npcName + "foot2", addresses2, numbers);
170 171 172 173 174 175 176 177
            addresses2[numbers] = npcName + "foot2";
            addresses[numbers++] = npcName + "foot";
            //cellRender.scaleMesh(Ogre::Vector3(1, -1, 1), addresses, numbers);
        }
        
         
        if (arm){
            //010
178
            cellRender.insertMesh("meshes\\" + arm->model, Ogre::Vector3(-12.5, 0, 104), Ogre::Vector3(0, 1, 0), -kOgrePiOverTwo, npcName + "upper arm", upperleft, uppernumbers);   //1, 0,.75
179
             //cellRender.rotateMesh(Ogre::Vector3(1, 0, 0), Ogre::Radian (.45), upperarmpath, 2);                                                                                          //-.5, 0, -.75
180
            cellRender.insertMesh("meshes\\" + arm->model, Ogre::Vector3(12.5, 0, 105), Ogre::Vector3(-.5, 0, -.75), kOgrePi, npcName + "upper arm2", upperright, uppernumbers);
181 182 183
            upperleft[uppernumbers] = npcName + "upper arm";
            upperright[uppernumbers++] = npcName + "upper arm2";
            cellRender.scaleMesh(Ogre::Vector3(1, -1, 1), upperleft, uppernumbers);        //1 -1 1
184
            cellRender.rotateMesh(Ogre::Vector3(0, 1, 0),  kOgrePiOverTwo, upperleft, uppernumbers);
185
        }
Jason Hooks's avatar
Jason Hooks committed
186

187 188 189
        if (forearm)
        {
        //addresses[1] = npcName + "upper arm";
190 191
            cellRender.insertMesh("meshes\\" + forearm->model, Ogre::Vector3(-12.5, 0, 0), Ogre::Vector3(0, 0, 0), kOgrePi, npcName + "forearm", upperleft, uppernumbers);
            cellRender.insertMesh("meshes\\" + forearm->model, Ogre::Vector3(-12.5, 0, 0), Ogre::Vector3(0, 0, 0), kOgrePi, npcName + "forearm2", upperright, uppernumbers);
192 193 194 195 196 197 198 199 200
            upperleft[uppernumbers] = npcName + "forearm";
            upperright[uppernumbers++] = npcName + "forearm2";
        }
        //else
        //  std::cout << npcName << "has no forearm";
        if (wrist)
        {
            if(upperleft[uppernumbers - 1].compare(npcName + "upper arm") == 0)
            {
201 202
                cellRender.insertMesh("meshes\\b\\B_N_Argonian_M_Forearm.nif", Ogre::Vector3(-12.5, 0, 0), Ogre::Vector3(0, 0, 0), kOgrePi, npcName + "forearm", upperleft, uppernumbers);
                cellRender.insertMesh("meshes\\b\\B_N_Argonian_M_Forearm.nif", Ogre::Vector3(-12.5, 0, 0), Ogre::Vector3(0, 0, 0), kOgrePi, npcName + "forearm2", upperright, uppernumbers);
203 204
                upperleft[uppernumbers] = npcName + "forearm";
                upperright[uppernumbers++] = npcName + "forearm2";
Jason Hooks's avatar
Jason Hooks committed
205

206
            }
207 208
            cellRender.insertMesh("meshes\\" + wrist->model, Ogre::Vector3(-9.5, 0, 0), Ogre::Vector3(0, 0, 0), kOgrePi, npcName + "wrist", upperleft, uppernumbers);
            cellRender.insertMesh("meshes\\" + wrist->model, Ogre::Vector3(-9.5, 0, 0), Ogre::Vector3(0, 0, 0), kOgrePi, npcName + "wrist2", upperright, uppernumbers);
209 210 211 212
            upperleft[uppernumbers] = npcName + "wrist";
            upperright[uppernumbers++] = npcName + "wrist2";
        }
        
Jason Hooks's avatar
Jason Hooks committed
213

214 215 216 217 218 219 220 221 222 223
        if(hand)
        {
            //std::cout << "WE FOUND A HAND\n";
                                                            //-50, 0, -120
            //std::cout << "WE FOUND HANDS\n";
            std::string pass;
            if(hand->model.compare("b\\B_N_Dark Elf_F_Hands.1st.NIF")==0 && bodyRaceID.compare("b_n_dark elf_m_") == 0)
                pass = "b\\B_N_Dark Elf_M_Hands.1st.NIF";   
            else
                pass = hand->model;
224 225
            cellRender.insertMesh("meshes\\" + pass, Ogre::Vector3(42, 1, -110), Ogre::Vector3(0, 0, 0), kOgrePi, npcName + "hand", upperleft, uppernumbers,false);   //0, 100, -100    0,0,120
            cellRender.insertMesh("meshes\\" + pass, Ogre::Vector3(42, 1, -110), Ogre::Vector3(0, 0,0), kOgrePi, npcName + "hand2", upperright, uppernumbers, false);   //0, 100, -100    0,0,120
226 227
            upperleft[uppernumbers] = npcName + "hand";
            upperright[uppernumbers++] = npcName + "hand2";
228
            //cellRender.rotateMesh(Ogre::Vector3(0, 0,0),  kOgrePi, upperleft, uppernumbers);
229 230 231 232 233 234 235 236 237 238 239 240
            cellRender.scaleMesh(Ogre::Vector3(1, -1, 1), upperleft, uppernumbers);
            cellRender.scaleMesh(Ogre::Vector3(1, -1, 1), upperright, uppernumbers);
        }
        if(hands)
        {
            std::string pass;
            if(hands->model.compare("b\\B_N_Redguard_F_Hands.1st.nif")==0 && bodyRaceID.compare("b_n_redguard_m_") == 0)
                pass = "b\\B_N_Redguard_M_Hands.1st.nif";
            else if(hands->model.compare("b\\B_N_Imperial_M_Hands.1st.nif") == 0 && bodyRaceID.compare("b_n_nord_m_") == 0)
                pass = "b\\B_N_Nord_M_Hands.1st.nif";
            else
                pass =hands->model;                             //-50, 0, -120
241 242 243
            cellRender.insertMesh("meshes\\" + pass, Ogre::Vector3(42, 1,-110), Ogre::Vector3(0, 0, 0), kOgrePi, npcName + "hand", upperleft, uppernumbers, false);   //0, 100, -100    42, 0, -110
            //cellRender.insertMesh("meshes\\" + hands->model, Ogre::Vector3(42, 0,110), Ogre::Vector3(1, 0, 0), kOgrePi, npcName + "hand", upperleft, uppernumbers, false);   //0, 100, -100    42, 0, -110
            cellRender.insertMesh("meshes\\" + pass, Ogre::Vector3(42, 1, -110), Ogre::Vector3(0, 0, 0), kOgrePi, npcName + "hand2", upperright, uppernumbers, false);   //0, 100, -100    0,0,120
244 245 246 247 248
            upperleft[uppernumbers] = npcName + "hand";
            upperright[uppernumbers++] = npcName + "hand2";
            cellRender.scaleMesh(Ogre::Vector3(1, -1, 1), upperleft, uppernumbers);
            cellRender.scaleMesh(Ogre::Vector3(1, -1, 1), upperright, uppernumbers);
        }
Jason Hooks's avatar
Jason Hooks committed
249

250 251 252
        //neck will reset chest counter
        if(neck)
        {
253
            cellRender.insertMesh ("meshes\\" + neck->model, Ogre::Vector3( 0, 0, 120), axis, kOgrePi, npcName + "neck", neckandup, neckNumbers);
254 255 256 257 258 259 260 261
            neckandup[neckNumbers++] = npcName + "neck";
        }
        cellRender.insertMesh (headModel, Ogre::Vector3( 0, 0, 5), axis, Ogre::Radian(0), npcName + "head", neckandup, neckNumbers);
        neckandup[neckNumbers++] = npcName + "head";
        cellRender.insertMesh (hairModel, Ogre::Vector3( 0, -1, 0), axis, Ogre::Radian(0), npcName + "hair", neckandup, neckNumbers);
        ref->mData.setHandle (rendering.end (ref->mData.isEnabled()));
        
    }
262

263 264 265 266 267 268 269 270 271 272
    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
273 274 275 276 277 278 279 280
    std::string Npc::getName (const MWWorld::Ptr& ptr) const
    {
        ESMS::LiveCellRef<ESM::NPC, MWWorld::RefData> *ref =
            ptr.get<ESM::NPC>();

        return ref->base->name;
    }

281
    MWMechanics::CreatureStats& Npc::getCreatureStats (const MWWorld::Ptr& ptr) const
282 283 284 285 286 287
    {
        if (!ptr.getRefData().getCreatureStats().get())
        {
            boost::shared_ptr<MWMechanics::CreatureStats> stats (
                new MWMechanics::CreatureStats);

288
            ESMS::LiveCellRef<ESM::NPC, MWWorld::RefData> *ref = ptr.get<ESM::NPC>();
289 290 291 292 293 294 295 296 297 298 299 300 301

            stats->mAttributes[0].set (ref->base->npdt52.strength);
            stats->mAttributes[1].set (ref->base->npdt52.intelligence);
            stats->mAttributes[2].set (ref->base->npdt52.willpower);
            stats->mAttributes[3].set (ref->base->npdt52.agility);
            stats->mAttributes[4].set (ref->base->npdt52.speed);
            stats->mAttributes[5].set (ref->base->npdt52.endurance);
            stats->mAttributes[6].set (ref->base->npdt52.personality);
            stats->mAttributes[7].set (ref->base->npdt52.luck);
            stats->mDynamic[0].set (ref->base->npdt52.health);
            stats->mDynamic[1].set (ref->base->npdt52.mana);
            stats->mDynamic[2].set (ref->base->npdt52.fatigue);

302 303
            stats->mLevel = ref->base->npdt52.level;

304 305 306 307 308 309
            ptr.getRefData().getCreatureStats() = stats;
        }

        return *ptr.getRefData().getCreatureStats();
    }

Marc Zinnschlag's avatar
Marc Zinnschlag committed
310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326
    MWMechanics::NpcStats& Npc::getNpcStats (const MWWorld::Ptr& ptr) const
    {
        if (!ptr.getRefData().getNpcStats().get())
        {
            // xxx
            boost::shared_ptr<MWMechanics::NpcStats> stats (
                new MWMechanics::NpcStats);

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

            if (!ref->base->faction.empty())
            {
                // TODO research how initial rank is stored. The information in loadnpc.hpp are at
                // best very unclear.
                stats->mFactionRank[ref->base->faction] = 0;
            }

327 328 329
            for (int i=0; i<27; ++i)
                stats->mSkill[i].setBase (ref->base->npdt52.skills[i]);

Marc Zinnschlag's avatar
Marc Zinnschlag committed
330 331 332 333 334 335
            ptr.getRefData().getNpcStats() = stats;
        }

        return *ptr.getRefData().getNpcStats();
    }

336 337 338 339
    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));
340
    }
Marc Zinnschlag's avatar
Marc Zinnschlag committed
341

342 343
    MWWorld::ContainerStore<MWWorld::RefData>& Npc::getContainerStore (const MWWorld::Ptr& ptr)
        const
Marc Zinnschlag's avatar
Marc Zinnschlag committed
344 345 346 347 348 349 350 351 352 353 354 355 356 357
    {
        if (!ptr.getRefData().getContainerStore().get())
        {
            boost::shared_ptr<MWWorld::ContainerStore<MWWorld::RefData> > store (
                new MWWorld::ContainerStore<MWWorld::RefData>);

            // TODO add initial content

            ptr.getRefData().getContainerStore() = store;
        }

        return *ptr.getRefData().getContainerStore();
    }

358 359 360 361 362 363 364 365
    std::string Npc::getScript (const MWWorld::Ptr& ptr) const
    {
        ESMS::LiveCellRef<ESM::NPC, MWWorld::RefData> *ref =
            ptr.get<ESM::NPC>();

        return ref->base->script;
    }

366 367 368 369 370 371 372
    void Npc::registerSelf()
    {
        boost::shared_ptr<Class> instance (new Npc);

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