Merge remote-tracking branch 'scrawl/master'

celladd
Marc Zinnschlag 10 years ago
commit 8b84fa5579

@ -245,7 +245,8 @@ namespace MWClass
else
typeText = "#{sHeavy}";
text += "\n#{sArmorRating}: " + MWGui::ToolTips::toString(ref->mBase->mData.mArmor);
text += "\n#{sArmorRating}: " + MWGui::ToolTips::toString(getEffectiveArmorRating(ptr,
MWBase::Environment::get().getWorld()->getPlayerPtr()));
int remainingHealth = getItemHealth(ptr);
text += "\n#{sCondition}: " + MWGui::ToolTips::toString(remainingHealth) + "/"
@ -290,6 +291,22 @@ namespace MWClass
return record->mId;
}
int Armor::getEffectiveArmorRating(const MWWorld::Ptr &ptr, const MWWorld::Ptr &actor) const
{
MWWorld::LiveCellRef<ESM::Armor> *ref = ptr.get<ESM::Armor>();
int armorSkillType = getEquipmentSkill(ptr);
int armorSkill = actor.getClass().getSkill(actor, armorSkillType);
const MWBase::World *world = MWBase::Environment::get().getWorld();
int iBaseArmorSkill = world->getStore().get<ESM::GameSetting>().find("iBaseArmorSkill")->getInt();
if(ref->mBase->mData.mWeight == 0)
return ref->mBase->mData.mArmor;
else
return ref->mBase->mData.mArmor * armorSkill / iBaseArmorSkill;
}
std::pair<int, std::string> Armor::canBeEquipped(const MWWorld::Ptr &ptr, const MWWorld::Ptr &npc) const
{
MWWorld::InventoryStore& invStore = npc.getClass().getInventoryStore(npc);

@ -86,6 +86,9 @@ namespace MWClass
virtual int getEnchantmentPoints (const MWWorld::Ptr& ptr) const;
virtual bool canSell (const MWWorld::Ptr& item, int npcServices) const;
/// Get the effective armor rating, factoring in the actor's skills, for the given armor.
virtual int getEffectiveArmorRating(const MWWorld::Ptr& ptr, const MWWorld::Ptr& actor) const;
};
}

@ -1086,7 +1086,6 @@ namespace MWClass
MWMechanics::NpcStats &stats = getNpcStats(ptr);
MWWorld::InventoryStore &invStore = getInventoryStore(ptr);
int iBaseArmorSkill = store.find("iBaseArmorSkill")->getInt();
float fUnarmoredBase1 = store.find("fUnarmoredBase1")->getFloat();
float fUnarmoredBase2 = store.find("fUnarmoredBase2")->getFloat();
int unarmoredSkill = stats.getSkill(ESM::Skill::Unarmored).getModified();
@ -1102,15 +1101,7 @@ namespace MWClass
}
else
{
MWWorld::LiveCellRef<ESM::Armor> *ref = it->get<ESM::Armor>();
int armorSkillType = it->getClass().getEquipmentSkill(*it);
int armorSkill = stats.getSkill(armorSkillType).getModified();
if(ref->mBase->mData.mWeight == 0)
ratings[i] = ref->mBase->mData.mArmor;
else
ratings[i] = ref->mBase->mData.mArmor * armorSkill / iBaseArmorSkill;
ratings[i] = it->getClass().getEffectiveArmorRating(*it, ptr);
}
}

@ -653,16 +653,13 @@ namespace MWGui
if (selected != -1)
lastId = model.getItem(selected).mBase.getCellRef().getRefId();
ItemModel::ModelIndex cycled = selected;
while (!found)
for (int i=0; i<model.getItemCount(); ++i)
{
cycled += incr;
cycled = (cycled + model.getItemCount()) % model.getItemCount();
MWWorld::Ptr item = model.getItem(cycled).mBase;
if (cycled == selected) // we've been through all items, nothing found
return;
// skip different stacks of the same item, or we will get stuck as stacking/unstacking them may change their relative ordering
if (Misc::StringUtils::ciEqual(lastId, item.getCellRef().getRefId()))
continue;
@ -670,9 +667,15 @@ namespace MWGui
lastId = item.getCellRef().getRefId();
if (item.getClass().getTypeName() == typeid(ESM::Weapon).name() && isRightHandWeapon(item))
{
found = true;
break;
}
}
if (!found)
return;
useItem(model.getItem(cycled).mBase);
}

