diff --git a/apps/esmtool/record.cpp b/apps/esmtool/record.cpp index fd4b97acb..bcf16091f 100644 --- a/apps/esmtool/record.cpp +++ b/apps/esmtool/record.cpp @@ -707,9 +707,9 @@ void Record::print() std::cout << " Faction Reaction: " << mData.mData.mRankData[i].mFactReaction << std::endl; } - std::vector::iterator rit; + std::map::iterator rit; for (rit = mData.mReactions.begin(); rit != mData.mReactions.end(); rit++) - std::cout << " Reaction: " << rit->mReaction << " = " << rit->mFaction << std::endl; + std::cout << " Reaction: " << rit->second << " = " << rit->first << std::endl; } template<> diff --git a/apps/openmw/mwbase/dialoguemanager.hpp b/apps/openmw/mwbase/dialoguemanager.hpp index f51fba07b..cab6809aa 100644 --- a/apps/openmw/mwbase/dialoguemanager.hpp +++ b/apps/openmw/mwbase/dialoguemanager.hpp @@ -68,6 +68,12 @@ namespace MWBase virtual void write (ESM::ESMWriter& writer, Loading::Listener& progress) const = 0; virtual void readRecord (ESM::ESMReader& reader, int32_t type) = 0; + + /// Changes faction1's opinion of faction2 by \a diff. + virtual void modFactionReaction (const std::string& faction1, const std::string& faction2, int diff) = 0; + + /// @return faction1's opinion of faction2 + virtual int getFactionReaction (const std::string& faction1, const std::string& faction2) const = 0; }; } diff --git a/apps/openmw/mwdialogue/dialoguemanagerimp.cpp b/apps/openmw/mwdialogue/dialoguemanagerimp.cpp index c7e832e4a..b6cef2fe7 100644 --- a/apps/openmw/mwdialogue/dialoguemanagerimp.cpp +++ b/apps/openmw/mwdialogue/dialoguemanagerimp.cpp @@ -642,6 +642,8 @@ namespace MWDialogue if (iter->second) state.mKnownTopics.push_back (iter->first); + state.mModFactionReaction = mModFactionReaction; + writer.startRecord (ESM::REC_DIAS); state.save (writer); writer.endRecord (ESM::REC_DIAS); @@ -661,9 +663,46 @@ namespace MWDialogue iter!=state.mKnownTopics.end(); ++iter) if (store.get().search (*iter)) mKnownTopics.insert (std::make_pair (*iter, true)); + + mModFactionReaction = state.mModFactionReaction; } } + void DialogueManager::modFactionReaction(const std::string &faction1, const std::string &faction2, int diff) + { + std::string fact1 = Misc::StringUtils::lowerCase(faction1); + std::string fact2 = Misc::StringUtils::lowerCase(faction2); + + // Make sure the factions exist + MWBase::Environment::get().getWorld()->getStore().get().find(fact1); + MWBase::Environment::get().getWorld()->getStore().get().find(fact2); + + std::map& map = mModFactionReaction[fact1]; + if (map.find(fact2) == map.end()) + map[fact2] = 0; + map[fact2] += diff; + } + + int DialogueManager::getFactionReaction(const std::string &faction1, const std::string &faction2) const + { + std::string fact1 = Misc::StringUtils::lowerCase(faction1); + std::string fact2 = Misc::StringUtils::lowerCase(faction2); + + ModFactionReactionMap::const_iterator map = mModFactionReaction.find(fact1); + int diff = 0; + if (map != mModFactionReaction.end() && map->second.find(fact2) != map->second.end()) + diff = map->second.at(fact2); + + const ESM::Faction* faction = MWBase::Environment::get().getWorld()->getStore().get().find(fact1); + + std::map::const_iterator it = faction->mReactions.begin(); + for (; it != faction->mReactions.end(); ++it) + { + if (Misc::StringUtils::ciEqual(it->first, fact2)) + return it->second + diff; + } + return diff; + } std::vector ParseHyperText(const std::string& text) { diff --git a/apps/openmw/mwdialogue/dialoguemanagerimp.hpp b/apps/openmw/mwdialogue/dialoguemanagerimp.hpp index 6cd2c75af..db0b78d59 100644 --- a/apps/openmw/mwdialogue/dialoguemanagerimp.hpp +++ b/apps/openmw/mwdialogue/dialoguemanagerimp.hpp @@ -24,6 +24,11 @@ namespace MWDialogue { std::map mDialogueMap; std::map mKnownTopics;// Those are the topics the player knows. + + // Modified faction reactions. > + typedef std::map > ModFactionReactionMap; + ModFactionReactionMap mModFactionReaction; + std::list mActorKnownTopics; Translation::Storage& mTranslationDataStorage; @@ -86,6 +91,12 @@ namespace MWDialogue virtual void write (ESM::ESMWriter& writer, Loading::Listener& progress) const; virtual void readRecord (ESM::ESMReader& reader, int32_t type); + + /// Changes faction1's opinion of faction2 by \a diff. + virtual void modFactionReaction (const std::string& faction1, const std::string& faction2, int diff); + + /// @return faction1's opinion of faction2 + virtual int getFactionReaction (const std::string& faction1, const std::string& faction2) const; }; diff --git a/apps/openmw/mwdialogue/filter.cpp b/apps/openmw/mwdialogue/filter.cpp index 3d67f3bce..d301e88aa 100644 --- a/apps/openmw/mwdialogue/filter.cpp +++ b/apps/openmw/mwdialogue/filter.cpp @@ -396,16 +396,15 @@ int MWDialogue::Filter::getSelectStructInteger (const SelectWrapper& select) con int value = 0; - const ESM::Faction& faction = - *MWBase::Environment::get().getWorld()->getStore().get().find (factionId); - MWMechanics::NpcStats& playerStats = player.getClass().getNpcStats (player); - for (std::vector::const_iterator iter (faction.mReactions.begin()); - iter!=faction.mReactions.end(); ++iter) - if (playerStats.getFactionRanks().find (iter->mFaction)!=playerStats.getFactionRanks().end()) - if (low ? iter->mReactionmReaction>value) - value = iter->mReaction; + std::map::const_iterator playerFactionIt = playerStats.getFactionRanks().begin(); + for (; playerFactionIt != playerStats.getFactionRanks().end(); ++playerFactionIt) + { + int reaction = MWBase::Environment::get().getDialogueManager()->getFactionReaction(factionId, playerFactionIt->first); + if (low ? reaction < value : reaction > value) + value = reaction; + } return value; } diff --git a/apps/openmw/mwinput/inputmanagerimp.cpp b/apps/openmw/mwinput/inputmanagerimp.cpp index cf71cc1aa..8cfe2c2b3 100644 --- a/apps/openmw/mwinput/inputmanagerimp.cpp +++ b/apps/openmw/mwinput/inputmanagerimp.cpp @@ -492,7 +492,8 @@ namespace MWInput } if (arg.keysym.sym == SDLK_x && (arg.keysym.mod & SDL_Keymod(KMOD_CTRL))) { - std::string text = edit->getTextSelection(); + // Discard color codes and other escape characters + std::string text = MyGUI::TextIterator::getOnlyText(edit->getTextSelection()); if (text.length()) { SDL_SetClipboardText(text.c_str()); @@ -504,7 +505,8 @@ namespace MWInput { if (arg.keysym.sym == SDLK_c && (arg.keysym.mod & SDL_Keymod(KMOD_CTRL))) { - std::string text = edit->getTextSelection(); + // Discard color codes and other escape characters + std::string text = MyGUI::TextIterator::getOnlyText(edit->getTextSelection()); if (text.length()) SDL_SetClipboardText(text.c_str()); } diff --git a/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp b/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp index 1ea4be843..1f9846aa7 100644 --- a/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp +++ b/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp @@ -498,27 +498,24 @@ namespace MWMechanics if (playerStats.getFactionRanks().find(npcFaction) != playerStats.getFactionRanks().end()) { - for(std::vector::const_iterator it = MWBase::Environment::get().getWorld()->getStore().get().find(npcFaction)->mReactions.begin(); - it != MWBase::Environment::get().getWorld()->getStore().get().find(npcFaction)->mReactions.end(); ++it) + if (!playerStats.getExpelled(npcFaction)) { - if(Misc::StringUtils::ciEqual(it->mFaction, npcFaction) - && !playerStats.getExpelled(it->mFaction)) - reaction = it->mReaction; + reaction = playerStats.getFactionReputation(npcFaction); + + rank = playerStats.getFactionRanks().find(npcFaction)->second; } - rank = playerStats.getFactionRanks().find(npcFaction)->second; } - else if (npcFaction != "") + else if (!npcFaction.empty()) { - for(std::vector::const_iterator it = MWBase::Environment::get().getWorld()->getStore().get().find(npcFaction)->mReactions.begin(); - it != MWBase::Environment::get().getWorld()->getStore().get().find(npcFaction)->mReactions.end();++it) + std::map::const_iterator playerFactionIt = playerStats.getFactionRanks().begin(); + for (; playerFactionIt != playerStats.getFactionRanks().end(); ++playerFactionIt) { - if(playerStats.getFactionRanks().find(Misc::StringUtils::lowerCase(it->mFaction)) != playerStats.getFactionRanks().end() ) - { - if(it->mReaction < reaction) - reaction = it->mReaction; - } + std::string itFaction = playerFactionIt->first; + + int itReaction = MWBase::Environment::get().getDialogueManager()->getFactionReaction(npcFaction, itFaction); + if (playerFactionIt == playerStats.getFactionRanks().begin() || itReaction < reaction) + reaction = itReaction; } - rank = 0; } else { diff --git a/apps/openmw/mwscript/dialogueextensions.cpp b/apps/openmw/mwscript/dialogueextensions.cpp index 047c4d92f..9dde65ab2 100644 --- a/apps/openmw/mwscript/dialogueextensions.cpp +++ b/apps/openmw/mwscript/dialogueextensions.cpp @@ -196,6 +196,45 @@ namespace MWScript } }; + class OpModFactionReaction : public Interpreter::Opcode0 + { + public: + + virtual void execute (Interpreter::Runtime& runtime) + { + std::string faction1 = runtime.getStringLiteral (runtime[0].mInteger); + runtime.pop(); + + std::string faction2 = runtime.getStringLiteral (runtime[0].mInteger); + runtime.pop(); + + int modReaction = runtime[0].mInteger; + runtime.pop(); + + MWBase::Environment::get().getDialogueManager()->modFactionReaction(faction1, faction2, modReaction); + } + }; + + class OpGetFactionReaction : public Interpreter::Opcode0 + { + public: + + virtual void execute (Interpreter::Runtime& runtime) + { + std::string faction1 = runtime.getStringLiteral (runtime[0].mInteger); + runtime.pop(); + + std::string faction2 = runtime.getStringLiteral (runtime[0].mInteger); + runtime.pop(); + + // ignore extra garbage argument + runtime.pop(); + + runtime.push(MWBase::Environment::get().getDialogueManager() + ->getFactionReaction(faction1, faction2)); + } + }; + void installOpcodes (Interpreter::Interpreter& interpreter) { @@ -215,6 +254,8 @@ namespace MWScript interpreter.installSegment5 (Compiler::Dialogue::opcodeGetReputationExplicit, new OpGetReputation); interpreter.installSegment5 (Compiler::Dialogue::opcodeSameFaction, new OpSameFaction); interpreter.installSegment5 (Compiler::Dialogue::opcodeSameFactionExplicit, new OpSameFaction); + interpreter.installSegment5 (Compiler::Dialogue::opcodeModFactionReaction, new OpModFactionReaction); + interpreter.installSegment5 (Compiler::Dialogue::opcodeGetFactionReaction, new OpGetFactionReaction); } } diff --git a/apps/openmw/mwscript/docs/vmformat.txt b/apps/openmw/mwscript/docs/vmformat.txt index bf2273b17..53c80a943 100644 --- a/apps/openmw/mwscript/docs/vmformat.txt +++ b/apps/openmw/mwscript/docs/vmformat.txt @@ -390,5 +390,7 @@ op 0x200023e: GetPcInJail op 0x200023f: GetPcTraveling op 0x2000240: onKnockout op 0x2000241: onKnockoutExplicit +op 0x2000242: ModFactionReaction +op 0x2000243: GetFactionReaction -opcodes 0x2000242-0x3ffffff unused +opcodes 0x2000244-0x3ffffff unused diff --git a/apps/openmw/mwscript/statsextensions.cpp b/apps/openmw/mwscript/statsextensions.cpp index d9c9e5e0b..8b61237a1 100644 --- a/apps/openmw/mwscript/statsextensions.cpp +++ b/apps/openmw/mwscript/statsextensions.cpp @@ -541,6 +541,9 @@ namespace MWScript runtime.pop(); } ::Misc::StringUtils::toLower(factionID); + // Make sure this faction exists + MWBase::Environment::get().getWorld()->getStore().get().find(factionID); + if(factionID != "") { MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayerPtr(); @@ -572,6 +575,9 @@ namespace MWScript runtime.pop(); } ::Misc::StringUtils::toLower(factionID); + // Make sure this faction exists + MWBase::Environment::get().getWorld()->getStore().get().find(factionID); + if(factionID != "") { MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayerPtr(); @@ -607,6 +613,9 @@ namespace MWScript runtime.pop(); } ::Misc::StringUtils::toLower(factionID); + // Make sure this faction exists + MWBase::Environment::get().getWorld()->getStore().get().find(factionID); + if(factionID != "") { MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayerPtr(); @@ -645,6 +654,9 @@ namespace MWScript } } ::Misc::StringUtils::toLower(factionID); + // Make sure this faction exists + MWBase::Environment::get().getWorld()->getStore().get().find(factionID); + MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayerPtr(); if(factionID!="") { diff --git a/apps/openmw/mwworld/physicssystem.cpp b/apps/openmw/mwworld/physicssystem.cpp index b8f0f8699..e93d9e640 100644 --- a/apps/openmw/mwworld/physicssystem.cpp +++ b/apps/openmw/mwworld/physicssystem.cpp @@ -492,7 +492,7 @@ namespace MWWorld return std::make_pair(true, ray.getPoint(len * test.second)); } - std::pair PhysicsSystem::castRay(float mouseX, float mouseY) + std::pair PhysicsSystem::castRay(float mouseX, float mouseY, Ogre::Vector3* normal) { Ogre::Ray ray = mRender.getCamera()->getCameraToViewportRay( mouseX, @@ -504,7 +504,7 @@ namespace MWWorld _from = btVector3(from.x, from.y, from.z); _to = btVector3(to.x, to.y, to.z); - std::pair result = mEngine->rayTest(_from, _to); + std::pair result = mEngine->rayTest(_from, _to, true, false, normal); if (result.first == "") return std::make_pair(false, Ogre::Vector3()); diff --git a/apps/openmw/mwworld/physicssystem.hpp b/apps/openmw/mwworld/physicssystem.hpp index 3dcd088f5..899d7144d 100644 --- a/apps/openmw/mwworld/physicssystem.hpp +++ b/apps/openmw/mwworld/physicssystem.hpp @@ -70,8 +70,9 @@ namespace MWWorld std::pair castRay(const Ogre::Vector3 &orig, const Ogre::Vector3 &dir, float len); - std::pair castRay(float mouseX, float mouseY); - ///< cast ray from the mouse, return true if it hit something and the first result (in OGRE coordinates) + std::pair castRay(float mouseX, float mouseY, Ogre::Vector3* normal = NULL); + ///< cast ray from the mouse, return true if it hit something and the first result + /// @param normal if non-NULL, the hit normal will be written there (if there is a hit) OEngine::Physic::PhysicEngine* getEngine(); diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index 435ca8b36..38edd8b8d 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -1620,25 +1620,39 @@ namespace MWWorld bool World::canPlaceObject(float cursorX, float cursorY) { - std::pair result = mPhysics->castRay(cursorX, cursorY); - - /// \todo also check if the wanted position is on a flat surface, and not e.g. against a vertical wall! + Ogre::Vector3 normal(0,0,0); + std::pair result = mPhysics->castRay(cursorX, cursorY, &normal); - if (!result.first) + if (result.first) + { + // check if the wanted position is on a flat surface, and not e.g. against a vertical wall + return (normal.angleBetween(Ogre::Vector3(0.f,0.f,1.f)).valueDegrees() < 30); + } + else return false; - return true; } Ptr World::copyObjectToCell(const Ptr &object, CellStore* cell, ESM::Position pos, bool adjustPos) { - if (object.getClass().isActor() || adjustPos) + if (!object.getClass().isActor() && adjustPos) { + // Adjust position so the location we wanted ends up in the middle of the object bounding box Ogre::Vector3 min, max; if (mPhysics->getObjectAABB(object, min, max)) { - pos.pos[0] -= (min.x + max.x) / 2; - pos.pos[1] -= (min.y + max.y) / 2; - pos.pos[2] -= min.z; + Ogre::Quaternion xr(Ogre::Radian(-pos.rot[0]), Ogre::Vector3::UNIT_X); + Ogre::Quaternion yr(Ogre::Radian(-pos.rot[1]), Ogre::Vector3::UNIT_Y); + Ogre::Quaternion zr(Ogre::Radian(-pos.rot[2]), Ogre::Vector3::UNIT_Z); + + Ogre::Vector3 adjust ( + (min.x + max.x) / 2, + (min.y + max.y) / 2, + min.z + ); + adjust = (xr*yr*zr) * adjust; + pos.pos[0] -= adjust.x; + pos.pos[1] -= adjust.y; + pos.pos[2] -= adjust.z; } } diff --git a/components/compiler/extensions0.cpp b/components/compiler/extensions0.cpp index db1ac1609..4ef638ef8 100644 --- a/components/compiler/extensions0.cpp +++ b/components/compiler/extensions0.cpp @@ -179,6 +179,8 @@ namespace Compiler opcodeGetReputationExplicit); extensions.registerFunction("samefaction", 'l', "", opcodeSameFaction, opcodeSameFactionExplicit); + extensions.registerInstruction("modfactionreaction", "ccl", opcodeModFactionReaction); + extensions.registerFunction("getfactionreaction", 'l', "ccl", opcodeGetFactionReaction); } } diff --git a/components/compiler/opcodes.hpp b/components/compiler/opcodes.hpp index 9e36cb68d..1dff04665 100644 --- a/components/compiler/opcodes.hpp +++ b/components/compiler/opcodes.hpp @@ -152,6 +152,8 @@ namespace Compiler const int opcodeGetReputationExplicit = 0x20001b2; const int opcodeSameFaction = 0x20001b5; const int opcodeSameFactionExplicit = 0x20001b6; + const int opcodeModFactionReaction = 0x2000242; + const int opcodeGetFactionReaction = 0x2000243; } namespace Gui diff --git a/components/esm/dialoguestate.cpp b/components/esm/dialoguestate.cpp index b3544c85c..14301ac19 100644 --- a/components/esm/dialoguestate.cpp +++ b/components/esm/dialoguestate.cpp @@ -8,6 +8,20 @@ void ESM::DialogueState::load (ESMReader &esm) { while (esm.isNextSub ("TOPI")) mKnownTopics.push_back (esm.getHString()); + + while (esm.isNextSub ("FACT")) + { + std::string faction = esm.getHString(); + + while (esm.isNextSub ("REAC")) + { + std::string faction2 = esm.getHString(); + int reaction; + esm.getHNT(reaction, "INTV"); + + mModFactionReaction[faction][faction2] = reaction; + } + } } void ESM::DialogueState::save (ESMWriter &esm) const @@ -16,6 +30,18 @@ void ESM::DialogueState::save (ESMWriter &esm) const iter!=mKnownTopics.end(); ++iter) { esm.writeHNString ("TOPI", *iter); + } + + for (std::map >::const_iterator iter = mModFactionReaction.begin(); + iter != mModFactionReaction.end(); ++iter) + { + esm.writeHNString ("FACT", iter->first); + for (std::map::const_iterator reactIter = iter->second.begin(); + reactIter != iter->second.end(); ++reactIter) + { + esm.writeHNString ("REAC", reactIter->first); + esm.writeHNT ("INTV", reactIter->second); + } } -} \ No newline at end of file +} diff --git a/components/esm/dialoguestate.hpp b/components/esm/dialoguestate.hpp index 9aa9eaefd..5e5f602a3 100644 --- a/components/esm/dialoguestate.hpp +++ b/components/esm/dialoguestate.hpp @@ -3,6 +3,7 @@ #include #include +#include namespace ESM { @@ -15,9 +16,11 @@ namespace ESM { std::vector mKnownTopics; + std::map > mModFactionReaction; + void load (ESMReader &esm); void save (ESMWriter &esm) const; }; } -#endif \ No newline at end of file +#endif diff --git a/components/esm/loadfact.cpp b/components/esm/loadfact.cpp index 84be21938..0924efb17 100644 --- a/components/esm/loadfact.cpp +++ b/components/esm/loadfact.cpp @@ -44,10 +44,10 @@ void Faction::load(ESMReader &esm) // Read faction response values while (esm.hasMoreSubs()) { - Reaction r; - r.mFaction = esm.getHNString("ANAM"); - esm.getHNT(r.mReaction, "INTV"); - mReactions.push_back(r); + std::string faction = esm.getHNString("ANAM"); + int reaction; + esm.getHNT(reaction, "INTV"); + mReactions[faction] = reaction; } } void Faction::save(ESMWriter &esm) const @@ -64,10 +64,10 @@ void Faction::save(ESMWriter &esm) const esm.writeHNT("FADT", mData, 240); - for (std::vector::const_iterator it = mReactions.begin(); it != mReactions.end(); ++it) + for (std::map::const_iterator it = mReactions.begin(); it != mReactions.end(); ++it) { - esm.writeHNString("ANAM", it->mFaction); - esm.writeHNT("INTV", it->mReaction); + esm.writeHNString("ANAM", it->first); + esm.writeHNT("INTV", it->second); } } diff --git a/components/esm/loadfact.hpp b/components/esm/loadfact.hpp index 9c257e068..75e30a5bf 100644 --- a/components/esm/loadfact.hpp +++ b/components/esm/loadfact.hpp @@ -2,7 +2,7 @@ #define OPENMW_ESM_FACT_H #include -#include +#include namespace ESM { @@ -53,13 +53,8 @@ struct Faction FADTstruct mData; - struct Reaction - { - std::string mFaction; - int mReaction; - }; - - std::vector mReactions; + // + std::map mReactions; // Name of faction ranks (may be empty for NPC factions) std::string mRanks[10]; diff --git a/libs/openengine/bullet/physic.cpp b/libs/openengine/bullet/physic.cpp index 6646ce273..235300b43 100644 --- a/libs/openengine/bullet/physic.cpp +++ b/libs/openengine/bullet/physic.cpp @@ -677,7 +677,7 @@ namespace Physic { } - std::pair PhysicEngine::rayTest(btVector3& from,btVector3& to,bool raycastingObjectOnly,bool ignoreHeightMap) + std::pair PhysicEngine::rayTest(btVector3& from,btVector3& to,bool raycastingObjectOnly,bool ignoreHeightMap, Ogre::Vector3* normal) { std::string name = ""; float d = -1; @@ -694,7 +694,11 @@ namespace Physic if (resultCallback1.hasHit()) { name = static_cast(*resultCallback1.m_collisionObject).mName; - d = resultCallback1.m_closestHitFraction;; + d = resultCallback1.m_closestHitFraction; + if (normal) + *normal = Ogre::Vector3(resultCallback1.m_hitNormalWorld.x(), + resultCallback1.m_hitNormalWorld.y(), + resultCallback1.m_hitNormalWorld.z()); } return std::pair(name,d); diff --git a/libs/openengine/bullet/physic.hpp b/libs/openengine/bullet/physic.hpp index 16eb45306..803986d5b 100644 --- a/libs/openengine/bullet/physic.hpp +++ b/libs/openengine/bullet/physic.hpp @@ -308,8 +308,10 @@ namespace Physic /** * Return the closest object hit by a ray. If there are no objects, it will return ("",-1). + * If \a normal is non-NULL, the hit normal will be written there (if there is a hit) */ - std::pair rayTest(btVector3& from,btVector3& to,bool raycastingObjectOnly = true,bool ignoreHeightMap = false); + std::pair rayTest(btVector3& from,btVector3& to,bool raycastingObjectOnly = true, + bool ignoreHeightMap = false, Ogre::Vector3* normal = NULL); /** * Return all objects hit by a ray.