mirror of
				https://github.com/OpenMW/openmw.git
				synced 2025-10-29 03:26:38 +00:00 
			
		
		
		
	Merge remote-tracking branch 'mrcheko/master'
This commit is contained in:
		
						commit
						56c4367c1a
					
				
					 13 changed files with 275 additions and 114 deletions
				
			
		|  | @ -181,55 +181,66 @@ namespace MWMechanics | |||
|             calculateDynamicStats (ptr); | ||||
| 
 | ||||
|         calculateCreatureStatModifiers (ptr, duration); | ||||
| 
 | ||||
|         // AI
 | ||||
|         if(MWBase::Environment::get().getMechanicsManager()->isAIActive()) | ||||
|         { | ||||
|             CreatureStats& creatureStats = MWWorld::Class::get(ptr).getCreatureStats(ptr); | ||||
|             MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayerPtr(); | ||||
| 
 | ||||
|             //engage combat or not?
 | ||||
|             if(ptr != player && !creatureStats.isHostile()) | ||||
|             { | ||||
|                 ESM::Position playerpos = player.getRefData().getPosition(); | ||||
|                 ESM::Position actorpos = ptr.getRefData().getPosition(); | ||||
|                 float d = sqrt((actorpos.pos[0] - playerpos.pos[0])*(actorpos.pos[0] - playerpos.pos[0]) | ||||
|                     +(actorpos.pos[1] - playerpos.pos[1])*(actorpos.pos[1] - playerpos.pos[1]) | ||||
|                     +(actorpos.pos[2] - playerpos.pos[2])*(actorpos.pos[2] - playerpos.pos[2])); | ||||
|                 float fight = ptr.getClass().getCreatureStats(ptr).getAiSetting(CreatureStats::AI_Fight).getModified(); | ||||
| 
 | ||||
|                 if(    (fight == 100 ) | ||||
|                     || (fight >= 95 && d <= 3000) | ||||
|                     || (fight >= 90 && d <= 2000) | ||||
|                     || (fight >= 80 && d <= 1000) | ||||
|                     ) | ||||
|                 { | ||||
|                     bool LOS = MWBase::Environment::get().getWorld()->getLOS(ptr,player) | ||||
|                             && MWBase::Environment::get().getMechanicsManager()->awarenessCheck(player, ptr); | ||||
| 
 | ||||
|                     if (LOS) | ||||
|                     { | ||||
|                         MWBase::Environment::get().getMechanicsManager()->startCombat(ptr, player); | ||||
|                     } | ||||
|                 } | ||||
|             } | ||||
|             updateCrimePersuit(ptr, duration); | ||||
|             creatureStats.getAiSequence().execute (ptr,duration); | ||||
|         } | ||||
| 
 | ||||
|         // fatigue restoration
 | ||||
|         calculateRestoration(ptr, duration, false); | ||||
|     } | ||||
| 
 | ||||
|     void Actors::updateNpc (const MWWorld::Ptr& ptr, float duration, bool paused) | ||||
|     void Actors::engageCombat (const MWWorld::Ptr& actor1, const MWWorld::Ptr& actor2, bool againstPlayer) | ||||
|     { | ||||
|         if(!paused) | ||||
|         CreatureStats& creatureStats = MWWorld::Class::get(actor1).getCreatureStats(actor1); | ||||
|          | ||||
|         if (againstPlayer && creatureStats.isHostile()) return; // already fighting against player
 | ||||
| 
 | ||||
|         float fight; | ||||
| 
 | ||||
|         if (againstPlayer)  | ||||
|             fight = actor1.getClass().getCreatureStats(actor1).getAiSetting(CreatureStats::AI_Fight).getModified(); | ||||
|         else | ||||
|         { | ||||
|             fight = 0; | ||||
|             // if one of actors is creature then we should make a decision to start combat or not
 | ||||
|             // NOTE: function doesn't take into account combat between 2 creatures
 | ||||
|             if (!actor1.getClass().isNpc()) | ||||
|             { | ||||
|                 // if creature is hostile then it is necessarily to start combat
 | ||||
|                 if (creatureStats.isHostile()) fight = 100; | ||||
|                 else fight = creatureStats.getAiSetting(CreatureStats::AI_Fight).getModified(); | ||||
|             } | ||||
|         } | ||||
| 
 | ||||
|         ESM::Position actor1Pos = actor1.getRefData().getPosition(); | ||||
|         ESM::Position actor2Pos = actor2.getRefData().getPosition(); | ||||
|         float d = Ogre::Vector3(actor1Pos.pos).distance(Ogre::Vector3(actor2Pos.pos)); | ||||
| 
 | ||||
|         if(   (fight == 100 && d <= 5000) | ||||
|             || (fight >= 95 && d <= 3000) | ||||
|             || (fight >= 90 && d <= 2000) | ||||
|             || (fight >= 80 && d <= 1000)) | ||||
|         { | ||||
|             if (againstPlayer || actor2.getClass().getCreatureStats(actor2).getAiSequence().canAddTarget(actor2Pos, d)) | ||||
|             { | ||||
|                 bool LOS = MWBase::Environment::get().getWorld()->getLOS(actor1, actor2); | ||||
| 
 | ||||
|                 if (againstPlayer) LOS &= MWBase::Environment::get().getMechanicsManager()->awarenessCheck(actor2, actor1); | ||||
| 
 | ||||
|                 if (LOS) | ||||
|                 { | ||||
|                     MWBase::Environment::get().getMechanicsManager()->startCombat(actor1, actor2); | ||||
|                     if (!againstPlayer) // start combat between each other
 | ||||
|                     { | ||||
|                         MWBase::Environment::get().getMechanicsManager()->startCombat(actor2, actor1); | ||||
|                     } | ||||
|                 } | ||||
|             } | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     void Actors::updateNpc (const MWWorld::Ptr& ptr, float duration) | ||||
|     { | ||||
|         updateDrowning(ptr, duration); | ||||
|         calculateNpcStatModifiers(ptr); | ||||
|         updateEquippedLight(ptr, duration); | ||||
|     } | ||||
|     } | ||||
| 
 | ||||
|     void Actors::adjustMagicEffects (const MWWorld::Ptr& creature) | ||||
|     { | ||||
|  | @ -861,10 +872,24 @@ namespace MWMechanics | |||
|         } | ||||
|     } | ||||
| 
 | ||||