@ -56,6 +56,64 @@ namespace
}
}
void applyDynamicStatsEffect(int attribute, const MWWorld::Ptr& target, float magnitude)
{
MWMechanics::DynamicStat<float> value = target.getClass().getCreatureStats(target).getDynamic(attribute);
value.setCurrent(value.getCurrent()+magnitude, attribute == 2);
target.getClass().getCreatureStats(target).setDynamic(attribute, value);
}
// TODO: refactor the effect tick functions in Actors so they can be reused here
void applyInstantEffectTick(MWMechanics::EffectKey effect, const MWWorld::Ptr& target, float magnitude)
{
int effectId = effect.mId;
if (effectId == ESM::MagicEffect::DamageHealth)
{
applyDynamicStatsEffect(0, target, magnitude * -1);
}
else if (effectId == ESM::MagicEffect::RestoreHealth)
{
applyDynamicStatsEffect(0, target, magnitude);
}
else if (effectId == ESM::MagicEffect::DamageFatigue)
{
applyDynamicStatsEffect(2, target, magnitude * -1);
}
else if (effectId == ESM::MagicEffect::RestoreFatigue)
{
applyDynamicStatsEffect(2, target, magnitude);
}
else if (effectId == ESM::MagicEffect::DamageMagicka)
{
applyDynamicStatsEffect(1, target, magnitude * -1);
}
else if (effectId == ESM::MagicEffect::RestoreMagicka)
{
applyDynamicStatsEffect(1, target, magnitude);
}
else if (effectId == ESM::MagicEffect::DamageAttribute || effectId == ESM::MagicEffect::RestoreAttribute)
{
int attribute = effect.mArg;
MWMechanics::AttributeValue value = target.getClass().getCreatureStats(target).getAttribute(attribute);
if (effectId == ESM::MagicEffect::DamageAttribute)
value.damage(magnitude);
else
value.restore(magnitude);
target.getClass().getCreatureStats(target).setAttribute(attribute, value);
}
else if (effectId == ESM::MagicEffect::DamageSkill || effectId == ESM::MagicEffect::RestoreSkill)
{
if (target.getTypeName() != typeid(ESM::NPC).name())
return;
int skill = effect.mArg;
MWMechanics::SkillValue& value = target.getClass().getNpcStats(target).getSkill(skill);
if (effectId == ESM::MagicEffect::DamageSkill)
value.damage(magnitude);
else
value.restore(magnitude);
}
}
}
namespace MWMechanics
@ -438,8 +496,8 @@ namespace MWMechanics
float magnitude = effectIt->mMagnMin + (effectIt->mMagnMax - effectIt->mMagnMin) * random;
magnitude *= magnitudeMult;
bool hasDuration = !(magicEffect->mData.mFlags & ESM::MagicEffect::NoDuration) && effectIt->mDuration > 0;
if (target.getClass().isActor() && hasDuration)
bool hasDuration = !(magicEffect->mData.mFlags & ESM::MagicEffect::NoDuration);
if (target.getClass().isActor() && hasDuration && effectIt->mDuration > 0)
{
ActiveSpells::ActiveEffect effect;
effect.mEffectId = effectIt->mEffectID;
@ -471,7 +529,12 @@ namespace MWMechanics
}
}
else
applyInstantEffect(target, caster, EffectKey(*effectIt), magnitude);
{
if (hasDuration && target.getClass().isActor())
applyInstantEffectTick(EffectKey(*effectIt), target, magnitude);
else
applyInstantEffect(target, caster, EffectKey(*effectIt), magnitude);
}
// Re-casting a summon effect will remove the creature from previous castings of that effect.
if (isSummoningEffect(effectIt->mEffectID) && !target.isEmpty() && target.getClass().isActor())
@ -485,16 +548,6 @@ namespace MWMechanics
}
}
// HACK: Damage attribute/skill actually has a duration, even though the actual effect is instant and permanent.
// This was probably just done to have the effect visible in the magic menu for a while
// to notify the player they've been damaged?
if (effectIt->mEffectID == ESM::MagicEffect::DamageAttribute
|| effectIt->mEffectID == ESM::MagicEffect::DamageSkill
|| effectIt->mEffectID == ESM::MagicEffect::RestoreAttribute
|| effectIt->mEffectID == ESM::MagicEffect::RestoreSkill
)
applyInstantEffect(target, caster, EffectKey(*effectIt), magnitude);
if (target.getClass().isActor() || magicEffect->mData.mFlags & ESM::MagicEffect::NoDuration)
{
// Play sound, only for the first effect
@ -584,53 +637,6 @@ namespace MWMechanics
}
else
{
if (effectId == ESM::MagicEffect::DamageAttribute || effectId == ESM::MagicEffect::RestoreAttribute)
{
int attribute = effect.mArg;
AttributeValue value = target.getClass().getCreatureStats(target).getAttribute(attribute);
if (effectId == ESM::MagicEffect::DamageAttribute)
value.damage(magnitude);
else
value.restore(magnitude);
target.getClass().getCreatureStats(target).setAttribute(attribute, value);
}
// TODO: refactor the effect tick functions in Actors so they can be reused here
else if (effectId == ESM::MagicEffect::DamageHealth)
{
applyDynamicStatsEffect(0, target, magnitude * -1);
}
else if (effectId == ESM::MagicEffect::RestoreHealth)
{
applyDynamicStatsEffect(0, target, magnitude);
}
else if (effectId == ESM::MagicEffect::DamageFatigue)
{
applyDynamicStatsEffect(2, target, magnitude * -1);
}
else if (effectId == ESM::MagicEffect::RestoreFatigue)
{
applyDynamicStatsEffect(2, target, magnitude);
}
else if (effectId == ESM::MagicEffect::DamageMagicka)
{
applyDynamicStatsEffect(1, target, magnitude * -1);
}
else if (effectId == ESM::MagicEffect::RestoreMagicka)
{
applyDynamicStatsEffect(1, target, magnitude);
}
else if (effectId == ESM::MagicEffect::DamageSkill || effectId == ESM::MagicEffect::RestoreSkill)
{
if (target.getTypeName() != typeid(ESM::NPC).name())
return;
int skill = effect.mArg;
SkillValue& value = target.getClass().getNpcStats(target).getSkill(skill);
if (effectId == ESM::MagicEffect::DamageSkill)
value.damage(magnitude);
else
value.restore(magnitude);
}
if (effectId == ESM::MagicEffect::CurePoison)
target.getClass().getCreatureStats(target).getActiveSpells().purgeEffect(ESM::MagicEffect::Poison);
else if (effectId == ESM::MagicEffect::CureParalyzation)
@ -680,13 +686,7 @@ namespace MWMechanics
}
}
}
void CastSpell::applyDynamicStatsEffect(int attribute, const MWWorld::Ptr& target, float magnitude)
{
DynamicStat<float> value = target.getClass().getCreatureStats(target).getDynamic(attribute);
value.setCurrent(value.getCurrent()+magnitude, attribute == 2);
target.getClass().getCreatureStats(target).setDynamic(attribute, value);
}
bool CastSpell::cast(const std::string &id)
{

@ -97,8 +97,6 @@ namespace MWMechanics
/// @note \a caster can be any type of object, or even an empty object.
void applyInstantEffect (const MWWorld::Ptr& target, const MWWorld::Ptr& caster, const MWMechanics::EffectKey& effect, float magnitude);
void applyDynamicStatsEffect (int attribute, const MWWorld::Ptr& target, float magnitude);
};
}

