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 #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 #4432: Guards behaviour is incorrect if they do not have AI packages
Bug #4433: Guard behaviour is incorrect with Alarm = 0 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 #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 #4345: Add equivalents for the command line commands to Launcher
Feature #4444: Per-group KF-animation files support Feature #4444: Per-group KF-animation files support

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

@ -120,6 +120,9 @@ bool MWMechanics::AiPackage::pathTo(const MWWorld::Ptr& actor, const ESM::Pathgr
if (!isDestReached && mTimer > AI_REACTION_TIME) if (!isDestReached && mTimer > AI_REACTION_TIME)
{ {
if (actor.getClass().isBipedal(actor))
openDoors(actor);
bool wasShortcutting = mIsShortcutting; bool wasShortcutting = mIsShortcutting;
bool destInLOS = false; bool destInLOS = false;
@ -209,41 +212,10 @@ void MWMechanics::AiPackage::evadeObstacles(const MWWorld::Ptr& actor, float dur
// first check if obstacle is a door // first check if obstacle is a door
static float distance = MWBase::Environment::get().getWorld()->getMaxActivationDistance(); static float distance = MWBase::Environment::get().getWorld()->getMaxActivationDistance();
MWWorld::Ptr door = getNearbyDoor(actor, distance); const MWWorld::Ptr door = getNearbyDoor(actor, distance);
if (door != MWWorld::Ptr() && actor.getClass().isBipedal(actor)) if (!door.isEmpty() && actor.getClass().isBipedal(actor))
{ {
// note: AiWander currently does not open doors openDoors(actor);
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);
}
} }
else 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 MWMechanics::PathgridGraph& MWMechanics::AiPackage::getPathGridGraph(const MWWorld::CellStore *cell)
{ {
const ESM::CellId& id = cell->getCell()->getCellId(); 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); 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 evadeObstacles(const MWWorld::Ptr& actor, float duration, const ESM::Position& pos);
void openDoors(const MWWorld::Ptr& actor);
const PathgridGraph& getPathGridGraph(const MWWorld::CellStore* cell); const PathgridGraph& getPathGridGraph(const MWWorld::CellStore* cell);

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

@ -17,7 +17,7 @@ namespace MWMechanics
/// Returns door pointer within range. No guarantee is given as to which one /// Returns door pointer within range. No guarantee is given as to which one
/** \return Pointer to the door, or NULL if none exists **/ /** \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 class ObstacleCheck
{ {

@ -47,7 +47,7 @@ namespace
for (typename MWWorld::CellRefList<T>::List::iterator iter (list.mList.begin()); for (typename MWWorld::CellRefList<T>::List::iterator iter (list.mList.begin());
iter!=list.mList.end(); ++iter) 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); MWWorld::Ptr ptr (&*iter, 0);
ptr.setContainerStore (store); ptr.setContainerStore (store);

Loading…
Cancel
Save