diff --git a/apps/openmw/mwbase/world.hpp b/apps/openmw/mwbase/world.hpp index a67ac666d2..b9033daac4 100644 --- a/apps/openmw/mwbase/world.hpp +++ b/apps/openmw/mwbase/world.hpp @@ -218,6 +218,10 @@ namespace MWBase virtual MWWorld::Ptr getFacedObject() = 0; ///< Return pointer to the object the player is looking at, if it is within activation range + /// Returns a pointer to the object the provided object is facing (if within the + /// specified distance). This will attempt to use the "Bip01 Head" node as a basis. + virtual MWWorld::Ptr getFacedObject(const MWWorld::Ptr &ptr, float distance) = 0; + virtual void adjustPosition (const MWWorld::Ptr& ptr) = 0; ///< Adjust position after load to be on ground. Must be called after model load. diff --git a/apps/openmw/mwclass/npc.cpp b/apps/openmw/mwclass/npc.cpp index 5cc09624b5..de239d6346 100644 --- a/apps/openmw/mwclass/npc.cpp +++ b/apps/openmw/mwclass/npc.cpp @@ -305,14 +305,19 @@ namespace MWClass void Npc::hit(const MWWorld::Ptr& ptr, int type) const { + MWBase::World *world = MWBase::Environment::get().getWorld(); + const MWWorld::Store &gmst = world->getStore().get(); + // Get the weapon used (if hand-to-hand, weapon = inv.end()) MWWorld::InventoryStore &inv = getInventoryStore(ptr); MWWorld::ContainerStoreIterator weapon = inv.getSlot(MWWorld::InventoryStore::Slot_CarriedRight); if(weapon != inv.end() && weapon->getTypeName() != typeid(ESM::Weapon).name()) weapon = inv.end(); - // FIXME: Detect what was hit - MWWorld::Ptr victim; + float dist = 100.0f * ((weapon != inv.end()) ? + weapon->get()->mBase->mData.mReach : + gmst.find("fHandToHandReach")->getFloat()); + MWWorld::Ptr victim = world->getFacedObject(ptr, dist); if(victim.isEmpty()) // Didn't hit anything return; @@ -362,8 +367,6 @@ namespace MWClass //damage *= weapon_current_health / weapon_max_health; if(!othercls.hasDetected(victim, ptr)) { - const MWBase::World *world = MWBase::Environment::get().getWorld(); - const MWWorld::Store &gmst = world->getStore().get(); damage *= gmst.find("fCombatCriticalStrikeMult")->getFloat(); MWBase::Environment::get().getWindowManager()->messageBox("#{sTargetCriticalStrike}"); } diff --git a/apps/openmw/mwworld/physicssystem.cpp b/apps/openmw/mwworld/physicssystem.cpp index 3881523769..9cf944656c 100644 --- a/apps/openmw/mwworld/physicssystem.cpp +++ b/apps/openmw/mwworld/physicssystem.cpp @@ -304,6 +304,19 @@ namespace MWWorld return results; } + std::pair PhysicsSystem::getFacedHandle(const Ogre::Vector3 &origin_, const Ogre::Quaternion &orient_, float queryDistance) + { + Ogre::Vector3 dest_ = origin_ + orient_.yAxis()*queryDistance; + + btVector3 origin(origin_.x, origin_.y, origin_.z); + btVector3 dest(dest_.x, dest_.y, dest_.z); + + std::pair result = mEngine->rayTest(origin, dest); + result.second *= queryDistance; + return result; + } + + void PhysicsSystem::setCurrentWater(bool hasWater, int waterHeight) { // TODO: store and use diff --git a/apps/openmw/mwworld/physicssystem.hpp b/apps/openmw/mwworld/physicssystem.hpp index d7e8532601..2b8cb00afc 100644 --- a/apps/openmw/mwworld/physicssystem.hpp +++ b/apps/openmw/mwworld/physicssystem.hpp @@ -55,6 +55,9 @@ namespace MWWorld Ogre::Vector3 traceDown(const MWWorld::Ptr &ptr); std::pair getFacedHandle (MWWorld::World& world, float queryDistance); + std::pair getFacedHandle(const Ogre::Vector3 &origin, + const Ogre::Quaternion &orientation, + float queryDistance); std::vector < std::pair > getFacedHandles (float queryDistance); std::vector < std::pair > getFacedHandles (float mouseX, float mouseY, float queryDistance); diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index d839a051a1..cf651a2e71 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -18,6 +18,7 @@ #include "../mwmechanics/movement.hpp" #include "../mwrender/sky.hpp" +#include "../mwrender/animation.hpp" #include "../mwclass/door.hpp" @@ -776,6 +777,28 @@ namespace MWWorld return object; } + MWWorld::Ptr World::getFacedObject(const MWWorld::Ptr &ptr, float distance) + { + const ESM::Position &posdata = ptr.getRefData().getPosition(); + Ogre::Vector3 pos(posdata.pos); + Ogre::Quaternion rot = Ogre::Quaternion(Ogre::Radian(posdata.rot[2]), Ogre::Vector3::NEGATIVE_UNIT_Z) * + Ogre::Quaternion(Ogre::Radian(posdata.rot[0]), Ogre::Vector3::UNIT_X); + + MWRender::Animation *anim = mRendering->getAnimation(ptr); + if(anim != NULL) + { + Ogre::Node *node = anim->getNode("Head"); + if(node != NULL) + pos += node->_getDerivedPosition(); + } + + std::pair result = mPhysics->getFacedHandle(pos, rot, distance); + if(result.first.empty()) + return MWWorld::Ptr(); + + return searchPtrViaHandle(result.first); + } + void World::deleteObject (const Ptr& ptr) { if (ptr.getRefData().getCount()>0) diff --git a/apps/openmw/mwworld/worldimp.hpp b/apps/openmw/mwworld/worldimp.hpp index 1b436373ba..45cb1f61e8 100644 --- a/apps/openmw/mwworld/worldimp.hpp +++ b/apps/openmw/mwworld/worldimp.hpp @@ -252,6 +252,10 @@ namespace MWWorld virtual MWWorld::Ptr getFacedObject(); ///< Return pointer to the object the player is looking at, if it is within activation range + /// Returns a pointer to the object the provided object is facing (if within the + /// specified distance). This will attempt to use the "Bip01 Head" node as a basis. + virtual MWWorld::Ptr getFacedObject(const MWWorld::Ptr &ptr, float distance); + virtual void deleteObject (const Ptr& ptr); virtual void moveObject (const Ptr& ptr, float x, float y, float z);