@ -1271,7 +1271,11 @@ void Animation::addEffect(const std::string &model, int effectId, bool loop, con
if (bonename.empty())
params.mObjects = NifOgre::Loader::createObjects(mInsert, model);
else
{
if (!mSkelBase)
return;
params.mObjects = NifOgre::Loader::createObjects(mSkelBase, bonename, "", mInsert, model);
}
setRenderProperties(params.mObjects, RV_Effects,
RQG_Main, RQG_Alpha, 0.f, false, NULL);

@ -88,6 +88,9 @@ void CreatureWeaponAnimation::updateParts()
void CreatureWeaponAnimation::updatePart(NifOgre::ObjectScenePtr& scene, int slot)
{
if (!mSkelBase)
return;
MWWorld::InventoryStore& inv = mPtr.getClass().getInventoryStore(mPtr);
MWWorld::ContainerStoreIterator it = inv.getSlot(slot);
@ -181,7 +184,9 @@ void CreatureWeaponAnimation::releaseArrow()
Ogre::Vector3 CreatureWeaponAnimation::runAnimation(float duration)
{
Ogre::Vector3 ret = Animation::runAnimation(duration);
pitchSkeleton(mPtr.getRefData().getPosition().rot[0], mSkelBase->getSkeleton());
if (mSkelBase)
pitchSkeleton(mPtr.getRefData().getPosition().rot[0], mSkelBase->getSkeleton());
if (!mWeapon.isNull())
{

@ -335,7 +335,10 @@ void NpcAnimation::updateNpcBase()
}
void NpcAnimation::updateParts()
{
{
if (!mSkelBase)
return;
mAlpha = 1.f;
const MWWorld::Class &cls = mPtr.getClass();
@ -621,30 +624,33 @@ NifOgre::ObjectScenePtr NpcAnimation::insertBoundedPart(const std::string &model
}
Ogre::Vector3 NpcAnimation::runAnimation(float timepassed)
{
{
Ogre::Vector3 ret = Animation::runAnimation(timepassed);
mHeadAnimationTime->update(timepassed);
Ogre::SkeletonInstance *baseinst = mSkelBase->getSkeleton();
if(mViewMode == VM_FirstPerson)
if (mSkelBase)
{
float pitch = mPtr.getRefData().getPosition().rot[0];
Ogre::Node *node = baseinst->getBone("Bip01 Neck");
node->pitch(Ogre::Radian(-pitch), Ogre::Node::TS_WORLD);
Ogre::SkeletonInstance *baseinst = mSkelBase->getSkeleton();
if(mViewMode == VM_FirstPerson)
{
float pitch = mPtr.getRefData().getPosition().rot[0];
Ogre::Node *node = baseinst->getBone("Bip01 Neck");
node->pitch(Ogre::Radian(-pitch), Ogre::Node::TS_WORLD);
// This has to be done before this function ends;
// updateSkeletonInstance, below, touches the hands.
node->translate(mFirstPersonOffset, Ogre::Node::TS_WORLD);
}
else
{
// In third person mode we may still need pitch for ranged weapon targeting
pitchSkeleton(mPtr.getRefData().getPosition().rot[0], baseinst);
// This has to be done before this function ends;
// updateSkeletonInstance, below, touches the hands.
node->translate(mFirstPersonOffset, Ogre::Node::TS_WORLD);
}
else
{
// In third person mode we may still need pitch for ranged weapon targeting
pitchSkeleton(mPtr.getRefData().getPosition().rot[0], baseinst);
Ogre::Node* node = baseinst->getBone("Bip01 Head");
if (node)
node->rotate(Ogre::Quaternion(mHeadYaw, Ogre::Vector3::UNIT_Z) * Ogre::Quaternion(mHeadPitch, Ogre::Vector3::UNIT_X), Ogre::Node::TS_WORLD);
Ogre::Node* node = baseinst->getBone("Bip01 Head");
if (node)
node->rotate(Ogre::Quaternion(mHeadYaw, Ogre::Vector3::UNIT_Z) * Ogre::Quaternion(mHeadPitch, Ogre::Vector3::UNIT_X), Ogre::Node::TS_WORLD);
}
}
mFirstPersonOffset = 0.f; // reset the X, Y, Z offset for the next frame.
@ -659,7 +665,9 @@ Ogre::Vector3 NpcAnimation::runAnimation(float timepassed)
if (!isSkinned(mObjectParts[i]))
continue;
updateSkeletonInstance(baseinst, mObjectParts[i]->mSkelBase->getSkeleton());
if (mSkelBase)
updateSkeletonInstance(mSkelBase->getSkeleton(), mObjectParts[i]->mSkelBase->getSkeleton());
mObjectParts[i]->mSkelBase->getAllAnimationStates()->_notifyDirty();
}

@ -454,4 +454,9 @@ namespace MWWorld
{
return -1;
}
int Class::getEffectiveArmorRating(const Ptr &ptr, const Ptr &actor) const
{
throw std::runtime_error("class does not support armor ratings");
}
}

@ -347,6 +347,9 @@ namespace MWWorld
virtual std::string getPrimaryFaction (const MWWorld::Ptr& ptr) const;
virtual int getPrimaryFactionRank (const MWWorld::Ptr& ptr) const;
/// Get the effective armor rating, factoring in the actor's skills, for the given armor.
virtual int getEffectiveArmorRating(const MWWorld::Ptr& ptr, const MWWorld::Ptr& actor) const;
};
}

@ -199,7 +199,7 @@ namespace MWWorld
(*iter)->getCell()->getGridX(),
(*iter)->getCell()->getGridY()
);
if (land)
if (land && land->mDataTypes&ESM::Land::DATA_VHGT)
mPhysics->removeHeightField ((*iter)->getCell()->getGridX(), (*iter)->getCell()->getGridY());
}

@ -274,10 +274,12 @@ void ManualBulletShapeLoader::handleNode(const Nif::Node *node, int flags,
// No collision. Use an internal flag setting to mark this.
flags |= 0x800;
}
else if (sd->string == "MRK" && !mShowMarkers)
// Marker objects. These are only visible in the
// editor.
else if (sd->string == "MRK" && !mShowMarkers && raycasting)
{
// Marker objects should be invisible, but still have collision.
// Except in the editor, the marker objects are visible.
return;
}
}
}

