From 4ed4c1e3199e437871dbc6683be7b78852b61d6c Mon Sep 17 00:00:00 2001 From: scrawl Date: Thu, 21 Nov 2013 00:27:22 +0100 Subject: [PATCH] Add Vampirism and Sun Damage effects. Some fixes. --- apps/openmw/mwmechanics/actors.cpp | 40 +++++++++++------ apps/openmw/mwmechanics/actors.hpp | 2 - apps/openmw/mwmechanics/spells.cpp | 2 +- apps/openmw/mwrender/characterpreview.cpp | 12 ++--- apps/openmw/mwrender/npcanimation.cpp | 55 ++++++++++++++++++++--- 5 files changed, 83 insertions(+), 28 deletions(-) diff --git a/apps/openmw/mwmechanics/actors.cpp b/apps/openmw/mwmechanics/actors.cpp index ec22c8d7f..b9a56e30c 100644 --- a/apps/openmw/mwmechanics/actors.cpp +++ b/apps/openmw/mwmechanics/actors.cpp @@ -211,7 +211,7 @@ namespace MWMechanics float currentDiff = creatureStats.getMagicEffects().get(EffectKey(ESM::MagicEffect::RestoreHealth+i)).mMagnitude - creatureStats.getMagicEffects().get(EffectKey(ESM::MagicEffect::DamageHealth+i)).mMagnitude - - creatureStats.getMagicEffects().get(EffectKey(ESM::MagicEffect::AbsorbHealth)).mMagnitude; + - creatureStats.getMagicEffects().get(EffectKey(ESM::MagicEffect::AbsorbHealth+i)).mMagnitude; stat.setCurrent(stat.getCurrent() + currentDiff * duration); creatureStats.setDynamic(i, stat); @@ -219,16 +219,34 @@ namespace MWMechanics // Apply damage ticks int damageEffects[] = { - ESM::MagicEffect::FireDamage, ESM::MagicEffect::ShockDamage, ESM::MagicEffect::FrostDamage, ESM::MagicEffect::Poison + ESM::MagicEffect::FireDamage, ESM::MagicEffect::ShockDamage, ESM::MagicEffect::FrostDamage, ESM::MagicEffect::Poison, + ESM::MagicEffect::SunDamage }; + DynamicStat health = creatureStats.getHealth(); for (unsigned int i=0; i health = creatureStats.getHealth(); - health.setCurrent(health.getCurrent() - magnitude * duration); - creatureStats.setHealth(health); + + if (damageEffects[i] == ESM::MagicEffect::SunDamage) + { + // isInCell shouldn't be needed, but updateActor called during game start + if (!ptr.isInCell() || !ptr.getCell()->isExterior()) + continue; + float time = MWBase::Environment::get().getWorld()->getTimeStamp().getHour(); + float timeDiff = std::min(7.f, std::max(0.f, std::abs(time - 13))); + float damageScale = 1.f - timeDiff / 7.f; + // When cloudy, the sun damage effect is halved + int weather = MWBase::Environment::get().getWorld()->getCurrentWeather(); + if (weather > 1) + damageScale *= 0.5; + health.setCurrent(health.getCurrent() - magnitude * duration * damageScale); + } + else + health.setCurrent(health.getCurrent() - magnitude * duration); + } + creatureStats.setHealth(health); } void Actors::calculateNpcStatModifiers (const MWWorld::Ptr& ptr) @@ -324,7 +342,7 @@ namespace MWMechanics } } - Actors::Actors() : mDuration (0) {} + Actors::Actors() {} void Actors::addActor (const MWWorld::Ptr& ptr) { @@ -377,14 +395,8 @@ namespace MWMechanics void Actors::update (float duration, bool paused) { - mDuration += duration; - - //if (mDuration>=0.25) if (!paused) { - float totalDuration = mDuration; - mDuration = 0; - for(PtrControllerMap::iterator iter(mActors.begin());iter != mActors.end();iter++) { const MWWorld::Class &cls = MWWorld::Class::get(iter->first); @@ -396,9 +408,9 @@ namespace MWMechanics if(iter->second->isDead()) iter->second->resurrect(); - updateActor(iter->first, totalDuration); + updateActor(iter->first, duration); if(iter->first.getTypeName() == typeid(ESM::NPC).name()) - updateNpc(iter->first, totalDuration, paused); + updateNpc(iter->first, duration, paused); if(!stats.isDead()) continue; diff --git a/apps/openmw/mwmechanics/actors.hpp b/apps/openmw/mwmechanics/actors.hpp index 01a96f199..b733c966b 100644 --- a/apps/openmw/mwmechanics/actors.hpp +++ b/apps/openmw/mwmechanics/actors.hpp @@ -30,8 +30,6 @@ namespace MWMechanics std::map mDeathCount; - float mDuration; - void updateNpc(const MWWorld::Ptr &ptr, float duration, bool paused); diff --git a/apps/openmw/mwmechanics/spells.cpp b/apps/openmw/mwmechanics/spells.cpp index 5b18e2a3c..6e7ac6f31 100644 --- a/apps/openmw/mwmechanics/spells.cpp +++ b/apps/openmw/mwmechanics/spells.cpp @@ -66,7 +66,7 @@ namespace MWMechanics int i=0; for (std::vector::const_iterator it = spell->mEffects.mList.begin(); it != spell->mEffects.mList.end(); ++it) { - effects.add (*it, iter->second[i]); + effects.add (*it, it->mMagnMin + (it->mMagnMax - it->mMagnMin) * iter->second[i]); ++i; } } diff --git a/apps/openmw/mwrender/characterpreview.cpp b/apps/openmw/mwrender/characterpreview.cpp index b9818efbb..2cae30611 100644 --- a/apps/openmw/mwrender/characterpreview.cpp +++ b/apps/openmw/mwrender/characterpreview.cpp @@ -72,7 +72,6 @@ namespace MWRender mAnimation = new NpcAnimation(mCharacter, mNode, 0, true, (renderHeadOnly() ? NpcAnimation::VM_HeadOnly : NpcAnimation::VM_Normal)); - mAnimation->updateParts(); Ogre::Vector3 scale = mNode->getScale(); mCamera->setPosition(mPosition * scale); @@ -114,7 +113,6 @@ namespace MWRender delete mAnimation; mAnimation = new NpcAnimation(mCharacter, mNode, 0, true, (renderHeadOnly() ? NpcAnimation::VM_HeadOnly : NpcAnimation::VM_Normal)); - mAnimation->updateParts(); float scale=1.f; MWWorld::Class::get(mCharacter).adjustScale(mCharacter, scale); @@ -142,6 +140,9 @@ namespace MWRender void InventoryPreview::update(int sizeX, int sizeY) { + // TODO: can we avoid this. Vampire state needs to be updated. + mAnimation->rebuild(); + MWWorld::InventoryStore &inv = MWWorld::Class::get(mCharacter).getInventoryStore(mCharacter); MWWorld::ContainerStoreIterator iter = inv.getSlot(MWWorld::InventoryStore::Slot_CarriedRight); std::string groupname; @@ -176,11 +177,12 @@ namespace MWRender groupname = "inventoryhandtohand"; } - if(groupname != mCurrentAnimGroup) - { + // TODO see above + //if(groupname != mCurrentAnimGroup) + //{ mCurrentAnimGroup = groupname; mAnimation->play(mCurrentAnimGroup, 1, Animation::Group_All, false, 1.0f, "start", "stop", 0.0f, 0); - } + //} MWWorld::ContainerStoreIterator torch = inv.getSlot(MWWorld::InventoryStore::Slot_CarriedLeft); if(torch != inv.end() && torch->getTypeName() == typeid(ESM::Light).name()) diff --git a/apps/openmw/mwrender/npcanimation.cpp b/apps/openmw/mwrender/npcanimation.cpp index c71428941..093a40c8e 100644 --- a/apps/openmw/mwrender/npcanimation.cpp +++ b/apps/openmw/mwrender/npcanimation.cpp @@ -19,6 +19,42 @@ #include "renderconst.hpp" #include "camera.hpp" +namespace +{ + +std::string getVampireHead(const std::string& race, bool female) +{ + static std::map , const ESM::BodyPart* > sVampireMapping; + + std::pair thisCombination = std::make_pair(race, int(female)); + + if (sVampireMapping.find(thisCombination) == sVampireMapping.end()) + { + const MWWorld::ESMStore &store = MWBase::Environment::get().getWorld()->getStore(); + const MWWorld::Store &partStore = store.get(); + for(MWWorld::Store::iterator it = partStore.begin(); it != partStore.end(); ++it) + { + const ESM::BodyPart& bodypart = *it; + if (!bodypart.mData.mVampire) + continue; + if (bodypart.mData.mType != ESM::BodyPart::MT_Skin) + continue; + if (bodypart.mData.mPart != ESM::BodyPart::MP_Head) + continue; + if (female != (bodypart.mData.mFlags & ESM::BodyPart::BPF_Female)) + continue; + if (!Misc::StringUtils::ciEqual(bodypart.mRace, race)) + continue; + sVampireMapping[thisCombination] = &*it; + } + } + + assert(sVampireMapping[thisCombination]); + return "meshes\\" + sVampireMapping[thisCombination]->mModel; +} + +} + namespace MWRender { @@ -110,17 +146,22 @@ void NpcAnimation::updateNpcBase() const MWWorld::ESMStore &store = MWBase::Environment::get().getWorld()->getStore(); const ESM::Race *race = store.get().find(mNpc->mRace); - bool isWerewolf = MWWorld::Class::get(mPtr).getNpcStats(mPtr).isWerewolf(); + bool isWerewolf = mPtr.getClass().getNpcStats(mPtr).isWerewolf(); + bool vampire = mPtr.getClass().getCreatureStats(mPtr).getMagicEffects().get(ESM::MagicEffect::Vampirism).mMagnitude; - if(!isWerewolf) + if (isWerewolf) { - mHeadModel = "meshes\\" + store.get().find(mNpc->mHead)->mModel; - mHairModel = "meshes\\" + store.get().find(mNpc->mHair)->mModel; + mHeadModel = "meshes\\" + store.get().find("WerewolfHead")->mModel; + mHairModel = "meshes\\" + store.get().find("WerewolfHair")->mModel; } else { - mHeadModel = "meshes\\" + store.get().find("WerewolfHead")->mModel; - mHairModel = "meshes\\" + store.get().find("WerewolfHair")->mModel; + if (vampire) + mHeadModel = getVampireHead(mNpc->mRace, mNpc->mFlags & ESM::NPC::Female); + else + mHeadModel = "meshes\\" + store.get().find(mNpc->mHead)->mModel; + + mHairModel = "meshes\\" + store.get().find(mNpc->mHair)->mModel; } bool isBeast = (race->mData.mFlags & ESM::Race::Beast) != 0; @@ -270,6 +311,8 @@ void NpcAnimation::updateParts() // 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::vector > sRaceMapping; + static std::map , std::vector > sVampireMapping; + static const int Flag_Female = 1<<0; static const int Flag_FirstPerson = 1<<1;