diff --git a/apps/openmw/mwbase/world.hpp b/apps/openmw/mwbase/world.hpp index cdfdfc358a..7432db734b 100644 --- a/apps/openmw/mwbase/world.hpp +++ b/apps/openmw/mwbase/world.hpp @@ -392,6 +392,7 @@ namespace MWBase virtual bool isFlying(const MWWorld::Ptr &ptr) const = 0; virtual bool isSlowFalling(const MWWorld::Ptr &ptr) const = 0; virtual bool isSwimming(const MWWorld::Ptr &object) const = 0; + virtual bool isWading(const MWWorld::Ptr &object) const = 0; ///Is the head of the creature underwater? virtual bool isSubmerged(const MWWorld::Ptr &object) const = 0; virtual bool isUnderwater(const MWWorld::CellStore* cell, const Ogre::Vector3 &pos) const = 0; diff --git a/apps/openmw/mwclass/creature.cpp b/apps/openmw/mwclass/creature.cpp index 2146fdfdea..e21676f108 100644 --- a/apps/openmw/mwclass/creature.cpp +++ b/apps/openmw/mwclass/creature.cpp @@ -348,9 +348,9 @@ namespace MWClass // Self defense bool setOnPcHitMe = true; // Note OnPcHitMe is not set for friendly hits. - if ((canWalk(ptr) || canFly(ptr) || canSwim(ptr)) // No retaliation for totally static creatures - // (they have no movement or attacks anyway) - && !attacker.isEmpty()) + + // No retaliation for totally static creatures (they have no movement or attacks anyway) + if (isMobile(ptr) && !attacker.isEmpty()) { setOnPcHitMe = MWBase::Environment::get().getMechanicsManager()->actorAttacked(ptr, attacker); } diff --git a/apps/openmw/mwmechanics/actors.cpp b/apps/openmw/mwmechanics/actors.cpp index c0fc806925..0a25ddd42e 100644 --- a/apps/openmw/mwmechanics/actors.cpp +++ b/apps/openmw/mwmechanics/actors.cpp @@ -309,8 +309,8 @@ namespace MWMechanics // pure water creatures won't try to fight with the target on the ground // except that creature is already hostile if ((againstPlayer || !creatureStats.getAiSequence().isInCombat()) - && ((actor1.getClass().canSwim(actor1) && !actor1.getClass().canWalk(actor1) // pure water creature - && !MWBase::Environment::get().getWorld()->isSwimming(actor2)) + && ((actor1.getClass().isPureWaterCreature(actor1) + && !MWBase::Environment::get().getWorld()->isWading(actor2)) || (!actor1.getClass().canSwim(actor1) && MWBase::Environment::get().getWorld()->isSwimming(actor2)))) // creature can't swim to target return; diff --git a/apps/openmw/mwmechanics/aicombat.cpp b/apps/openmw/mwmechanics/aicombat.cpp index 5d04705544..ce5963a917 100644 --- a/apps/openmw/mwmechanics/aicombat.cpp +++ b/apps/openmw/mwmechanics/aicombat.cpp @@ -209,7 +209,7 @@ namespace MWMechanics if (!actorClass.isNpc() && // 1. pure water creature and Player moved out of water ((target == world->getPlayerPtr() && - actorClass.canSwim(actor) && !actor.getClass().canWalk(actor) && !world->isSwimming(target)) + actorClass.isPureWaterCreature(actor) && !world->isWading(target)) // 2. creature can't swim to target || (!actorClass.canSwim(actor) && world->isSwimming(target)))) { diff --git a/apps/openmw/mwworld/class.cpp b/apps/openmw/mwworld/class.cpp index 61c597517a..939b72ddb7 100644 --- a/apps/openmw/mwworld/class.cpp +++ b/apps/openmw/mwworld/class.cpp @@ -383,6 +383,16 @@ namespace MWWorld return false; } + bool Class::isPureWaterCreature(const MWWorld::Ptr& ptr) const + { + return canSwim(ptr) && !canWalk(ptr); + } + + bool Class::isMobile(const MWWorld::Ptr& ptr) const + { + return canSwim(ptr) || canWalk(ptr) || canFly(ptr); + } + int Class::getSkill(const MWWorld::Ptr& ptr, int skill) const { throw std::runtime_error("class does not support skills"); diff --git a/apps/openmw/mwworld/class.hpp b/apps/openmw/mwworld/class.hpp index cc18d830cc..b738cdd445 100644 --- a/apps/openmw/mwworld/class.hpp +++ b/apps/openmw/mwworld/class.hpp @@ -308,6 +308,8 @@ namespace MWWorld virtual bool canFly(const MWWorld::Ptr& ptr) const; virtual bool canSwim(const MWWorld::Ptr& ptr) const; virtual bool canWalk(const MWWorld::Ptr& ptr) const; + bool isPureWaterCreature(const MWWorld::Ptr& ptr) const; + bool isMobile(const MWWorld::Ptr& ptr) const; virtual int getSkill(const MWWorld::Ptr& ptr, int skill) const; diff --git a/apps/openmw/mwworld/physicssystem.cpp b/apps/openmw/mwworld/physicssystem.cpp index 3a7aa04903..5b712648c2 100644 --- a/apps/openmw/mwworld/physicssystem.cpp +++ b/apps/openmw/mwworld/physicssystem.cpp @@ -281,7 +281,7 @@ namespace MWWorld // Early-out for totally static creatures // (Not sure if gravity should still apply?) - if (!ptr.getClass().canWalk(ptr) && !ptr.getClass().canFly(ptr) && !ptr.getClass().canSwim(ptr)) + if (!ptr.getClass().isMobile(ptr)) return position; OEngine::Physic::PhysicActor *physicActor = engine->getCharacter(ptr.getRefData().getHandle()); @@ -434,7 +434,7 @@ namespace MWWorld if(result) { // don't let pure water creatures move out of water after stepMove - if((ptr.getClass().canSwim(ptr) && !ptr.getClass().canWalk(ptr)) + if (ptr.getClass().isPureWaterCreature(ptr) && newPosition.z > (waterlevel - halfExtents.z * 0.5)) newPosition = oldPosition; } diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index a939a6db91..f9642226bb 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -1978,25 +1978,36 @@ namespace MWWorld bool World::isSubmerged(const MWWorld::Ptr &object) const { - const float *fpos = object.getRefData().getPosition().pos; - Ogre::Vector3 pos(fpos[0], fpos[1], fpos[2]); - - const OEngine::Physic::PhysicActor *actor = mPhysEngine->getCharacter(object.getRefData().getHandle()); - if(actor) pos.z += 1.85*actor->getHalfExtents().z; - - return isUnderwater(object.getCell(), pos); + const float neckDeep = 1.85f; + return isUnderwater(object, neckDeep); } bool World::isSwimming(const MWWorld::Ptr &object) const { /// \todo add check ifActor() - only actors can swim + /// \fixme 3/4ths submerged? + return isUnderwater(object, 1.5f); + } + + bool + World::isWading(const MWWorld::Ptr &object) const + { + const float kneeDeep = 0.5f; + return isUnderwater(object, kneeDeep); + } + + bool + World::isUnderwater(const MWWorld::Ptr &object, const float heightRatio) const + { const float *fpos = object.getRefData().getPosition().pos; Ogre::Vector3 pos(fpos[0], fpos[1], fpos[2]); - /// \fixme 3/4ths submerged? const OEngine::Physic::PhysicActor *actor = mPhysEngine->getCharacter(object.getRefData().getHandle()); - if(actor) pos.z += actor->getHalfExtents().z * 1.5; + if (actor) + { + pos.z += heightRatio*actor->getHalfExtents().z; + } return isUnderwater(object.getCell(), pos); } diff --git a/apps/openmw/mwworld/worldimp.hpp b/apps/openmw/mwworld/worldimp.hpp index 5810fe42fa..dfaa9f7894 100644 --- a/apps/openmw/mwworld/worldimp.hpp +++ b/apps/openmw/mwworld/worldimp.hpp @@ -139,6 +139,9 @@ namespace MWWorld void loadContentFiles(const Files::Collections& fileCollections, const std::vector& content, ContentLoader& contentLoader); + bool isUnderwater(const MWWorld::Ptr &object, const float heightRatio) const; + ///< helper function for implementing isSwimming(), isSubmerged(), isWading() + bool mTeleportEnabled; bool mLevitationEnabled; bool mGoToJail; @@ -454,6 +457,7 @@ namespace MWWorld virtual bool isSubmerged(const MWWorld::Ptr &object) const; virtual bool isSwimming(const MWWorld::Ptr &object) const; virtual bool isUnderwater(const MWWorld::CellStore* cell, const Ogre::Vector3 &pos) const; + virtual bool isWading(const MWWorld::Ptr &object) const; virtual bool isOnGround(const MWWorld::Ptr &ptr) const; virtual void togglePOV() {