Merge remote-tracking branch 'scrawl/master'

openmw-35
Marc Zinnschlag 10 years ago
commit 640d473866

@ -15,7 +15,7 @@
#include <extern/shiny/Platforms/Ogre/OgrePlatform.hpp>
#include <components/ogreinit/ogreinit.hpp>
#include <components/nifogre/ogrenifloader.hpp>
#include <components/bsa/resources.hpp>
#include "model/doc/document.hpp"
@ -35,6 +35,8 @@ CS::Editor::Editor (OgreInit::OgreInit& ogreInit)
ogreInit.init ((mCfgMgr.getUserConfigPath() / "opencsOgre.log").string());
NifOgre::Loader::setShowMarkers(true);
mOverlaySystem.reset (new CSVRender::OverlaySystem);
Bsa::registerResources (Files::Collections (config.first, !mFsStrict), config.second, true,

@ -16,7 +16,7 @@ namespace CSVWorld
PhysicsSystem::PhysicsSystem()
{
// Create physics. shapeLoader is deleted by the physic engine
NifBullet::ManualBulletShapeLoader* shapeLoader = new NifBullet::ManualBulletShapeLoader();
NifBullet::ManualBulletShapeLoader* shapeLoader = new NifBullet::ManualBulletShapeLoader(true);
mEngine = new OEngine::Physic::PhysicEngine(shapeLoader);
}

@ -42,6 +42,12 @@
namespace
{
bool isConscious(const MWWorld::Ptr& ptr)
{
const MWMechanics::CreatureStats& stats = ptr.getClass().getCreatureStats(ptr);
return !stats.isDead() && !stats.getKnockedDown();
}
void adjustBoundItem (const std::string& item, bool bound, const MWWorld::Ptr& actor)
{
if (bound)
@ -1101,12 +1107,12 @@ namespace MWMechanics
updateCrimePersuit(iter->first, duration);
if (iter->first != player)
iter->first.getClass().getCreatureStats(iter->first).getAiSequence().execute(iter->first,iter->second->getAiState(), duration);
CreatureStats &stats = iter->first.getClass().getCreatureStats(iter->first);
if(!stats.isDead())
{
if (stats.getAiSequence().isInCombat()) hostilesCount++;
CreatureStats &stats = iter->first.getClass().getCreatureStats(iter->first);
if (isConscious(iter->first))
stats.getAiSequence().execute(iter->first,iter->second->getAiState(), duration);
if (stats.getAiSequence().isInCombat() && !stats.isDead()) hostilesCount++;
}
}
@ -1515,7 +1521,9 @@ namespace MWMechanics
for (PtrActorMap::iterator it = map.begin(); it != map.end(); ++it)
{
MWWorld::Ptr ptr = it->first;
if (ptr == MWBase::Environment::get().getWorld()->getPlayerPtr())
if (ptr == MWBase::Environment::get().getWorld()->getPlayerPtr()
|| !isConscious(ptr)
|| ptr.getClass().getCreatureStats(ptr).getMagicEffects().get(ESM::MagicEffect::Paralyze).getMagnitude() > 0)
continue;
MWMechanics::AiSequence& seq = ptr.getClass().getCreatureStats(ptr).getAiSequence();
seq.fastForward(ptr, it->second->getAiState());

@ -152,8 +152,7 @@ bool AiSequence::isPackageDone() const
void AiSequence::execute (const MWWorld::Ptr& actor, AiState& state,float duration)
{
if(actor != MWBase::Environment::get().getWorld()->getPlayerPtr()
&& !actor.getClass().getCreatureStats(actor).getKnockedDown())
if(actor != MWBase::Environment::get().getWorld()->getPlayerPtr())
{
if (!mPackages.empty())
{

@ -308,22 +308,26 @@ namespace MWMechanics
// Play idle voiced dialogue entries randomly
int hello = cStats.getAiSetting(CreatureStats::AI_Hello).getModified();
if (hello > 0 && !MWBase::Environment::get().getWorld()->isSwimming(actor)
&& actor.getRefData().getPosition().pos[2] < 3000 &&
MWBase::Environment::get().getSoundManager()->sayDone(actor))
&& MWBase::Environment::get().getSoundManager()->sayDone(actor))
{
float roll = std::rand()/ (static_cast<double> (RAND_MAX) + 1) * 10000; // [0, 9999]
MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayerPtr();
// Don't bother if the player is out of hearing range
static float fVoiceIdleOdds = MWBase::Environment::get().getWorld()->getStore()
.get<ESM::GameSetting>().find("fVoiceIdleOdds")->getFloat();
float x = fVoiceIdleOdds * MWBase::Environment::get().getFrameDuration();
float roll = std::rand()/ (static_cast<double> (RAND_MAX) + 1) * 10000;
// In vanilla MW the chance was FPS dependent, and did not allow proper changing of fVoiceIdleOdds
// due to the roll being an integer.
// Our implementation does not have these issues, so needs to be recalibrated. We chose to
// use the chance MW would have when run at 60 FPS with the default value of the GMST for calibration.
float x = fVoiceIdleOdds * 0.6 * (MWBase::Environment::get().getFrameDuration() / 0.1);
// Only say Idle voices when player is in LOS
// A bit counterintuitive, likely vanilla did this to reduce the appearance of
// voices going through walls?
if (roll < x && Ogre::Vector3(player.getRefData().getPosition().pos).squaredDistance(Ogre::Vector3(pos.pos)) < 1500*1500
if (roll < x && Ogre::Vector3(player.getRefData().getPosition().pos).squaredDistance(Ogre::Vector3(pos.pos))
< 3000*3000 // maybe should be fAudioVoiceDefaultMaxDistance*fAudioMaxDistanceMult instead
&& MWBase::Environment::get().getWorld()->getLOS(player, actor))
MWBase::Environment::get().getDialogueManager()->say(actor, "idle");
}

@ -70,13 +70,15 @@ void animateCollisionShapes (std::map<OEngine::Physic::RigidBody*, OEngine::Phys
if (bone == NULL)
continue;
btCompoundShape* compound = dynamic_cast<btCompoundShape*>(instance.mCompound);
btCompoundShape* compound = static_cast<btCompoundShape*>(instance.mCompound);
btTransform trans;
trans.setOrigin(BtOgre::Convert::toBullet(bone->_getDerivedPosition()));
trans.setOrigin(BtOgre::Convert::toBullet(bone->_getDerivedPosition()) * compound->getLocalScaling());
trans.setRotation(BtOgre::Convert::toBullet(bone->_getDerivedOrientation()));
compound->getChildShape(shapeIt->second)->setLocalScaling(BtOgre::Convert::toBullet(bone->_getDerivedScale()));
compound->getChildShape(shapeIt->second)->setLocalScaling(
compound->getLocalScaling() *
BtOgre::Convert::toBullet(bone->_getDerivedScale()));
compound->updateChildTransform(shapeIt->second, trans);
}
@ -348,6 +350,8 @@ namespace MWWorld
velocity *= 1.f-(fStromWalkMult * (angle.valueDegrees()/180.f));
}
Ogre::Vector3 origVelocity = velocity;
Ogre::Vector3 newPosition = position;
/*
* A loop to find newPosition using tracer, if successful different from the starting position.
@ -425,10 +429,18 @@ namespace MWWorld
else
{
// Can't move this way, try to find another spot along the plane
Ogre::Real movelen = velocity.normalise();
Ogre::Vector3 direction = velocity;
Ogre::Real movelen = direction.normalise();
Ogre::Vector3 reflectdir = velocity.reflect(tracer.mPlaneNormal);
reflectdir.normalise();
velocity = slide(reflectdir, tracer.mPlaneNormal)*movelen;
Ogre::Vector3 newVelocity = slide(reflectdir, tracer.mPlaneNormal)*movelen;
if ((newVelocity-velocity).squaredLength() < 0.01)
break;
if (velocity.dotProduct(origVelocity) <= 0.f)
break;
velocity = newVelocity;
// Do not allow sliding upward if there is gravity. Stepping will have taken
// care of that.

@ -21,6 +21,18 @@
namespace
{
void addObject(const MWWorld::Ptr& ptr, MWWorld::PhysicsSystem& physics,
MWRender::RenderingManager& rendering)
{
std::string model = Misc::ResourceHelpers::correctActorModelPath(ptr.getClass().getModel(ptr));
std::string id = ptr.getClass().getId(ptr);
if (id == "prisonmarker" || id == "divinemarker" || id == "templemarker" || id == "northmarker")
model = ""; // marker objects that have a hardcoded function in the game logic, should be hidden from the player
rendering.addObject(ptr, model);
ptr.getClass().insertObject (ptr, model, physics);
}
void updateObjectLocalRotation (const MWWorld::Ptr& ptr, MWWorld::PhysicsSystem& physics,
MWRender::RenderingManager& rendering)
{
@ -80,10 +92,7 @@ namespace
{
try
{
const std::string& model = Misc::ResourceHelpers::correctActorModelPath(ptr.getClass().getModel(ptr));
mRendering.addObject(ptr, model);
ptr.getClass().insertObject (ptr, model, mPhysics);
addObject(ptr, mPhysics, mRendering);
updateObjectLocalRotation(ptr, mPhysics, mRendering);
if (ptr.getRefData().getBaseNode())
{
@ -530,9 +539,7 @@ namespace MWWorld
void Scene::addObjectToScene (const Ptr& ptr)
{
const std::string& model = Misc::ResourceHelpers::correctActorModelPath(ptr.getClass().getModel(ptr));
mRendering.addObject(ptr, model);
ptr.getClass().insertObject (ptr, model, *mPhysics);
addObject(ptr, *mPhysics, mRendering);
MWBase::Environment::get().getWorld()->rotateObject(ptr, 0, 0, 0, true);
MWBase::Environment::get().getWorld()->scaleObject(ptr, ptr.getCellRef().getScale());
}

@ -2107,6 +2107,9 @@ namespace MWWorld
Ogre::Vector3 playerPos(refdata.getPosition().pos);
const OEngine::Physic::PhysicActor *physactor = mPhysEngine->getCharacter(refdata.getHandle());
if (!physactor)
throw std::runtime_error("can't find player");
if((!physactor->getOnGround()&&physactor->getCollisionMode()) || isUnderwater(currentCell, playerPos) || isWalkingOnWater(player))
return 2;
if((currentCell->getCell()->mData.mFlags&ESM::Cell::NoSleep) ||
@ -2326,9 +2329,15 @@ namespace MWWorld
if (!targetActor.getRefData().getBaseNode() || !targetActor.getRefData().getBaseNode())
return false; // not in active cell
Ogre::Vector3 halfExt1 = mPhysEngine->getCharacter(actor.getRefData().getHandle())->getHalfExtents();
OEngine::Physic::PhysicActor* actor1 = mPhysEngine->getCharacter(actor.getRefData().getHandle());
OEngine::Physic::PhysicActor* actor2 = mPhysEngine->getCharacter(targetActor.getRefData().getHandle());
if (!actor1 || !actor2)
return false;
Ogre::Vector3 halfExt1 = actor1->getHalfExtents();
const float* pos1 = actor.getRefData().getPosition().pos;
Ogre::Vector3 halfExt2 = mPhysEngine->getCharacter(targetActor.getRefData().getHandle())->getHalfExtents();
Ogre::Vector3 halfExt2 = actor2->getHalfExtents();
const float* pos2 = targetActor.getRefData().getPosition().pos;
btVector3 from(pos1[0],pos1[1],pos1[2]+halfExt1.z*2*0.9); // eye level

@ -158,7 +158,7 @@ void ManualBulletShapeLoader::loadResource(Ogre::Resource *resource)
mShape->mAutogenerated = hasAutoGeneratedCollision(node);
//do a first pass
handleNode(node,0,false,false,false);
handleNode(node,0,false,false);
if(mBoundingBox != NULL)
{
@ -232,7 +232,7 @@ bool ManualBulletShapeLoader::hasAutoGeneratedCollision(Nif::Node const * rootNo
void ManualBulletShapeLoader::handleNode(const Nif::Node *node, int flags,
bool isCollisionNode,
bool raycasting, bool isMarker, bool isAnimated)
bool raycasting, bool isAnimated)
{
// Accumulate the flags from all the child nodes. This works for all
// the flags we currently use, at least.
@ -254,13 +254,6 @@ void ManualBulletShapeLoader::handleNode(const Nif::Node *node, int flags,
if(node->recType == Nif::RC_AvoidNode)
flags |= 0x800;
// Marker objects
/// \todo don't do this in the editor
std::string nodename = node->name;
Misc::StringUtils::toLower(nodename);
if (nodename.find("marker") != std::string::npos)
isMarker = true;
// Check for extra data
Nif::Extra const *e = node;
while (!e->extra.empty())
@ -281,16 +274,14 @@ 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")
else if (sd->string == "MRK" && !mShowMarkers)
// Marker objects. These are only visible in the
// editor. Until and unless we add an editor component to
// the engine, just skip this entire node.
isMarker = true;
// editor.
return;
}
}
if ( (isCollisionNode || (mShape->mAutogenerated && !raycasting))
&& (!isMarker || (!mShape->mAutogenerated && !raycasting)))
if (isCollisionNode || (mShape->mAutogenerated && !raycasting))
{
// NOTE: a trishape with hasBounds=true, but no BBoxCollision flag should NOT go through handleNiTriShape!
// It must be ignored completely.
@ -319,7 +310,7 @@ void ManualBulletShapeLoader::handleNode(const Nif::Node *node, int flags,
for(size_t i = 0;i < list.length();i++)
{
if(!list[i].empty())
handleNode(list[i].getPtr(), flags, isCollisionNode, raycasting, isMarker, isAnimated);
handleNode(list[i].getPtr(), flags, isCollisionNode, raycasting, isAnimated);
}
}
}
@ -374,10 +365,17 @@ void ManualBulletShapeLoader::handleNiTriShape(const Nif::NiTriShape *shape, int
TriangleMeshShape* childShape = new TriangleMeshShape(childMesh,true);
childShape->setLocalScaling(btVector3(transform[0][0], transform[1][1], transform[2][2]));
float scale = shape->trafo.scale;
const Nif::Node* parent = shape;
while (parent->parent)
{
parent = parent->parent;
scale *= parent->trafo.scale;
}
Ogre::Quaternion q = transform.extractQuaternion();
Ogre::Vector3 v = transform.getTrans();
childShape->setLocalScaling(btVector3(scale, scale, scale));
btTransform trans(btQuaternion(q.x, q.y, q.z, q.w), btVector3(v.x, v.y, v.z));
if (raycasting)

@ -67,11 +67,12 @@ struct TriangleMeshShape : public btBvhTriangleMeshShape
class ManualBulletShapeLoader : public OEngine::Physic::BulletShapeLoader
{
public:
ManualBulletShapeLoader()
ManualBulletShapeLoader(bool showMarkers=false)
: mShape(NULL)
, mStaticMesh(NULL)
, mCompoundShape(NULL)
, mBoundingBox(NULL)
, mShowMarkers(showMarkers)
{
}
@ -107,7 +108,7 @@ private:
*Parse a node.
*/
void handleNode(Nif::Node const *node, int flags, bool isCollisionNode,
bool raycasting, bool isMarker, bool isAnimated=false);
bool raycasting, bool isAnimated=false);
/**
*Helper function
@ -130,6 +131,8 @@ private:
btBoxShape *mBoundingBox;
std::set<std::string> mControlledNodes;
bool mShowMarkers;
};

@ -689,6 +689,14 @@ public:
*/
class NIFObjectLoader
{
static bool sShowMarkers;
public:
static void setShowMarkers(bool show)
{
sShowMarkers = show;
}
private:
static void warn(const std::string &msg)
{
std::cerr << "NIFObjectLoader: Warn: " << msg << std::endl;
@ -1176,11 +1184,6 @@ class NIFObjectLoader
if(node->recType == Nif::RC_RootCollisionNode)
isRootCollisionNode = true;
// Marker objects: just skip the entire node branch
/// \todo don't do this in the editor
if (node->name.find("marker") != std::string::npos)
return;
if(node->recType == Nif::RC_NiBSAnimationNode)
animflags |= node->flags;
else if(node->recType == Nif::RC_NiBSParticleNode)
@ -1213,7 +1216,7 @@ class NIFObjectLoader
const Nif::NiStringExtraData *sd = static_cast<const Nif::NiStringExtraData*>(e.getPtr());
// String markers may contain important information
// affecting the entire subtree of this obj
if(sd->string == "MRK")
if(sd->string == "MRK" && !sShowMarkers)
{
// Marker objects. These meshes are only visible in the
// editor.
@ -1476,5 +1479,14 @@ void Loader::createKfControllers(Ogre::Entity *skelBase,
NIFObjectLoader::loadKf(skelBase->getSkeleton(), name, textKeys, ctrls);
}
bool Loader::sShowMarkers = false;
bool NIFObjectLoader::sShowMarkers = false;
void Loader::setShowMarkers(bool show)
{
sShowMarkers = show;
NIFObjectLoader::setShowMarkers(show);
}
} // namespace NifOgre

@ -110,10 +110,18 @@ public:
std::string name,
const std::string &group="General");
/// Set whether or not nodes marked as "MRK" should be shown.
/// These should be hidden ingame, but visible in the editior.
/// Default: false.
static void setShowMarkers(bool show);
static void createKfControllers(Ogre::Entity *skelBase,
const std::string &name,
TextKeyMap &textKeys,
std::vector<Ogre::Controller<Ogre::Real> > &ctrls);
private:
static bool sShowMarkers;
};
// FIXME: Should be with other general Ogre extensions.

@ -36,6 +36,9 @@ namespace ICS
, mDetectingBindingControl(NULL)
, mLog(log)
, mXmouseAxisBinded(false), mYmouseAxisBinded(false)
, mClientHeight(1)
, mClientWidth(1)
, mDetectingBindingDirection(Control::STOP)
{
ICS_LOG(" - Creating InputControlSystem - ");

Loading…
Cancel
Save