@ -127,35 +127,35 @@
</Widget>
<!-- Basic FPSCounter box -->
<Widget type="Widget" skin="HUD_Box" position="12 12 32 26" align="Left Top" name="FPSBox">
<Widget type="Widget" skin="" position="12 12 32 26" align="Left Top" name="FPSBox">
<Property key="Visible" value="false"/>
<Widget type="TextBox" skin="NumFPS" position="3 3 25 17" align="Center" name="FPSCounter"/>
</Widget>
<!-- Advanced FPSCounter box -->
<Widget type="Widget" skin="HUD_Box" position="12 12 165 64" align="Left Top" name="FPSBoxAdv">
<Widget type="Widget" skin="" position="12 12 135 64" align="Left Top" name="FPSBoxAdv">
<Property key="Visible" value="false"/>
<Widget type="Widget" skin="" position="0 0 110 60" align="Left Top">
<Widget type="Widget" skin="" position="0 0 80 60" align="Left Top">
<Widget type="TextBox" skin="NumFPS" position="0 0 110 32" align="Left Top">
<Widget type="TextBox" skin="NumFPS" position="0 0 80 32" align="Left Top">
<Property key="Caption" value="FPS: "/>
<Property key="TextAlign" value="Right"/>
</Widget>
<Widget type="TextBox" skin="NumFPS" position="0 16 110 32" align="Left Top">
<Property key="Caption" value="Tri Count: "/>
<Widget type="TextBox" skin="NumFPS" position="0 16 80 32" align="Left Top">
<Property key="Caption" value="Triangles: "/>
<Property key="TextAlign" value="Right"/>
</Widget>
<Widget type="TextBox" skin="NumFPS" position="0 32 110 32" align="Left Top">
<Property key="Caption" value="Batch Count: "/>
<Widget type="TextBox" skin="NumFPS" position="0 32 80 32" align="Left Top">
<Property key="Caption" value="Batches: "/>
<Property key="TextAlign" value="Right"/>
</Widget>
</Widget>
<Widget type="Widget" skin="" position="110 0 55 60" align="Left Top">
<Widget type="Widget" skin="" position="80 0 55 60" align="Left Top">
<Widget type="TextBox" skin="NumFPS" position="0 0 55 32" align="Left Top" name="FPSCounterAdv">
<Property key="TextAlign" value="Left"/>

