|
|
|
@ -305,56 +305,83 @@ void NpcAnimation::updateParts(bool forceupdate)
|
|
|
|
|
if(mViewMode == VM_HeadOnly)
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
static const struct {
|
|
|
|
|
ESM::PartReferenceType type;
|
|
|
|
|
const char name[2][12];
|
|
|
|
|
} PartTypeList[] = {
|
|
|
|
|
{ ESM::PRT_Neck, { "neck", "" } },
|
|
|
|
|
{ ESM::PRT_Cuirass, { "chest", "" } },
|
|
|
|
|
{ ESM::PRT_Groin, { "groin", "" } },
|
|
|
|
|
{ ESM::PRT_RHand, { "hand", "hands" } },
|
|
|
|
|
{ ESM::PRT_LHand, { "hand", "hands" } },
|
|
|
|
|
{ ESM::PRT_RWrist, { "wrist", "" } },
|
|
|
|
|
{ ESM::PRT_LWrist, { "wrist", "" } },
|
|
|
|
|
{ ESM::PRT_RForearm, { "forearm", "" } },
|
|
|
|
|
{ ESM::PRT_LForearm, { "forearm", "" } },
|
|
|
|
|
{ ESM::PRT_RUpperarm, { "upper arm", "" } },
|
|
|
|
|
{ ESM::PRT_LUpperarm, { "upper arm", "" } },
|
|
|
|
|
{ ESM::PRT_RFoot, { "foot", "feet" } },
|
|
|
|
|
{ ESM::PRT_LFoot, { "foot", "feet" } },
|
|
|
|
|
{ ESM::PRT_RAnkle, { "ankle", "" } },
|
|
|
|
|
{ ESM::PRT_LAnkle, { "ankle", "" } },
|
|
|
|
|
{ ESM::PRT_RKnee, { "knee", "" } },
|
|
|
|
|
{ ESM::PRT_LKnee, { "knee", "" } },
|
|
|
|
|
{ ESM::PRT_RLeg, { "upper leg", "" } },
|
|
|
|
|
{ ESM::PRT_LLeg, { "upper leg", "" } },
|
|
|
|
|
{ ESM::PRT_Tail, { "tail", "" } }
|
|
|
|
|
};
|
|
|
|
|
std::map<int, int> bodypartMap;
|
|
|
|
|
bodypartMap[ESM::PRT_Neck] = ESM::BodyPart::MP_Neck;
|
|
|
|
|
bodypartMap[ESM::PRT_Cuirass] = ESM::BodyPart::MP_Chest;
|
|
|
|
|
bodypartMap[ESM::PRT_Groin] = ESM::BodyPart::MP_Groin;
|
|
|
|
|
bodypartMap[ESM::PRT_RHand] = ESM::BodyPart::MP_Hand;
|
|
|
|
|
bodypartMap[ESM::PRT_LHand] = ESM::BodyPart::MP_Hand;
|
|
|
|
|
bodypartMap[ESM::PRT_RWrist] = ESM::BodyPart::MP_Wrist;
|
|
|
|
|
bodypartMap[ESM::PRT_LWrist] = ESM::BodyPart::MP_Wrist;
|
|
|
|
|
bodypartMap[ESM::PRT_RForearm] = ESM::BodyPart::MP_Forearm;
|
|
|
|
|
bodypartMap[ESM::PRT_LForearm] = ESM::BodyPart::MP_Forearm;
|
|
|
|
|
bodypartMap[ESM::PRT_RUpperarm] = ESM::BodyPart::MP_Upperarm;
|
|
|
|
|
bodypartMap[ESM::PRT_LUpperarm] = ESM::BodyPart::MP_Upperarm;
|
|
|
|
|
bodypartMap[ESM::PRT_RFoot] = ESM::BodyPart::MP_Foot;
|
|
|
|
|
bodypartMap[ESM::PRT_LFoot] = ESM::BodyPart::MP_Foot;
|
|
|
|
|
bodypartMap[ESM::PRT_RAnkle] = ESM::BodyPart::MP_Ankle;
|
|
|
|
|
bodypartMap[ESM::PRT_LAnkle] = ESM::BodyPart::MP_Ankle;
|
|
|
|
|
bodypartMap[ESM::PRT_RKnee] = ESM::BodyPart::MP_Knee;
|
|
|
|
|
bodypartMap[ESM::PRT_LKnee] = ESM::BodyPart::MP_Knee;
|
|
|
|
|
bodypartMap[ESM::PRT_RLeg] = ESM::BodyPart::MP_Upperleg;
|
|
|
|
|
bodypartMap[ESM::PRT_LLeg] = ESM::BodyPart::MP_Upperleg;
|
|
|
|
|
bodypartMap[ESM::PRT_Tail] = ESM::BodyPart::MP_Tail;
|
|
|
|
|
|
|
|
|
|
const char *ext = (mViewMode == VM_FirstPerson) ? ".1st" : "";
|
|
|
|
|
const MWWorld::ESMStore &store = MWBase::Environment::get().getWorld()->getStore();
|
|
|
|
|
for(size_t i = 0;i < sizeof(PartTypeList)/sizeof(PartTypeList[0]);i++)
|
|
|
|
|
|
|
|
|
|
const int Flag_Female = 0x01;
|
|
|
|
|
const int Flag_FirstPerson = 0x02;
|
|
|
|
|
|
|
|
|
|
int flags = 0;
|
|
|
|
|
if (!mNpc->isMale())
|
|
|
|
|
flags |= Flag_Female;
|
|
|
|
|
if (mViewMode == VM_FirstPerson)
|
|
|
|
|
flags |= Flag_FirstPerson;
|
|
|
|
|
|
|
|
|
|
// Remember body parts so we only have to search through the store once for each race/gender/viewmode combination
|
|
|
|
|
static std::map< std::pair<std::string, int> , std::vector<const ESM::BodyPart*> > sRaceMapping;
|
|
|
|
|
std::string race = Misc::StringUtils::lowerCase(mNpc->mRace);
|
|
|
|
|
std::pair<std::string, int> thisCombination = std::make_pair(race, flags);
|
|
|
|
|
if (sRaceMapping.find(thisCombination) == sRaceMapping.end())
|
|
|
|
|
{
|
|
|
|
|
if(mPartPriorities[PartTypeList[i].type] < 1)
|
|
|
|
|
{
|
|
|
|
|
const ESM::BodyPart *part = NULL;
|
|
|
|
|
const MWWorld::Store<ESM::BodyPart> &partStore = store.get<ESM::BodyPart>();
|
|
|
|
|
sRaceMapping[thisCombination].resize(ESM::PRT_Count);
|
|
|
|
|
for (int i=0; i<ESM::PRT_Count; ++i)
|
|
|
|
|
sRaceMapping[thisCombination][i] = NULL;
|
|
|
|
|
|
|
|
|
|
if(!mNpc->isMale())
|
|
|
|
|
const MWWorld::Store<ESM::BodyPart> &partStore = store.get<ESM::BodyPart>();
|
|
|
|
|
|
|
|
|
|
for (MWWorld::Store<ESM::BodyPart>::iterator it = partStore.begin(); it != partStore.end(); ++it)
|
|
|
|
|
{
|
|
|
|
|
const ESM::BodyPart& bodypart = *it;
|
|
|
|
|
if (bodypart.mData.mFlags & ESM::BodyPart::BPF_NotPlayable)
|
|
|
|
|
continue;
|
|
|
|
|
if (bodypart.mData.mType != ESM::BodyPart::MT_Skin)
|
|
|
|
|
{
|
|
|
|
|
part = partStore.search(mBodyPrefix + "_f_" + PartTypeList[i].name[0]+ext);
|
|
|
|
|
if(part == 0)
|
|
|
|
|
part = partStore.search(mBodyPrefix + "_f_" + PartTypeList[i].name[1]+ext);
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
if(part == 0)
|
|
|
|
|
part = partStore.search(mBodyPrefix + "_m_" + PartTypeList[i].name[0]+ext);
|
|
|
|
|
if(part == 0)
|
|
|
|
|
part = partStore.search(mBodyPrefix + "_m_" + PartTypeList[i].name[1]+ext);
|
|
|
|
|
|
|
|
|
|
if(part)
|
|
|
|
|
addOrReplaceIndividualPart(PartTypeList[i].type, -1,1, "meshes\\"+part->mModel);
|
|
|
|
|
if (!mNpc->isMale() != (bodypart.mData.mFlags & ESM::BodyPart::BPF_Female))
|
|
|
|
|
continue;
|
|
|
|
|
if (!Misc::StringUtils::ciEqual(bodypart.mRace, mNpc->mRace))
|
|
|
|
|
continue;
|
|
|
|
|
|
|
|
|
|
bool firstPerson = (bodypart.mId.size() >= 3)
|
|
|
|
|
&& bodypart.mId[bodypart.mId.size()-3] == '1'
|
|
|
|
|
&& bodypart.mId[bodypart.mId.size()-2] == 's'
|
|
|
|
|
&& bodypart.mId[bodypart.mId.size()-1] == 't';
|
|
|
|
|
if (firstPerson != (mViewMode == VM_FirstPerson))
|
|
|
|
|
continue;
|
|
|
|
|
for (std::map<int, int>::iterator bIt = bodypartMap.begin(); bIt != bodypartMap.end(); ++bIt )
|
|
|
|
|
if (bIt->second == bodypart.mData.mPart)
|
|
|
|
|
sRaceMapping[thisCombination][bIt->first] = &*it;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
for (int part = ESM::PRT_Neck; part < ESM::PRT_Count; ++part)
|
|
|
|
|
{
|
|
|
|
|
const ESM::BodyPart* bodypart = sRaceMapping[thisCombination][part];
|
|
|
|
|
if (mPartPriorities[part] < 1 && bodypart)
|
|
|
|
|
addOrReplaceIndividualPart(part, -1,1, "meshes\\"+bodypart->mModel);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
NifOgre::ObjectList NpcAnimation::insertBoundedPart(const std::string &model, int group, const std::string &bonename)
|
|
|
|
|