From 7fe2f86d06237a6f9d8f4c4289cec8e0143fc6b7 Mon Sep 17 00:00:00 2001 From: dteviot Date: Fri, 9 Jan 2015 21:40:53 +1300 Subject: [PATCH] Slaughter fish attacks when player only knee deep in water (Fixes #2076) --- apps/openmw/mwbase/world.hpp | 1 + apps/openmw/mwclass/creature.cpp | 6 +++--- apps/openmw/mwmechanics/actors.cpp | 4 ++-- apps/openmw/mwmechanics/aicombat.cpp | 2 +- apps/openmw/mwworld/class.cpp | 10 ++++++++++ apps/openmw/mwworld/class.hpp | 2 ++ apps/openmw/mwworld/physicssystem.cpp | 4 ++-- apps/openmw/mwworld/worldimp.cpp | 27 ++++++++++++++++++--------- apps/openmw/mwworld/worldimp.hpp | 4 ++++ 9 files changed, 43 insertions(+), 17 deletions(-) diff --git a/apps/openmw/mwbase/world.hpp b/apps/openmw/mwbase/world.hpp index cdfdfc358..7432db734 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 2146fdfde..e21676f10 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 c0fc80692..0a25ddd42 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 5d0470554..ce5963a91 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 61c597517..939b72ddb 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 cc18d830c..b738cdd44 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 3a7aa0490..5b712648c 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 a939a6db9..b99b4ff24 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -1978,25 +1978,34 @@ 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); + return isUnderwater(object, 1.85f); } 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 + { + return isUnderwater(object, 0.5f); + } + + bool + World::isUnderwater(const MWWorld::Ptr &object, const float hightRatio) 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 += hightRatio*actor->getHalfExtents().z; + } return isUnderwater(object.getCell(), pos); } diff --git a/apps/openmw/mwworld/worldimp.hpp b/apps/openmw/mwworld/worldimp.hpp index 5810fe42f..708a9abc3 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 hightRatio) 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() {