@ -10,7 +10,7 @@
<Property key="TextAlign" value="Center"/>
</Widget>
<Widget type="ScrollBar" skin="MW_ProgressScroll_Loading" position="20 30 260 6" name="ProgressBar">
<Widget type="ScrollBar" skin="MW_ProgressScroll_Loading" position="20 30 260 6" align="Top HCenter" name="ProgressBar">
</Widget>
</Widget>

@ -19,9 +19,11 @@ color_misc=0,205,205 # ????
</Resource>
<Resource type="ResourceSkin" name="NumFPS" size="16 16">
<Property key="FontName" value="Default"/>
<Property key="FontName" value="MonoFont"/>
<Property key="TextAlign" value="HCenter Bottom"/>
<Property key="TextColour" value="1 1 1"/>
<Property key="TextShadow" value="true"/>
<BasisSkin type="SimpleText" offset="0 0 16 16" align="Stretch"/>
</Resource>

@ -414,13 +414,17 @@ namespace Physic
+ boost::lexical_cast<std::string>(x) + "_"
+ boost::lexical_cast<std::string>(y);
HeightField hf = mHeightFieldMap [name];
HeightFieldContainer::iterator it = mHeightFieldMap.find(name);
if (it == mHeightFieldMap.end())
return;
const HeightField& hf = it->second;
mDynamicsWorld->removeRigidBody(hf.mBody);
delete hf.mShape;
delete hf.mBody;
mHeightFieldMap.erase(name);
mHeightFieldMap.erase(it);
}
void PhysicEngine::adjustRigidBody(RigidBody* body, const Ogre::Vector3 &position, const Ogre::Quaternion &rotation,

Loading…
Cancel
Save