|     static Ogre::Vector3 sBasePoint; | ||||
|     bool comparePtrDist (const MWWorld::Ptr& ptr1, const MWWorld::Ptr& ptr2) | ||||
|     { | ||||
|         return (sBasePoint.squaredDistance(Ogre::Vector3(ptr1.getRefData().getPosition().pos)) | ||||
|             < sBasePoint.squaredDistance(Ogre::Vector3(ptr2.getRefData().getPosition().pos))); | ||||
|     } | ||||
| 
 | ||||
|     void Actors::update (float duration, bool paused) | ||||
|     { | ||||
|         if(!paused) | ||||
|         { | ||||
|             std::list<MWWorld::Ptr> listGuards; // at the moment only guards certainly will fight with creatures
 | ||||
|              | ||||
|             static float timerUpdateAITargets = 0; | ||||
| 
 | ||||
|             // target lists get updated once every 1.0 sec
 | ||||
|             if (timerUpdateAITargets >= 1.0f) timerUpdateAITargets = 0; | ||||
| 
 | ||||
|             // Reset data from previous frame
 | ||||
|             for (PtrControllerMap::iterator iter(mActors.begin()); iter != mActors.end(); ++iter) | ||||
|             { | ||||
|  | @ -872,19 +897,53 @@ namespace MWMechanics | |||
|                 // Note, the new hit object for this frame may be set by CharacterController::update -> Animation::runAnimation
 | ||||
|                 // (below)
 | ||||
|                 iter->first.getClass().getCreatureStats(iter->first).setLastHitObject(std::string()); | ||||
| 
 | ||||
|                 // add guards to list to later make them fight with creatures
 | ||||
|                 if (timerUpdateAITargets == 0 && iter->first.getClass().isClass(iter->first, "Guard")) | ||||
|                     listGuards.push_back(iter->first); | ||||
|             } | ||||
| 
 | ||||
|             MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayerPtr(); | ||||
| 
 | ||||
|             listGuards.push_back(player); | ||||
| 
 | ||||
|              // AI and magic effects update
 | ||||
|             for(PtrControllerMap::iterator iter(mActors.begin()); iter != mActors.end(); ++iter) | ||||
|             { | ||||
|                 if (!iter->first.getClass().getCreatureStats(iter->first).isDead()) | ||||
|                 { | ||||
|                     updateActor(iter->first, duration); | ||||
| 
 | ||||
|                     if (MWBase::Environment::get().getMechanicsManager()->isAIActive()) | ||||
|                     { | ||||
|                         // make guards and creatures fight each other
 | ||||
|                         if (timerUpdateAITargets == 0 && iter->first.getTypeName() == typeid(ESM::Creature).name() && !listGuards.empty()) | ||||
|                         { | ||||
|                             sBasePoint = Ogre::Vector3(iter->first.getRefData().getPosition().pos); | ||||
|                             listGuards.sort(comparePtrDist); // try to engage combat starting from the nearest creature
 | ||||
|                              | ||||
|                             for (std::list<MWWorld::Ptr>::iterator it = listGuards.begin(); it != listGuards.end(); ++it) | ||||
|                             { | ||||
|                                 engageCombat(iter->first, *it, false); | ||||
|                             } | ||||
|                         } | ||||
| 
 | ||||
|                         if (iter->first != player) engageCombat(iter->first, player, true); | ||||
| 
 | ||||
|                         if (iter->first.getClass().isNpc() && iter->first != player) | ||||
|                             updateCrimePersuit(iter->first, duration); | ||||
| 
 | ||||
|                         if (iter->first != player) | ||||
|                             iter->first.getClass().getCreatureStats(iter->first).getAiSequence().execute(iter->first, duration); | ||||
|                     } | ||||
| 
 | ||||
|                     if(iter->first.getTypeName() == typeid(ESM::NPC).name()) | ||||
|                         updateNpc(iter->first, duration, paused); | ||||
|                         updateNpc(iter->first, duration); | ||||
|                 } | ||||
|             } | ||||
| 
 | ||||
|             timerUpdateAITargets += duration; | ||||
| 
 | ||||
|             // Looping magic VFX update
 | ||||
|             // Note: we need to do this before any of the animations are updated.
 | ||||
|             // Reaching the text keys may trigger Hit / Spellcast (and as such, particles),
 | ||||
|  | @ -903,7 +962,7 @@ namespace MWMechanics | |||
|             } | ||||
| 
 | ||||
|             // Kill dead actors, update some variables
 | ||||
|             for (PtrControllerMap::iterator iter(mActors.begin());iter != mActors.end();iter++) | ||||
|             for(PtrControllerMap::iterator iter(mActors.begin()); iter != mActors.end(); ++iter) | ||||
|             { | ||||
|                 const MWWorld::Class &cls = MWWorld::Class::get(iter->first); | ||||
|                 CreatureStats &stats = cls.getCreatureStats(iter->first); | ||||
|  | @ -975,7 +1034,6 @@ namespace MWMechanics | |||
|             } | ||||
| 
 | ||||
|             // if player is in sneak state see if anyone detects him
 | ||||
|             const MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayerPtr(); | ||||
|             if (player.getClass().getCreatureStats(player).getMovementFlag(MWMechanics::CreatureStats::Flag_Sneak)) | ||||
|             { | ||||
|                 const MWWorld::ESMStore& esmStore = MWBase::Environment::get().getWorld()->getStore(); | ||||
|  | @ -1105,9 +1163,7 @@ namespace MWMechanics | |||
|             if(!stats.isDead() && stats.getAiSequence().getTypeId() == AiPackage::TypeIdCombat) | ||||
|             { | ||||
|                 MWMechanics::AiCombat* package = static_cast<MWMechanics::AiCombat*>(stats.getAiSequence().getActivePackage()); | ||||
|                 // TODO: This is wrong! It's comparing Ref IDs with Ogre handles. The only case where this (coincidentally) works is the player.
 | ||||
|                 // possibly applies to other code using getTargetId.
 | ||||
|                 if(package->getTargetId() == actor.getCellRef().mRefID) | ||||
|                 if(package->getTarget() == actor) | ||||
|                     list.push_front(*iter); | ||||
|             } | ||||
|         } | ||||
|  |  | |||
|  | @ -27,7 +27,7 @@ namespace MWMechanics | |||
|     { | ||||
|             std::map<std::string, int> mDeathCount; | ||||
| 
 | ||||
|             void updateNpc(const MWWorld::Ptr &ptr, float duration, bool paused); | ||||
|             void updateNpc(const MWWorld::Ptr &ptr, float duration); | ||||
| 
 | ||||
|             void adjustMagicEffects (const MWWorld::Ptr& creature); | ||||
| 
 | ||||
|  | @ -81,6 +81,12 @@ namespace MWMechanics | |||
|             ///< This function is normally called automatically during the update process, but it can
 | ||||
|             /// also be called explicitly at any time to force an update.
 | ||||
| 
 | ||||
|             /** Start combat between two actors
 | ||||
|                 @Notes: If againstPlayer = true then actor2 should be the Player. | ||||
|                         If one of the combatants is creature it should be actor1. | ||||
|             */ | ||||
|             void engageCombat(const MWWorld::Ptr& actor1, const MWWorld::Ptr& actor2, bool againstPlayer); | ||||
| 
 | ||||
|             void restoreDynamicStats(bool sleep); | ||||
|             ///< If the player is sleeping, this should be called every hour.
 | ||||
| 
 | ||||
|  |  | |||
|  | @ -149,9 +149,7 @@ namespace MWMechanics | |||
|     bool AiCombat::execute (const MWWorld::Ptr& actor,float duration) | ||||
|     { | ||||
|         //General description
 | ||||
|         if(!actor.getClass().getCreatureStats(actor).isHostile() | ||||
|                 || actor.getClass().getCreatureStats(actor).getHealth().getCurrent() <= 0) | ||||
|             return true; | ||||
|         if(actor.getClass().getCreatureStats(actor).isDead()) return true; | ||||
| 
 | ||||
|         MWWorld::Ptr target = MWBase::Environment::get().getWorld()->searchPtrViaActorId(mTargetActorId); | ||||
| 
 | ||||
|  | @ -629,12 +627,9 @@ namespace MWMechanics | |||
|         return 1; | ||||
|     } | ||||
| 
 | ||||
|     std::string AiCombat::getTargetId() const | ||||
|     MWWorld::Ptr AiCombat::getTarget() const | ||||
|     { | ||||
|         MWWorld::Ptr target = MWBase::Environment::get().getWorld()->searchPtrViaActorId(mTargetActorId); | ||||
|         if (target.isEmpty()) | ||||
|             return ""; | ||||
|         return target.getRefData().getHandle(); | ||||
|         return MWBase::Environment::get().getWorld()->searchPtrViaActorId(mTargetActorId); | ||||
|     } | ||||
| 
 | ||||
| 
 | ||||
|  |  | |||
|  | @ -31,7 +31,7 @@ namespace MWMechanics | |||
|             virtual unsigned int getPriority() const; | ||||
| 
 | ||||
|             ///Returns target ID
 | ||||
|             std::string getTargetId() const; | ||||
|             MWWorld::Ptr getTarget() const; | ||||
| 
 | ||||
|         private: | ||||
|             PathFinder mPathFinder; | ||||
|  |  | |||
|  | @ -1,6 +1,5 @@ | |||
| #include "aipursue.hpp" | ||||
| 
 | ||||
| #include "../mwbase/world.hpp" | ||||
| #include "../mwbase/environment.hpp" | ||||
| 
 | ||||
| #include "../mwworld/class.hpp" | ||||
|  | @ -9,23 +8,24 @@ | |||
| 
 | ||||
| #include "../mwmechanics/creaturestats.hpp" | ||||
| 
 | ||||
| #include "steering.hpp" | ||||
| #include "movement.hpp" | ||||
| #include "creaturestats.hpp" | ||||
| 
 | ||||
| MWMechanics::AiPursue::AiPursue(const MWWorld::Ptr& actor) | ||||
|     : mActorId(actor.getClass().getCreatureStats(actor).getActorId()) | ||||
| namespace MWMechanics | ||||
| { | ||||
| 
 | ||||
| AiPursue::AiPursue(const MWWorld::Ptr& actor) | ||||
|     : mTargetActorId(actor.getClass().getCreatureStats(actor).getActorId()) | ||||
| { | ||||
| } | ||||
| MWMechanics::AiPursue *MWMechanics::AiPursue::clone() const | ||||
| AiPursue *MWMechanics::AiPursue::clone() const | ||||
| { | ||||
|     return new AiPursue(*this); | ||||
| } | ||||
| bool MWMechanics::AiPursue::execute (const MWWorld::Ptr& actor, float duration) | ||||
| bool AiPursue::execute (const MWWorld::Ptr& actor, float duration) | ||||
| { | ||||
| 
 | ||||
|     ESM::Position pos = actor.getRefData().getPosition(); //position of the actor
 | ||||
|     const MWWorld::Ptr target = MWBase::Environment::get().getWorld()->searchPtrViaActorId(mActorId); //The target to follow
 | ||||
|     const MWWorld::Ptr target = MWBase::Environment::get().getWorld()->searchPtrViaActorId(mTargetActorId); //The target to follow
 | ||||
| 
 | ||||
|     if(target == MWWorld::Ptr()) | ||||
|         return true; //Target doesn't exist
 | ||||
|  | @ -47,7 +47,14 @@ bool MWMechanics::AiPursue::execute (const MWWorld::Ptr& actor, float duration) | |||
|     return false; | ||||
| } | ||||
| 
 | ||||
| int MWMechanics::AiPursue::getTypeId() const | ||||
| int AiPursue::getTypeId() const | ||||
| { | ||||
|     return TypeIdPursue; | ||||
| } | ||||
| 
 | ||||
| MWWorld::Ptr AiPursue::getTarget() const | ||||
| { | ||||
|     return MWBase::Environment::get().getWorld()->searchPtrViaActorId(mTargetActorId); | ||||
| } | ||||
| 
 | ||||
| } // namespace MWMechanics
 | ||||
|  |  | |||
|  | @ -2,7 +2,8 @@ | |||
| #define GAME_MWMECHANICS_AIPURSUE_H | ||||
| 
 | ||||
| #include "aipackage.hpp" | ||||
| #include <string> | ||||
| 
 | ||||
| #include "../mwbase/world.hpp" | ||||
| 
 | ||||
| #include "pathfinding.hpp" | ||||
| 
 | ||||
|  | @ -18,12 +19,16 @@ namespace MWMechanics | |||
|             ///Constructor
 | ||||
|             /** \param actor Actor to pursue **/ | ||||
|             AiPursue(const MWWorld::Ptr& actor); | ||||
| 
 | ||||
|             virtual AiPursue *clone() const; | ||||
|             virtual bool execute (const MWWorld::Ptr& actor,float duration); | ||||
|             virtual int getTypeId() const; | ||||
| 
 | ||||
|             MWWorld::Ptr getTarget() const; | ||||
| 
 | ||||
|         private: | ||||
|             int mActorId; // The actor to pursue
 | ||||
| 
 | ||||
|             int mTargetActorId; // The actor to pursue
 | ||||
|             int mCellX; | ||||
|             int mCellY; | ||||
|     }; | ||||
|  |  | |||
|  | @ -9,6 +9,7 @@ | |||
| #include "aifollow.hpp" | ||||
| #include "aiactivate.hpp" | ||||
| #include "aicombat.hpp" | ||||
| #include "aipursue.hpp" | ||||
| 
 | ||||
| #include "../mwworld/class.hpp" | ||||
| #include "creaturestats.hpp" | ||||
|  | @ -16,21 +17,24 @@ | |||
| #include "../mwbase/environment.hpp" | ||||
| #include "../mwbase/world.hpp" | ||||
| 
 | ||||
| void MWMechanics::AiSequence::copy (const AiSequence& sequence) | ||||
| namespace MWMechanics | ||||
| { | ||||
| 
 | ||||
| void AiSequence::copy (const AiSequence& sequence) | ||||
| { | ||||
|     for (std::list<AiPackage *>::const_iterator iter (sequence.mPackages.begin()); | ||||
|         iter!=sequence.mPackages.end(); ++iter) | ||||
|         mPackages.push_back ((*iter)->clone()); | ||||
| } | ||||
| 
 | ||||
| MWMechanics::AiSequence::AiSequence() : mDone (false), mLastAiPackage(-1) {} | ||||
| AiSequence::AiSequence() : mDone (false), mLastAiPackage(-1) {} | ||||
| 
 | ||||
| MWMechanics::AiSequence::AiSequence (const AiSequence& sequence) : mDone (false) | ||||
| AiSequence::AiSequence (const AiSequence& sequence) : mDone (false) | ||||
| { | ||||
|     copy (sequence); | ||||
| } | ||||
| 
 | ||||
| MWMechanics::AiSequence& MWMechanics::AiSequence::operator= (const AiSequence& sequence) | ||||
| AiSequence& AiSequence::operator= (const AiSequence& sequence) | ||||
| { | ||||
|     if (this!=&sequence) | ||||
|     { | ||||
|  | @ -42,12 +46,12 @@ MWMechanics::AiSequence& MWMechanics::AiSequence::operator= (const AiSequence& s | |||
|     return *this; | ||||
| } | ||||
| 
 | ||||
| MWMechanics::AiSequence::~AiSequence() | ||||
| AiSequence::~AiSequence() | ||||
| { | ||||
|     clear(); | ||||
| } | ||||
| 
 | ||||
| int MWMechanics::AiSequence::getTypeId() const | ||||
| int AiSequence::getTypeId() const | ||||
| { | ||||
|     if (mPackages.empty()) | ||||
|         return -1; | ||||
|  | @ -55,16 +59,45 @@ int MWMechanics::AiSequence::getTypeId() const | |||
|     return mPackages.front()->getTypeId(); | ||||
| } | ||||
| 
 | ||||
| bool MWMechanics::AiSequence::getCombatTarget(std::string &targetActorId) const | ||||
| bool AiSequence::getCombatTarget(MWWorld::Ptr &targetActor) const | ||||
| { | ||||
|     if (getTypeId() != AiPackage::TypeIdCombat) | ||||
|         return false; | ||||
|     const AiCombat *combat = static_cast<const AiCombat *>(mPackages.front()); | ||||
|     targetActorId = combat->getTargetId(); | ||||
|      | ||||
|     targetActor = combat->getTarget(); | ||||
| 
 | ||||
|     return true; | ||||
| } | ||||
| 
 | ||||
| void MWMechanics::AiSequence::stopCombat() | ||||
| bool AiSequence::canAddTarget(const ESM::Position& actorPos, float distToTarget) const | ||||
| { | ||||
|     bool firstCombatFound = false; | ||||
|     MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayerPtr(); | ||||
| 
 | ||||
|     for(std::list<AiPackage*>::const_iterator it = mPackages.begin(); it != mPackages.end(); ++it) | ||||
|     { | ||||
|         if ((*it)->getTypeId() == AiPackage::TypeIdCombat) | ||||
|         { | ||||
|             firstCombatFound = true; | ||||
| 
 | ||||
|             const AiCombat *combat = static_cast<const AiCombat *>(*it); | ||||
|             if (combat->getTarget() != player ) return false; // only 1 non-player target allowed
 | ||||
|             else | ||||
|             { | ||||
|                 // add new target only if current target (player) is farther
 | ||||
|                 ESM::Position &targetPos = combat->getTarget().getRefData().getPosition(); | ||||
| 
 | ||||
|                 float distToCurrTarget = (Ogre::Vector3(targetPos.pos) - Ogre::Vector3(actorPos.pos)).length(); | ||||
|                 return (distToCurrTarget > distToTarget); | ||||
|             } | ||||
|         } | ||||
|         else if (firstCombatFound) break; // assumes combat packages go one-by-one in packages list
 | ||||
|     } | ||||
|     return true; | ||||
| } | ||||
| 
 | ||||
| void AiSequence::stopCombat() | ||||
| { | ||||
|     while (getTypeId() == AiPackage::TypeIdCombat) | ||||
|     { | ||||
|  | @ -73,7 +106,7 @@ void MWMechanics::AiSequence::stopCombat() | |||
|     } | ||||
| } | ||||
| 
 | ||||
| void MWMechanics::AiSequence::stopPursuit() | ||||
| void AiSequence::stopPursuit() | ||||
| { | ||||
|     while (getTypeId() == AiPackage::TypeIdPursue) | ||||
|     { | ||||
|  | @ -82,12 +115,12 @@ void MWMechanics::AiSequence::stopPursuit() | |||
|     } | ||||
| } | ||||
| 
 | ||||
| bool MWMechanics::AiSequence::isPackageDone() const | ||||
| bool AiSequence::isPackageDone() const | ||||
| { | ||||
|     return mDone; | ||||
| } | ||||
| 
 | ||||
| void MWMechanics::AiSequence::execute (const MWWorld::Ptr& actor,float duration) | ||||
| void AiSequence::execute (const MWWorld::Ptr& actor,float duration) | ||||
| { | ||||
|     if(actor != MWBase::Environment::get().getWorld()->getPlayerPtr()) | ||||
|     { | ||||
|  | @ -95,6 +128,36 @@ void MWMechanics::AiSequence::execute (const MWWorld::Ptr& actor,float duration) | |||
|         { | ||||
|             MWMechanics::AiPackage* package = mPackages.front(); | ||||
|             mLastAiPackage = package->getTypeId(); | ||||
| 
 | ||||
|             // if active package is combat one, choose nearest target
 | ||||
|             if (mLastAiPackage == AiPackage::TypeIdCombat) | ||||
|             { | ||||
|                 std::list<AiPackage *>::iterator itActualCombat; | ||||
| 
 | ||||
|                 float nearestDist = std::numeric_limits<float>::max(); | ||||
|                 Ogre::Vector3 vActorPos = Ogre::Vector3(actor.getRefData().getPosition().pos); | ||||
| 
 | ||||
|                 for(std::list<AiPackage *>::iterator it = mPackages.begin(); it != mPackages.end(); ++it) | ||||
|                 { | ||||
|                     if ((*it)->getTypeId() != AiPackage::TypeIdCombat) break; | ||||
| 
 | ||||
|                     ESM::Position &targetPos = static_cast<const AiCombat *>(*it)->getTarget().getRefData().getPosition(); | ||||
| 
 | ||||
|                     float distTo = (Ogre::Vector3(targetPos.pos) - vActorPos).length(); | ||||
|                     if (distTo < nearestDist) | ||||
|                     { | ||||
|                         nearestDist = distTo; | ||||
|                         itActualCombat = it; | ||||
|                     } | ||||
|                 } | ||||
| 
 | ||||
|                 if (mPackages.begin() != itActualCombat) | ||||
|                 { | ||||
|                     // move combat package with nearest target to the front
 | ||||
|                     mPackages.splice(mPackages.begin(), mPackages, itActualCombat); | ||||
|                 } | ||||
|             } | ||||
| 
 | ||||
|             if (package->execute (actor,duration)) | ||||
|             { | ||||
|                 // To account for the rare case where AiPackage::execute() queued another AI package
 | ||||
|  | @ -113,7 +176,7 @@ void MWMechanics::AiSequence::execute (const MWWorld::Ptr& actor,float duration) | |||
|     } | ||||
| } | ||||
| 
 | ||||
| void MWMechanics::AiSequence::clear() | ||||
| void AiSequence::clear() | ||||
| { | ||||
|     for (std::list<AiPackage *>::const_iterator iter (mPackages.begin()); iter!=mPackages.end(); ++iter) | ||||
|         delete *iter; | ||||
|  | @ -121,14 +184,19 @@ void MWMechanics::AiSequence::clear() | |||
|     mPackages.clear(); | ||||
| } | ||||
| 
 | ||||
| void MWMechanics::AiSequence::stack (const AiPackage& package, const MWWorld::Ptr& actor) | ||||
| void AiSequence::stack (const AiPackage& package, const MWWorld::Ptr& actor) | ||||
| { | ||||
|     if (package.getTypeId() == AiPackage::TypeIdCombat || package.getTypeId() == AiPackage::TypeIdPursue) | ||||
|     { | ||||
|         // Notify AiWander of our current position so we can return to it after combat finished
 | ||||
|         for (std::list<AiPackage *>::const_iterator iter (mPackages.begin()); iter!=mPackages.end(); ++iter) | ||||
|         { | ||||
|             if ((*iter)->getTypeId() == AiPackage::TypeIdWander) | ||||
|             if((*iter)->getTypeId() == AiPackage::TypeIdPursue && package.getTypeId() == AiPackage::TypeIdPursue | ||||
|                 && static_cast<const AiPursue*>(*iter)->getTarget() == static_cast<const AiPursue*>(&package)->getTarget()) | ||||
|             { | ||||
|                 return; // target is already pursued
 | ||||
|             } | ||||
|             else if ((*iter)->getTypeId() == AiPackage::TypeIdWander) | ||||
|                 static_cast<AiWander*>(*iter)->setReturnPosition(Ogre::Vector3(actor.getRefData().getPosition().pos)); | ||||
|         } | ||||
|     } | ||||
|  | @ -146,12 +214,12 @@ void MWMechanics::AiSequence::stack (const AiPackage& package, const MWWorld::Pt | |||
|         mPackages.push_front (package.clone()); | ||||
| } | ||||
| 
 | ||||
| void MWMechanics::AiSequence::queue (const AiPackage& package) | ||||
| void AiSequence::queue (const AiPackage& package) | ||||
| { | ||||
|     mPackages.push_back (package.clone()); | ||||
| } | ||||
| 
 | ||||
| MWMechanics::AiPackage* MWMechanics::AiSequence::getActivePackage() | ||||
| AiPackage* MWMechanics::AiSequence::getActivePackage() | ||||
| { | ||||
|     if(mPackages.empty()) | ||||
|         throw std::runtime_error(std::string("No AI Package!")); | ||||
|  | @ -159,7 +227,7 @@ MWMechanics::AiPackage* MWMechanics::AiSequence::getActivePackage() | |||
|         return mPackages.front(); | ||||
| } | ||||
| 
 | ||||
| void MWMechanics::AiSequence::fill(const ESM::AIPackageList &list) | ||||
| void AiSequence::fill(const ESM::AIPackageList &list) | ||||
| { | ||||
|     for (std::vector<ESM::AIPackage>::const_iterator it = list.mList.begin(); it != list.mList.end(); ++it) | ||||
|     { | ||||
|  | @ -195,3 +263,5 @@ void MWMechanics::AiSequence::fill(const ESM::AIPackageList &list) | |||
|         mPackages.push_back(package); | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| } // namespace MWMechanics
 | ||||
|  |  | |||
|  | @ -53,7 +53,10 @@ namespace MWMechanics | |||
|             int getLastRunTypeId() const { return mLastAiPackage; } | ||||
| 
 | ||||
|             /// Return true and assign target if combat package is currently active, return false otherwise
 | ||||
|             bool getCombatTarget (std::string &targetActorId) const; | ||||
|             bool getCombatTarget (MWWorld::Ptr &targetActor) const; | ||||
| 
 | ||||
|             bool canAddTarget(const ESM::Position& actorPos, float distToTarget) const; | ||||
|             ///< Function assumes that actor can have only 1 target apart player
 | ||||
| 
 | ||||
|             /// Removes all combat packages until first non-combat or stack empty.
 | ||||
|             void stopCombat(); | ||||
|  |  | |||
|  | @ -1012,7 +1012,16 @@ void CharacterController::update(float duration) | |||
|         bool flying = world->isFlying(mPtr); | ||||
|         //Ogre::Vector3 vec = cls.getMovementVector(mPtr);
 | ||||
|         Ogre::Vector3 vec(cls.getMovementSettings(mPtr).mPosition); | ||||
|         if(vec.z > 0.0f) // to avoid slow-down when jumping
 | ||||
|         { | ||||
|             Ogre::Vector2 vecXY = Ogre::Vector2(vec.x, vec.y); | ||||
|             vecXY.normalise(); | ||||
|             vec.x = vecXY.x; | ||||
|             vec.y = vecXY.y; | ||||
|         } | ||||
|         else  | ||||
|             vec.normalise(); | ||||
| 
 | ||||
|         if(mHitState != CharState_None && mJumpState == JumpState_None) | ||||
|             vec = Ogre::Vector3(0.0f); | ||||
|         Ogre::Vector3 rot = cls.getRotationVector(mPtr); | ||||
|  | @ -1113,9 +1122,12 @@ void CharacterController::update(float duration) | |||
|             if(cls.isNpc()) | ||||
|             { | ||||
|                 const NpcStats &stats = cls.getNpcStats(mPtr); | ||||
|                 mult = gmst.find("fJumpMoveBase")->getFloat() + | ||||
|                 static const float fJumpMoveBase = gmst.find("fJumpMoveBase")->getFloat(); | ||||
|                 static const float fJumpMoveMult = gmst.find("fJumpMoveMult")->getFloat(); | ||||
| 
 | ||||
|                 mult = fJumpMoveBase + | ||||
|                        (stats.getSkill(ESM::Skill::Acrobatics).getModified()/100.0f * | ||||
|                         gmst.find("fJumpMoveMult")->getFloat()); | ||||
|                         fJumpMoveMult); | ||||
|             } | ||||
| 
 | ||||
|             vec.x *= mult; | ||||
|  | @ -1125,14 +1137,7 @@ void CharacterController::update(float duration) | |||
|         else if(vec.z > 0.0f && mJumpState == JumpState_None) | ||||
|         { | ||||
|             // Started a jump.
 | ||||
|             float z = cls.getJump(mPtr); | ||||
|             if(vec.x == 0 && vec.y == 0) | ||||
|                 vec = Ogre::Vector3(0.0f, 0.0f, z); | ||||
|             else | ||||
|             { | ||||
|                 Ogre::Vector3 lat = Ogre::Vector3(vec.x, vec.y, 0.0f).normalisedCopy(); | ||||
|                 vec = Ogre::Vector3(lat.x, lat.y, 1.0f) * z * 0.707f; | ||||
|             } | ||||
|             vec.z = cls.getJump(mPtr); | ||||
| 
 | ||||
|             // advance acrobatics
 | ||||
|             if (mPtr.getRefData().getHandle() == "player") | ||||
|  | @ -1448,10 +1453,10 @@ void CharacterController::determineAttackType() | |||
| 
 | ||||
|     if(mPtr.getClass().hasInventoryStore(mPtr)) | ||||
|     { | ||||
|         if (move[0] && !move[1]) //sideway
 | ||||
|             mAttackType = "slash"; | ||||
|         else if (move[1]) //forward
 | ||||
|         if (move[1]) // forward-backward
 | ||||
|             mAttackType = "thrust"; | ||||
|         else if (move[0]) //sideway
 | ||||
|             mAttackType = "slash"; | ||||
|         else | ||||
|             mAttackType = "chop"; | ||||
|     } | ||||
|  |  | |||
|  | @ -321,12 +321,10 @@ namespace MWMechanics | |||
|     } | ||||
| 
 | ||||
|     bool CreatureStats::getCreatureTargetted() const | ||||
|     { | ||||
|         std::string target; | ||||
|         if (mAiSequence.getCombatTarget(target)) | ||||
|     { | ||||
|         MWWorld::Ptr targetPtr; | ||||
|             targetPtr = MWBase::Environment::get().getWorld()->getPtr(target, true); | ||||
|         if (mAiSequence.getCombatTarget(targetPtr)) | ||||
|         { | ||||
|             return targetPtr.getTypeName() == typeid(ESM::Creature).name(); | ||||
|         } | ||||
|         return false; | ||||
|  |  | |||
|  | @ -328,6 +328,12 @@ namespace MWMechanics | |||
|             path.push_front(pt); | ||||
|             current = graphParent[current]; | ||||
|         } | ||||
| 
 | ||||
|         // add first node to path explicitly
 | ||||
|         ESM::Pathgrid::Point pt = mPathgrid->mPoints[start]; | ||||
|         pt.mX += xCell; | ||||
|         pt.mY += yCell; | ||||
|         path.push_front(pt); | ||||
|         return path; | ||||
|     } | ||||
| } | ||||
|  |  | |||
|  | @ -415,9 +415,10 @@ namespace MWScript | |||
|                     std::string currentTargetId; | ||||
| 
 | ||||
|                     bool targetsAreEqual = false; | ||||
|                     if (creatureStats.getAiSequence().getCombatTarget (currentTargetId)) | ||||
|                     MWWorld::Ptr targetPtr; | ||||
|                     if (creatureStats.getAiSequence().getCombatTarget (targetPtr)) | ||||
|                     { | ||||
|                         if (currentTargetId == testedTargetId) | ||||
|                         if (targetPtr.getRefData().getHandle() == testedTargetId) | ||||
|                             targetsAreEqual = true; | ||||
|                     } | ||||
|                     runtime.push(int(targetsAreEqual)); | ||||
|  |  | |||
|  | @ -242,6 +242,15 @@ namespace MWWorld | |||
|                     // If falling, add part of the incoming velocity with the current inertia
 | ||||
|                     // TODO: but we could be jumping up?
 | ||||
|                     velocity = velocity * time + physicActor->getInertialForce(); | ||||
| 
 | ||||
|                     // avoid getting infinite inertia in air
 | ||||
|                     float actorSpeed = ptr.getClass().getSpeed(ptr); | ||||
|                     float speedXY = Ogre::Vector2(velocity.x, velocity.y).length(); | ||||
|                     if (speedXY > actorSpeed)  | ||||
|                     { | ||||
|                         velocity.x *= actorSpeed / speedXY; | ||||
|                         velocity.y *= actorSpeed / speedXY; | ||||
|                     } | ||||
|                 } | ||||
|                 inertia = velocity; // NOTE: velocity is for z axis only in this code block
 | ||||
| 
 | ||||
|  |  | |||
		Loading…
	
		Reference in a new issue