mirror of
https://github.com/TES3MP/openmw-tes3mp.git
synced 2025-06-05 10:41:34 +00:00
Merge pull request #142 from OpenMW/master
Add OpenMW commits up to 6 Feb 2017
This commit is contained in:
commit
27242cdab9
11 changed files with 95 additions and 77 deletions
|
@ -68,12 +68,14 @@ namespace MWGui
|
||||||
|
|
||||||
for (int i = 0; i < ESM::Skill::Length; ++i)
|
for (int i = 0; i < ESM::Skill::Length; ++i)
|
||||||
{
|
{
|
||||||
mSkillValues.insert(std::pair<int, MWMechanics::SkillValue >(i, MWMechanics::SkillValue()));
|
mSkillValues.insert(std::make_pair(i, MWMechanics::SkillValue()));
|
||||||
mSkillWidgetMap.insert(std::pair<int, MyGUI::TextBox*>(i, (MyGUI::TextBox*)NULL));
|
mSkillWidgetMap.insert(std::make_pair(i, std::make_pair((MyGUI::TextBox*)NULL, (MyGUI::TextBox*)NULL)));
|
||||||
}
|
}
|
||||||
|
|
||||||
MyGUI::Window* t = mMainWidget->castType<MyGUI::Window>();
|
MyGUI::Window* t = mMainWidget->castType<MyGUI::Window>();
|
||||||
t->eventWindowChangeCoord += MyGUI::newDelegate(this, &StatsWindow::onWindowResize);
|
t->eventWindowChangeCoord += MyGUI::newDelegate(this, &StatsWindow::onWindowResize);
|
||||||
|
|
||||||
|
onWindowResize(t);
|
||||||
}
|
}
|
||||||
|
|
||||||
void StatsWindow::onMouseWheel(MyGUI::Widget* _sender, int _rel)
|
void StatsWindow::onMouseWheel(MyGUI::Widget* _sender, int _rel)
|
||||||
|
@ -188,11 +190,32 @@ namespace MWGui
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void setSkillProgress(MyGUI::Widget* w, float progress, int skillId)
|
||||||
|
{
|
||||||
|
MWWorld::Ptr player = MWMechanics::getPlayer();
|
||||||
|
const MWWorld::ESMStore &esmStore =
|
||||||
|
MWBase::Environment::get().getWorld()->getStore();
|
||||||
|
|
||||||
|
float progressRequirement = player.getClass().getNpcStats(player).getSkillProgressRequirement(skillId,
|
||||||
|
*esmStore.get<ESM::Class>().find(player.get<ESM::NPC>()->mBase->mClass));
|
||||||
|
|
||||||
|
// This is how vanilla MW displays the progress bar (I think). Note it's slightly inaccurate,
|
||||||
|
// due to the int casting in the skill levelup logic. Also the progress label could in rare cases
|
||||||
|
// reach 100% without the skill levelling up.
|
||||||
|
// Leaving the original display logic for now, for consistency with ess-imported savegames.
|
||||||
|
int progressPercent = int(float(progress) / float(progressRequirement) * 100.f + 0.5f);
|
||||||
|
|
||||||
|
w->setUserString("Caption_SkillProgressText", MyGUI::utility::toString(progressPercent)+"/100");
|
||||||
|
w->setUserString("RangePosition_SkillProgress", MyGUI::utility::toString(progressPercent));
|
||||||
|
}
|
||||||
|
|
||||||
void StatsWindow::setValue(const ESM::Skill::SkillEnum parSkill, const MWMechanics::SkillValue& value)
|
void StatsWindow::setValue(const ESM::Skill::SkillEnum parSkill, const MWMechanics::SkillValue& value)
|
||||||
{
|
{
|
||||||
mSkillValues[parSkill] = value;
|
mSkillValues[parSkill] = value;
|
||||||
MyGUI::TextBox* widget = mSkillWidgetMap[(int)parSkill];
|
std::pair<MyGUI::TextBox*, MyGUI::TextBox*> widgets = mSkillWidgetMap[(int)parSkill];
|
||||||
if (widget)
|
MyGUI::TextBox* valueWidget = widgets.second;
|
||||||
|
MyGUI::TextBox* nameWidget = widgets.first;
|
||||||
|
if (valueWidget && nameWidget)
|
||||||
{
|
{
|
||||||
int modified = value.getModified(), base = value.getBase();
|
int modified = value.getModified(), base = value.getBase();
|
||||||
std::string text = MyGUI::utility::toString(modified);
|
std::string text = MyGUI::utility::toString(modified);
|
||||||
|
@ -202,8 +225,20 @@ namespace MWGui
|
||||||
else if (modified < base)
|
else if (modified < base)
|
||||||
state = "decreased";
|
state = "decreased";
|
||||||
|
|
||||||
widget->setCaption(text);
|
int widthBefore = valueWidget->getTextSize().width;
|
||||||
widget->_setWidgetState(state);
|
|
||||||
|
valueWidget->setCaption(text);
|
||||||
|
valueWidget->_setWidgetState(state);
|
||||||
|
|
||||||
|
int widthAfter = valueWidget->getTextSize().width;
|
||||||
|
if (widthBefore != widthAfter)
|
||||||
|
{
|
||||||
|
valueWidget->setCoord(valueWidget->getLeft() - (widthAfter-widthBefore), valueWidget->getTop(), valueWidget->getWidth() + (widthAfter-widthBefore), valueWidget->getHeight());
|
||||||
|
nameWidget->setSize(nameWidget->getWidth() - (widthAfter-widthBefore), nameWidget->getHeight());
|
||||||
|
}
|
||||||
|
|
||||||
|
if (value.getBase() < 100)
|
||||||
|
setSkillProgress(valueWidget, value.getProgress(), parSkill);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -316,7 +351,7 @@ namespace MWGui
|
||||||
coord2.top += sLineHeight;
|
coord2.top += sLineHeight;
|
||||||
}
|
}
|
||||||
|
|
||||||
MyGUI::TextBox* StatsWindow::addValueItem(const std::string& text, const std::string &value, const std::string& state, MyGUI::IntCoord &coord1, MyGUI::IntCoord &coord2)
|
std::pair<MyGUI::TextBox*, MyGUI::TextBox*> StatsWindow::addValueItem(const std::string& text, const std::string &value, const std::string& state, MyGUI::IntCoord &coord1, MyGUI::IntCoord &coord2)
|
||||||
{
|
{
|
||||||
MyGUI::TextBox *skillNameWidget, *skillValueWidget;
|
MyGUI::TextBox *skillNameWidget, *skillValueWidget;
|
||||||
|
|
||||||
|
@ -340,7 +375,7 @@ namespace MWGui
|
||||||
coord1.top += sLineHeight;
|
coord1.top += sLineHeight;
|
||||||
coord2.top += sLineHeight;
|
coord2.top += sLineHeight;
|
||||||
|
|
||||||
return skillValueWidget;
|
return std::make_pair(skillNameWidget, skillValueWidget);
|
||||||
}
|
}
|
||||||
|
|
||||||
MyGUI::Widget* StatsWindow::addItem(const std::string& text, MyGUI::IntCoord &coord1, MyGUI::IntCoord &coord2)
|
MyGUI::Widget* StatsWindow::addItem(const std::string& text, MyGUI::IntCoord &coord1, MyGUI::IntCoord &coord2)
|
||||||
|
@ -384,19 +419,9 @@ namespace MWGui
|
||||||
int base = stat.getBase();
|
int base = stat.getBase();
|
||||||
int modified = stat.getModified();
|
int modified = stat.getModified();
|
||||||
|
|
||||||
MWWorld::Ptr player = MWMechanics::getPlayer();
|
|
||||||
const MWWorld::ESMStore &esmStore =
|
const MWWorld::ESMStore &esmStore =
|
||||||
MWBase::Environment::get().getWorld()->getStore();
|
MWBase::Environment::get().getWorld()->getStore();
|
||||||
|
|
||||||
float progressRequirement = player.getClass().getNpcStats(player).getSkillProgressRequirement(skillId,
|
|
||||||
*esmStore.get<ESM::Class>().find(player.get<ESM::NPC>()->mBase->mClass));
|
|
||||||
|
|
||||||
// This is how vanilla MW displays the progress bar (I think). Note it's slightly inaccurate,
|
|
||||||
// due to the int casting in the skill levelup logic. Also the progress label could in rare cases
|
|
||||||
// reach 100% without the skill levelling up.
|
|
||||||
// Leaving the original display logic for now, for consistency with ess-imported savegames.
|
|
||||||
int progressPercent = int(float(stat.getProgress()) / float(progressRequirement) * 100.f + 0.5f);
|
|
||||||
|
|
||||||
const ESM::Skill* skill = esmStore.get<ESM::Skill>().find(skillId);
|
const ESM::Skill* skill = esmStore.get<ESM::Skill>().find(skillId);
|
||||||
|
|
||||||
std::string icon = "icons\\k\\" + ESM::Skill::sIconNames[skillId];
|
std::string icon = "icons\\k\\" + ESM::Skill::sIconNames[skillId];
|
||||||
|
@ -409,7 +434,7 @@ namespace MWGui
|
||||||
state = "increased";
|
state = "increased";
|
||||||
else if (modified < base)
|
else if (modified < base)
|
||||||
state = "decreased";
|
state = "decreased";
|
||||||
MyGUI::TextBox* widget = addValueItem(MWBase::Environment::get().getWindowManager()->getGameSettingString(skillNameId, skillNameId),
|
std::pair<MyGUI::TextBox*, MyGUI::TextBox*> widgets = addValueItem(MWBase::Environment::get().getWindowManager()->getGameSettingString(skillNameId, skillNameId),
|
||||||
MyGUI::utility::toString(static_cast<int>(modified)), state, coord1, coord2);
|
MyGUI::utility::toString(static_cast<int>(modified)), state, coord1, coord2);
|
||||||
|
|
||||||
for (int i=0; i<2; ++i)
|
for (int i=0; i<2; ++i)
|
||||||
|
@ -420,6 +445,7 @@ namespace MWGui
|
||||||
mSkillWidgets[mSkillWidgets.size()-1-i]->setUserString("Caption_SkillDescription", skill->mDescription);
|
mSkillWidgets[mSkillWidgets.size()-1-i]->setUserString("Caption_SkillDescription", skill->mDescription);
|
||||||
mSkillWidgets[mSkillWidgets.size()-1-i]->setUserString("Caption_SkillAttribute", "#{sGoverningAttribute}: #{" + attr->mName + "}");
|
mSkillWidgets[mSkillWidgets.size()-1-i]->setUserString("Caption_SkillAttribute", "#{sGoverningAttribute}: #{" + attr->mName + "}");
|
||||||
mSkillWidgets[mSkillWidgets.size()-1-i]->setUserString("ImageTexture_SkillImage", icon);
|
mSkillWidgets[mSkillWidgets.size()-1-i]->setUserString("ImageTexture_SkillImage", icon);
|
||||||
|
mSkillWidgets[mSkillWidgets.size()-1-i]->setUserString("Range_SkillProgress", "100");
|
||||||
if (base < 100)
|
if (base < 100)
|
||||||
{
|
{
|
||||||
mSkillWidgets[mSkillWidgets.size()-1-i]->setUserString("Visible_SkillMaxed", "false");
|
mSkillWidgets[mSkillWidgets.size()-1-i]->setUserString("Visible_SkillMaxed", "false");
|
||||||
|
@ -428,9 +454,7 @@ namespace MWGui
|
||||||
mSkillWidgets[mSkillWidgets.size()-1-i]->setUserString("Visible_SkillProgressVBox", "true");
|
mSkillWidgets[mSkillWidgets.size()-1-i]->setUserString("Visible_SkillProgressVBox", "true");
|
||||||
mSkillWidgets[mSkillWidgets.size()-1-i]->setUserString("UserData^Hidden_SkillProgressVBox", "false");
|
mSkillWidgets[mSkillWidgets.size()-1-i]->setUserString("UserData^Hidden_SkillProgressVBox", "false");
|
||||||
|
|
||||||
mSkillWidgets[mSkillWidgets.size()-1-i]->setUserString("Caption_SkillProgressText", MyGUI::utility::toString(progressPercent)+"/100");
|
setSkillProgress(mSkillWidgets[mSkillWidgets.size()-1-i], stat.getProgress(), skillId);
|
||||||
mSkillWidgets[mSkillWidgets.size()-1-i]->setUserString("Range_SkillProgress", "100");
|
|
||||||
mSkillWidgets[mSkillWidgets.size()-1-i]->setUserString("RangePosition_SkillProgress", MyGUI::utility::toString(progressPercent));
|
|
||||||
} else {
|
} else {
|
||||||
mSkillWidgets[mSkillWidgets.size()-1-i]->setUserString("Visible_SkillMaxed", "true");
|
mSkillWidgets[mSkillWidgets.size()-1-i]->setUserString("Visible_SkillMaxed", "true");
|
||||||
mSkillWidgets[mSkillWidgets.size()-1-i]->setUserString("UserData^Hidden_SkillMaxed", "false");
|
mSkillWidgets[mSkillWidgets.size()-1-i]->setUserString("UserData^Hidden_SkillMaxed", "false");
|
||||||
|
@ -440,7 +464,7 @@ namespace MWGui
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
mSkillWidgetMap[skillId] = widget;
|
mSkillWidgetMap[skillId] = widgets;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -43,7 +43,7 @@ namespace MWGui
|
||||||
void addSkills(const SkillList &skills, const std::string &titleId, const std::string &titleDefault, MyGUI::IntCoord &coord1, MyGUI::IntCoord &coord2);
|
void addSkills(const SkillList &skills, const std::string &titleId, const std::string &titleDefault, MyGUI::IntCoord &coord1, MyGUI::IntCoord &coord2);
|
||||||
void addSeparator(MyGUI::IntCoord &coord1, MyGUI::IntCoord &coord2);
|
void addSeparator(MyGUI::IntCoord &coord1, MyGUI::IntCoord &coord2);
|
||||||
void addGroup(const std::string &label, MyGUI::IntCoord &coord1, MyGUI::IntCoord &coord2);
|
void addGroup(const std::string &label, MyGUI::IntCoord &coord1, MyGUI::IntCoord &coord2);
|
||||||
MyGUI::TextBox* addValueItem(const std::string& text, const std::string &value, const std::string& state, MyGUI::IntCoord &coord1, MyGUI::IntCoord &coord2);
|
std::pair<MyGUI::TextBox*, MyGUI::TextBox*> addValueItem(const std::string& text, const std::string &value, const std::string& state, MyGUI::IntCoord &coord1, MyGUI::IntCoord &coord2);
|
||||||
MyGUI::Widget* addItem(const std::string& text, MyGUI::IntCoord &coord1, MyGUI::IntCoord &coord2);
|
MyGUI::Widget* addItem(const std::string& text, MyGUI::IntCoord &coord1, MyGUI::IntCoord &coord2);
|
||||||
|
|
||||||
void setFactions (const FactionList& factions);
|
void setFactions (const FactionList& factions);
|
||||||
|
@ -62,7 +62,7 @@ namespace MWGui
|
||||||
|
|
||||||
SkillList mMajorSkills, mMinorSkills, mMiscSkills;
|
SkillList mMajorSkills, mMinorSkills, mMiscSkills;
|
||||||
std::map<int, MWMechanics::SkillValue > mSkillValues;
|
std::map<int, MWMechanics::SkillValue > mSkillValues;
|
||||||
std::map<int, MyGUI::TextBox*> mSkillWidgetMap;
|
std::map<int, std::pair<MyGUI::TextBox*, MyGUI::TextBox*> > mSkillWidgetMap;
|
||||||
std::map<std::string, MyGUI::Widget*> mFactionWidgetMap;
|
std::map<std::string, MyGUI::Widget*> mFactionWidgetMap;
|
||||||
FactionList mFactions; ///< Stores a list of factions and the current rank
|
FactionList mFactions; ///< Stores a list of factions and the current rank
|
||||||
std::string mBirthSignId;
|
std::string mBirthSignId;
|
||||||
|
|
|
@ -1487,6 +1487,10 @@ namespace MWInput
|
||||||
ret.push_back(A_QuickKey8);
|
ret.push_back(A_QuickKey8);
|
||||||
ret.push_back(A_QuickKey9);
|
ret.push_back(A_QuickKey9);
|
||||||
ret.push_back(A_QuickKey10);
|
ret.push_back(A_QuickKey10);
|
||||||
|
ret.push_back(A_CycleSpellLeft);
|
||||||
|
ret.push_back(A_CycleSpellRight);
|
||||||
|
ret.push_back(A_CycleWeaponLeft);
|
||||||
|
ret.push_back(A_CycleWeaponRight);
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1137,6 +1137,7 @@ namespace MWMechanics
|
||||||
|
|
||||||
timerUpdateAITargets += duration;
|
timerUpdateAITargets += duration;
|
||||||
timerUpdateHeadTrack += duration;
|
timerUpdateHeadTrack += duration;
|
||||||
|
timerUpdateEquippedLight += duration;
|
||||||
|
|
||||||
// Looping magic VFX update
|
// Looping magic VFX update
|
||||||
// Note: we need to do this before any of the animations are updated.
|
// Note: we need to do this before any of the animations are updated.
|
||||||
|
|
|
@ -338,22 +338,16 @@ namespace MWMechanics
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool update = false;
|
|
||||||
|
|
||||||
//Loop over ESM::Skill::SkillEnum
|
//Loop over ESM::Skill::SkillEnum
|
||||||
for(int i = 0; i < ESM::Skill::Length; ++i)
|
for(int i = 0; i < ESM::Skill::Length; ++i)
|
||||||
{
|
{
|
||||||
if(stats.getSkill(i) != mWatchedSkills[i] || mWatchedStatsEmpty)
|
if(stats.getSkill(i) != mWatchedSkills[i] || mWatchedStatsEmpty)
|
||||||
{
|
{
|
||||||
update = true;
|
|
||||||
mWatchedSkills[i] = stats.getSkill(i);
|
mWatchedSkills[i] = stats.getSkill(i);
|
||||||
winMgr->setValue((ESM::Skill::SkillEnum)i, stats.getSkill(i));
|
winMgr->setValue((ESM::Skill::SkillEnum)i, stats.getSkill(i));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if(update)
|
|
||||||
winMgr->updateSkillArea();
|
|
||||||
|
|
||||||
winMgr->setValue("level", stats.getLevel());
|
winMgr->setValue("level", stats.getLevel());
|
||||||
|
|
||||||
mWatchedStatsEmpty = false;
|
mWatchedStatsEmpty = false;
|
||||||
|
|
|
@ -29,7 +29,8 @@ void Objects::addObject(const MWWorld::Ptr& ptr)
|
||||||
removeObject(ptr);
|
removeObject(ptr);
|
||||||
|
|
||||||
MWRender::Animation *anim = MWBase::Environment::get().getWorld()->getAnimation(ptr);
|
MWRender::Animation *anim = MWBase::Environment::get().getWorld()->getAnimation(ptr);
|
||||||
if(anim) mObjects.insert(std::make_pair(ptr, new CharacterController(ptr, anim)));
|
if (anim && anim->hasAnimSources())
|
||||||
|
mObjects.insert(std::make_pair(ptr, new CharacterController(ptr, anim)));
|
||||||
}
|
}
|
||||||
|
|
||||||
void Objects::removeObject(const MWWorld::Ptr& ptr)
|
void Objects::removeObject(const MWWorld::Ptr& ptr)
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
#include "actor.hpp"
|
#include "actor.hpp"
|
||||||
|
|
||||||
#include <BulletCollision/CollisionShapes/btCylinderShape.h>
|
#include <BulletCollision/CollisionShapes/btCapsuleShape.h>
|
||||||
#include <BulletCollision/CollisionShapes/btBoxShape.h>
|
#include <BulletCollision/CollisionShapes/btBoxShape.h>
|
||||||
#include <BulletCollision/CollisionDispatch/btCollisionWorld.h>
|
#include <BulletCollision/CollisionDispatch/btCollisionWorld.h>
|
||||||
|
|
||||||
|
@ -18,7 +18,7 @@ namespace MWPhysics
|
||||||
|
|
||||||
Actor::Actor(const MWWorld::Ptr& ptr, osg::ref_ptr<const Resource::BulletShape> shape, btCollisionWorld* world)
|
Actor::Actor(const MWWorld::Ptr& ptr, osg::ref_ptr<const Resource::BulletShape> shape, btCollisionWorld* world)
|
||||||
: mCanWaterWalk(false), mWalkingOnWater(false)
|
: mCanWaterWalk(false), mWalkingOnWater(false)
|
||||||
, mCollisionObject(0), mForce(0.f, 0.f, 0.f), mOnGround(false)
|
, mCollisionObject(0), mForce(0.f, 0.f, 0.f), mOnGround(true), mOnSlope(false)
|
||||||
, mInternalCollisionMode(true)
|
, mInternalCollisionMode(true)
|
||||||
, mExternalCollisionMode(true)
|
, mExternalCollisionMode(true)
|
||||||
, mCollisionWorld(world)
|
, mCollisionWorld(world)
|
||||||
|
@ -31,8 +31,7 @@ Actor::Actor(const MWWorld::Ptr& ptr, osg::ref_ptr<const Resource::BulletShape>
|
||||||
// Use capsule shape only if base is square (nonuniform scaling apparently doesn't work on it)
|
// Use capsule shape only if base is square (nonuniform scaling apparently doesn't work on it)
|
||||||
if (std::abs(mHalfExtents.x()-mHalfExtents.y())<mHalfExtents.x()*0.05 && mHalfExtents.z() >= mHalfExtents.x())
|
if (std::abs(mHalfExtents.x()-mHalfExtents.y())<mHalfExtents.x()*0.05 && mHalfExtents.z() >= mHalfExtents.x())
|
||||||
{
|
{
|
||||||
// Could also be btCapsuleShapeZ, but the movement solver seems to have issues with it (jumping on slopes doesn't work)
|
mShape.reset(new btCapsuleShapeZ(mHalfExtents.x(), 2*mHalfExtents.z() - 2*mHalfExtents.x()));
|
||||||
mShape.reset(new btCylinderShapeZ(toBullet(mHalfExtents)));
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
mShape.reset(new btBoxShape(toBullet(mHalfExtents)));
|
mShape.reset(new btBoxShape(toBullet(mHalfExtents)));
|
||||||
|
@ -180,6 +179,11 @@ void Actor::setOnGround(bool grounded)
|
||||||
mOnGround = grounded;
|
mOnGround = grounded;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Actor::setOnSlope(bool slope)
|
||||||
|
{
|
||||||
|
mOnSlope = slope;
|
||||||
|
}
|
||||||
|
|
||||||
bool Actor::isWalkingOnWater() const
|
bool Actor::isWalkingOnWater() const
|
||||||
{
|
{
|
||||||
return mWalkingOnWater;
|
return mWalkingOnWater;
|
||||||
|
|
|
@ -124,6 +124,13 @@ namespace MWPhysics
|
||||||
return mInternalCollisionMode && mOnGround;
|
return mInternalCollisionMode && mOnGround;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void setOnSlope(bool slope);
|
||||||
|
|
||||||
|
bool getOnSlope() const
|
||||||
|
{
|
||||||
|
return mInternalCollisionMode && mOnSlope;
|
||||||
|
}
|
||||||
|
|
||||||
btCollisionObject* getCollisionObject() const
|
btCollisionObject* getCollisionObject() const
|
||||||
{
|
{
|
||||||
return mCollisionObject.get();
|
return mCollisionObject.get();
|
||||||
|
@ -160,6 +167,7 @@ namespace MWPhysics
|
||||||
|
|
||||||
osg::Vec3f mForce;
|
osg::Vec3f mForce;
|
||||||
bool mOnGround;
|
bool mOnGround;
|
||||||
|
bool mOnSlope;
|
||||||
bool mInternalCollisionMode;
|
bool mInternalCollisionMode;
|
||||||
bool mExternalCollisionMode;
|
bool mExternalCollisionMode;
|
||||||
|
|
||||||
|
|
|
@ -250,6 +250,8 @@ namespace MWPhysics
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
actor->setOnGround(true);
|
||||||
|
|
||||||
// Check if we actually found a valid spawn point (use an infinitely thin ray this time).
|
// Check if we actually found a valid spawn point (use an infinitely thin ray this time).
|
||||||
// Required for some broken door destinations in Morrowind.esm, where the spawn point
|
// Required for some broken door destinations in Morrowind.esm, where the spawn point
|
||||||
// intersects with other geometry if the actor's base is taken into account
|
// intersects with other geometry if the actor's base is taken into account
|
||||||
|
@ -266,11 +268,13 @@ namespace MWPhysics
|
||||||
( (toOsg(resultCallback1.m_hitPointWorld) - tracer.mEndPos).length2() > 35*35
|
( (toOsg(resultCallback1.m_hitPointWorld) - tracer.mEndPos).length2() > 35*35
|
||||||
|| !isWalkableSlope(tracer.mPlaneNormal)))
|
|| !isWalkableSlope(tracer.mPlaneNormal)))
|
||||||
{
|
{
|
||||||
actor->setOnGround(isWalkableSlope(resultCallback1.m_hitNormalWorld));
|
actor->setOnSlope(isWalkableSlope(resultCallback1.m_hitNormalWorld));
|
||||||
return toOsg(resultCallback1.m_hitPointWorld) + osg::Vec3f(0.f, 0.f, 1.f);
|
return toOsg(resultCallback1.m_hitPointWorld) + osg::Vec3f(0.f, 0.f, 1.f);
|
||||||
}
|
}
|
||||||
|
else
|
||||||
actor->setOnGround(isWalkableSlope(tracer.mPlaneNormal));
|
{
|
||||||
|
actor->setOnSlope(isWalkableSlope(tracer.mPlaneNormal));
|
||||||
|
}
|
||||||
|
|
||||||
return tracer.mEndPos;
|
return tracer.mEndPos;
|
||||||
}
|
}
|
||||||
|
@ -322,12 +326,10 @@ namespace MWPhysics
|
||||||
{
|
{
|
||||||
velocity = (osg::Quat(refpos.rot[2], osg::Vec3f(0, 0, -1))) * movement;
|
velocity = (osg::Quat(refpos.rot[2], osg::Vec3f(0, 0, -1))) * movement;
|
||||||
|
|
||||||
if (velocity.z() > 0.f && physicActor->getOnGround())
|
if (velocity.z() > 0.f && physicActor->getOnGround() && !physicActor->getOnSlope())
|
||||||
inertia = velocity;
|
inertia = velocity;
|
||||||
else if(!physicActor->getOnGround())
|
else if(!physicActor->getOnGround() || physicActor->getOnSlope())
|
||||||
{
|
|
||||||
velocity = velocity + physicActor->getInertialForce();
|
velocity = velocity + physicActor->getInertialForce();
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// dead actors underwater will float to the surface, if the CharacterController tells us to do so
|
// dead actors underwater will float to the surface, if the CharacterController tells us to do so
|
||||||
|
@ -440,13 +442,14 @@ namespace MWPhysics
|
||||||
}
|
}
|
||||||
|
|
||||||
bool isOnGround = false;
|
bool isOnGround = false;
|
||||||
|
bool isOnSlope = false;
|
||||||
if (!(inertia.z() > 0.f) && !(newPosition.z() < swimlevel))
|
if (!(inertia.z() > 0.f) && !(newPosition.z() < swimlevel))
|
||||||
{
|
{
|
||||||
osg::Vec3f from = newPosition;
|
osg::Vec3f from = newPosition;
|
||||||
osg::Vec3f to = newPosition - (physicActor->getOnGround() ?
|
osg::Vec3f to = newPosition - (physicActor->getOnGround() ?
|
||||||
osg::Vec3f(0,0,sStepSizeDown+2.f) : osg::Vec3f(0,0,2.f));
|
osg::Vec3f(0,0,sStepSizeDown+2.f) : osg::Vec3f(0,0,2.f));
|
||||||
tracer.doTrace(colobj, from, to, collisionWorld);
|
tracer.doTrace(colobj, from, to, collisionWorld);
|
||||||
if(tracer.mFraction < 1.0f && isWalkableSlope(tracer.mPlaneNormal)
|
if(tracer.mFraction < 1.0f
|
||||||
&& tracer.mHitObject->getBroadphaseHandle()->m_collisionFilterGroup != CollisionType_Actor)
|
&& tracer.mHitObject->getBroadphaseHandle()->m_collisionFilterGroup != CollisionType_Actor)
|
||||||
{
|
{
|
||||||
const btCollisionObject* standingOn = tracer.mHitObject;
|
const btCollisionObject* standingOn = tracer.mHitObject;
|
||||||
|
@ -460,6 +463,8 @@ namespace MWPhysics
|
||||||
newPosition.z() = tracer.mEndPos.z() + 1.0f;
|
newPosition.z() = tracer.mEndPos.z() + 1.0f;
|
||||||
|
|
||||||
isOnGround = true;
|
isOnGround = true;
|
||||||
|
|
||||||
|
isOnSlope = !isWalkableSlope(tracer.mPlaneNormal);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -483,7 +488,7 @@ namespace MWPhysics
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if(isOnGround || newPosition.z() < swimlevel || isFlying)
|
if((isOnGround && !isOnSlope) || newPosition.z() < swimlevel || isFlying)
|
||||||
physicActor->setInertialForce(osg::Vec3f(0.f, 0.f, 0.f));
|
physicActor->setInertialForce(osg::Vec3f(0.f, 0.f, 0.f));
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -497,6 +502,7 @@ namespace MWPhysics
|
||||||
physicActor->setInertialForce(inertia);
|
physicActor->setInertialForce(inertia);
|
||||||
}
|
}
|
||||||
physicActor->setOnGround(isOnGround);
|
physicActor->setOnGround(isOnGround);
|
||||||
|
physicActor->setOnSlope(isOnSlope);
|
||||||
|
|
||||||
newPosition.z() -= halfExtents.z(); // remove what was added at the beginning
|
newPosition.z() -= halfExtents.z(); // remove what was added at the beginning
|
||||||
return newPosition;
|
return newPosition;
|
||||||
|
@ -989,41 +995,10 @@ namespace MWPhysics
|
||||||
return !result.mHit;
|
return !result.mHit;
|
||||||
}
|
}
|
||||||
|
|
||||||
// physactor->getOnGround() is not a reliable indicator of whether the actor
|
|
||||||
// is on the ground (defaults to false, which means code blocks such as
|
|
||||||
// CharacterController::update() may falsely detect "falling").
|
|
||||||
//
|
|
||||||
// Also, collisions can move z position slightly off zero, giving a false
|
|
||||||
// indication. In order to reduce false detection of jumping, small distance
|
|
||||||
// below the actor is detected and ignored. A value of 1.5 is used here, but
|
|
||||||
// something larger may be more suitable. This change should resolve Bug#1271.
|
|
||||||
//
|
|
||||||
// TODO: There might be better places to update PhysicActor::mOnGround.
|
|
||||||
bool PhysicsSystem::isOnGround(const MWWorld::Ptr &actor)
|
bool PhysicsSystem::isOnGround(const MWWorld::Ptr &actor)
|
||||||
{
|
{
|
||||||
Actor* physactor = getActor(actor);
|
Actor* physactor = getActor(actor);
|
||||||
if(!physactor)
|
return physactor->getOnGround();
|
||||||
return false;
|
|
||||||
if(physactor->getOnGround())
|
|
||||||
return true;
|
|
||||||
else
|
|
||||||
{
|
|
||||||
osg::Vec3f pos(actor.getRefData().getPosition().asVec3());
|
|
||||||
|
|
||||||
ActorTracer tracer;
|
|
||||||
// a small distance above collision object is considered "on ground"
|
|
||||||
tracer.findGround(physactor,
|
|
||||||
pos,
|
|
||||||
pos - osg::Vec3f(0, 0, 1.5f), // trace a small amount down
|
|
||||||
mCollisionWorld);
|
|
||||||
if(tracer.mFraction < 1.0f) // collision, must be close to something below
|
|
||||||
{
|
|
||||||
physactor->setOnGround(true);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool PhysicsSystem::canMoveToWaterSurface(const MWWorld::ConstPtr &actor, const float waterlevel)
|
bool PhysicsSystem::canMoveToWaterSurface(const MWWorld::ConstPtr &actor, const float waterlevel)
|
||||||
|
|
|
@ -565,6 +565,11 @@ namespace MWRender
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool Animation::hasAnimSources() const
|
||||||
|
{
|
||||||
|
return !mAnimSources.empty();
|
||||||
|
}
|
||||||
|
|
||||||
void Animation::clearAnimSources()
|
void Animation::clearAnimSources()
|
||||||
{
|
{
|
||||||
mStates.clear();
|
mStates.clear();
|
||||||
|
|
|
@ -341,6 +341,8 @@ public:
|
||||||
Animation(const MWWorld::Ptr &ptr, osg::ref_ptr<osg::Group> parentNode, Resource::ResourceSystem* resourceSystem);
|
Animation(const MWWorld::Ptr &ptr, osg::ref_ptr<osg::Group> parentNode, Resource::ResourceSystem* resourceSystem);
|
||||||
virtual ~Animation();
|
virtual ~Animation();
|
||||||
|
|
||||||
|
bool hasAnimSources() const;
|
||||||
|
|
||||||
MWWorld::ConstPtr getPtr() const;
|
MWWorld::ConstPtr getPtr() const;
|
||||||
|
|
||||||
/// Set active flag on the object skeleton, if one exists.
|
/// Set active flag on the object skeleton, if one exists.
|
||||||
|
|
Loading…
Reference in a new issue