AI: try to open doors every AI_REACTION_TIME seconds (bug #4454)

0.6.3
Andrei Kortunov 7 years ago
parent da37585a8e
commit 81b78a82e8

@ -24,6 +24,7 @@
Bug #4429: [Windows] Error on build INSTALL.vcxproj project (debug) with cmake 3.7.2
Bug #4432: Guards behaviour is incorrect if they do not have AI packages
Bug #4433: Guard behaviour is incorrect with Alarm = 0
Bug #4454: AI opens doors too slow
Feature #4324: Add CFBundleIdentifier in Info.plist to allow for macOS function key shortcuts
Feature #4345: Add equivalents for the command line commands to Launcher
Feature #4444: Per-group KF-animation files support

@ -139,24 +139,21 @@ namespace MWClass
const std::string trapActivationSound = "Disarm Trap Fail";
MWWorld::Ptr player = MWBase::Environment::get().getWorld ()->getPlayerPtr();
const MWWorld::InventoryStore& invStore = player.getClass().getInventoryStore(player);
MWWorld::InventoryStore& invStore = player.getClass().getInventoryStore(player);
bool isLocked = ptr.getCellRef().getLockLevel() > 0;
bool isTrapped = !ptr.getCellRef().getTrap().empty();
bool hasKey = false;
std::string keyName;
// make key id lowercase
std::string keyId = ptr.getCellRef().getKey();
Misc::StringUtils::lowerCaseInPlace(keyId);
for (MWWorld::ConstContainerStoreIterator it = invStore.cbegin(); it != invStore.cend(); ++it)
const std::string keyId = ptr.getCellRef().getKey();
if (!keyId.empty())
{
std::string refId = it->getCellRef().getRefId();
Misc::StringUtils::lowerCaseInPlace(refId);
if (refId == keyId)
MWWorld::Ptr keyPtr = invStore.search(keyId);
if (!keyPtr.isEmpty())
{
hasKey = true;
keyName = it->getClass().getName(*it);
keyName = keyPtr.getClass().getName(keyPtr);
}
}

@ -114,7 +114,7 @@ namespace MWClass
const std::string lockedSound = "LockedDoor";
const std::string trapActivationSound = "Disarm Trap Fail";
const MWWorld::ContainerStore &invStore = actor.getClass().getContainerStore(actor);
MWWorld::ContainerStore &invStore = actor.getClass().getContainerStore(actor);
bool isLocked = ptr.getCellRef().getLockLevel() > 0;
bool isTrapped = !ptr.getCellRef().getTrap().empty();
@ -135,21 +135,14 @@ namespace MWClass
animation->addSpellCastGlow(effect, 1); // 1 second glow to match the time taken for a door opening or closing
}
// make key id lowercase
std::string keyId = ptr.getCellRef().getKey();
const std::string keyId = ptr.getCellRef().getKey();
if (!keyId.empty())
{
Misc::StringUtils::lowerCaseInPlace(keyId);
for (MWWorld::ConstContainerStoreIterator it = invStore.cbegin(); it != invStore.cend(); ++it)
MWWorld::Ptr keyPtr = invStore.search(keyId);
if (!keyPtr.isEmpty())
{
std::string refId = it->getCellRef().getRefId();
Misc::StringUtils::lowerCaseInPlace(refId);
if (refId == keyId)
{
hasKey = true;
keyName = it->getClass().getName(*it);
break;
}
hasKey = true;
keyName = keyPtr.getClass().getName(keyPtr);
}
}

