From aba72258173db213bdccc82682ca1938a88d7559 Mon Sep 17 00:00:00 2001 From: dteviot Date: Sun, 26 Jul 2015 11:15:21 +1200 Subject: [PATCH 1/9] Removed some duplicated operations. --- apps/openmw/mwmechanics/aicombat.cpp | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/apps/openmw/mwmechanics/aicombat.cpp b/apps/openmw/mwmechanics/aicombat.cpp index 6a39178ce0..bdd09a1a8f 100644 --- a/apps/openmw/mwmechanics/aicombat.cpp +++ b/apps/openmw/mwmechanics/aicombat.cpp @@ -181,13 +181,15 @@ namespace MWMechanics // get or create temporary storage AiCombatStorage& storage = state.get(); + const MWWorld::Class& actorClass = actor.getClass(); //General description - if(actor.getClass().getCreatureStats(actor).isDead()) + if (actorClass.getCreatureStats(actor).isDead()) return true; - MWWorld::Ptr target = MWBase::Environment::get().getWorld()->searchPtrViaActorId(mTargetActorId); + MWBase::World* world = MWBase::Environment::get().getWorld(); + MWWorld::Ptr target = world->searchPtrViaActorId(mTargetActorId); if (target.isEmpty()) return false; @@ -196,9 +198,6 @@ namespace MWMechanics || target.getClass().getCreatureStats(target).isDead()) return true; - const MWWorld::Class& actorClass = actor.getClass(); - MWBase::World* world = MWBase::Environment::get().getWorld(); - //Update every frame bool& combatMove = storage.mCombatMove; From b3d5b47fea3b949d632f9168dd8cd5f273dc8b00 Mon Sep 17 00:00:00 2001 From: dteviot Date: Sun, 26 Jul 2015 17:23:45 +1200 Subject: [PATCH 2/9] extracted function UpdateActorsMovement(). --- apps/openmw/mwmechanics/aicombat.cpp | 37 ++++++++++++++++++---------- apps/openmw/mwmechanics/aicombat.hpp | 5 ++++ 2 files changed, 29 insertions(+), 13 deletions(-) diff --git a/apps/openmw/mwmechanics/aicombat.cpp b/apps/openmw/mwmechanics/aicombat.cpp index bdd09a1a8f..1beb0024cd 100644 --- a/apps/openmw/mwmechanics/aicombat.cpp +++ b/apps/openmw/mwmechanics/aicombat.cpp @@ -214,20 +214,8 @@ namespace MWMechanics } } - actorClass.getMovementSettings(actor) = movement; - actorClass.getMovementSettings(actor).mRotation[0] = 0; - actorClass.getMovementSettings(actor).mRotation[2] = 0; + UpdateActorsMovement(actor, movement); - if(movement.mRotation[2] != 0) - { - if(zTurn(actor, movement.mRotation[2])) movement.mRotation[2] = 0; - } - - if(movement.mRotation[0] != 0) - { - if(smoothTurn(actor, movement.mRotation[0], 0)) movement.mRotation[0] = 0; - } - bool& attack = storage.mAttack; bool& readyToAttack = storage.mReadyToAttack; @@ -579,6 +567,29 @@ namespace MWMechanics return false; } + void AiCombat::UpdateActorsMovement(const MWWorld::Ptr& actor, MWMechanics::Movement& desiredMovement) + { + MWMechanics::Movement& actorMovementSettings = actor.getClass().getMovementSettings(actor); + actorMovementSettings = desiredMovement; + RotateActorOnAxis(actor, 2, actorMovementSettings, desiredMovement); + RotateActorOnAxis(actor, 0, actorMovementSettings, desiredMovement); + } + + void AiCombat::RotateActorOnAxis(const MWWorld::Ptr& actor, int axis, + MWMechanics::Movement& actorMovementSettings, MWMechanics::Movement& desiredMovement) + { + actorMovementSettings.mRotation[axis] = 0; + float& targetAngleRadians = desiredMovement.mRotation[axis]; + if (targetAngleRadians != 0) + { + if (smoothTurn(actor, targetAngleRadians, axis)) + { + // actor now facing desired direction, no need to turn any more + targetAngleRadians = 0; + } + } + } + bool AiCombat::doesPathNeedRecalc(ESM::Pathgrid::Point dest, const ESM::Cell *cell) { if (!mPathFinder.getPath().empty()) diff --git a/apps/openmw/mwmechanics/aicombat.hpp b/apps/openmw/mwmechanics/aicombat.hpp index 083f233849..c81ad0544a 100644 --- a/apps/openmw/mwmechanics/aicombat.hpp +++ b/apps/openmw/mwmechanics/aicombat.hpp @@ -60,6 +60,11 @@ namespace MWMechanics void buildNewPath(const MWWorld::Ptr& actor, const MWWorld::Ptr& target); + + /// Transfer desired movement (from AiCombatStorage) to Actor + void UpdateActorsMovement(const MWWorld::Ptr& actor, MWMechanics::Movement& movement); + void RotateActorOnAxis(const MWWorld::Ptr& actor, int axis, + MWMechanics::Movement& actorMovementSettings, MWMechanics::Movement& desiredMovement); }; From 5ec310dfbab45a6952cb8fcb94b64f6f8b364a7f Mon Sep 17 00:00:00 2001 From: dteviot Date: Sun, 26 Jul 2015 17:24:33 +1200 Subject: [PATCH 3/9] extract function onIdleStatePerFrameActions(). --- apps/openmw/mwmechanics/aiwander.cpp | 68 ++++++++++++++++------------ apps/openmw/mwmechanics/aiwander.hpp | 1 + 2 files changed, 39 insertions(+), 30 deletions(-) diff --git a/apps/openmw/mwmechanics/aiwander.cpp b/apps/openmw/mwmechanics/aiwander.cpp index 5c9949a5a3..8b05299a44 100644 --- a/apps/openmw/mwmechanics/aiwander.cpp +++ b/apps/openmw/mwmechanics/aiwander.cpp @@ -195,18 +195,10 @@ namespace MWMechanics WanderState& wanderState = storage.mState; - // Check if an idle actor is too close to a door - if so start walking - mDoorCheckDuration += duration; - if(mDoorCheckDuration >= DOOR_CHECK_INTERVAL) + + if (wanderState == Wander_IdleNow) { - mDoorCheckDuration = 0; // restart timer - if(mDistance && // actor is not intended to be stationary - (wanderState == Wander_IdleNow) && // but is in idle - proximityToDoor(actor, MIN_DIST_TO_DOOR_SQUARED*1.6f*1.6f)) // NOTE: checks interior cells only - { - wanderState = Wander_MoveNow; - mTrimCurrentNode = false; // just in case - } + onIdleStatePerFrameActions(actor, duration, storage); } // Are we there yet? @@ -229,29 +221,11 @@ namespace MWMechanics evadeObstacles(actor, storage, duration); } - bool& rotate = storage.mTurnActorGivingGreetingToFacePlayer; - if (rotate) - { - // Reduce the turning animation glitch by using a *HUGE* value of - // epsilon... TODO: a proper fix might be in either the physics or the - // animation subsystem - if (zTurn(actor, storage.mTargetAngleRadians, osg::DegreesToRadians(5.f))) - rotate = false; - } - - // Check if idle animation finished - short unsigned& idleAnimation = storage.mIdleAnimation; - GreetingState& greetingState = storage.mSaidGreeting; - if ((wanderState == Wander_IdleNow) && - !checkIdle(actor, idleAnimation) && (greetingState == Greet_Done || greetingState == Greet_None)) - { - wanderState = Wander_ChooseAction; - } - MWBase::World *world = MWBase::Environment::get().getWorld(); if (wanderState == Wander_ChooseAction) { + short unsigned& idleAnimation = storage.mIdleAnimation; idleAnimation = getRandomIdle(); if(!idleAnimation && mDistance) @@ -355,6 +329,40 @@ namespace MWMechanics return false; // AiWander package not yet completed } + void AiWander::onIdleStatePerFrameActions(const MWWorld::Ptr& actor, float duration, AiWanderStorage& storage) + { + // Check if an idle actor is too close to a door - if so start walking + mDoorCheckDuration += duration; + if (mDoorCheckDuration >= DOOR_CHECK_INTERVAL) + { + mDoorCheckDuration = 0; // restart timer + if (mDistance && // actor is not intended to be stationary + proximityToDoor(actor, MIN_DIST_TO_DOOR_SQUARED*1.6f*1.6f)) // NOTE: checks interior cells only + { + storage.mState = Wander_MoveNow; + mTrimCurrentNode = false; // just in case + return; + } + } + + bool& rotate = storage.mTurnActorGivingGreetingToFacePlayer; + if (rotate) + { + // Reduce the turning animation glitch by using a *HUGE* value of + // epsilon... TODO: a proper fix might be in either the physics or the + // animation subsystem + if (zTurn(actor, storage.mTargetAngleRadians, osg::DegreesToRadians(5.f))) + rotate = false; + } + + // Check if idle animation finished + GreetingState& greetingState = storage.mSaidGreeting; + if (!checkIdle(actor, storage.mIdleAnimation) && (greetingState == Greet_Done || greetingState == Greet_None)) + { + storage.mState = Wander_ChooseAction; + } + } + void AiWander::evadeObstacles(const MWWorld::Ptr& actor, AiWanderStorage& storage, float duration) { if (mObstacleCheck.check(actor, duration)) diff --git a/apps/openmw/mwmechanics/aiwander.hpp b/apps/openmw/mwmechanics/aiwander.hpp index d1dab3f50e..92af5b7178 100644 --- a/apps/openmw/mwmechanics/aiwander.hpp +++ b/apps/openmw/mwmechanics/aiwander.hpp @@ -83,6 +83,7 @@ namespace MWMechanics void evadeObstacles(const MWWorld::Ptr& actor, AiWanderStorage& storage, float duration); void playIdleDialogueRandomly(const MWWorld::Ptr& actor); void turnActorToFacePlayer(const osg::Vec3f& actorPosition, const osg::Vec3f& playerPosition, AiWanderStorage& storage); + void onIdleStatePerFrameActions(const MWWorld::Ptr& actor, float duration, AiWanderStorage& storage); int mDistance; // how far the actor can wander from the spawn point int mDuration; From 76f95eafe7c4db0ecb7a223465c5d010d2be0742 Mon Sep 17 00:00:00 2001 From: dteviot Date: Sun, 26 Jul 2015 17:25:00 +1200 Subject: [PATCH 4/9] extract function onWalkingStatePerFrameActions(). --- apps/openmw/mwmechanics/aiwander.cpp | 40 ++++++++++++++++------------ apps/openmw/mwmechanics/aiwander.hpp | 1 + 2 files changed, 24 insertions(+), 17 deletions(-) diff --git a/apps/openmw/mwmechanics/aiwander.cpp b/apps/openmw/mwmechanics/aiwander.cpp index 8b05299a44..77cd9e1375 100644 --- a/apps/openmw/mwmechanics/aiwander.cpp +++ b/apps/openmw/mwmechanics/aiwander.cpp @@ -201,26 +201,11 @@ namespace MWMechanics onIdleStatePerFrameActions(actor, duration, storage); } - // Are we there yet? - if ((wanderState == Wander_Walking) && - storage.mPathFinder.checkPathCompleted(pos.pos[0], pos.pos[1], DESTINATION_TOLERANCE)) + if (wanderState == Wander_Walking) { - stopWalking(actor, storage); - wanderState = Wander_ChooseAction; - mHasReturnPosition = false; + onWalkingStatePerFrameActions(actor, duration, storage, pos); } - - - if (wanderState == Wander_Walking) // have not yet reached the destination - { - // turn towards the next point in mPath - zTurn(actor, storage.mPathFinder.getZAngleToNext(pos.pos[0], pos.pos[1])); - actor.getClass().getMovementSettings(actor).mPosition[1] = 1; - - evadeObstacles(actor, storage, duration); - } - MWBase::World *world = MWBase::Environment::get().getWorld(); if (wanderState == Wander_ChooseAction) @@ -363,6 +348,27 @@ namespace MWMechanics } } + void AiWander::onWalkingStatePerFrameActions(const MWWorld::Ptr& actor, + float duration, AiWanderStorage& storage, ESM::Position& pos) + { + // Are we there yet? + if (storage.mPathFinder.checkPathCompleted(pos.pos[0], pos.pos[1], DESTINATION_TOLERANCE)) + { + stopWalking(actor, storage); + storage.mState = Wander_ChooseAction; + mHasReturnPosition = false; + } + else + { + // have not yet reached the destination + //... turn towards the next point in mPath + zTurn(actor, storage.mPathFinder.getZAngleToNext(pos.pos[0], pos.pos[1])); + actor.getClass().getMovementSettings(actor).mPosition[1] = 1; + + evadeObstacles(actor, storage, duration); + } + } + void AiWander::evadeObstacles(const MWWorld::Ptr& actor, AiWanderStorage& storage, float duration) { if (mObstacleCheck.check(actor, duration)) diff --git a/apps/openmw/mwmechanics/aiwander.hpp b/apps/openmw/mwmechanics/aiwander.hpp index 92af5b7178..4750df1dc5 100644 --- a/apps/openmw/mwmechanics/aiwander.hpp +++ b/apps/openmw/mwmechanics/aiwander.hpp @@ -84,6 +84,7 @@ namespace MWMechanics void playIdleDialogueRandomly(const MWWorld::Ptr& actor); void turnActorToFacePlayer(const osg::Vec3f& actorPosition, const osg::Vec3f& playerPosition, AiWanderStorage& storage); void onIdleStatePerFrameActions(const MWWorld::Ptr& actor, float duration, AiWanderStorage& storage); + void onWalkingStatePerFrameActions(const MWWorld::Ptr& actor, float duration, AiWanderStorage& storage, ESM::Position& pos); int mDistance; // how far the actor can wander from the spawn point int mDuration; From 9c0e3d6c28bd66717d8cd385e5e9099a1a01ad56 Mon Sep 17 00:00:00 2001 From: dteviot Date: Sun, 26 Jul 2015 17:25:44 +1200 Subject: [PATCH 5/9] extracted functions doPerFrameActionsForState() and onChooseActionStatePerFrameActions(). --- apps/openmw/mwmechanics/aiwander.cpp | 85 ++++++++++++++++------------ apps/openmw/mwmechanics/aiwander.hpp | 2 + 2 files changed, 52 insertions(+), 35 deletions(-) diff --git a/apps/openmw/mwmechanics/aiwander.cpp b/apps/openmw/mwmechanics/aiwander.cpp index 77cd9e1375..e6d7d44225 100644 --- a/apps/openmw/mwmechanics/aiwander.cpp +++ b/apps/openmw/mwmechanics/aiwander.cpp @@ -193,39 +193,7 @@ namespace MWMechanics ESM::Position pos = actor.getRefData().getPosition(); - - WanderState& wanderState = storage.mState; - - if (wanderState == Wander_IdleNow) - { - onIdleStatePerFrameActions(actor, duration, storage); - } - - if (wanderState == Wander_Walking) - { - onWalkingStatePerFrameActions(actor, duration, storage, pos); - } - - MWBase::World *world = MWBase::Environment::get().getWorld(); - - if (wanderState == Wander_ChooseAction) - { - short unsigned& idleAnimation = storage.mIdleAnimation; - idleAnimation = getRandomIdle(); - - if(!idleAnimation && mDistance) - { - wanderState = Wander_MoveNow; - } - else - { - // Play idle animation and recreate vanilla (broken?) behavior of resetting start time of AIWander: - MWWorld::TimeStamp currentTime = world->getTimeStamp(); - mStartTime = currentTime; - playIdle(actor, idleAnimation); - wanderState = Wander_IdleNow; - } - } + doPerFrameActionsForState(actor, duration, storage, pos); playIdleDialogueRandomly(actor); @@ -243,7 +211,7 @@ namespace MWMechanics if(mDuration) { // End package if duration is complete or mid-night hits: - MWWorld::TimeStamp currentTime = world->getTimeStamp(); + MWWorld::TimeStamp currentTime = MWBase::Environment::get().getWorld()->getTimeStamp(); if((currentTime.getHour() >= mStartTime.getHour() + mDuration) || (int(currentTime.getHour()) == 0 && currentTime.getDay() != mStartTime.getDay())) { @@ -288,12 +256,13 @@ namespace MWMechanics if(storage.mPathFinder.isPathConstructed()) { - wanderState = Wander_Walking; + storage.mState = Wander_Walking; } } } // Allow interrupting a walking actor to trigger a greeting + WanderState& wanderState = storage.mState; if ((wanderState == Wander_IdleNow) || (wanderState == Wander_Walking)) { playGreetingIfPlayerGetsTooClose(actor, storage); @@ -314,6 +283,32 @@ namespace MWMechanics return false; // AiWander package not yet completed } + void AiWander::doPerFrameActionsForState(const MWWorld::Ptr& actor, float duration, AiWanderStorage& storage, ESM::Position& pos) + { + switch (storage.mState) + { + case Wander_IdleNow: + onIdleStatePerFrameActions(actor, duration, storage); + break; + + case Wander_Walking: + onWalkingStatePerFrameActions(actor, duration, storage, pos); + break; + + case Wander_ChooseAction: + onChooseActionStatePerFrameActions(actor, storage); + break; + + case Wander_MoveNow: + break; // nothing to do + + default: + // should never get here + assert(false); + break; + } + } + void AiWander::onIdleStatePerFrameActions(const MWWorld::Ptr& actor, float duration, AiWanderStorage& storage) { // Check if an idle actor is too close to a door - if so start walking @@ -369,6 +364,26 @@ namespace MWMechanics } } + void AiWander::onChooseActionStatePerFrameActions(const MWWorld::Ptr& actor, AiWanderStorage& storage) + { + + short unsigned& idleAnimation = storage.mIdleAnimation; + idleAnimation = getRandomIdle(); + + if (!idleAnimation && mDistance) + { + storage.mState = Wander_MoveNow; + } + else + { + // Play idle animation and recreate vanilla (broken?) behavior of resetting start time of AIWander: + MWWorld::TimeStamp currentTime = MWBase::Environment::get().getWorld()->getTimeStamp(); + mStartTime = currentTime; + playIdle(actor, idleAnimation); + storage.mState = Wander_IdleNow; + } + } + void AiWander::evadeObstacles(const MWWorld::Ptr& actor, AiWanderStorage& storage, float duration) { if (mObstacleCheck.check(actor, duration)) diff --git a/apps/openmw/mwmechanics/aiwander.hpp b/apps/openmw/mwmechanics/aiwander.hpp index 4750df1dc5..9b21415c4e 100644 --- a/apps/openmw/mwmechanics/aiwander.hpp +++ b/apps/openmw/mwmechanics/aiwander.hpp @@ -83,8 +83,10 @@ namespace MWMechanics void evadeObstacles(const MWWorld::Ptr& actor, AiWanderStorage& storage, float duration); void playIdleDialogueRandomly(const MWWorld::Ptr& actor); void turnActorToFacePlayer(const osg::Vec3f& actorPosition, const osg::Vec3f& playerPosition, AiWanderStorage& storage); + void doPerFrameActionsForState(const MWWorld::Ptr& actor, float duration, AiWanderStorage& storage, ESM::Position& pos); void onIdleStatePerFrameActions(const MWWorld::Ptr& actor, float duration, AiWanderStorage& storage); void onWalkingStatePerFrameActions(const MWWorld::Ptr& actor, float duration, AiWanderStorage& storage, ESM::Position& pos); + void onChooseActionStatePerFrameActions(const MWWorld::Ptr& actor, AiWanderStorage& storage); int mDistance; // how far the actor can wander from the spawn point int mDuration; From ad0d8071037d4fda4e8b5151f5e6c9ec561d9af3 Mon Sep 17 00:00:00 2001 From: dteviot Date: Sun, 26 Jul 2015 17:28:32 +1200 Subject: [PATCH 6/9] extracted function reactionTimeActions(). --- apps/openmw/mwmechanics/aiwander.cpp | 13 ++++++++----- apps/openmw/mwmechanics/aiwander.hpp | 2 ++ 2 files changed, 10 insertions(+), 5 deletions(-) diff --git a/apps/openmw/mwmechanics/aiwander.cpp b/apps/openmw/mwmechanics/aiwander.cpp index e6d7d44225..228f4b32d1 100644 --- a/apps/openmw/mwmechanics/aiwander.cpp +++ b/apps/openmw/mwmechanics/aiwander.cpp @@ -199,15 +199,18 @@ namespace MWMechanics float& lastReaction = storage.mReaction; lastReaction += duration; - if(lastReaction < REACTION_INTERVAL) + if (REACTION_INTERVAL <= lastReaction) { - return false; + lastReaction = 0; + return reactionTimeActions(actor, storage, currentCell, cellChange, pos); } else - lastReaction = 0; - - // NOTE: everything below get updated every REACTION_INTERVAL seconds + return false; + } + bool AiWander::reactionTimeActions(const MWWorld::Ptr& actor, AiWanderStorage& storage, + const MWWorld::CellStore*& currentCell, bool cellChange, ESM::Position& pos) + { if(mDuration) { // End package if duration is complete or mid-night hits: diff --git a/apps/openmw/mwmechanics/aiwander.hpp b/apps/openmw/mwmechanics/aiwander.hpp index 9b21415c4e..3468c212d4 100644 --- a/apps/openmw/mwmechanics/aiwander.hpp +++ b/apps/openmw/mwmechanics/aiwander.hpp @@ -87,6 +87,8 @@ namespace MWMechanics void onIdleStatePerFrameActions(const MWWorld::Ptr& actor, float duration, AiWanderStorage& storage); void onWalkingStatePerFrameActions(const MWWorld::Ptr& actor, float duration, AiWanderStorage& storage, ESM::Position& pos); void onChooseActionStatePerFrameActions(const MWWorld::Ptr& actor, AiWanderStorage& storage); + bool reactionTimeActions(const MWWorld::Ptr& actor, AiWanderStorage& storage, + const MWWorld::CellStore*& currentCell, bool cellChange, ESM::Position& pos); int mDistance; // how far the actor can wander from the spawn point int mDuration; From 5e519ef550abbceda13d501cccb83d07d1f1dba8 Mon Sep 17 00:00:00 2001 From: dteviot Date: Sun, 26 Jul 2015 17:29:01 +1200 Subject: [PATCH 7/9] extract function isPackageFinished(). --- apps/openmw/mwmechanics/aiwander.cpp | 40 ++++++++++++++++++---------- apps/openmw/mwmechanics/aiwander.hpp | 1 + 2 files changed, 27 insertions(+), 14 deletions(-) diff --git a/apps/openmw/mwmechanics/aiwander.cpp b/apps/openmw/mwmechanics/aiwander.cpp index 228f4b32d1..ff26bc116c 100644 --- a/apps/openmw/mwmechanics/aiwander.cpp +++ b/apps/openmw/mwmechanics/aiwander.cpp @@ -211,21 +211,9 @@ namespace MWMechanics bool AiWander::reactionTimeActions(const MWWorld::Ptr& actor, AiWanderStorage& storage, const MWWorld::CellStore*& currentCell, bool cellChange, ESM::Position& pos) { - if(mDuration) + if (isPackageCompleted(actor, storage)) { - // End package if duration is complete or mid-night hits: - MWWorld::TimeStamp currentTime = MWBase::Environment::get().getWorld()->getTimeStamp(); - if((currentTime.getHour() >= mStartTime.getHour() + mDuration) || - (int(currentTime.getHour()) == 0 && currentTime.getDay() != mStartTime.getDay())) - { - if(!mRepeat) - { - stopWalking(actor, storage); - return true; - } - else - mStartTime = currentTime; - } + return true; } // Initialization to discover & store allowed node points for this actor. @@ -286,6 +274,30 @@ namespace MWMechanics return false; // AiWander package not yet completed } + bool AiWander::isPackageCompleted(const MWWorld::Ptr& actor, AiWanderStorage& storage) + { + if (mDuration) + { + // End package if duration is complete or mid-night hits: + MWWorld::TimeStamp currentTime = MWBase::Environment::get().getWorld()->getTimeStamp(); + if ((currentTime.getHour() >= mStartTime.getHour() + mDuration) || + (int(currentTime.getHour()) == 0 && currentTime.getDay() != mStartTime.getDay())) + { + if (!mRepeat) + { + stopWalking(actor, storage); + return true; + } + else + { + mStartTime = currentTime; + } + } + } + // if get here, not yet completed + return false; + } + void AiWander::doPerFrameActionsForState(const MWWorld::Ptr& actor, float duration, AiWanderStorage& storage, ESM::Position& pos) { switch (storage.mState) diff --git a/apps/openmw/mwmechanics/aiwander.hpp b/apps/openmw/mwmechanics/aiwander.hpp index 3468c212d4..2364ac5430 100644 --- a/apps/openmw/mwmechanics/aiwander.hpp +++ b/apps/openmw/mwmechanics/aiwander.hpp @@ -89,6 +89,7 @@ namespace MWMechanics void onChooseActionStatePerFrameActions(const MWWorld::Ptr& actor, AiWanderStorage& storage); bool reactionTimeActions(const MWWorld::Ptr& actor, AiWanderStorage& storage, const MWWorld::CellStore*& currentCell, bool cellChange, ESM::Position& pos); + bool isPackageCompleted(const MWWorld::Ptr& actor, AiWanderStorage& storage); int mDistance; // how far the actor can wander from the spawn point int mDuration; From c7aacaee706a9226ff947a038cdbae519920e708 Mon Sep 17 00:00:00 2001 From: dteviot Date: Sun, 26 Jul 2015 17:29:32 +1200 Subject: [PATCH 8/9] extracted function returnToStartLocation(). --- apps/openmw/mwmechanics/aiwander.cpp | 38 ++++++++++++++++------------ apps/openmw/mwmechanics/aiwander.hpp | 1 + 2 files changed, 23 insertions(+), 16 deletions(-) diff --git a/apps/openmw/mwmechanics/aiwander.cpp b/apps/openmw/mwmechanics/aiwander.cpp index ff26bc116c..e230998eb5 100644 --- a/apps/openmw/mwmechanics/aiwander.cpp +++ b/apps/openmw/mwmechanics/aiwander.cpp @@ -233,23 +233,10 @@ namespace MWMechanics // For stationary NPCs, move back to the starting location if another AiPackage moved us elsewhere if (cellChange) mHasReturnPosition = false; - if (mDistance == 0 && mHasReturnPosition && (pos.asVec3() - mReturnPosition).length2() > 20*20) + if (mDistance == 0 && mHasReturnPosition + && (pos.asVec3() - mReturnPosition).length2() > (DESTINATION_TOLERANCE * DESTINATION_TOLERANCE)) { - if (!storage.mPathFinder.isPathConstructed()) - { - ESM::Pathgrid::Point dest(PathFinder::MakePathgridPoint(mReturnPosition)); - - // actor position is already in world co-ordinates - ESM::Pathgrid::Point start(PathFinder::MakePathgridPoint(pos)); - - // don't take shortcuts for wandering - storage.mPathFinder.buildSyncedPath(start, dest, actor.getCell(), false); - - if(storage.mPathFinder.isPathConstructed()) - { - storage.mState = Wander_Walking; - } - } + returnToStartLocation(actor, storage, pos); } // Allow interrupting a walking actor to trigger a greeting @@ -298,6 +285,25 @@ namespace MWMechanics return false; } + void AiWander::returnToStartLocation(const MWWorld::Ptr& actor, AiWanderStorage& storage, ESM::Position& pos) + { + if (!storage.mPathFinder.isPathConstructed()) + { + ESM::Pathgrid::Point dest(PathFinder::MakePathgridPoint(mReturnPosition)); + + // actor position is already in world co-ordinates + ESM::Pathgrid::Point start(PathFinder::MakePathgridPoint(pos)); + + // don't take shortcuts for wandering + storage.mPathFinder.buildSyncedPath(start, dest, actor.getCell(), false); + + if (storage.mPathFinder.isPathConstructed()) + { + storage.mState = Wander_Walking; + } + } + } + void AiWander::doPerFrameActionsForState(const MWWorld::Ptr& actor, float duration, AiWanderStorage& storage, ESM::Position& pos) { switch (storage.mState) diff --git a/apps/openmw/mwmechanics/aiwander.hpp b/apps/openmw/mwmechanics/aiwander.hpp index 2364ac5430..8a489c783c 100644 --- a/apps/openmw/mwmechanics/aiwander.hpp +++ b/apps/openmw/mwmechanics/aiwander.hpp @@ -90,6 +90,7 @@ namespace MWMechanics bool reactionTimeActions(const MWWorld::Ptr& actor, AiWanderStorage& storage, const MWWorld::CellStore*& currentCell, bool cellChange, ESM::Position& pos); bool isPackageCompleted(const MWWorld::Ptr& actor, AiWanderStorage& storage); + void returnToStartLocation(const MWWorld::Ptr& actor, AiWanderStorage& storage, ESM::Position& pos); int mDistance; // how far the actor can wander from the spawn point int mDuration; From 04aee1fe20a1d742292ac09d0c162dc9a30c3de2 Mon Sep 17 00:00:00 2001 From: dteviot Date: Sun, 26 Jul 2015 17:32:29 +1200 Subject: [PATCH 9/9] extracted function reactionTimeActions(). --- apps/openmw/mwmechanics/aicombat.cpp | 54 +++++++++++++++------------- apps/openmw/mwmechanics/aicombat.hpp | 5 ++- 2 files changed, 34 insertions(+), 25 deletions(-) diff --git a/apps/openmw/mwmechanics/aicombat.cpp b/apps/openmw/mwmechanics/aicombat.cpp index 1beb0024cd..fc1c31c26d 100644 --- a/apps/openmw/mwmechanics/aicombat.cpp +++ b/apps/openmw/mwmechanics/aicombat.cpp @@ -45,6 +45,7 @@ namespace return -std::asin(dir.z() / len); } + const float REACTION_INTERVAL = 0.25f; const float PATHFIND_Z_REACH = 50.0f; // distance at which actor pays more attention to decide whether to shortcut or stick to pathgrid @@ -181,15 +182,11 @@ namespace MWMechanics // get or create temporary storage AiCombatStorage& storage = state.get(); - const MWWorld::Class& actorClass = actor.getClass(); - - //General description - if (actorClass.getCreatureStats(actor).isDead()) + if (actor.getClass().getCreatureStats(actor).isDead()) return true; - MWBase::World* world = MWBase::Environment::get().getWorld(); - MWWorld::Ptr target = world->searchPtrViaActorId(mTargetActorId); + MWWorld::Ptr target = MWBase::Environment::get().getWorld()->searchPtrViaActorId(mTargetActorId); if (target.isEmpty()) return false; @@ -217,8 +214,6 @@ namespace MWMechanics UpdateActorsMovement(actor, movement); bool& attack = storage.mAttack; - bool& readyToAttack = storage.mReadyToAttack; - if (attack && (characterController.getAttackStrength() >= storage.mStrength || characterController.readyToPrepareAttack())) attack = false; @@ -228,14 +223,22 @@ namespace MWMechanics actionCooldown -= duration; float& timerReact = storage.mTimerReact; - float tReaction = 0.25f; - if(timerReact < tReaction) + if(timerReact < REACTION_INTERVAL) { timerReact += duration; return false; } + else + { + timerReact = 0; + return reactionTimeActions(actor, characterController, storage, target); + } + } - //Update with period = tReaction + bool AiCombat::reactionTimeActions(const MWWorld::Ptr& actor, CharacterController& characterController, + AiCombatStorage& storage, MWWorld::Ptr target) + { + MWMechanics::Movement& movement = storage.mMovement; // Stop attacking if target is not seen if (target.getClass().getCreatureStats(target).getMagicEffects().get(ESM::MagicEffect::Invisibility).getMagnitude() > 0 @@ -245,7 +248,6 @@ namespace MWMechanics return false; // TODO: run away instead of doing nothing } - timerReact = 0; const MWWorld::CellStore*& currentCell = storage.mCell; bool cellChange = currentCell && (actor.getCell() != currentCell); if(!currentCell || cellChange) @@ -253,8 +255,10 @@ namespace MWMechanics currentCell = actor.getCell(); } + const MWWorld::Class& actorClass = actor.getClass(); actorClass.getCreatureStats(actor).setMovementFlag(CreatureStats::Flag_Run, true); + float& actionCooldown = storage.mActionCooldown; if (actionCooldown > 0) return false; @@ -276,6 +280,7 @@ namespace MWMechanics float weapRange = 1.0f; // Get weapon characteristics + MWBase::World* world = MWBase::Environment::get().getWorld(); if (actorClass.hasInventoryStore(actor)) { //Get weapon speed and range @@ -326,13 +331,14 @@ namespace MWMechanics float& strength = storage.mStrength; + bool& readyToAttack = storage.mReadyToAttack; // start new attack if(readyToAttack && characterController.readyToStartAttack()) { if (storage.mAttackCooldown <= 0) { - attack = true; // attack starts just now - characterController.setAttackingOrSpell(attack); + storage.mAttack = true; // attack starts just now + characterController.setAttackingOrSpell(true); if (!distantCombat) chooseBestAttack(weapon, movement); @@ -356,7 +362,7 @@ namespace MWMechanics storage.mAttackCooldown = std::min(baseDelay + 0.01 * Misc::Rng::roll0to99(), baseDelay + 0.9); } else - storage.mAttackCooldown -= tReaction; + storage.mAttackCooldown -= REACTION_INTERVAL; } @@ -400,7 +406,7 @@ namespace MWMechanics bool isStuck = false; float speed = 0.0f; - if(movement.mPosition[1] && (lastActorPos - vActorPos).length() < (speed = actorClass.getSpeed(actor)) * tReaction / 2) + if(movement.mPosition[1] && (lastActorPos - vActorPos).length() < (speed = actorClass.getSpeed(actor)) * REACTION_INTERVAL / 2) isStuck = true; lastActorPos = vActorPos; @@ -437,7 +443,7 @@ namespace MWMechanics if (distantCombat) { osg::Vec3f& lastTargetPos = storage.mLastTargetPos; - osg::Vec3f vAimDir = AimDirToMovingTarget(actor, target, lastTargetPos, tReaction, weaptype, strength); + osg::Vec3f vAimDir = AimDirToMovingTarget(actor, target, lastTargetPos, REACTION_INTERVAL, weaptype, strength); lastTargetPos = vTargetPos; movement.mRotation[0] = getXAngleToDir(vAimDir); movement.mRotation[2] = getZAngleToDir(vAimDir); @@ -458,8 +464,8 @@ namespace MWMechanics { if(movement.mPosition[0] || movement.mPosition[1]) { - timerCombatMove = 0.1f + 0.1f * Misc::Rng::rollClosedProbability(); - combatMove = true; + storage.mTimerCombatMove = 0.1f + 0.1f * Misc::Rng::rollClosedProbability(); + storage.mCombatMove = true; } // only NPCs are smart enough to use dodge movements else if(actorClass.isNpc() && (!distantCombat || (distantCombat && distToTarget < rangeAttack/2))) @@ -468,8 +474,8 @@ namespace MWMechanics if (Misc::Rng::rollClosedProbability() < 0.25) { movement.mPosition[0] = Misc::Rng::rollProbability() < 0.5 ? 1.0f : -1.0f; - timerCombatMove = 0.05f + 0.15f * Misc::Rng::rollClosedProbability(); - combatMove = true; + storage.mTimerCombatMove = 0.05f + 0.15f * Misc::Rng::rollClosedProbability(); + storage.mCombatMove = true; } } @@ -497,7 +503,7 @@ namespace MWMechanics { if(speed == 0.0f) speed = actorClass.getSpeed(actor); // maximum dist before pit/obstacle for actor to avoid them depending on his speed - float maxAvoidDist = tReaction * speed + speed / MAX_VEL_ANGULAR_RADIANS * 2; // *2 - for reliability + float maxAvoidDist = REACTION_INTERVAL * speed + speed / MAX_VEL_ANGULAR_RADIANS * 2; // *2 - for reliability preferShortcut = checkWayIsClear(vActorPos, vTargetPos, osg::Vec3f(vDirToTarget.x(), vDirToTarget.y(), 0).length() > maxAvoidDist*1.5? maxAvoidDist : maxAvoidDist/2); } @@ -558,8 +564,8 @@ namespace MWMechanics if (readyToAttack) { // to stop possible sideway moving after target moved out of attack range - combatMove = true; - timerCombatMove = 0; + storage.mCombatMove = true; + storage.mTimerCombatMove = 0; } readyToAttack = false; } diff --git a/apps/openmw/mwmechanics/aicombat.hpp b/apps/openmw/mwmechanics/aicombat.hpp index c81ad0544a..4e40608196 100644 --- a/apps/openmw/mwmechanics/aicombat.hpp +++ b/apps/openmw/mwmechanics/aicombat.hpp @@ -26,6 +26,8 @@ namespace MWMechanics { class Action; + struct AiCombatStorage; + /// \brief Causes the actor to fight another actor class AiCombat : public AiPackage { @@ -58,8 +60,9 @@ namespace MWMechanics int mTargetActorId; - void buildNewPath(const MWWorld::Ptr& actor, const MWWorld::Ptr& target); + bool reactionTimeActions(const MWWorld::Ptr& actor, CharacterController& characterController, + AiCombatStorage& storage, MWWorld::Ptr target); /// Transfer desired movement (from AiCombatStorage) to Actor void UpdateActorsMovement(const MWWorld::Ptr& actor, MWMechanics::Movement& movement);