From 3dfd08cf2de36dd081c25a75b1c637e9ede987ea Mon Sep 17 00:00:00 2001 From: cc9cii Date: Sun, 20 Apr 2014 08:31:02 +1000 Subject: [PATCH] Cleanup and little tweaking. --- apps/openmw/mwmechanics/aicombat.cpp | 235 ++++++++++++--------------- apps/openmw/mwmechanics/aicombat.hpp | 5 +- apps/openmw/mwmechanics/pathgrid.hpp | 2 + apps/openmw/mwworld/cellstore.hpp | 2 +- 4 files changed, 107 insertions(+), 137 deletions(-) diff --git a/apps/openmw/mwmechanics/aicombat.cpp b/apps/openmw/mwmechanics/aicombat.cpp index e94899359..335bc8702 100644 --- a/apps/openmw/mwmechanics/aicombat.cpp +++ b/apps/openmw/mwmechanics/aicombat.cpp @@ -35,7 +35,7 @@ namespace namespace MWMechanics { - static const float DOOR_CHECK_INTERVAL = 1.5f; + static const float DOOR_CHECK_INTERVAL = 1.5f; // same as AiWander // NOTE: MIN_DIST_TO_DOOR_SQUARED is defined in obstacle.hpp AiCombat::AiCombat(const MWWorld::Ptr& actor) : @@ -50,70 +50,49 @@ namespace MWMechanics mBackOffDoor(false), mRotate(false), mMovement(), + mCell(NULL), mDoorIter(actor.getCell()->get().mList.end()), - mDoors(actor.getCell()->get().mList), + mDoors(actor.getCell()->get()), mDoorCheckDuration(0), mTargetAngle(0) { } /* - * The 'pursuit' part of AiCombat now has some memory to allow backtracking. - * The intention is to allow actors to detect being 'stuck' somewhere, whether - * in a river or facing a door, to go back to a known 'good' position. - * - * Each actor goes through these states of movement once alerted and an AiCombat - * package is queued (FIXME: below is a DRAFT proposal only): - * - * - Maybe remember the starting position so that the actor can return if - * lose sight of the target? Last Known Target Location Tracking - keep track - * of target positions every sec, paired with actor's location at the time - * - * - Get to the target if far away (need path finding), how close depends on - * the current best (selected?) weapon. As the actor moves, some breadcrumb - * is left (e.g. every second store a position in a FIFO) so that the actor - * can back track if necessary. - * - * - If the actor gets stuck (need a way of detecting this) then decide what - * to do next. For example, if next to a door then maybe back track one or - * two positions and check LOS of the target every x frames (reaction time?). - * Or maybe back track then look for a new path. - * - * - Once in weapon range, may need a strategy to get to the target for a - * strike (maybe there are others nearby attacking the same target). - * - * * Current AiCombat movement states (as of 0.29.0), ignoring the details of the * attack states such as CombatMove, Strike and ReadyToAttack: * - * +-----(within strike range)----->attack--(beyond strike range)-->follow - * | | ^ | | - * | | | | | - * pursue<----(beyond follow range)-----+ +----(within strike range)---+ | - * ^ | - * | | - * +--------------------------(beyond follow range)--------------------+ + * +----(within strike range)----->attack--(beyond strike range)-->follow + * | | ^ | | + * | | | | | + * pursue<---(beyond follow range)-----+ +----(within strike range)---+ | + * ^ | + * | | + * +-------------------------(beyond follow range)--------------------+ * * - * Below diagram is high level only, FIXME: code detail may be different: + * Below diagram is high level only, the code detail is a little different + * (but including those detail will just complicate the diagram w/o adding much) * - * +-----------(same)-------------->attack---------(same)---------->follow - * | |^^ | | - * | ||| | | - * | +--(same)-----------------+|+----------(same)------------+ | - * | | | in range | - * | | too far | | - * | | +---------------got hit or LOS<---+ | - * | <----+ | | | - * pursue<---------+ door | | - * ^^ <--> maybe stuck, check --------------> back up and wait | - * || | ^ | | ^ | | - * || | | | stuck | | | waited | - * || +---+ | +---+ | too long | - * || backtrack | | | - * |+----------------------+ go back? <-----------+ | - * | | - * +----------------------------(same)---------------------------------+ + * +----------(same)-------------->attack---------(same)---------->follow + * | |^^ ||| + * | ||| ||| + * | +--(same)-----------------+|+----------(same)------------+|| + * | | | || + * | | | (in range) || + * | <---+ (too far) | || + * pursue<-------------------------[door open]<-----+ || + * ^^^ | || + * ||| | || + * ||+----------evade-----+ | || + * || | [closed door] | || + * |+----> maybe stuck, check --------------> back up, check door || + * | ^ | ^ | ^ || + * | | | | | | || + * | | +---+ +---+ || + * | +-------------------------------------------------------+| + * | | + * +---------------------------(same)---------------------------------+ * * FIXME: * @@ -124,26 +103,6 @@ namespace MWMechanics * * Use the Observer Pattern to co-ordinate attacks, provide intelligence on * whether the target was hit, etc. - * - * TODO: - * - * Auto-generate large cubes or squares as a poor-man's navmesh? Many - * external cells do not have any pathgrids, and certainly none for flying - * or swimming. - * - * - * Called from: (check Doxygen as this comment could be out of date) - * - * OMW::Engine::go() | - * Ogre::Root::renderOneFrame() | - * Ogre::Root::... | ... detail omitted - * Ogre::Root::fireFrameRenderingQueued() | - * OMW::Engine::frameRenderingQueued() | virtual Ogre::FrameListener - * MWMechanics::MechanicsManager::update() | - * MWMechanics::Actors::update() | - * MWMechanics::Actors::updateActor() | - * MWMechanics::AiSequence::execute() | from priority queue mPackages - * MWMechanics::AiCombat::execute() | virtual MWMechanics::AiPackage */ bool AiCombat::execute (const MWWorld::Ptr& actor,float duration) { @@ -175,7 +134,6 @@ namespace MWMechanics mRotate = false; } - mTimerAttack -= duration; actor.getClass().getCreatureStats(actor).setAttackingOrSpell(mStrike); @@ -190,6 +148,12 @@ namespace MWMechanics mTimerReact = 0; + bool cellChange = mCell && (actor.getCell() != mCell); + if(!mCell || cellChange) + { + mCell = actor.getCell(); + } + //actual attacking logic //TODO: Some skills affect period of strikes.For berserk-like style period ~ 0.25f float attackPeriod = 1.0f; @@ -298,7 +262,6 @@ namespace MWMechanics * (the shortcut really only applies to cells where pathgrids are * available, since the default path without pathgrids is direct to * target even if LOS is not achieved) - * */ float rangeMelee; float rangeCloseUp; @@ -395,55 +358,6 @@ namespace MWMechanics mMovement.mPosition[1] = 1; mReadyToAttack = false; - - // remember that this section gets updated every tReaction, which is - // currently hard coded at 250ms or 1/4 second - if(mObstacleCheck.check(actor, tReaction)) // true if evasive action needed - { - std::cout<<"found obstacle"<getCell()->isExterior()) - { - // Check all the doors in this cell - mDoors = cell->get().mList; // update list member - mDoorIter = mDoors.begin(); - Ogre::Vector3 actorPos(actor.getRefData().getPosition().pos); - for (; mDoorIter != mDoors.end(); ++mDoorIter) - { - MWWorld::LiveCellRef& ref = *mDoorIter; - if(actorPos.squaredDistance(Ogre::Vector3(ref.mRef.mPos.pos)) < 1.3*1.3*MIN_DIST_TO_DOOR_SQUARED && - ref.mData.getLocalRotation().rot[2] == 0) - { - std::cout<<"closed door id \""< rangeMelee) @@ -476,26 +390,77 @@ namespace MWMechanics } } + // NOTE: This section gets updated every tReaction, which is currently hard + // coded at 250ms or 1/4 second + // + // TODO: Add a parameter to vary DURATION_SAME_SPOT? + if((distBetween > rangeMelee || mFollowTarget) && + mObstacleCheck.check(actor, tReaction)) // check if evasive action needed + { + // first check if we're walking into a door + mDoorCheckDuration += 1.0f; // add time taken for obstacle check + MWWorld::CellStore *cell = actor.getCell(); + if(mDoorCheckDuration >= DOOR_CHECK_INTERVAL && !cell->getCell()->isExterior()) + { + mDoorCheckDuration = 0; + // Check all the doors in this cell + mDoors = cell->get(); // update + mDoorIter = mDoors.mList.begin(); + Ogre::Vector3 actorPos(actor.getRefData().getPosition().pos); + for (; mDoorIter != mDoors.mList.end(); ++mDoorIter) + { + MWWorld::LiveCellRef& ref = *mDoorIter; + float minSqr = 1.3*1.3*MIN_DIST_TO_DOOR_SQUARED; // for legibility + if(actorPos.squaredDistance(Ogre::Vector3(ref.mRef.mPos.pos)) < minSqr && + ref.mData.getLocalRotation().rot[2] < 0.4f) // even small opening + { + //std::cout<<"closed door id \""<& ref = *mDoorIter; Ogre::Vector3 actorPos(actor.getRefData().getPosition().pos); + float minSqr = 1.6 * 1.6 * MIN_DIST_TO_DOOR_SQUARED; // for legibility + // TODO: add reaction to checking open doors if(mBackOffDoor && - actorPos.squaredDistance(Ogre::Vector3(ref.mRef.mPos.pos)) < 1.5*1.5*MIN_DIST_TO_DOOR_SQUARED) + actorPos.squaredDistance(Ogre::Vector3(ref.mRef.mPos.pos)) < minSqr) { mMovement.mPosition[1] = -0.2; // back off, but slowly - if(mDoorIter != mDoors.end() && ref.mData.getLocalRotation().rot[2] >= 1) // open - { - mDoorIter = mDoors.end(); - mBackOffDoor = false; - std::cout<<"open door id \""<= 1) + { + mDoorIter = mDoors.mList.end(); + mBackOffDoor = false; + //std::cout<<"open door id \""<::List::iterator mDoorIter; - MWWorld::CellRefList::List& mDoors; + MWWorld::CellRefList& mDoors; void buildNewPath(const MWWorld::Ptr& actor); }; diff --git a/apps/openmw/mwmechanics/pathgrid.hpp b/apps/openmw/mwmechanics/pathgrid.hpp index ac545efbc..5d01dca00 100644 --- a/apps/openmw/mwmechanics/pathgrid.hpp +++ b/apps/openmw/mwmechanics/pathgrid.hpp @@ -30,6 +30,8 @@ namespace MWMechanics // the input parameters are pathgrid point indexes // the output list is in local (internal cells) or world (external // cells) co-ordinates + // + // NOTE: if start equals end an empty path is returned std::list aStarSearch(const int start, const int end) const; private: diff --git a/apps/openmw/mwworld/cellstore.hpp b/apps/openmw/mwworld/cellstore.hpp index b970afe1b..88b49ed1c 100644 --- a/apps/openmw/mwworld/cellstore.hpp +++ b/apps/openmw/mwworld/cellstore.hpp @@ -8,7 +8,7 @@ #include "esmstore.hpp" #include "cellreflist.hpp" -#include "../mwmechanics/pathgrid.hpp" +#include "../mwmechanics/pathgrid.hpp" // TODO: maybe belongs in mwworld namespace ESM {