From fba32e406c94e13ba23fe8834911f9b520e45895 Mon Sep 17 00:00:00 2001 From: scrawl Date: Tue, 6 Nov 2012 15:26:51 +0100 Subject: [PATCH 01/12] changed OIS includes since OIS_INCLUDE_DIR is already an include directory --- apps/openmw/mwinput/inputmanagerimp.cpp | 2 +- apps/openmw/mwinput/inputmanagerimp.hpp | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/apps/openmw/mwinput/inputmanagerimp.cpp b/apps/openmw/mwinput/inputmanagerimp.cpp index c3e131440..af30c9b04 100644 --- a/apps/openmw/mwinput/inputmanagerimp.cpp +++ b/apps/openmw/mwinput/inputmanagerimp.cpp @@ -9,7 +9,7 @@ #include -#include +#include #include #include diff --git a/apps/openmw/mwinput/inputmanagerimp.hpp b/apps/openmw/mwinput/inputmanagerimp.hpp index 5e6169f68..718d6b76f 100644 --- a/apps/openmw/mwinput/inputmanagerimp.hpp +++ b/apps/openmw/mwinput/inputmanagerimp.hpp @@ -42,8 +42,8 @@ namespace OIS class InputManager; } -#include -#include +#include +#include #include #include From c3f0dc0dfb76c75c40e5fbef9657c601900ad768 Mon Sep 17 00:00:00 2001 From: greye Date: Thu, 8 Nov 2012 13:46:24 +0400 Subject: [PATCH 02/12] m prefix for NpcAnimation members --- apps/openmw/mwrender/npcanimation.cpp | 327 +++++++++++++------------- apps/openmw/mwrender/npcanimation.hpp | 95 ++++---- apps/openmw/mwrender/player.cpp | 1 + components/esm/loadnpc.hpp | 4 + 4 files changed, 221 insertions(+), 206 deletions(-) diff --git a/apps/openmw/mwrender/npcanimation.cpp b/apps/openmw/mwrender/npcanimation.cpp index 2153b1407..e6a8006e2 100644 --- a/apps/openmw/mwrender/npcanimation.cpp +++ b/apps/openmw/mwrender/npcanimation.cpp @@ -17,44 +17,54 @@ using namespace NifOgre; namespace MWRender{ NpcAnimation::~NpcAnimation() { - removeEntities(head); - removeEntities(hair); - removeEntities(neck); - removeEntities(chest); - removeEntities(groin); - removeEntities(skirt); - removeEntities(rHand); - removeEntities(lHand); - removeEntities(rWrist); - removeEntities(lWrist); - removeEntities(rForearm); - removeEntities(lForearm); - removeEntities(rupperArm); - removeEntities(lupperArm); - removeEntities(rfoot); - removeEntities(lfoot); - removeEntities(rAnkle); - removeEntities(lAnkle); - removeEntities(rKnee); - removeEntities(lKnee); - removeEntities(rUpperLeg); - removeEntities(lUpperLeg); - removeEntities(rclavicle); - removeEntities(lclavicle); - removeEntities(tail); + removeEntities(mHead); + removeEntities(mHair); + removeEntities(mNeck); + removeEntities(mChest); + removeEntities(mGroin); + removeEntities(mSkirt); + removeEntities(mHandL); + removeEntities(mHandR); + removeEntities(mWristL); + removeEntities(mWristR); + removeEntities(mForearmL); + removeEntities(mForearmR); + removeEntities(mUpperArmL); + removeEntities(mUpperArmR); + removeEntities(mFootL); + removeEntities(mFootR); + removeEntities(mAnkleL); + removeEntities(mAnkleR); + removeEntities(mKneeL); + removeEntities(mKneeR); + removeEntities(mUpperLegL); + removeEntities(mUpperLegR); + removeEntities(mClavicleL); + removeEntities(mClavicleR); + removeEntities(mTail); } -NpcAnimation::NpcAnimation(const MWWorld::Ptr& ptr, Ogre::SceneNode* node, MWWorld::InventoryStore& _inv, int visibilityFlags) - : Animation(), mStateID(-1), mInv(_inv), timeToChange(0), mVisibilityFlags(visibilityFlags), - robe(mInv.end()), helmet(mInv.end()), shirt(mInv.end()), - cuirass(mInv.end()), greaves(mInv.end()), - leftpauldron(mInv.end()), rightpauldron(mInv.end()), - boots(mInv.end()), - leftglove(mInv.end()), rightglove(mInv.end()), skirtiter(mInv.end()), - pants(mInv.end()) +NpcAnimation::NpcAnimation(const MWWorld::Ptr& ptr, Ogre::SceneNode* node, MWWorld::InventoryStore& inv, int visibilityFlags) + : Animation(), + mStateID(-1), + mInv(inv), + mTimeToChange(0), + mVisibilityFlags(visibilityFlags), + mRobe(mInv.end()), + mHelmet(mInv.end()), + mShirt(mInv.end()), + mCuirass(mInv.end()), + mGreaves(mInv.end()), + mPauldronL(mInv.end()), + mPauldronR(mInv.end()), + mBoots(mInv.end()), + mPants(mInv.end()), + mGloveL(mInv.end()), + mGloveR(mInv.end()), + mSkirtIter(mInv.end()) { - MWWorld::LiveCellRef *ref = ptr.get(); + mNpc = ptr.get()->mBase; for (int init = 0; init < 27; init++) { @@ -64,24 +74,18 @@ NpcAnimation::NpcAnimation(const MWWorld::Ptr& ptr, Ogre::SceneNode* node, MWWor const MWWorld::ESMStore &store = MWBase::Environment::get().getWorld()->getStore(); - const ESM::Race *race = store.get().find(ref->mBase->mRace); + const ESM::Race *race = store.get().find(mNpc->mRace); - std::string hairID = ref->mBase->mHair; - std::string headID = ref->mBase->mHead; - headModel = "meshes\\" + store.get().find(headID)->mModel; - hairModel = "meshes\\" + store.get().find(hairID)->mModel; - npcName = ref->mBase->mName; - - isFemale = !!(ref->mBase->mFlags&ESM::NPC::Female); - isBeast = !!(race->mData.mFlags&ESM::Race::Beast); - - bodyRaceID = "b_n_"+ref->mBase->mRace; - std::transform(bodyRaceID.begin(), bodyRaceID.end(), bodyRaceID.begin(), ::tolower); + mHeadModel = "meshes\\" + store.get().find(mNpc->mHead)->mModel; + mHairModel = "meshes\\" + store.get().find(mNpc->mHair)->mModel; + mBodyPrefix = "b_n_" + mNpc->mRace; + std::transform(mBodyPrefix.begin(), mBodyPrefix.end(), mBodyPrefix.begin(), ::tolower); mInsert = node; assert(mInsert); + bool isBeast = (race->mData.mFlags & ESM::Race::Beast) != 0; std::string smodel = (!isBeast ? "meshes\\base_anim.nif" : "meshes\\base_animkna.nif"); mEntityList = NifOgre::NIFLoader::createEntities(mInsert, &mTextKeys, smodel); @@ -125,7 +129,7 @@ NpcAnimation::NpcAnimation(const MWWorld::Ptr& ptr, Ogre::SceneNode* node, MWWor } float scale = race->mData.mHeight.mMale; - if (isFemale) { + if (!mNpc->isMale()) { scale = race->mData.mHeight.mFemale; } mInsert->scale(scale, scale, scale); @@ -141,18 +145,18 @@ void NpcAnimation::updateParts() MWWorld::ContainerStoreIterator *iter; int slot; } slotlist[] = { - { &robe, MWWorld::InventoryStore::Slot_Robe }, - { &skirtiter, MWWorld::InventoryStore::Slot_Skirt }, - { &helmet, MWWorld::InventoryStore::Slot_Helmet }, - { &cuirass, MWWorld::InventoryStore::Slot_Cuirass }, - { &greaves, MWWorld::InventoryStore::Slot_Greaves }, - { &leftpauldron, MWWorld::InventoryStore::Slot_LeftPauldron }, - { &rightpauldron, MWWorld::InventoryStore::Slot_RightPauldron }, - { &boots, MWWorld::InventoryStore::Slot_Boots }, - { &leftglove, MWWorld::InventoryStore::Slot_LeftGauntlet }, - { &rightglove, MWWorld::InventoryStore::Slot_RightGauntlet }, - { &shirt, MWWorld::InventoryStore::Slot_Shirt }, - { &pants, MWWorld::InventoryStore::Slot_Pants }, + { &mRobe, MWWorld::InventoryStore::Slot_Robe }, + { &mSkirtIter, MWWorld::InventoryStore::Slot_Skirt }, + { &mHelmet, MWWorld::InventoryStore::Slot_Helmet }, + { &mCuirass, MWWorld::InventoryStore::Slot_Cuirass }, + { &mGreaves, MWWorld::InventoryStore::Slot_Greaves }, + { &mPauldronL, MWWorld::InventoryStore::Slot_LeftPauldron }, + { &mPauldronR, MWWorld::InventoryStore::Slot_RightPauldron }, + { &mBoots, MWWorld::InventoryStore::Slot_Boots }, + { &mGloveL, MWWorld::InventoryStore::Slot_LeftGauntlet }, + { &mGloveR, MWWorld::InventoryStore::Slot_RightGauntlet }, + { &mShirt, MWWorld::InventoryStore::Slot_Shirt }, + { &mPants, MWWorld::InventoryStore::Slot_Pants }, }; for(size_t i = 0;i < sizeof(slotlist)/sizeof(slotlist[0]);i++) { @@ -167,9 +171,9 @@ void NpcAnimation::updateParts() if(apparelChanged) { - if(robe != mInv.end()) + if(mRobe != mInv.end()) { - MWWorld::Ptr ptr = *robe; + MWWorld::Ptr ptr = *mRobe; const ESM::Clothing *clothes = (ptr.get())->mBase; std::vector parts = clothes->mParts.mParts; @@ -187,9 +191,9 @@ void NpcAnimation::updateParts() reserveIndividualPart(ESM::PRT_RPauldron, MWWorld::InventoryStore::Slot_Robe, 5); reserveIndividualPart(ESM::PRT_LPauldron, MWWorld::InventoryStore::Slot_Robe, 5); } - if(skirtiter != mInv.end()) + if(mSkirtIter != mInv.end()) { - MWWorld::Ptr ptr = *skirtiter; + MWWorld::Ptr ptr = *mSkirtIter; const ESM::Clothing *clothes = (ptr.get())->mBase; std::vector parts = clothes->mParts.mParts; @@ -199,103 +203,103 @@ void NpcAnimation::updateParts() reserveIndividualPart(ESM::PRT_LLeg, MWWorld::InventoryStore::Slot_Skirt, 4); } - if(helmet != mInv.end()) + if(mHelmet != mInv.end()) { removeIndividualPart(ESM::PRT_Hair); - const ESM::Armor *armor = (helmet->get())->mBase; + const ESM::Armor *armor = (mHelmet->get())->mBase; std::vector parts = armor->mParts.mParts; addPartGroup(MWWorld::InventoryStore::Slot_Helmet, 3, parts); } - if(cuirass != mInv.end()) + if(mCuirass != mInv.end()) { - const ESM::Armor *armor = (cuirass->get())->mBase; + const ESM::Armor *armor = (mCuirass->get())->mBase; std::vector parts = armor->mParts.mParts; addPartGroup(MWWorld::InventoryStore::Slot_Cuirass, 3, parts); } - if(greaves != mInv.end()) + if(mGreaves != mInv.end()) { - const ESM::Armor *armor = (greaves->get())->mBase; + const ESM::Armor *armor = (mGreaves->get())->mBase; std::vector parts = armor->mParts.mParts; addPartGroup(MWWorld::InventoryStore::Slot_Greaves, 3, parts); } - if(leftpauldron != mInv.end()) + if(mPauldronL != mInv.end()) { - const ESM::Armor *armor = (leftpauldron->get())->mBase; + const ESM::Armor *armor = (mPauldronL->get())->mBase; std::vector parts = armor->mParts.mParts; addPartGroup(MWWorld::InventoryStore::Slot_LeftPauldron, 3, parts); } - if(rightpauldron != mInv.end()) + if(mPauldronR != mInv.end()) { - const ESM::Armor *armor = (rightpauldron->get())->mBase; + const ESM::Armor *armor = (mPauldronR->get())->mBase; std::vector parts = armor->mParts.mParts; addPartGroup(MWWorld::InventoryStore::Slot_RightPauldron, 3, parts); } - if(boots != mInv.end()) + if(mBoots != mInv.end()) { - if(boots->getTypeName() == typeid(ESM::Clothing).name()) + if(mBoots->getTypeName() == typeid(ESM::Clothing).name()) { - const ESM::Clothing *clothes = (boots->get())->mBase; + const ESM::Clothing *clothes = (mBoots->get())->mBase; std::vector parts = clothes->mParts.mParts; addPartGroup(MWWorld::InventoryStore::Slot_Boots, 2, parts); } - else if(boots->getTypeName() == typeid(ESM::Armor).name()) + else if(mBoots->getTypeName() == typeid(ESM::Armor).name()) { - const ESM::Armor *armor = (boots->get())->mBase; + const ESM::Armor *armor = (mBoots->get())->mBase; std::vector parts = armor->mParts.mParts; addPartGroup(MWWorld::InventoryStore::Slot_Boots, 3, parts); } } - if(leftglove != mInv.end()) + if(mGloveL != mInv.end()) { - if(leftglove->getTypeName() == typeid(ESM::Clothing).name()) + if(mGloveL->getTypeName() == typeid(ESM::Clothing).name()) { - const ESM::Clothing *clothes = (leftglove->get())->mBase; + const ESM::Clothing *clothes = (mGloveL->get())->mBase; std::vector parts = clothes->mParts.mParts; addPartGroup(MWWorld::InventoryStore::Slot_LeftGauntlet, 2, parts); } else { - const ESM::Armor *armor = (leftglove->get())->mBase; + const ESM::Armor *armor = (mGloveL->get())->mBase; std::vector parts = armor->mParts.mParts; addPartGroup(MWWorld::InventoryStore::Slot_LeftGauntlet, 3, parts); } } - if(rightglove != mInv.end()) + if(mGloveR != mInv.end()) { - if(rightglove->getTypeName() == typeid(ESM::Clothing).name()) + if(mGloveR->getTypeName() == typeid(ESM::Clothing).name()) { - const ESM::Clothing *clothes = (rightglove->get())->mBase; + const ESM::Clothing *clothes = (mGloveR->get())->mBase; std::vector parts = clothes->mParts.mParts; addPartGroup(MWWorld::InventoryStore::Slot_RightGauntlet, 2, parts); } else { - const ESM::Armor *armor = (rightglove->get())->mBase; + const ESM::Armor *armor = (mGloveR->get())->mBase; std::vector parts = armor->mParts.mParts; addPartGroup(MWWorld::InventoryStore::Slot_RightGauntlet, 3, parts); } } - if(shirt != mInv.end()) + if(mShirt != mInv.end()) { - const ESM::Clothing *clothes = (shirt->get())->mBase; + const ESM::Clothing *clothes = (mShirt->get())->mBase; std::vector parts = clothes->mParts.mParts; addPartGroup(MWWorld::InventoryStore::Slot_Shirt, 2, parts); } - if(pants != mInv.end()) + if(mPants != mInv.end()) { - const ESM::Clothing *clothes = (pants->get())->mBase; + const ESM::Clothing *clothes = (mPants->get())->mBase; std::vector parts = clothes->mParts.mParts; addPartGroup(MWWorld::InventoryStore::Slot_Pants, 2, parts); } } if(mPartPriorities[ESM::PRT_Head] < 1) - addOrReplaceIndividualPart(ESM::PRT_Head, -1,1, headModel); + addOrReplaceIndividualPart(ESM::PRT_Head, -1,1, mHeadModel); if(mPartPriorities[ESM::PRT_Hair] < 1 && mPartPriorities[ESM::PRT_Head] <= 1) - addOrReplaceIndividualPart(ESM::PRT_Hair, -1,1, hairModel); + addOrReplaceIndividualPart(ESM::PRT_Hair, -1,1, mHairModel); static const struct { ESM::PartReferenceType type; @@ -329,20 +333,21 @@ void NpcAnimation::updateParts() if(mPartPriorities[PartTypeList[i].type] < 1) { const ESM::BodyPart *part = NULL; - bool tryfemale = isFemale; - int ni = 0; - do { - part = store.get().search(bodyRaceID+(tryfemale?"_f_":"_m_")+PartTypeList[i].name[ni]); - if(part) break; + const MWWorld::Store &partStore = + store.get(); - ni ^= 1; - if(ni == 0) - { - if(!tryfemale) - break; - tryfemale = false; + if (!mNpc->isMale()) { + part = partStore.search(mBodyPrefix + "_f_" + PartTypeList[i].name[0]); + if (part == 0) { + part = partStore.search(mBodyPrefix + "_f_" + PartTypeList[i].name[1]); } - } while(1); + } + if (part == 0) { + part = partStore.search(mBodyPrefix + "_m_" + PartTypeList[i].name[0]); + } + if (part == 0) { + part = partStore.search(mBodyPrefix + "_m_" + PartTypeList[i].name[1]); + } if(part) addOrReplaceIndividualPart(PartTypeList[i].type, -1,1, "meshes\\"+part->mModel); @@ -365,12 +370,12 @@ NifOgre::EntityList NpcAnimation::insertBoundedPart(const std::string &mesh, int void NpcAnimation::runAnimation(float timepassed) { - if(timeToChange > .2) + if(mTimeToChange > .2) { - timeToChange = 0; + mTimeToChange = 0; updateParts(); } - timeToChange += timepassed; + mTimeToChange += timepassed; Animation::runAnimation(timepassed); } @@ -395,61 +400,61 @@ void NpcAnimation::removeIndividualPart(int type) mPartslots[type] = -1; if(type == ESM::PRT_Head) //0 - removeEntities(head); + removeEntities(mHead); else if(type == ESM::PRT_Hair) //1 - removeEntities(hair); + removeEntities(mHair); else if(type == ESM::PRT_Neck) //2 - removeEntities(neck); + removeEntities(mNeck); else if(type == ESM::PRT_Cuirass)//3 - removeEntities(chest); + removeEntities(mChest); else if(type == ESM::PRT_Groin)//4 - removeEntities(groin); + removeEntities(mGroin); else if(type == ESM::PRT_Skirt)//5 - removeEntities(skirt); + removeEntities(mSkirt); else if(type == ESM::PRT_RHand)//6 - removeEntities(rHand); + removeEntities(mHandR); else if(type == ESM::PRT_LHand)//7 - removeEntities(lHand); + removeEntities(mHandL); else if(type == ESM::PRT_RWrist)//8 - removeEntities(rWrist); + removeEntities(mWristR); else if(type == ESM::PRT_LWrist) //9 - removeEntities(lWrist); + removeEntities(mWristL); else if(type == ESM::PRT_Shield) //10 { } else if(type == ESM::PRT_RForearm) //11 - removeEntities(rForearm); + removeEntities(mForearmR); else if(type == ESM::PRT_LForearm) //12 - removeEntities(lForearm); + removeEntities(mForearmL); else if(type == ESM::PRT_RUpperarm) //13 - removeEntities(rupperArm); + removeEntities(mUpperArmR); else if(type == ESM::PRT_LUpperarm) //14 - removeEntities(lupperArm); + removeEntities(mUpperArmL); else if(type == ESM::PRT_RFoot) //15 - removeEntities(rfoot); + removeEntities(mFootR); else if(type == ESM::PRT_LFoot) //16 - removeEntities(lfoot); + removeEntities(mFootL); else if(type == ESM::PRT_RAnkle) //17 - removeEntities(rAnkle); + removeEntities(mAnkleR); else if(type == ESM::PRT_LAnkle) //18 - removeEntities(lAnkle); + removeEntities(mAnkleL); else if(type == ESM::PRT_RKnee) //19 - removeEntities(rKnee); + removeEntities(mKneeR); else if(type == ESM::PRT_LKnee) //20 - removeEntities(lKnee); + removeEntities(mKneeL); else if(type == ESM::PRT_RLeg) //21 - removeEntities(rUpperLeg); + removeEntities(mUpperLegR); else if(type == ESM::PRT_LLeg) //22 - removeEntities(lUpperLeg); + removeEntities(mUpperLegL); else if(type == ESM::PRT_RPauldron) //23 - removeEntities(rclavicle); + removeEntities(mClavicleR); else if(type == ESM::PRT_LPauldron) //24 - removeEntities(lclavicle); + removeEntities(mClavicleL); else if(type == ESM::PRT_Weapon) //25 { } else if(type == ESM::PRT_Tail) //26 - removeEntities(tail); + removeEntities(mTail); } void NpcAnimation::reserveIndividualPart(int type, int group, int priority) @@ -482,83 +487,83 @@ bool NpcAnimation::addOrReplaceIndividualPart(int type, int group, int priority, switch(type) { case ESM::PRT_Head: //0 - head = insertBoundedPart(mesh, group, "Head"); + mHead = insertBoundedPart(mesh, group, "Head"); break; case ESM::PRT_Hair: //1 - hair = insertBoundedPart(mesh, group, "Head"); + mHair = insertBoundedPart(mesh, group, "Head"); break; case ESM::PRT_Neck: //2 - neck = insertBoundedPart(mesh, group, "Neck"); + mNeck = insertBoundedPart(mesh, group, "Neck"); break; case ESM::PRT_Cuirass: //3 - chest = insertBoundedPart(mesh, group, "Chest"); + mChest = insertBoundedPart(mesh, group, "Chest"); break; case ESM::PRT_Groin: //4 - groin = insertBoundedPart(mesh, group, "Groin"); + mGroin = insertBoundedPart(mesh, group, "Groin"); break; case ESM::PRT_Skirt: //5 - skirt = insertBoundedPart(mesh, group, "Groin"); + mSkirt = insertBoundedPart(mesh, group, "Groin"); break; case ESM::PRT_RHand: //6 - rHand = insertBoundedPart(mesh, group, "Right Hand"); + mHandR = insertBoundedPart(mesh, group, "Right Hand"); break; case ESM::PRT_LHand: //7 - lHand = insertBoundedPart(mesh, group, "Left Hand"); + mHandL = insertBoundedPart(mesh, group, "Left Hand"); break; case ESM::PRT_RWrist: //8 - rWrist = insertBoundedPart(mesh, group, "Right Wrist"); + mWristR = insertBoundedPart(mesh, group, "Right Wrist"); break; case ESM::PRT_LWrist: //9 - lWrist = insertBoundedPart(mesh, group, "Left Wrist"); + mWristL = insertBoundedPart(mesh, group, "Left Wrist"); break; case ESM::PRT_Shield: //10 break; case ESM::PRT_RForearm: //11 - rForearm = insertBoundedPart(mesh, group, "Right Forearm"); + mForearmR = insertBoundedPart(mesh, group, "Right Forearm"); break; case ESM::PRT_LForearm: //12 - lForearm = insertBoundedPart(mesh, group, "Left Forearm"); + mForearmL = insertBoundedPart(mesh, group, "Left Forearm"); break; case ESM::PRT_RUpperarm: //13 - rupperArm = insertBoundedPart(mesh, group, "Right Upper Arm"); + mUpperArmR = insertBoundedPart(mesh, group, "Right Upper Arm"); break; case ESM::PRT_LUpperarm: //14 - lupperArm = insertBoundedPart(mesh, group, "Left Upper Arm"); + mUpperArmL = insertBoundedPart(mesh, group, "Left Upper Arm"); break; case ESM::PRT_RFoot: //15 - rfoot = insertBoundedPart(mesh, group, "Right Foot"); + mFootR = insertBoundedPart(mesh, group, "Right Foot"); break; case ESM::PRT_LFoot: //16 - lfoot = insertBoundedPart(mesh, group, "Left Foot"); + mFootL = insertBoundedPart(mesh, group, "Left Foot"); break; case ESM::PRT_RAnkle: //17 - rAnkle = insertBoundedPart(mesh, group, "Right Ankle"); + mAnkleR = insertBoundedPart(mesh, group, "Right Ankle"); break; case ESM::PRT_LAnkle: //18 - lAnkle = insertBoundedPart(mesh, group, "Left Ankle"); + mAnkleL = insertBoundedPart(mesh, group, "Left Ankle"); break; case ESM::PRT_RKnee: //19 - rKnee = insertBoundedPart(mesh, group, "Right Knee"); + mKneeR = insertBoundedPart(mesh, group, "Right Knee"); break; case ESM::PRT_LKnee: //20 - lKnee = insertBoundedPart(mesh, group, "Left Knee"); + mKneeL = insertBoundedPart(mesh, group, "Left Knee"); break; case ESM::PRT_RLeg: //21 - rUpperLeg = insertBoundedPart(mesh, group, "Right Upper Leg"); + mUpperLegR = insertBoundedPart(mesh, group, "Right Upper Leg"); break; case ESM::PRT_LLeg: //22 - lUpperLeg = insertBoundedPart(mesh, group, "Left Upper Leg"); + mUpperLegL = insertBoundedPart(mesh, group, "Left Upper Leg"); break; case ESM::PRT_RPauldron: //23 - rclavicle = insertBoundedPart(mesh , group, "Right Clavicle"); + mClavicleR = insertBoundedPart(mesh , group, "Right Clavicle"); break; case ESM::PRT_LPauldron: //24 - lclavicle = insertBoundedPart(mesh, group, "Left Clavicle"); + mClavicleL = insertBoundedPart(mesh, group, "Left Clavicle"); break; case ESM::PRT_Weapon: //25 break; case ESM::PRT_Tail: //26 - tail = insertBoundedPart(mesh, group, "Tail"); + mTail = insertBoundedPart(mesh, group, "Tail"); break; } return true; @@ -570,14 +575,14 @@ void NpcAnimation::addPartGroup(int group, int priority, std::vector &parts = + const MWWorld::Store &partStore = MWBase::Environment::get().getWorld()->getStore().get(); const ESM::BodyPart *bodypart = 0; - if(isFemale) - bodypart = parts.search(part.mFemale); + if(!mNpc->isMale()) + bodypart = partStore.search(part.mFemale); if(!bodypart) - bodypart = parts.search(part.mMale); + bodypart = partStore.search(part.mMale); if(bodypart) addOrReplaceIndividualPart(part.mPart, group, priority,"meshes\\" + bodypart->mModel); diff --git a/apps/openmw/mwrender/npcanimation.hpp b/apps/openmw/mwrender/npcanimation.hpp index 21edb3be4..ca76dcc22 100644 --- a/apps/openmw/mwrender/npcanimation.hpp +++ b/apps/openmw/mwrender/npcanimation.hpp @@ -8,6 +8,11 @@ #include "../mwclass/npc.hpp" #include "../mwworld/containerstore.hpp" +namespace ESM +{ + struct NPC; +} + namespace MWRender{ class NpcAnimation: public Animation{ @@ -19,57 +24,57 @@ private: int mPartPriorities[27]; //Bounded Parts - NifOgre::EntityList lclavicle; - NifOgre::EntityList rclavicle; - NifOgre::EntityList rupperArm; - NifOgre::EntityList lupperArm; - NifOgre::EntityList rUpperLeg; - NifOgre::EntityList lUpperLeg; - NifOgre::EntityList lForearm; - NifOgre::EntityList rForearm; - NifOgre::EntityList lWrist; - NifOgre::EntityList rWrist; - NifOgre::EntityList rKnee; - NifOgre::EntityList lKnee; - NifOgre::EntityList neck; - NifOgre::EntityList rAnkle; - NifOgre::EntityList lAnkle; - NifOgre::EntityList groin; - NifOgre::EntityList skirt; - NifOgre::EntityList lfoot; - NifOgre::EntityList rfoot; - NifOgre::EntityList hair; - NifOgre::EntityList rHand; - NifOgre::EntityList lHand; - NifOgre::EntityList head; - NifOgre::EntityList chest; - NifOgre::EntityList tail; + NifOgre::EntityList mClavicleL; + NifOgre::EntityList mClavicleR; + NifOgre::EntityList mUpperArmL; + NifOgre::EntityList mUpperArmR; + NifOgre::EntityList mUpperLegL; + NifOgre::EntityList mUpperLegR; + NifOgre::EntityList mForearmL; + NifOgre::EntityList mForearmR; + NifOgre::EntityList mWristL; + NifOgre::EntityList mWristR; + NifOgre::EntityList mKneeR; + NifOgre::EntityList mKneeL; + NifOgre::EntityList mNeck; + NifOgre::EntityList mAnkleL; + NifOgre::EntityList mAnkleR; + NifOgre::EntityList mGroin; + NifOgre::EntityList mSkirt; + NifOgre::EntityList mFootL; + NifOgre::EntityList mFootR; + NifOgre::EntityList mHair; + NifOgre::EntityList mHandL; + NifOgre::EntityList mHandR; + NifOgre::EntityList mHead; + NifOgre::EntityList mChest; + NifOgre::EntityList mTail; - bool isBeast; - bool isFemale; - std::string headModel; - std::string hairModel; - std::string npcName; - std::string bodyRaceID; - float timeToChange; - MWWorld::ContainerStoreIterator robe; - MWWorld::ContainerStoreIterator helmet; - MWWorld::ContainerStoreIterator shirt; - MWWorld::ContainerStoreIterator cuirass; - MWWorld::ContainerStoreIterator greaves; - MWWorld::ContainerStoreIterator leftpauldron; - MWWorld::ContainerStoreIterator rightpauldron; - MWWorld::ContainerStoreIterator boots; - MWWorld::ContainerStoreIterator pants; - MWWorld::ContainerStoreIterator leftglove; - MWWorld::ContainerStoreIterator rightglove; - MWWorld::ContainerStoreIterator skirtiter; + const ESM::NPC *mNpc; + std::string mHeadModel; + std::string mHairModel; + std::string mBodyPrefix; + + + float mTimeToChange; + MWWorld::ContainerStoreIterator mRobe; + MWWorld::ContainerStoreIterator mHelmet; + MWWorld::ContainerStoreIterator mShirt; + MWWorld::ContainerStoreIterator mCuirass; + MWWorld::ContainerStoreIterator mGreaves; + MWWorld::ContainerStoreIterator mPauldronL; + MWWorld::ContainerStoreIterator mPauldronR; + MWWorld::ContainerStoreIterator mBoots; + MWWorld::ContainerStoreIterator mPants; + MWWorld::ContainerStoreIterator mGloveL; + MWWorld::ContainerStoreIterator mGloveR; + MWWorld::ContainerStoreIterator mSkirtIter; int mVisibilityFlags; public: NpcAnimation(const MWWorld::Ptr& ptr, Ogre::SceneNode* node, - MWWorld::InventoryStore& _inv, int visibilityFlags); + MWWorld::InventoryStore& inv, int visibilityFlags); virtual ~NpcAnimation(); NifOgre::EntityList insertBoundedPart(const std::string &mesh, int group, const std::string &bonename); virtual void runAnimation(float timepassed); diff --git a/apps/openmw/mwrender/player.cpp b/apps/openmw/mwrender/player.cpp index bbc75cade..f2c313e14 100644 --- a/apps/openmw/mwrender/player.cpp +++ b/apps/openmw/mwrender/player.cpp @@ -18,6 +18,7 @@ namespace MWRender : mCamera(camera), mPlayerNode(node), mCameraNode(mPlayerNode->createChildSceneNode()), + mAnimation(0), mFirstPersonView(true), mPreviewMode(false), mFreeLook(true), diff --git a/components/esm/loadnpc.hpp b/components/esm/loadnpc.hpp index ee9ef6b0b..d446ee08f 100644 --- a/components/esm/loadnpc.hpp +++ b/components/esm/loadnpc.hpp @@ -117,6 +117,10 @@ struct NPC // Implementation moved to load_impl.cpp void load(ESMReader &esm); void save(ESMWriter &esm); + + bool isMale() const { + return (mFlags & Female) == 0; + } }; } #endif From f6a9029c4b3dec7172d677a22a979d02106f4d53 Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 9 Nov 2012 18:33:11 +0100 Subject: [PATCH 03/12] bounty & disease disposition effect --- .../openmw/mwmechanics/mechanicsmanagerimp.cpp | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp b/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp index 3b5a80ef3..62b116a47 100644 --- a/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp +++ b/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp @@ -397,7 +397,7 @@ namespace MWMechanics MWWorld::Ptr playerPtr = MWBase::Environment::get().getWorld()->getPlayer().getPlayer(); MWWorld::LiveCellRef* player = playerPtr.get(); MWMechanics::CreatureStats playerStats = MWWorld::Class::get(playerPtr).getCreatureStats(playerPtr); - MWMechanics::NpcStats playerSkill = MWWorld::Class::get(playerPtr).getNpcStats(playerPtr); + MWMechanics::NpcStats playerNpcStats = MWWorld::Class::get(playerPtr).getNpcStats(playerPtr); if (toLower(npc->mBase->mRace) == toLower(player->mBase->mRace)) x += MWBase::Environment::get().getWorld()->getStore().get().find("fDispRaceMod")->getFloat(); @@ -409,21 +409,21 @@ namespace MWMechanics std::string npcFaction = ""; if(!npcSkill.getFactionRanks().empty()) npcFaction = npcSkill.getFactionRanks().begin()->first; - if (playerSkill.getFactionRanks().find(toLower(npcFaction)) != playerSkill.getFactionRanks().end()) + if (playerNpcStats.getFactionRanks().find(toLower(npcFaction)) != playerNpcStats.getFactionRanks().end()) { for(std::vector::const_iterator it = MWBase::Environment::get().getWorld()->getStore().get().find(toLower(npcFaction))->mReactions.begin(); it != MWBase::Environment::get().getWorld()->getStore().get().find(toLower(npcFaction))->mReactions.end(); it++) { if(toLower(it->mFaction) == toLower(npcFaction)) reaction = it->mReaction; } - rank = playerSkill.getFactionRanks().find(toLower(npcFaction))->second; + rank = playerNpcStats.getFactionRanks().find(toLower(npcFaction))->second; } else if (npcFaction != "") { for(std::vector::const_iterator it = MWBase::Environment::get().getWorld()->getStore().get().find(toLower(npcFaction))->mReactions.begin(); it != MWBase::Environment::get().getWorld()->getStore().get().find(toLower(npcFaction))->mReactions.end();it++) { - if(playerSkill.getFactionRanks().find(toLower(it->mFaction)) != playerSkill.getFactionRanks().end() ) + if(playerNpcStats.getFactionRanks().find(toLower(it->mFaction)) != playerNpcStats.getFactionRanks().end() ) { if(it->mReactionmReaction; } @@ -439,10 +439,12 @@ namespace MWMechanics + MWBase::Environment::get().getWorld()->getStore().get().find("fDispFactionRankBase")->getFloat()) * MWBase::Environment::get().getWorld()->getStore().get().find("fDispFactionMod")->getFloat() * reaction; - /// \todo implement bounty and disease - //x -= MWBase::Environment::get().getWorld()->getStore().get().find("fDispCrimeMod") * pcBounty; - //if (pc has a disease) x += MWBase::Environment::get().getWorld()->getStore().get().find("fDispDiseaseMod"); - if (playerSkill.getDrawState() == MWMechanics::DrawState_::DrawState_Weapon) x += MWBase::Environment::get().getWorld()->getStore().get().find("fDispWeaponDrawn")->getFloat(); + x -= MWBase::Environment::get().getWorld()->getStore().get().find("fDispCrimeMod")->getFloat() * playerNpcStats.getBounty(); + if (playerStats.hasCommonDisease() || playerStats.hasBlightDisease()) + x += MWBase::Environment::get().getWorld()->getStore().get().find("fDispDiseaseMod")->getFloat(); + + if (playerNpcStats.getDrawState() == MWMechanics::DrawState_::DrawState_Weapon) + x += MWBase::Environment::get().getWorld()->getStore().get().find("fDispWeaponDrawn")->getFloat(); int effective_disposition = std::max(0,std::min(int(x),100));//, normally clamped to [0..100] when used return effective_disposition; From ace9ee9c835273686e4b1928335461f89de664f9 Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 9 Nov 2012 20:18:38 +0100 Subject: [PATCH 04/12] persuasion dialog --- apps/openmw/mwbase/mechanicsmanager.hpp | 12 ++ apps/openmw/mwclass/npc.cpp | 2 +- apps/openmw/mwgui/dialogue.cpp | 103 ++++++++++++++++++ apps/openmw/mwgui/dialogue.hpp | 32 ++++++ .../mwmechanics/mechanicsmanagerimp.cpp | 8 +- .../mwmechanics/mechanicsmanagerimp.hpp | 2 + apps/openmw/mwmechanics/npcstats.cpp | 4 +- apps/openmw/mwmechanics/npcstats.hpp | 4 +- apps/openmw/mwrender/player.cpp | 3 +- files/mygui/CMakeLists.txt | 1 + 10 files changed, 164 insertions(+), 7 deletions(-) diff --git a/apps/openmw/mwbase/mechanicsmanager.hpp b/apps/openmw/mwbase/mechanicsmanager.hpp index 9f9b5af70..0be111ea7 100644 --- a/apps/openmw/mwbase/mechanicsmanager.hpp +++ b/apps/openmw/mwbase/mechanicsmanager.hpp @@ -85,6 +85,18 @@ namespace MWBase virtual int countDeaths (const std::string& id) const = 0; ///< Return the number of deaths for actors with the given ID. + + enum PersuasionType + { + PT_Admire, + PT_Intimidate, + PT_Taunt, + PT_Bribe10, + PT_Bribe100, + PT_Bribe1000 + }; + virtual float getPersuasionDispositionChange (MWWorld::Ptr npc, PersuasionType type, bool& success) const = 0; + ///< Get amount to adjust temporary disposition for a given persuasion action on an NPC }; } diff --git a/apps/openmw/mwclass/npc.cpp b/apps/openmw/mwclass/npc.cpp index 6a516bcc8..c7f33504e 100644 --- a/apps/openmw/mwclass/npc.cpp +++ b/apps/openmw/mwclass/npc.cpp @@ -95,7 +95,7 @@ namespace MWClass data->mCreatureStats.setFatigue (ref->mBase->mNpdt52.mFatigue); data->mCreatureStats.setLevel(ref->mBase->mNpdt52.mLevel); - data->mNpcStats.setDisposition(ref->mBase->mNpdt52.mDisposition); + data->mNpcStats.setBaseDisposition(ref->mBase->mNpdt52.mDisposition); } else { diff --git a/apps/openmw/mwgui/dialogue.cpp b/apps/openmw/mwgui/dialogue.cpp index e1baaf8e0..be7bfde53 100644 --- a/apps/openmw/mwgui/dialogue.cpp +++ b/apps/openmw/mwgui/dialogue.cpp @@ -49,14 +49,87 @@ std::string::size_type find_str_ci(const std::string& str, const std::string& su } + +PersuasionDialog::PersuasionDialog(MWBase::WindowManager &parWindowManager) + : WindowModal("openmw_persuasion_dialog.layout", parWindowManager) +{ + getWidget(mCancelButton, "CancelButton"); + getWidget(mAdmireButton, "AdmireButton"); + getWidget(mIntimidateButton, "IntimidateButton"); + getWidget(mTauntButton, "TauntButton"); + getWidget(mBribe10Button, "Bribe10Button"); + getWidget(mBribe100Button, "Bribe100Button"); + getWidget(mBribe1000Button, "Bribe1000Button"); + getWidget(mGoldLabel, "GoldLabel"); + + mCancelButton->eventMouseButtonClick += MyGUI::newDelegate(this, &PersuasionDialog::onCancel); + mAdmireButton->eventMouseButtonClick += MyGUI::newDelegate(this, &PersuasionDialog::onPersuade); + mIntimidateButton->eventMouseButtonClick += MyGUI::newDelegate(this, &PersuasionDialog::onPersuade); + mTauntButton->eventMouseButtonClick += MyGUI::newDelegate(this, &PersuasionDialog::onPersuade); + mBribe10Button->eventMouseButtonClick += MyGUI::newDelegate(this, &PersuasionDialog::onPersuade); + mBribe100Button->eventMouseButtonClick += MyGUI::newDelegate(this, &PersuasionDialog::onPersuade); + mBribe1000Button->eventMouseButtonClick += MyGUI::newDelegate(this, &PersuasionDialog::onPersuade); +} + +void PersuasionDialog::onCancel(MyGUI::Widget *sender) +{ + setVisible(false); +} + +void PersuasionDialog::onPersuade(MyGUI::Widget *sender) +{ + MWBase::MechanicsManager::PersuasionType type; + if (sender == mAdmireButton) type = MWBase::MechanicsManager::PT_Admire; + else if (sender == mIntimidateButton) type = MWBase::MechanicsManager::PT_Intimidate; + else if (sender == mTauntButton) type = MWBase::MechanicsManager::PT_Taunt; + else if (sender == mBribe10Button) + { + mWindowManager.getTradeWindow()->addOrRemoveGold(-10); + type = MWBase::MechanicsManager::PT_Bribe10; + } + else if (sender == mBribe100Button) + { + mWindowManager.getTradeWindow()->addOrRemoveGold(-100); + type = MWBase::MechanicsManager::PT_Bribe100; + } + else /*if (sender == mBribe1000Button)*/ + { + mWindowManager.getTradeWindow()->addOrRemoveGold(-1000); + type = MWBase::MechanicsManager::PT_Bribe1000; + } + + eventPersuade(type, true, 0); + setVisible(false); +} + +void PersuasionDialog::open() +{ + WindowModal::open(); + center(); + + int playerGold = mWindowManager.getInventoryWindow()->getPlayerGold(); + + mBribe10Button->setEnabled (playerGold >= 10); + mBribe100Button->setEnabled (playerGold >= 100); + mBribe1000Button->setEnabled (playerGold >= 1000); + + mGoldLabel->setCaptionWithReplacing("#{sGold}: " + boost::lexical_cast(playerGold)); +} + +// -------------------------------------------------------------------------------------------------- + DialogueWindow::DialogueWindow(MWBase::WindowManager& parWindowManager) : WindowBase("openmw_dialogue_window.layout", parWindowManager) + , mPersuasionDialog(parWindowManager) , mEnabled(false) , mServices(0) { // Centre dialog center(); + mPersuasionDialog.setVisible(false); + mPersuasionDialog.eventPersuade += MyGUI::newDelegate(this, &DialogueWindow::onPersuade); + //History view getWidget(mHistory, "History"); mHistory->setOverflowToTheLeft(true); @@ -137,6 +210,10 @@ void DialogueWindow::onSelectTopic(std::string topic) mWindowManager.pushGuiMode(GM_Barter); mWindowManager.getTradeWindow()->startTrade(mPtr); } + if (topic == gmst.find("sPersuasion")->getString()) + { + mPersuasionDialog.setVisible(true); + } else if (topic == gmst.find("sSpells")->getString()) { mWindowManager.pushGuiMode(GM_SpellBuying); @@ -187,6 +264,9 @@ void DialogueWindow::setKeywords(std::list keyWords) const MWWorld::Store &gmst = MWBase::Environment::get().getWorld()->getStore().get(); + if (mPtr.getTypeName() == typeid(ESM::NPC).name()) + mTopicsList->addItem(gmst.find("sPersuasion")->getString()); + if (mServices & Service_Trade) mTopicsList->addItem(gmst.find("sBarter")->getString()); @@ -311,6 +391,8 @@ void DialogueWindow::updateOptions() void DialogueWindow::goodbye() { + // Apply temporary disposition change to NPC's base disposition + mHistory->addDialogText("\n#572D21" + MWBase::Environment::get().getWorld()->getStore().get().find("sGoodbye")->getString()); mTopicsList->setEnabled(false); mEnabled = false; @@ -331,3 +413,24 @@ void DialogueWindow::onFrame() mDispositionText->addText("#B29154"+boost::lexical_cast(MWBase::Environment::get().getMechanicsManager()->getDerivedDisposition(mPtr))+std::string("/100")+"#B29154"); } } + +void DialogueWindow::onPersuade(int type, bool success, float dispositionChange) +{ + std::string text; + + if (type == MWBase::MechanicsManager::PT_Admire) + text = "sAdmire"; + else if (type == MWBase::MechanicsManager::PT_Taunt) + text = "sTaunt"; + else if (type == MWBase::MechanicsManager::PT_Intimidate) + text = "sIntimidate"; + else + text = "sBribe"; + + text += success ? "Fail" : "Success"; + + mHistory->addDialogHeading( MyGUI::LanguageManager::getInstance().replaceTags("#{"+text+"}")); + + /// \todo text from INFO record, how to get the ID? + //mHistory->addDialogText(); +} diff --git a/apps/openmw/mwgui/dialogue.hpp b/apps/openmw/mwgui/dialogue.hpp index bb9acf5db..3d0d74d95 100644 --- a/apps/openmw/mwgui/dialogue.hpp +++ b/apps/openmw/mwgui/dialogue.hpp @@ -26,6 +26,31 @@ namespace MWGui { class DialogueHistory; + class PersuasionDialog : public WindowModal + { + public: + PersuasionDialog(MWBase::WindowManager& parWindowManager); + + virtual void open(); + + typedef MyGUI::delegates::CMultiDelegate3 EventHandle_Persuade; + + EventHandle_Persuade eventPersuade; + + private: + MyGUI::Button* mCancelButton; + MyGUI::Button* mAdmireButton; + MyGUI::Button* mIntimidateButton; + MyGUI::Button* mTauntButton; + MyGUI::Button* mBribe10Button; + MyGUI::Button* mBribe100Button; + MyGUI::Button* mBribe1000Button; + MyGUI::TextBox* mGoldLabel; + + void onCancel (MyGUI::Widget* sender); + void onPersuade (MyGUI::Widget* sender); + }; + class DialogueWindow: public WindowBase, public ReferenceInterface { public: @@ -86,6 +111,13 @@ namespace MWGui Widgets::MWList* mTopicsList; MyGUI::ProgressPtr mDispositionBar; MyGUI::EditPtr mDispositionText; + + PersuasionDialog mPersuasionDialog; + + + float mTemporaryDispositionChange; + + void onPersuade (int type, bool success, float dispositionChange); }; } #endif diff --git a/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp b/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp index 62b116a47..134a7fb06 100644 --- a/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp +++ b/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp @@ -391,7 +391,7 @@ namespace MWMechanics int MechanicsManager::getDerivedDisposition(const MWWorld::Ptr& ptr) { MWMechanics::NpcStats npcSkill = MWWorld::Class::get(ptr).getNpcStats(ptr); - float x = npcSkill.getDisposition(); + float x = npcSkill.getBaseDisposition(); MWWorld::LiveCellRef* npc = ptr.get(); MWWorld::Ptr playerPtr = MWBase::Environment::get().getWorld()->getPlayer().getPlayer(); @@ -489,4 +489,10 @@ namespace MWMechanics { return mActors.countDeaths (id); } + + + float MechanicsManager::getPersuasionDispositionChange (MWWorld::Ptr npc, PersuasionType type, bool& success) const + { + return 0.f; + } } diff --git a/apps/openmw/mwmechanics/mechanicsmanagerimp.hpp b/apps/openmw/mwmechanics/mechanicsmanagerimp.hpp index 0344d951c..1ec65a8af 100644 --- a/apps/openmw/mwmechanics/mechanicsmanagerimp.hpp +++ b/apps/openmw/mwmechanics/mechanicsmanagerimp.hpp @@ -88,6 +88,8 @@ namespace MWMechanics virtual int countDeaths (const std::string& id) const; ///< Return the number of deaths for actors with the given ID. + virtual float getPersuasionDispositionChange (MWWorld::Ptr npc, PersuasionType type, bool& success) const; + ///< Get amount to adjust temporary disposition for a given persuasion action on an NPC }; } diff --git a/apps/openmw/mwmechanics/npcstats.cpp b/apps/openmw/mwmechanics/npcstats.cpp index 5b2ce739f..70fd29684 100644 --- a/apps/openmw/mwmechanics/npcstats.cpp +++ b/apps/openmw/mwmechanics/npcstats.cpp @@ -37,12 +37,12 @@ void MWMechanics::NpcStats::setDrawState (DrawState_ state) mDrawState = state; } -int MWMechanics::NpcStats::getDisposition() const +int MWMechanics::NpcStats::getBaseDisposition() const { return mDisposition; } -void MWMechanics::NpcStats::setDisposition(int disposition) +void MWMechanics::NpcStats::setBaseDisposition(int disposition) { mDisposition = disposition; } diff --git a/apps/openmw/mwmechanics/npcstats.hpp b/apps/openmw/mwmechanics/npcstats.hpp index 35af4afa0..3e39eb7f1 100644 --- a/apps/openmw/mwmechanics/npcstats.hpp +++ b/apps/openmw/mwmechanics/npcstats.hpp @@ -62,9 +62,9 @@ namespace MWMechanics void setDrawState (DrawState_ state); - int getDisposition() const; + int getBaseDisposition() const; - void setDisposition(int disposition); + void setBaseDisposition(int disposition); bool getMovementFlag (Flag flag) const; diff --git a/apps/openmw/mwrender/player.cpp b/apps/openmw/mwrender/player.cpp index bbc75cade..d0b4641b9 100644 --- a/apps/openmw/mwrender/player.cpp +++ b/apps/openmw/mwrender/player.cpp @@ -23,7 +23,8 @@ namespace MWRender mFreeLook(true), mHeight(128.f), mCameraDistance(300.f), - mDistanceAdjusted(false) + mDistanceAdjusted(false), + mAnimation(NULL) { mVanity.enabled = false; mVanity.allowed = true; diff --git a/files/mygui/CMakeLists.txt b/files/mygui/CMakeLists.txt index da8fba62c..562668a90 100644 --- a/files/mygui/CMakeLists.txt +++ b/files/mygui/CMakeLists.txt @@ -80,6 +80,7 @@ set(MYGUI_FILES openmw_enchanting_dialog.layout openmw_trainingwindow.layout openmw_travel_window.layout + openmw_persuasion_dialog.layout smallbars.png VeraMono.ttf markers.png From 33b4b29fbc6285d6aea91b23517751cbe3226960 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sat, 10 Nov 2012 00:29:36 +0100 Subject: [PATCH 05/12] persuasion mechanics, added reputation --- apps/openmw/mwbase/dialoguemanager.hpp | 3 + apps/openmw/mwbase/mechanicsmanager.hpp | 5 +- apps/openmw/mwclass/npc.cpp | 1 + apps/openmw/mwdialogue/dialoguemanagerimp.cpp | 57 +++++++ apps/openmw/mwdialogue/dialoguemanagerimp.hpp | 5 + apps/openmw/mwgui/dialogue.cpp | 37 ++--- apps/openmw/mwgui/dialogue.hpp | 11 +- .../mwmechanics/mechanicsmanagerimp.cpp | 146 +++++++++++++++++- .../mwmechanics/mechanicsmanagerimp.hpp | 5 +- apps/openmw/mwmechanics/npcstats.cpp | 12 +- apps/openmw/mwmechanics/npcstats.hpp | 5 + 11 files changed, 245 insertions(+), 42 deletions(-) diff --git a/apps/openmw/mwbase/dialoguemanager.hpp b/apps/openmw/mwbase/dialoguemanager.hpp index ccffc6b21..e9854b246 100644 --- a/apps/openmw/mwbase/dialoguemanager.hpp +++ b/apps/openmw/mwbase/dialoguemanager.hpp @@ -40,6 +40,9 @@ namespace MWBase virtual void keywordSelected (const std::string& keyword) = 0; virtual void goodbyeSelected() = 0; virtual void questionAnswered (const std::string& answer) = 0; + + virtual void persuade (int type) = 0; + virtual int getTemporaryDispositionChange () const = 0; }; } diff --git a/apps/openmw/mwbase/mechanicsmanager.hpp b/apps/openmw/mwbase/mechanicsmanager.hpp index 0be111ea7..cdee048db 100644 --- a/apps/openmw/mwbase/mechanicsmanager.hpp +++ b/apps/openmw/mwbase/mechanicsmanager.hpp @@ -95,8 +95,9 @@ namespace MWBase PT_Bribe100, PT_Bribe1000 }; - virtual float getPersuasionDispositionChange (MWWorld::Ptr npc, PersuasionType type, bool& success) const = 0; - ///< Get amount to adjust temporary disposition for a given persuasion action on an NPC + virtual void getPersuasionDispositionChange (const MWWorld::Ptr& npc, PersuasionType type, + float currentTemporaryDispositionDelta, bool& success, float& tempChange, float& permChange) = 0; + ///< Perform a persuasion action on NPC }; } diff --git a/apps/openmw/mwclass/npc.cpp b/apps/openmw/mwclass/npc.cpp index c7f33504e..790d824f5 100644 --- a/apps/openmw/mwclass/npc.cpp +++ b/apps/openmw/mwclass/npc.cpp @@ -96,6 +96,7 @@ namespace MWClass data->mCreatureStats.setLevel(ref->mBase->mNpdt52.mLevel); data->mNpcStats.setBaseDisposition(ref->mBase->mNpdt52.mDisposition); + data->mNpcStats.setReputation(ref->mBase->mNpdt52.mReputation); } else { diff --git a/apps/openmw/mwdialogue/dialoguemanagerimp.cpp b/apps/openmw/mwdialogue/dialoguemanagerimp.cpp index 46fab0a4b..3eabe7383 100644 --- a/apps/openmw/mwdialogue/dialoguemanagerimp.cpp +++ b/apps/openmw/mwdialogue/dialoguemanagerimp.cpp @@ -12,6 +12,7 @@ #include "../mwbase/scriptmanager.hpp" #include "../mwbase/journal.hpp" #include "../mwbase/windowmanager.hpp" +#include "../mwbase/mechanicsmanager.hpp" #include "../mwworld/class.hpp" #include "../mwworld/refdata.hpp" @@ -584,6 +585,8 @@ namespace MWDialogue DialogueManager::DialogueManager (const Compiler::Extensions& extensions) : mCompilerContext (MWScript::CompilerContext::Type_Dialgoue), mErrorStream(std::cout.rdbuf()),mErrorHandler(mErrorStream) + , mTemporaryDispositionChange(0.f) + , mPermanentDispositionChange(0.f) { mChoice = -1; mIsInChoice = false; @@ -868,6 +871,12 @@ namespace MWDialogue void DialogueManager::goodbyeSelected() { MWBase::Environment::get().getWindowManager()->removeGuiMode(MWGui::GM_Dialogue); + + // Apply disposition change to NPC's base disposition + MWMechanics::NpcStats npcStats = MWWorld::Class::get(mActor).getNpcStats(mActor); + npcStats.setBaseDisposition(npcStats.getBaseDisposition() + mPermanentDispositionChange); + mPermanentDispositionChange = 0; + mTemporaryDispositionChange = 0; } void DialogueManager::questionAnswered (const std::string& answer) @@ -944,4 +953,52 @@ namespace MWDialogue win->goodbye(); } + + void DialogueManager::persuade(int type) + { + bool success; + float temp, perm; + MWBase::Environment::get().getMechanicsManager()->getPersuasionDispositionChange( + mActor, MWBase::MechanicsManager::PersuasionType(type), mTemporaryDispositionChange, + success, temp, perm); + mTemporaryDispositionChange += temp; + mPermanentDispositionChange += perm; + + // change temp disposition so that final disposition is between 0...100 + int curDisp = MWBase::Environment::get().getMechanicsManager()->getDerivedDisposition(mActor); + if (curDisp + mTemporaryDispositionChange < 0) + mTemporaryDispositionChange = -curDisp; + else if (curDisp + mTemporaryDispositionChange > 100) + mTemporaryDispositionChange = 100 - curDisp; + + // practice skill + MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayer().getPlayer(); + + MWWorld::Class::get(player).skillUsageSucceeded(player, ESM::Skill::Speechcraft, 0); + + + // add status message to dialogue window + std::string text; + + if (type == MWBase::MechanicsManager::PT_Admire) + text = "sAdmire"; + else if (type == MWBase::MechanicsManager::PT_Taunt) + text = "sTaunt"; + else if (type == MWBase::MechanicsManager::PT_Intimidate) + text = "sIntimidate"; + else + text = "sBribe"; + + text += (success ? "Success" : "Fail"); + + MWGui::DialogueWindow* win = MWBase::Environment::get().getWindowManager()->getDialogueWindow(); + win->addTitle(MyGUI::LanguageManager::getInstance().replaceTags("#{"+text+"}")); + + /// \todo text from INFO record, how to get the ID? + } + + int DialogueManager::getTemporaryDispositionChange() const + { + return mTemporaryDispositionChange; + } } diff --git a/apps/openmw/mwdialogue/dialoguemanagerimp.hpp b/apps/openmw/mwdialogue/dialoguemanagerimp.hpp index e3e9fd752..d0f48b65a 100644 --- a/apps/openmw/mwdialogue/dialoguemanagerimp.hpp +++ b/apps/openmw/mwdialogue/dialoguemanagerimp.hpp @@ -49,6 +49,9 @@ namespace MWDialogue ESM::DialInfo mLastDialogue; bool mIsInChoice; + float mTemporaryDispositionChange; + float mPermanentDispositionChange; + public: DialogueManager (const Compiler::Extensions& extensions); @@ -69,6 +72,8 @@ namespace MWDialogue virtual void goodbyeSelected(); virtual void questionAnswered (const std::string& answer); + virtual void persuade (int type); + virtual int getTemporaryDispositionChange () const; }; } diff --git a/apps/openmw/mwgui/dialogue.cpp b/apps/openmw/mwgui/dialogue.cpp index be7bfde53..d475bc56b 100644 --- a/apps/openmw/mwgui/dialogue.cpp +++ b/apps/openmw/mwgui/dialogue.cpp @@ -14,6 +14,8 @@ #include "../mwbase/windowmanager.hpp" #include "../mwbase/mechanicsmanager.hpp" +#include "../mwmechanics/npcstats.hpp" + #include "dialogue_history.hpp" #include "widgets.hpp" #include "list.hpp" @@ -98,7 +100,8 @@ void PersuasionDialog::onPersuade(MyGUI::Widget *sender) type = MWBase::MechanicsManager::PT_Bribe1000; } - eventPersuade(type, true, 0); + MWBase::Environment::get().getDialogueManager()->persuade(type); + setVisible(false); } @@ -128,7 +131,6 @@ DialogueWindow::DialogueWindow(MWBase::WindowManager& parWindowManager) center(); mPersuasionDialog.setVisible(false); - mPersuasionDialog.eventPersuade += MyGUI::newDelegate(this, &DialogueWindow::onPersuade); //History view getWidget(mHistory, "History"); @@ -212,6 +214,7 @@ void DialogueWindow::onSelectTopic(std::string topic) } if (topic == gmst.find("sPersuasion")->getString()) { + mPersuasionDialog.setPtr(mPtr); mPersuasionDialog.setVisible(true); } else if (topic == gmst.find("sSpells")->getString()) @@ -391,8 +394,6 @@ void DialogueWindow::updateOptions() void DialogueWindow::goodbye() { - // Apply temporary disposition change to NPC's base disposition - mHistory->addDialogText("\n#572D21" + MWBase::Environment::get().getWorld()->getStore().get().find("sGoodbye")->getString()); mTopicsList->setEnabled(false); mEnabled = false; @@ -407,30 +408,12 @@ void DialogueWindow::onFrame() { if(mEnabled && mPtr.getTypeName() == typeid(ESM::NPC).name()) { + int disp = std::max(0, std::min(100, + MWBase::Environment::get().getMechanicsManager()->getDerivedDisposition(mPtr) + + MWBase::Environment::get().getDialogueManager()->getTemporaryDispositionChange())); mDispositionBar->setProgressRange(100); - mDispositionBar->setProgressPosition(MWBase::Environment::get().getMechanicsManager()->getDerivedDisposition(mPtr)); + mDispositionBar->setProgressPosition(disp); mDispositionText->eraseText(0, mDispositionText->getTextLength()); - mDispositionText->addText("#B29154"+boost::lexical_cast(MWBase::Environment::get().getMechanicsManager()->getDerivedDisposition(mPtr))+std::string("/100")+"#B29154"); + mDispositionText->addText("#B29154"+boost::lexical_cast(disp)+std::string("/100")+"#B29154"); } } - -void DialogueWindow::onPersuade(int type, bool success, float dispositionChange) -{ - std::string text; - - if (type == MWBase::MechanicsManager::PT_Admire) - text = "sAdmire"; - else if (type == MWBase::MechanicsManager::PT_Taunt) - text = "sTaunt"; - else if (type == MWBase::MechanicsManager::PT_Intimidate) - text = "sIntimidate"; - else - text = "sBribe"; - - text += success ? "Fail" : "Success"; - - mHistory->addDialogHeading( MyGUI::LanguageManager::getInstance().replaceTags("#{"+text+"}")); - - /// \todo text from INFO record, how to get the ID? - //mHistory->addDialogText(); -} diff --git a/apps/openmw/mwgui/dialogue.hpp b/apps/openmw/mwgui/dialogue.hpp index 3d0d74d95..134792226 100644 --- a/apps/openmw/mwgui/dialogue.hpp +++ b/apps/openmw/mwgui/dialogue.hpp @@ -33,9 +33,7 @@ namespace MWGui virtual void open(); - typedef MyGUI::delegates::CMultiDelegate3 EventHandle_Persuade; - - EventHandle_Persuade eventPersuade; + void setPtr(MWWorld::Ptr ptr) { mPtr = ptr; } private: MyGUI::Button* mCancelButton; @@ -49,6 +47,8 @@ namespace MWGui void onCancel (MyGUI::Widget* sender); void onPersuade (MyGUI::Widget* sender); + + MWWorld::Ptr mPtr; }; class DialogueWindow: public WindowBase, public ReferenceInterface @@ -113,11 +113,6 @@ namespace MWGui MyGUI::EditPtr mDispositionText; PersuasionDialog mPersuasionDialog; - - - float mTemporaryDispositionChange; - - void onPersuade (int type, bool success, float dispositionChange); }; } #endif diff --git a/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp b/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp index 134a7fb06..797369e26 100644 --- a/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp +++ b/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp @@ -491,8 +491,150 @@ namespace MWMechanics } - float MechanicsManager::getPersuasionDispositionChange (MWWorld::Ptr npc, PersuasionType type, bool& success) const + void MechanicsManager::getPersuasionDispositionChange (const MWWorld::Ptr& npc, PersuasionType type, + float currentTemporaryDispositionDelta, bool& success, float& tempChange, float& permChange) { - return 0.f; + const MWWorld::Store &gmst = + MWBase::Environment::get().getWorld()->getStore().get(); + + MWWorld::Ptr playerPtr = MWBase::Environment::get().getWorld()->getPlayer().getPlayer(); + MWMechanics::NpcStats playerSkill = MWWorld::Class::get(playerPtr).getNpcStats(playerPtr); + MWMechanics::CreatureStats playerStats = MWWorld::Class::get(playerPtr).getCreatureStats(playerPtr); + + MWMechanics::NpcStats npcSkill = MWWorld::Class::get(npc).getNpcStats(npc); + MWMechanics::CreatureStats npcStats = MWWorld::Class::get(npc).getCreatureStats(npc); + + + float persTerm = playerStats.getAttribute(ESM::Attribute::Personality).getModified() + / gmst.find("fPersonalityMod")->getFloat(); + + float luckTerm = playerStats.getAttribute(ESM::Attribute::Luck).getModified() + / gmst.find("fLuckMod")->getFloat(); + + float repTerm = playerSkill.getReputation() * gmst.find("fReputationMod")->getFloat(); + + float levelTerm = playerStats.getLevel() * gmst.find("fLevelMod")->getFloat(); + + float fatigueTerm = playerStats.getFatigueTerm(); + + float playerRating1 = (repTerm + luckTerm + persTerm + playerSkill.getSkill(ESM::Skill::Speechcraft).getModified()) * fatigueTerm; + float playerRating2 = playerRating1 + levelTerm; + float playerRating3 = (playerSkill.getSkill(ESM::Skill::Mercantile).getModified() + luckTerm + persTerm) * fatigueTerm; + + float npcRating1 = (repTerm + luckTerm + persTerm + playerSkill.getSkill(ESM::Skill::Speechcraft).getModified()) * fatigueTerm; + float npcRating2 = (levelTerm + repTerm + luckTerm + persTerm + npcSkill.getSkill(ESM::Skill::Speechcraft).getModified()) * fatigueTerm; + float npcRating3 = (playerSkill.getSkill(ESM::Skill::Mercantile).getModified() + repTerm + luckTerm + persTerm) * fatigueTerm; + + int currentDisposition = std::min(100, std::max(0, int(getDerivedDisposition(npc) + currentTemporaryDispositionDelta))); + + float d = 1 - 0.02 * abs(currentDisposition - 50); + float target1 = d * (playerRating1 - npcRating1 + 50); + float target2 = d * (playerRating2 - npcRating2 + 50); + + float bribeMod; + if (type == PT_Bribe10) bribeMod = gmst.find("fBribe10Mod")->getFloat(); + if (type == PT_Bribe100) bribeMod = gmst.find("fBribe100Mod")->getFloat(); + else bribeMod = gmst.find("fBribe1000Mod")->getFloat(); + + float target3 = d * (playerRating3 - npcRating3 + 50) + bribeMod; + + float iPerMinChance = gmst.find("iPerMinChance")->getInt(); + float iPerMinChange = gmst.find("iPerMinChange")->getInt(); + float fPerDieRollMult = gmst.find("fPerDieRollMult")->getFloat(); + float fPerTempMult = gmst.find("fPerTempMult")->getFloat(); + + float x,y; + + float roll = static_cast (std::rand()) / RAND_MAX * 100; + + if (type == PT_Admire) + { + target1 = std::max(iPerMinChance, target1); + success = (roll <= target1); + float c = int(fPerDieRollMult * (target1 - roll)); + x = success ? std::max(iPerMinChange, c) : c; + } + else if (type == PT_Intimidate) + { + target2 = std::max(iPerMinChance, target2); + + success = (roll <= target2); + + float r; + if (roll != target2) + r = int(target2 - roll); + else + r = 1; + + if (roll <= target2) + { + float s = int(r * fPerDieRollMult * fPerTempMult); + + npcStats.setFlee ( std::max(0, std::min(100, npcStats.getFlee() + int(std::max(iPerMinChange, s))))); + npcStats.setFight ( std::max(0, std::min(100, npcStats.getFight() + int(std::min(-iPerMinChange, -s))))); + } + + float c = -std::abs(int(r * fPerDieRollMult)); + if (success) + { + if (std::abs(c) < iPerMinChange) + { + x = 0; + y = -iPerMinChange; + } + else + { + x = -int(c * fPerTempMult); + y = c; + } + } + else + { + x = int(c * fPerTempMult); + y = c; + } + } + else if (type == PT_Taunt) + { + target1 = std::max(iPerMinChance, target1); + success = (roll <= target1); + + float c = std::abs(int(target1 - roll)); + + if (roll <= target1) + { + float s = c * fPerDieRollMult * fPerTempMult; + + npcStats.setFlee ( std::max(0, std::min(100, npcStats.getFlee() + std::min(-int(iPerMinChange), int(-s))))); + npcStats.setFight ( std::max(0, std::min(100, npcStats.getFight() + std::max(int(iPerMinChange), int(s))))); + } + x = int(-c * fPerDieRollMult); + + if (success && std::abs(x) < iPerMinChange) + x = -iPerMinChange; + } + else // Bribe + { + target3 = std::max(iPerMinChance, target3); + success = (roll <= target3); + float c = int((target3 - roll) * fPerDieRollMult); + + x = success ? std::max(iPerMinChange, c) : c; + } + + tempChange = type == PT_Intimidate ? x : int(x * fPerTempMult); + + + float cappedDispositionChange = tempChange; + if (currentDisposition + tempChange > 100.f) + cappedDispositionChange = 100 - currentDisposition; + if (currentDisposition + tempChange < 0.f) + cappedDispositionChange = -currentDisposition; + + permChange = int(cappedDispositionChange / fPerTempMult); + if (type == PT_Intimidate) + { + permChange = success ? -int(cappedDispositionChange/ fPerTempMult) : y; + } } } diff --git a/apps/openmw/mwmechanics/mechanicsmanagerimp.hpp b/apps/openmw/mwmechanics/mechanicsmanagerimp.hpp index 1ec65a8af..b03eacecc 100644 --- a/apps/openmw/mwmechanics/mechanicsmanagerimp.hpp +++ b/apps/openmw/mwmechanics/mechanicsmanagerimp.hpp @@ -88,8 +88,9 @@ namespace MWMechanics virtual int countDeaths (const std::string& id) const; ///< Return the number of deaths for actors with the given ID. - virtual float getPersuasionDispositionChange (MWWorld::Ptr npc, PersuasionType type, bool& success) const; - ///< Get amount to adjust temporary disposition for a given persuasion action on an NPC + virtual void getPersuasionDispositionChange (const MWWorld::Ptr& npc, PersuasionType type, + float currentTemporaryDispositionDelta, bool& success, float& tempChange, float& permChange); + ///< Perform a persuasion action on NPC }; } diff --git a/apps/openmw/mwmechanics/npcstats.cpp b/apps/openmw/mwmechanics/npcstats.cpp index 70fd29684..f37a45b49 100644 --- a/apps/openmw/mwmechanics/npcstats.cpp +++ b/apps/openmw/mwmechanics/npcstats.cpp @@ -19,7 +19,7 @@ MWMechanics::NpcStats::NpcStats() : mMovementFlags (0), mDrawState (DrawState_Nothing), mBounty (0) -, mLevelProgress(0), mDisposition(0) +, mLevelProgress(0), mDisposition(0), mReputation(0) { mSkillIncreases.resize (ESM::Attribute::Length); @@ -259,3 +259,13 @@ void MWMechanics::NpcStats::setBounty (int bounty) { mBounty = bounty; } + +int MWMechanics::NpcStats::getReputation() const +{ + return mReputation; +} + +void MWMechanics::NpcStats::setReputation(int reputation) +{ + mReputation = reputation; +} diff --git a/apps/openmw/mwmechanics/npcstats.hpp b/apps/openmw/mwmechanics/npcstats.hpp index 3e39eb7f1..b6abbd342 100644 --- a/apps/openmw/mwmechanics/npcstats.hpp +++ b/apps/openmw/mwmechanics/npcstats.hpp @@ -47,6 +47,7 @@ namespace MWMechanics unsigned int mMovementFlags; Stat mSkill[27]; int mBounty; + int mReputation; int mLevelProgress; // 0-10 @@ -66,6 +67,10 @@ namespace MWMechanics void setBaseDisposition(int disposition); + int getReputation() const; + + void setReputation(int reputation); + bool getMovementFlag (Flag flag) const; void setMovementFlag (Flag flag, bool state); From 94aeb152202798757e1a246b9e22de953d401454 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sat, 10 Nov 2012 00:38:45 +0100 Subject: [PATCH 06/12] bartering disposition change --- apps/openmw/mwbase/dialoguemanager.hpp | 1 + apps/openmw/mwdialogue/dialoguemanagerimp.cpp | 12 ++++++++++-- apps/openmw/mwdialogue/dialoguemanagerimp.hpp | 1 + apps/openmw/mwgui/tradewindow.cpp | 14 +++++++++----- 4 files changed, 21 insertions(+), 7 deletions(-) diff --git a/apps/openmw/mwbase/dialoguemanager.hpp b/apps/openmw/mwbase/dialoguemanager.hpp index e9854b246..2181ddb58 100644 --- a/apps/openmw/mwbase/dialoguemanager.hpp +++ b/apps/openmw/mwbase/dialoguemanager.hpp @@ -43,6 +43,7 @@ namespace MWBase virtual void persuade (int type) = 0; virtual int getTemporaryDispositionChange () const = 0; + virtual void applyTemporaryDispositionChange (int delta) = 0; }; } diff --git a/apps/openmw/mwdialogue/dialoguemanagerimp.cpp b/apps/openmw/mwdialogue/dialoguemanagerimp.cpp index 3eabe7383..60ccda09f 100644 --- a/apps/openmw/mwdialogue/dialoguemanagerimp.cpp +++ b/apps/openmw/mwdialogue/dialoguemanagerimp.cpp @@ -873,8 +873,11 @@ namespace MWDialogue MWBase::Environment::get().getWindowManager()->removeGuiMode(MWGui::GM_Dialogue); // Apply disposition change to NPC's base disposition - MWMechanics::NpcStats npcStats = MWWorld::Class::get(mActor).getNpcStats(mActor); - npcStats.setBaseDisposition(npcStats.getBaseDisposition() + mPermanentDispositionChange); + if (mActor.getTypeName() == typeid(ESM::NPC).name()) + { + MWMechanics::NpcStats npcStats = MWWorld::Class::get(mActor).getNpcStats(mActor); + npcStats.setBaseDisposition(npcStats.getBaseDisposition() + mPermanentDispositionChange); + } mPermanentDispositionChange = 0; mTemporaryDispositionChange = 0; } @@ -1001,4 +1004,9 @@ namespace MWDialogue { return mTemporaryDispositionChange; } + + void DialogueManager::applyTemporaryDispositionChange(int delta) + { + mTemporaryDispositionChange += delta; + } } diff --git a/apps/openmw/mwdialogue/dialoguemanagerimp.hpp b/apps/openmw/mwdialogue/dialoguemanagerimp.hpp index d0f48b65a..a8dea3dba 100644 --- a/apps/openmw/mwdialogue/dialoguemanagerimp.hpp +++ b/apps/openmw/mwdialogue/dialoguemanagerimp.hpp @@ -74,6 +74,7 @@ namespace MWDialogue virtual void persuade (int type); virtual int getTemporaryDispositionChange () const; + virtual void applyTemporaryDispositionChange (int delta); }; } diff --git a/apps/openmw/mwgui/tradewindow.cpp b/apps/openmw/mwgui/tradewindow.cpp index 0707ad985..c6a21c461 100644 --- a/apps/openmw/mwgui/tradewindow.cpp +++ b/apps/openmw/mwgui/tradewindow.cpp @@ -7,6 +7,7 @@ #include "../mwbase/soundmanager.hpp" #include "../mwbase/windowmanager.hpp" #include "../mwbase/mechanicsmanager.hpp" +#include "../mwbase/dialoguemanager.hpp" #include "../mwworld/inventorystore.hpp" #include "../mwworld/manualref.hpp" @@ -206,7 +207,8 @@ namespace MWGui if (mCurrentMerchantOffer<0) d = int(100 * (a - b) / a); else d = int(100 * (b - a) / a); - float clampedDisposition = std::max(0,std::min(int(MWBase::Environment::get().getMechanicsManager()->getDerivedDisposition(mPtr)),100)); + float clampedDisposition = std::max(0,std::min(int(MWBase::Environment::get().getMechanicsManager()->getDerivedDisposition(mPtr) + + MWBase::Environment::get().getDialogueManager()->getTemporaryDispositionChange()),100)); MWMechanics::NpcStats sellerSkill = MWWorld::Class::get(mPtr).getNpcStats(mPtr); MWMechanics::CreatureStats sellerStats = MWWorld::Class::get(mPtr).getCreatureStats(mPtr); @@ -232,13 +234,15 @@ namespace MWGui { MWBase::Environment::get().getWindowManager()-> messageBox("#{sNotifyMessage9}", std::vector()); - /// \todo adjust npc temporary disposition by iBarterSuccessDisposition or iBarterFailDisposition - return ; + + int iBarterFailDisposition = gmst.find("iBarterFailDisposition")->getInt(); + MWBase::Environment::get().getDialogueManager()->applyTemporaryDispositionChange(iBarterFailDisposition); + return; } } - -/// \todo adjust npc temporary disposition by iBarterSuccessDisposition or iBarterFailDisposition + int iBarterSuccessDisposition = gmst.find("iBarterSuccessDisposition")->getInt(); + MWBase::Environment::get().getDialogueManager()->applyTemporaryDispositionChange(iBarterSuccessDisposition); // success! make the item transfer. transferBoughtItems(); From 553ea08eae85562e137d07c4f0597df3dc81a245 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sat, 10 Nov 2012 00:42:31 +0100 Subject: [PATCH 07/12] consider temporary disposition change when trading --- apps/openmw/mwmechanics/mechanicsmanagerimp.cpp | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp b/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp index 797369e26..e0c028b53 100644 --- a/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp +++ b/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp @@ -6,6 +6,7 @@ #include "../mwbase/environment.hpp" #include "../mwbase/world.hpp" #include "../mwbase/windowmanager.hpp" +#include "../mwbase/dialoguemanager.hpp" #include "../mwworld/class.hpp" #include "../mwworld/player.hpp" @@ -462,7 +463,10 @@ namespace MWMechanics MWMechanics::NpcStats playerSkill = MWWorld::Class::get(playerPtr).getNpcStats(playerPtr); MWMechanics::CreatureStats playerStats = MWWorld::Class::get(playerPtr).getCreatureStats(playerPtr); - int clampedDisposition = std::min(getDerivedDisposition(ptr),100); + // I suppose the temporary disposition change _has_ to be considered here, + // otherwise one would get different prices when exiting and re-entering the dialogue window... + int clampedDisposition = std::max(0, std::min(getDerivedDisposition(ptr) + + MWBase::Environment::get().getDialogueManager()->getTemporaryDispositionChange(),100)); float a = std::min(playerSkill.getSkill(ESM::Skill::Mercantile).getModified(), 100.f); float b = std::min(0.1f * playerStats.getAttribute(ESM::Attribute::Luck).getModified(), 10.f); float c = std::min(0.2f * playerStats.getAttribute(ESM::Attribute::Personality).getModified(), 10.f); From 92bba182189de2baacb21312d61cbfb267294f33 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sat, 10 Nov 2012 00:47:24 +0100 Subject: [PATCH 08/12] removed useless member --- apps/openmw/mwgui/dialogue.cpp | 1 - apps/openmw/mwgui/dialogue.hpp | 4 ---- 2 files changed, 5 deletions(-) diff --git a/apps/openmw/mwgui/dialogue.cpp b/apps/openmw/mwgui/dialogue.cpp index d475bc56b..e4c9945b4 100644 --- a/apps/openmw/mwgui/dialogue.cpp +++ b/apps/openmw/mwgui/dialogue.cpp @@ -214,7 +214,6 @@ void DialogueWindow::onSelectTopic(std::string topic) } if (topic == gmst.find("sPersuasion")->getString()) { - mPersuasionDialog.setPtr(mPtr); mPersuasionDialog.setVisible(true); } else if (topic == gmst.find("sSpells")->getString()) diff --git a/apps/openmw/mwgui/dialogue.hpp b/apps/openmw/mwgui/dialogue.hpp index 134792226..082d92524 100644 --- a/apps/openmw/mwgui/dialogue.hpp +++ b/apps/openmw/mwgui/dialogue.hpp @@ -33,8 +33,6 @@ namespace MWGui virtual void open(); - void setPtr(MWWorld::Ptr ptr) { mPtr = ptr; } - private: MyGUI::Button* mCancelButton; MyGUI::Button* mAdmireButton; @@ -47,8 +45,6 @@ namespace MWGui void onCancel (MyGUI::Widget* sender); void onPersuade (MyGUI::Widget* sender); - - MWWorld::Ptr mPtr; }; class DialogueWindow: public WindowBase, public ReferenceInterface From b1ef0026a9f64171d28471eb21aac8fc14490318 Mon Sep 17 00:00:00 2001 From: greye Date: Sat, 10 Nov 2012 11:41:12 +0400 Subject: [PATCH 09/12] race selection/inventory preview character model update --- apps/openmw/mwbase/mechanicsmanager.hpp | 2 +- apps/openmw/mwgui/charactercreation.cpp | 30 +++++++++++++---- apps/openmw/mwgui/inventorywindow.hpp | 4 +++ apps/openmw/mwgui/race.cpp | 23 +++++++++++++ apps/openmw/mwgui/race.hpp | 1 + .../mwmechanics/mechanicsmanagerimp.cpp | 10 +++--- .../mwmechanics/mechanicsmanagerimp.hpp | 2 +- apps/openmw/mwrender/characterpreview.cpp | 32 +++++++++++++++++-- apps/openmw/mwrender/characterpreview.hpp | 11 +++++++ components/esm/loadnpc.hpp | 7 ++++ 10 files changed, 104 insertions(+), 18 deletions(-) diff --git a/apps/openmw/mwbase/mechanicsmanager.hpp b/apps/openmw/mwbase/mechanicsmanager.hpp index 750fc2fff..e1a83c747 100644 --- a/apps/openmw/mwbase/mechanicsmanager.hpp +++ b/apps/openmw/mwbase/mechanicsmanager.hpp @@ -62,7 +62,7 @@ namespace MWBase virtual void setPlayerName (const std::string& name) = 0; ///< Set player name. - virtual void setPlayerRace (const std::string& id, bool male) = 0; + virtual void setPlayerRace (const std::string& id, bool male, const std::string &head, const std::string &hair) = 0; ///< Set player race. virtual void setPlayerBirthsign (const std::string& id) = 0; diff --git a/apps/openmw/mwgui/charactercreation.cpp b/apps/openmw/mwgui/charactercreation.cpp index a054f34dd..477846055 100644 --- a/apps/openmw/mwgui/charactercreation.cpp +++ b/apps/openmw/mwgui/charactercreation.cpp @@ -7,6 +7,7 @@ #include "review.hpp" #include "dialogue.hpp" #include "mode.hpp" +#include "inventorywindow.hpp" #include "../mwbase/environment.hpp" #include "../mwbase/soundmanager.hpp" @@ -459,9 +460,16 @@ void CharacterCreation::onRaceDialogBack() { if (mRaceDialog) { - mPlayerRaceId = mRaceDialog->getRaceId(); - if (!mPlayerRaceId.empty()) - MWBase::Environment::get().getMechanicsManager()->setPlayerRace(mPlayerRaceId, mRaceDialog->getGender() == RaceDialog::GM_Male); + const ESM::NPC &data = mRaceDialog->getResult(); + mPlayerRaceId = data.mId; + if (!mPlayerRaceId.empty()) { + MWBase::Environment::get().getMechanicsManager()->setPlayerRace( + data.mId, + data.isMale(), + data.mHead, + data.mHair + ); + } mWM->removeDialog(mRaceDialog); mRaceDialog = 0; } @@ -474,10 +482,18 @@ void CharacterCreation::onRaceDialogDone(WindowBase* parWindow) { if (mRaceDialog) { - mPlayerRaceId = mRaceDialog->getRaceId(); - mWM->setValue("race", mPlayerRaceId); - if (!mPlayerRaceId.empty()) - MWBase::Environment::get().getMechanicsManager()->setPlayerRace(mPlayerRaceId, mRaceDialog->getGender() == RaceDialog::GM_Male); + const ESM::NPC &data = mRaceDialog->getResult(); + mPlayerRaceId = data.mRace; + if (!mPlayerRaceId.empty()) { + MWBase::Environment::get().getMechanicsManager()->setPlayerRace( + data.mRace, + data.isMale(), + data.mHead, + data.mHair + ); + } + mWM->getInventoryWindow()->rebuildAvatar(); + mWM->removeDialog(mRaceDialog); mRaceDialog = 0; } diff --git a/apps/openmw/mwgui/inventorywindow.hpp b/apps/openmw/mwgui/inventorywindow.hpp index 84b576a58..6b45a9980 100644 --- a/apps/openmw/mwgui/inventorywindow.hpp +++ b/apps/openmw/mwgui/inventorywindow.hpp @@ -28,6 +28,10 @@ namespace MWGui MWWorld::Ptr getAvatarSelectedItem(int x, int y); + void rebuildAvatar() { + mPreview.rebuild(); + } + protected: MyGUI::Widget* mAvatar; MyGUI::ImageBox* mAvatarImage; diff --git a/apps/openmw/mwgui/race.cpp b/apps/openmw/mwgui/race.cpp index 943081e65..ff7c01ade 100644 --- a/apps/openmw/mwgui/race.cpp +++ b/apps/openmw/mwgui/race.cpp @@ -214,6 +214,29 @@ void RaceDialog::onSelectRace(MyGUI::ListBox* _sender, size_t _index) return; mCurrentRaceId = *raceId; + + ESM::NPC record = mPreview->getPrototype(); + record.mRace = mCurrentRaceId; + record.setIsMale(mGenderIndex == 0); + + std::string prefix = + "b_n_" + mCurrentRaceId + ((record.isMale()) ? "_m_" : "_f_"); + + record.mHead = prefix + "head_01"; + record.mHair = prefix + "hair_01"; + + const MWWorld::Store &parts = + MWBase::Environment::get().getWorld()->getStore().get(); + + if (parts.search(record.mHair) == 0) { + record.mHair = prefix + "hair01"; + } + + mFaceIndex = 0; + mHairIndex = 0; + + mPreview->setPrototype(record); + updateSkills(); updateSpellPowers(); } diff --git a/apps/openmw/mwgui/race.hpp b/apps/openmw/mwgui/race.hpp index 000b84523..ec73d1c3a 100644 --- a/apps/openmw/mwgui/race.hpp +++ b/apps/openmw/mwgui/race.hpp @@ -34,6 +34,7 @@ namespace MWGui GM_Female }; + const ESM::NPC &getResult() const { return mPreview->getPrototype(); } const std::string &getRaceId() const { return mCurrentRaceId; } Gender getGender() const { return mGenderIndex == 0 ? GM_Male : GM_Female; } // getFace() diff --git a/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp b/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp index 50868eeb3..aecde1252 100644 --- a/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp +++ b/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp @@ -318,7 +318,7 @@ namespace MWMechanics mUpdatePlayer = true; } - void MechanicsManager::setPlayerRace (const std::string& race, bool male) + void MechanicsManager::setPlayerRace (const std::string& race, bool male, const std::string &head, const std::string &hair) { MWBase::World *world = MWBase::Environment::get().getWorld(); @@ -326,11 +326,9 @@ namespace MWMechanics *world->getPlayer().getPlayer().get()->mBase; player.mRace = race; - - player.mFlags |= ESM::NPC::Female; - if (male) { - player.mFlags ^= ESM::NPC::Female; - } + player.mHead = head; + player.mHair = hair; + player.setIsMale(male); world->createRecord(player); diff --git a/apps/openmw/mwmechanics/mechanicsmanagerimp.hpp b/apps/openmw/mwmechanics/mechanicsmanagerimp.hpp index 38536d3bd..79a45821a 100644 --- a/apps/openmw/mwmechanics/mechanicsmanagerimp.hpp +++ b/apps/openmw/mwmechanics/mechanicsmanagerimp.hpp @@ -64,7 +64,7 @@ namespace MWMechanics virtual void setPlayerName (const std::string& name); ///< Set player name. - virtual void setPlayerRace (const std::string& id, bool male); + virtual void setPlayerRace (const std::string& id, bool male, const std::string &head, const std::string &hair); ///< Set player race. virtual void setPlayerBirthsign (const std::string& id); diff --git a/apps/openmw/mwrender/characterpreview.cpp b/apps/openmw/mwrender/characterpreview.cpp index 017062baa..0a11dc281 100644 --- a/apps/openmw/mwrender/characterpreview.cpp +++ b/apps/openmw/mwrender/characterpreview.cpp @@ -48,8 +48,9 @@ namespace MWRender mNode->setVisible (false); - mCamera->setPosition(mPosition); - mCamera->lookAt(mLookAt); + Ogre::Vector3 scale = mNode->getScale(); + mCamera->setPosition(mPosition * scale); + mCamera->lookAt(mLookAt * scale); mCamera->setNearClipDistance (0.01); mCamera->setFarClipDistance (1000); @@ -80,6 +81,22 @@ namespace MWRender delete mAnimation; } + void CharacterPreview::rebuild() + { + assert(mAnimation); + delete mAnimation; + + mAnimation = new NpcAnimation(mCharacter, mNode, + MWWorld::Class::get(mCharacter).getInventoryStore (mCharacter), RV_PlayerPreview); + + mNode->setVisible (false); + + Ogre::Vector3 scale = mNode->getScale(); + mCamera->setPosition(mPosition * scale); + mCamera->lookAt(mLookAt * scale); + + onSetup(); + } // -------------------------------------------------------------------------------------------------- @@ -128,8 +145,10 @@ namespace MWRender RaceSelectionPreview::RaceSelectionPreview() : CharacterPreview(MWBase::Environment::get().getWorld()->getPlayer().getPlayer(), 512, 512, "CharacterHeadPreview", Ogre::Vector3(0, 120, -35), Ogre::Vector3(0,125,0)) + , mRef(&mBase) { - + mBase = *mCharacter.get()->mBase; + mCharacter = MWWorld::Ptr(&mRef, mCharacter.getCell()); } void RaceSelectionPreview::update(float angle) @@ -141,4 +160,11 @@ namespace MWRender mNode->setVisible (false); } + void RaceSelectionPreview::setPrototype(const ESM::NPC &proto) + { + mBase = proto; + mBase.mId = "player"; + rebuild(); + update(0); + } } diff --git a/apps/openmw/mwrender/characterpreview.hpp b/apps/openmw/mwrender/characterpreview.hpp index 2a6b12b9e..18362d1db 100644 --- a/apps/openmw/mwrender/characterpreview.hpp +++ b/apps/openmw/mwrender/characterpreview.hpp @@ -4,6 +4,7 @@ #include #include +#include #include "externalrendering.hpp" @@ -32,6 +33,7 @@ namespace MWRender virtual void setup (Ogre::SceneManager *sceneManager); virtual void onSetup(); + virtual void rebuild(); protected: Ogre::TexturePtr mTexture; @@ -77,10 +79,19 @@ namespace MWRender class RaceSelectionPreview : public CharacterPreview { + ESM::NPC mBase; + MWWorld::LiveCellRef mRef; + public: RaceSelectionPreview(); void update(float angle); + + const ESM::NPC &getPrototype() const { + return mBase; + } + + void setPrototype(const ESM::NPC &proto); }; } diff --git a/components/esm/loadnpc.hpp b/components/esm/loadnpc.hpp index d446ee08f..46be29961 100644 --- a/components/esm/loadnpc.hpp +++ b/components/esm/loadnpc.hpp @@ -121,6 +121,13 @@ struct NPC bool isMale() const { return (mFlags & Female) == 0; } + + void setIsMale(bool value) { + mFlags |= Female; + if (value) { + mFlags ^= Female; + } + } }; } #endif From 235b565bb7c8c2ebe8500d5c72819ba46306863d Mon Sep 17 00:00:00 2001 From: greye Date: Sat, 10 Nov 2012 11:51:48 +0400 Subject: [PATCH 10/12] update main character model --- apps/openmw/mwrender/player.cpp | 3 +++ apps/openmw/mwworld/worldimp.cpp | 16 +++++++++++++++- 2 files changed, 18 insertions(+), 1 deletion(-) diff --git a/apps/openmw/mwrender/player.cpp b/apps/openmw/mwrender/player.cpp index f2c313e14..857878811 100644 --- a/apps/openmw/mwrender/player.cpp +++ b/apps/openmw/mwrender/player.cpp @@ -310,6 +310,9 @@ namespace MWRender void Player::setAnimation(NpcAnimation *anim) { + if (mAnimation) { + delete mAnimation; + } mAnimation = anim; } diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index af5745744..616a0be39 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -801,7 +801,21 @@ namespace MWWorld const ESM::NPC *World::createRecord(const ESM::NPC &record) { - return mStore.insert(record); + bool update = false; + if (StringUtils::ciEqual(record.mId, "player")) { + const ESM::NPC *player = + mPlayer->getPlayer().get()->mBase; + + update = record.isMale() != player->isMale() || + !StringUtils::ciEqual(record.mRace, player->mRace) || + !StringUtils::ciEqual(record.mHead, player->mHead) || + !StringUtils::ciEqual(record.mHair, player->mHair); + } + const ESM::NPC *ret = mStore.insert(record); + if (update) { + mRendering->renderPlayer(mPlayer->getPlayer()); + } + return ret; } void World::playAnimationGroup (const MWWorld::Ptr& ptr, const std::string& groupName, int mode, From 5fdc7ad809f380360965efe05160d4dd65e4e483 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sat, 10 Nov 2012 13:07:26 +0100 Subject: [PATCH 11/12] forgot to add file --- files/mygui/openmw_persuasion_dialog.layout | 49 +++++++++++++++++++++ 1 file changed, 49 insertions(+) create mode 100644 files/mygui/openmw_persuasion_dialog.layout diff --git a/files/mygui/openmw_persuasion_dialog.layout b/files/mygui/openmw_persuasion_dialog.layout new file mode 100644 index 000000000..87851b479 --- /dev/null +++ b/files/mygui/openmw_persuasion_dialog.layout @@ -0,0 +1,49 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + From 7b1788b03bbc26f7f4b09be5e0d6aead65987c8a Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Sat, 10 Nov 2012 15:11:21 +0100 Subject: [PATCH 12/12] minor fix --- apps/openmw/mwrender/player.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/apps/openmw/mwrender/player.cpp b/apps/openmw/mwrender/player.cpp index 4b0b562c4..857878811 100644 --- a/apps/openmw/mwrender/player.cpp +++ b/apps/openmw/mwrender/player.cpp @@ -24,8 +24,7 @@ namespace MWRender mFreeLook(true), mHeight(128.f), mCameraDistance(300.f), - mDistanceAdjusted(false), - mAnimation(NULL) + mDistanceAdjusted(false) { mVanity.enabled = false; mVanity.allowed = true;