@ -120,6 +120,9 @@ bool MWMechanics::AiPackage::pathTo(const MWWorld::Ptr& actor, const ESM::Pathgr
if (!isDestReached && mTimer > AI_REACTION_TIME)
{
if (actor.getClass().isBipedal(actor))
openDoors(actor);
bool wasShortcutting = mIsShortcutting;
bool destInLOS = false;
@ -209,41 +212,10 @@ void MWMechanics::AiPackage::evadeObstacles(const MWWorld::Ptr& actor, float dur
// first check if obstacle is a door
static float distance = MWBase::Environment::get().getWorld()->getMaxActivationDistance();
MWWorld::Ptr door = getNearbyDoor(actor, distance);
if (door != MWWorld::Ptr() && actor.getClass().isBipedal(actor))
const MWWorld::Ptr door = getNearbyDoor(actor, distance);
if (!door.isEmpty() && actor.getClass().isBipedal(actor))
{
// note: AiWander currently does not open doors
if (getTypeId() != TypeIdWander && !door.getCellRef().getTeleport() && door.getClass().getDoorState(door) == 0)
{
if ((door.getCellRef().getTrap().empty() && door.getCellRef().getLockLevel() <= 0 ))
{
MWBase::Environment::get().getWorld()->activate(door, actor);
return;
}
std::string keyId = door.getCellRef().getKey();
if (keyId.empty())
return;
bool hasKey = false;
const MWWorld::ContainerStore &invStore = actor.getClass().getContainerStore(actor);
// make key id lowercase
Misc::StringUtils::lowerCaseInPlace(keyId);
for (MWWorld::ConstContainerStoreIterator it = invStore.cbegin(); it != invStore.cend(); ++it)
{
std::string refId = it->getCellRef().getRefId();
Misc::StringUtils::lowerCaseInPlace(refId);
if (refId == keyId)
{
hasKey = true;
break;
}
}
if (hasKey)
MWBase::Environment::get().getWorld()->activate(door, actor);
}
openDoors(actor);
}
else
{
@ -251,6 +223,35 @@ void MWMechanics::AiPackage::evadeObstacles(const MWWorld::Ptr& actor, float dur
}
}
void MWMechanics::AiPackage::openDoors(const MWWorld::Ptr& actor)
{
static float distance = MWBase::Environment::get().getWorld()->getMaxActivationDistance();
const MWWorld::Ptr door = getNearbyDoor(actor, distance);
if (door == MWWorld::Ptr())
return;
// note: AiWander currently does not open doors
if (getTypeId() != TypeIdWander && !door.getCellRef().getTeleport() && door.getClass().getDoorState(door) == 0)
{
if ((door.getCellRef().getTrap().empty() && door.getCellRef().getLockLevel() <= 0 ))
{
MWBase::Environment::get().getWorld()->activate(door, actor);
return;
}
const std::string keyId = door.getCellRef().getKey();
if (keyId.empty())
return;
MWWorld::ContainerStore &invStore = actor.getClass().getContainerStore(actor);
MWWorld::Ptr keyPtr = invStore.search(keyId);
if (!keyPtr.isEmpty())
MWBase::Environment::get().getWorld()->activate(door, actor);
}
}
const MWMechanics::PathgridGraph& MWMechanics::AiPackage::getPathGridGraph(const MWWorld::CellStore *cell)
{
const ESM::CellId& id = cell->getCell()->getCellId();

@ -123,6 +123,7 @@ namespace MWMechanics
virtual bool doesPathNeedRecalc(const ESM::Pathgrid::Point& newDest, const MWWorld::CellStore* currentCell);
void evadeObstacles(const MWWorld::Ptr& actor, float duration, const ESM::Position& pos);
void openDoors(const MWWorld::Ptr& actor);
const PathgridGraph& getPathGridGraph(const MWWorld::CellStore* cell);

@ -26,13 +26,13 @@ namespace MWMechanics
bool proximityToDoor(const MWWorld::Ptr& actor, float minDist)
{
if(getNearbyDoor(actor, minDist)!=MWWorld::Ptr())
return true;
else
if(getNearbyDoor(actor, minDist).isEmpty())
return false;
else
return true;
}
MWWorld::Ptr getNearbyDoor(const MWWorld::Ptr& actor, float minDist)
const MWWorld::Ptr getNearbyDoor(const MWWorld::Ptr& actor, float minDist)
{
MWWorld::CellStore *cell = actor.getCell();
@ -50,6 +50,16 @@ namespace MWMechanics
const MWWorld::LiveCellRef<ESM::Door>& ref = *it;
osg::Vec3f doorPos(ref.mData.getPosition().asVec3());
// FIXME: cast
const MWWorld::Ptr doorPtr = MWWorld::Ptr(&const_cast<MWWorld::LiveCellRef<ESM::Door> &>(ref), actor.getCell());
int doorState = doorPtr.getClass().getDoorState(doorPtr);
float doorRot = ref.mData.getPosition().rot[2] - doorPtr.getCellRef().getPosition().rot[2];
if (doorState != 0 || doorRot != 0)
continue; // the door is already opened/opening
doorPos.z() = 0;
float angle = std::acos(actorDir * (doorPos - pos) / (actorDir.length() * (doorPos - pos).length()));
@ -62,8 +72,7 @@ namespace MWMechanics
if ((pos - doorPos).length2() > minDist*minDist)
continue;
// FIXME cast
return MWWorld::Ptr(&const_cast<MWWorld::LiveCellRef<ESM::Door> &>(ref), actor.getCell()); // found, stop searching
return doorPtr; // found, stop searching
}
return MWWorld::Ptr(); // none found

@ -17,7 +17,7 @@ namespace MWMechanics
/// Returns door pointer within range. No guarantee is given as to which one
/** \return Pointer to the door, or NULL if none exists **/
MWWorld::Ptr getNearbyDoor(const MWWorld::Ptr& actor, float minDist);
const MWWorld::Ptr getNearbyDoor(const MWWorld::Ptr& actor, float minDist);
class ObstacleCheck
{

@ -47,7 +47,7 @@ namespace
for (typename MWWorld::CellRefList<T>::List::iterator iter (list.mList.begin());
iter!=list.mList.end(); ++iter)
{
if (Misc::StringUtils::ciEqual(iter->mBase->mId, id2))
if (Misc::StringUtils::ciEqual(iter->mBase->mId, id2) && iter->mData.getCount())
{
MWWorld::Ptr ptr (&*iter, 0);
ptr.setContainerStore (store);

Loading…
Cancel
Save