mirror of
				https://github.com/OpenMW/openmw.git
				synced 2025-10-31 20:56:39 +00:00 
			
		
		
		
	Merge remote-tracking branch 'gus/AICombat'
Conflicts: apps/openmw/CMakeLists.txt apps/openmw/mwbase/mechanicsmanager.hpp apps/openmw/mwmechanics/mechanicsmanagerimp.cpp apps/openmw/mwmechanics/mechanicsmanagerimp.hpp
This commit is contained in:
		
						commit
						11e254aac8
					
				
					 29 changed files with 394 additions and 29 deletions
				
			
		|  | @ -72,7 +72,7 @@ add_openmw_dir (mwclass | |||
| add_openmw_dir (mwmechanics | ||||
|     mechanicsmanagerimp stat character creaturestats magiceffects movement actors objects | ||||
|     drawstate spells activespells npcstats aipackage aisequence alchemy aiwander aitravel aifollow | ||||
|     aiescort aiactivate repair enchanting pathfinding security spellsuccess spellcasting | ||||
|     aiescort aiactivate aicombat repair enchanting pathfinding security spellsuccess spellcasting | ||||
|     ) | ||||
| 
 | ||||
| add_openmw_dir (mwbase | ||||
|  |  | |||
|  | @ -119,6 +119,8 @@ namespace MWBase | |||
|         /// paused we may want to do it manually (after equipping permanent enchantment)
 | ||||
|         virtual void updateMagicEffects (const MWWorld::Ptr& ptr) = 0; | ||||
| 
 | ||||
|         virtual void toggleAI() = 0; | ||||
|         virtual bool isAIActive() = 0; | ||||
|     }; | ||||
| } | ||||
| 
 | ||||
|  |  | |||
|  | @ -362,6 +362,9 @@ namespace MWBase | |||
|             virtual void getItemsOwnedBy (const MWWorld::Ptr& npc, std::vector<MWWorld::Ptr>& out) = 0; | ||||
|             ///< get all items in active cells owned by this Npc
 | ||||
| 
 | ||||
|             virtual bool getLOS(const MWWorld::Ptr& npc,const MWWorld::Ptr& targetNpc) = 0; | ||||
|             ///< get Line of Sight (morrowind stupid implementation)
 | ||||
| 
 | ||||
|             virtual void enableActorCollision(const MWWorld::Ptr& actor, bool enable) = 0; | ||||
| 
 | ||||
|             virtual void setupExternalRendering (MWRender::ExternalRendering& rendering) = 0; | ||||
|  |  | |||
|  | @ -22,6 +22,11 @@ | |||
| #include "creaturestats.hpp" | ||||
| #include "movement.hpp" | ||||
| 
 | ||||
| #include "../mwbase/environment.hpp" | ||||
| #include "../mwbase/mechanicsmanager.hpp" | ||||
| 
 | ||||
| #include "aicombat.hpp" | ||||
| 
 | ||||
| namespace MWMechanics | ||||
| { | ||||
|     void Actors::updateActor (const MWWorld::Ptr& ptr, float duration) | ||||
|  | @ -34,8 +39,47 @@ namespace MWMechanics | |||
|         if(!MWBase::Environment::get().getWindowManager()->isGuiMode()) | ||||
|         { | ||||
|             // AI
 | ||||
|             CreatureStats& creatureStats =  MWWorld::Class::get (ptr).getCreatureStats (ptr); | ||||
|             creatureStats.getAiSequence().execute (ptr); | ||||
|             if(MWBase::Environment::get().getMechanicsManager())//check MechanismsManager is already created
 | ||||
|             { | ||||
|                 if(MWBase::Environment::get().getMechanicsManager()->isAIActive())//MWBase::Environment::get().getMechanicsManager()->isAIActive())
 | ||||
|                 { | ||||
|                     CreatureStats& creatureStats =  MWWorld::Class::get (ptr).getCreatureStats (ptr); | ||||
|                     if(ptr != MWBase::Environment::get().getWorld()->getPlayer().getPlayer())  MWBase::Environment::get().getMechanicsManager()->restoreDynamicStats(); | ||||
|                     //engage combat or not?
 | ||||
|                     if(ptr != MWBase::Environment::get().getWorld()->getPlayer().getPlayer() && !creatureStats.isHostile()) | ||||
|                     { | ||||
|                         ESM::Position playerpos = MWBase::Environment::get().getWorld()->getPlayer().getPlayer().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(1); | ||||
|                         float disp = 100; //creatures don't have disposition, so set it to 100 by default
 | ||||
|                         if(ptr.getTypeName() == typeid(ESM::NPC).name()) | ||||
|                         { | ||||
|                             disp = MWBase::Environment::get().getMechanicsManager()->getDerivedDisposition(ptr); | ||||
|                         } | ||||
|                         bool LOS = MWBase::Environment::get().getWorld()->getLOS(ptr,MWBase::Environment::get().getWorld()->getPlayer().getPlayer()); | ||||
|                         if(  ( (fight == 100 )  | ||||
|                             || (fight >= 95 && d <= 3000) | ||||
|                             || (fight >= 90 && d <= 2000) | ||||
|                             || (fight >= 80 && d <= 1000) | ||||
|                             || (fight >= 80 && disp <= 40)  | ||||
|                             || (fight >= 70 && disp <= 35 && d <= 1000)  | ||||
|                             || (fight >= 60 && disp <= 30 && d <= 1000)  | ||||
|                             || (fight >= 50 && disp == 0)  | ||||
|                             || (fight >= 40 && disp <= 10 && d <= 500) ) | ||||
|                             && LOS | ||||
|                             ) | ||||
|                         { | ||||
|                             creatureStats.getAiSequence().stack(AiCombat("player")); | ||||
|                             creatureStats.setHostile(true); | ||||
|                         } | ||||
|                     } | ||||
| 
 | ||||
|                     creatureStats.getAiSequence().execute (ptr,duration); | ||||
|                 } | ||||
|             } | ||||
| 
 | ||||
|             // fatigue restoration
 | ||||
|             calculateRestoration(ptr, duration); | ||||
|  |  | |||
|  | @ -9,7 +9,7 @@ MWMechanics::AiActivate *MWMechanics::AiActivate::clone() const | |||
| { | ||||
|     return new AiActivate(*this); | ||||
| } | ||||
| bool MWMechanics::AiActivate::execute (const MWWorld::Ptr& actor) | ||||
| bool MWMechanics::AiActivate::execute (const MWWorld::Ptr& actor,float duration) | ||||
| { | ||||
|     std::cout << "AiActivate completed.\n"; | ||||
|     return true; | ||||
|  |  | |||
|  | @ -12,7 +12,7 @@ namespace MWMechanics | |||
|         public: | ||||
|             AiActivate(const std::string &objectId); | ||||
|             virtual AiActivate *clone() const; | ||||
|             virtual bool execute (const MWWorld::Ptr& actor); | ||||
|             virtual bool execute (const MWWorld::Ptr& actor,float duration); | ||||
|                     ///< \return Package completed?
 | ||||
|             virtual int getTypeId() const; | ||||
| 
 | ||||
|  |  | |||
							
								
								
									
										148
									
								
								apps/openmw/mwmechanics/aicombat.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										148
									
								
								apps/openmw/mwmechanics/aicombat.cpp
									
									
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,148 @@ | |||
| #include "aicombat.hpp" | ||||
| 
 | ||||
| #include "movement.hpp" | ||||
| 
 | ||||
| #include "../mwworld/class.hpp" | ||||
| #include "../mwworld/player.hpp" | ||||
| #include "../mwworld/timestamp.hpp" | ||||
| #include "../mwbase/world.hpp" | ||||
| #include "../mwbase/environment.hpp" | ||||
| #include "../mwbase/mechanicsmanager.hpp" | ||||
| 
 | ||||
| #include "creaturestats.hpp" | ||||
| #include "npcstats.hpp" | ||||
| 
 | ||||
| #include "OgreMath.h" | ||||
| 
 | ||||
| namespace | ||||
| { | ||||
|     static float sgn(float a) | ||||
|     { | ||||
|         if(a > 0) | ||||
|             return 1.0; | ||||
|         return -1.0; | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| namespace MWMechanics | ||||
| { | ||||
| 
 | ||||
|     AiCombat::AiCombat(const std::string &targetId) | ||||
|         :mTargetId(targetId),mTimer(0),mTimer2(0) | ||||
|     { | ||||
|     } | ||||
| 
 | ||||
|     bool AiCombat::execute (const MWWorld::Ptr& actor,float duration) | ||||
|     { | ||||
|         if(!MWWorld::Class::get(actor).getCreatureStats(actor).isHostile()) return true; | ||||
| 
 | ||||
|         const MWWorld::Ptr target = MWBase::Environment::get().getWorld()->getPtr(mTargetId, false); | ||||
| 
 | ||||
|         if(MWWorld::Class::get(actor).getCreatureStats(actor).getHealth().getCurrent() <= 0) return true; | ||||
| 
 | ||||
|         if(actor.getTypeName() == typeid(ESM::NPC).name()) | ||||
|         { | ||||
|             MWWorld::Class::get(actor). | ||||
|             MWWorld::Class::get(actor).setStance(actor, MWWorld::Class::Run,true); | ||||
|             MWMechanics::DrawState_ state = MWWorld::Class::get(actor).getNpcStats(actor).getDrawState(); | ||||
|             if (state == MWMechanics::DrawState_Spell || state == MWMechanics::DrawState_Nothing) | ||||
|                 MWWorld::Class::get(actor).getNpcStats(actor).setDrawState(MWMechanics::DrawState_Weapon);     | ||||
|             //MWWorld::Class::get(actor).getCreatureStats(actor).setAttackingOrSpell(true);
 | ||||
|         } | ||||
|         ESM::Position pos = actor.getRefData().getPosition(); | ||||
|         const ESM::Pathgrid *pathgrid = | ||||
|             MWBase::Environment::get().getWorld()->getStore().get<ESM::Pathgrid>().search(*actor.getCell()->mCell); | ||||
| 
 | ||||
|         float xCell = 0; | ||||
|         float yCell = 0; | ||||
| 
 | ||||
|         if (actor.getCell()->mCell->isExterior()) | ||||
|         { | ||||
|             xCell = actor.getCell()->mCell->mData.mX * ESM::Land::REAL_SIZE; | ||||
|             yCell = actor.getCell()->mCell->mData.mY * ESM::Land::REAL_SIZE; | ||||
|         } | ||||
| 
 | ||||
|         ESM::Pathgrid::Point dest; | ||||
|         dest.mX = target.getRefData().getPosition().pos[0]; | ||||
|         dest.mY = target.getRefData().getPosition().pos[1]; | ||||
|         dest.mZ = target.getRefData().getPosition().pos[2]; | ||||
| 
 | ||||
|         ESM::Pathgrid::Point start; | ||||
|         start.mX = pos.pos[0]; | ||||
|         start.mY = pos.pos[1]; | ||||
|         start.mZ = pos.pos[2]; | ||||
| 
 | ||||
|         mTimer2 = mTimer2 + duration; | ||||
| 
 | ||||
|         if(!mPathFinder.isPathConstructed()) | ||||
|             mPathFinder.buildPath(start, dest, pathgrid, xCell, yCell, true); | ||||
|         else | ||||
|         { | ||||
|             mPathFinder2.buildPath(start, dest, pathgrid, xCell, yCell, true); | ||||
|             ESM::Pathgrid::Point lastPt = mPathFinder.getPath().back(); | ||||
|             if((mTimer2 > 0.25)&&(mPathFinder2.getPathSize() < mPathFinder.getPathSize() || | ||||
|                 (dest.mX - lastPt.mX)*(dest.mX - lastPt.mX)+(dest.mY - lastPt.mY)*(dest.mY - lastPt.mY)+(dest.mZ - lastPt.mZ)*(dest.mZ - lastPt.mZ) > 200*200)) | ||||
|             { | ||||
|                 mTimer2 = 0; | ||||
|                 mPathFinder = mPathFinder2; | ||||
|             } | ||||
|         } | ||||
| 
 | ||||
|         mPathFinder.checkPathCompleted(pos.pos[0],pos.pos[1],pos.pos[2]); | ||||
| 
 | ||||
|         float zAngle = mPathFinder.getZAngleToNext(pos.pos[0], pos.pos[1]); | ||||
|         MWBase::Environment::get().getWorld()->rotateObject(actor, 0, 0, zAngle, false); | ||||
|         MWWorld::Class::get(actor).getMovementSettings(actor).mPosition[1] = 1; | ||||
| 
 | ||||
| 
 | ||||
|         float range = 100; | ||||
|         MWWorld::Class::get(actor).getCreatureStats(actor).setAttackingOrSpell(false); | ||||
|         if((dest.mX - start.mX)*(dest.mX - start.mX)+(dest.mY - start.mY)*(dest.mY - start.mY)+(dest.mZ - start.mZ)*(dest.mZ - start.mZ) | ||||
|             < range*range) | ||||
|         { | ||||
|             float directionX = dest.mX - start.mX; | ||||
|             float directionY = dest.mY - start.mY; | ||||
|             float directionResult = sqrt(directionX * directionX + directionY * directionY); | ||||
| 
 | ||||
|             zAngle = Ogre::Radian( acos(directionY / directionResult) * sgn(asin(directionX / directionResult)) ).valueDegrees(); | ||||
|             MWBase::Environment::get().getWorld()->rotateObject(actor, 0, 0, zAngle, false); | ||||
| 
 | ||||
|             mPathFinder.clearPath(); | ||||
| 
 | ||||
|             if(mTimer == 0) | ||||
|             { | ||||
|                 MWWorld::Class::get(actor).getCreatureStats(actor).setAttackingOrSpell(false); | ||||
|                 //mTimer = mTimer + duration;
 | ||||
|             } | ||||
|             if( mTimer > 1) | ||||
|             { | ||||
|                 MWWorld::Class::get(actor).getCreatureStats(actor).setAttackingOrSpell(true); | ||||
|                 mTimer = 0; | ||||
|             } | ||||
|             else | ||||
|             { | ||||
|                 mTimer = mTimer + duration; | ||||
|             } | ||||
| 
 | ||||
|             MWWorld::Class::get(actor).getMovementSettings(actor).mPosition[1] = 0; | ||||
|             //MWWorld::Class::get(actor).getCreatureStats(actor).setAttackingOrSpell(!MWWorld::Class::get(actor).getCreatureStats(actor).getAttackingOrSpell());
 | ||||
|         } | ||||
|         return false; | ||||
|     } | ||||
| 
 | ||||
|     int AiCombat::getTypeId() const | ||||
|     { | ||||
|         return 5; | ||||
|     } | ||||
| 
 | ||||
|     unsigned int AiCombat::getPriority() const | ||||
|     { | ||||
|         return 1; | ||||
|     } | ||||
| 
 | ||||
|     AiCombat *MWMechanics::AiCombat::clone() const | ||||
|     { | ||||
|         return new AiCombat(*this); | ||||
|     } | ||||
| } | ||||
| 
 | ||||
							
								
								
									
										36
									
								
								apps/openmw/mwmechanics/aicombat.hpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										36
									
								
								apps/openmw/mwmechanics/aicombat.hpp
									
									
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,36 @@ | |||
| #ifndef GAME_MWMECHANICS_AICOMBAT_H | ||||
| #define GAME_MWMECHANICS_AICOMBAT_H | ||||
| 
 | ||||
| #include "aipackage.hpp" | ||||
| 
 | ||||
| #include "pathfinding.hpp" | ||||
| 
 | ||||
| #include "movement.hpp" | ||||
| 
 | ||||
| namespace MWMechanics | ||||
| { | ||||
|     class AiCombat : public AiPackage | ||||
|     { | ||||
|         public: | ||||
|             AiCombat(const std::string &targetId); | ||||
| 
 | ||||
|             virtual AiCombat *clone() const; | ||||
| 
 | ||||
|             virtual bool execute (const MWWorld::Ptr& actor,float duration); | ||||
|             ///< \return Package completed?
 | ||||
| 
 | ||||
|             virtual int getTypeId() const; | ||||
| 
 | ||||
|             virtual unsigned int getPriority() const; | ||||
| 
 | ||||
|         private: | ||||
|             std::string mTargetId; | ||||
| 
 | ||||
|             PathFinder mPathFinder; | ||||
|             PathFinder mPathFinder2; | ||||
|             float mTimer; | ||||
|             float mTimer2; | ||||
|     }; | ||||
| } | ||||
| 
 | ||||
| #endif | ||||
|  | @ -71,7 +71,7 @@ namespace MWMechanics | |||
|         return new AiEscort(*this); | ||||
|     } | ||||
| 
 | ||||
|     bool AiEscort::execute (const MWWorld::Ptr& actor) | ||||
|     bool AiEscort::execute (const MWWorld::Ptr& actor,float duration) | ||||
|     { | ||||
|         // If AiEscort has ran for as long or longer then the duration specified
 | ||||
|         // and the duration is not infinite, the package is complete.
 | ||||
|  |  | |||
|  | @ -18,7 +18,7 @@ namespace MWMechanics | |||
| 
 | ||||
|             virtual AiEscort *clone() const; | ||||
| 
 | ||||
|             virtual bool execute (const MWWorld::Ptr& actor); | ||||
|             virtual bool execute (const MWWorld::Ptr& actor,float duration); | ||||
|             ///< \return Package completed?
 | ||||
| 
 | ||||
|             virtual int getTypeId() const; | ||||
|  |  | |||
|  | @ -15,7 +15,7 @@ MWMechanics::AiFollow *MWMechanics::AiFollow::clone() const | |||
|     return new AiFollow(*this); | ||||
| } | ||||
| 
 | ||||
|  bool MWMechanics::AiFollow::execute (const MWWorld::Ptr& actor) | ||||
|  bool MWMechanics::AiFollow::execute (const MWWorld::Ptr& actor,float duration) | ||||
| { | ||||
|     std::cout << "AiFollow completed.\n"; | ||||
|     return true; | ||||
|  |  | |||
|  | @ -13,7 +13,7 @@ namespace MWMechanics | |||
|             AiFollow(const std::string &ActorId,float duration, float X, float Y, float Z); | ||||
|             AiFollow(const std::string &ActorId,const std::string &CellId,float duration, float X, float Y, float Z); | ||||
|             virtual AiFollow *clone() const; | ||||
|             virtual bool execute (const MWWorld::Ptr& actor); | ||||
|             virtual bool execute (const MWWorld::Ptr& actor,float duration); | ||||
|                     ///< \return Package completed?
 | ||||
|             virtual int getTypeId() const; | ||||
| 
 | ||||
|  |  | |||
|  | @ -17,11 +17,14 @@ namespace MWMechanics | |||
|        | ||||
|             virtual AiPackage *clone() const = 0; | ||||
|              | ||||
|             virtual bool execute (const MWWorld::Ptr& actor) = 0; | ||||
|             virtual bool execute (const MWWorld::Ptr& actor,float duration) = 0; | ||||
|             ///< \return Package completed?
 | ||||
|              | ||||
|             virtual int getTypeId() const = 0; | ||||
|             ///< 0: Wanter, 1 Travel, 2 Escort, 3 Follow, 4 Activate
 | ||||
| 
 | ||||
|             virtual unsigned int getPriority() const {return 0;} | ||||
|             ///< higher number is higher priority (0 beeing the lowest)
 | ||||
|     }; | ||||
| } | ||||
| 
 | ||||
|  |  | |||
|  | @ -8,6 +8,14 @@ | |||
| #include "aitravel.hpp" | ||||
| #include "aifollow.hpp" | ||||
| #include "aiactivate.hpp" | ||||
| #include "aicombat.hpp" | ||||
| 
 | ||||
| #include "../mwworld/class.hpp" | ||||
| #include "creaturestats.hpp" | ||||
| #include "npcstats.hpp" | ||||
| #include "../mwbase/environment.hpp" | ||||
| #include "../mwbase/world.hpp" | ||||
| #include "../mwworld/player.hpp" | ||||
| 
 | ||||
| void MWMechanics::AiSequence::copy (const AiSequence& sequence) | ||||
| { | ||||
|  | @ -52,17 +60,20 @@ bool MWMechanics::AiSequence::isPackageDone() const | |||
|     return mDone; | ||||
| } | ||||
| 
 | ||||
| void MWMechanics::AiSequence::execute (const MWWorld::Ptr& actor) | ||||
| void MWMechanics::AiSequence::execute (const MWWorld::Ptr& actor,float duration) | ||||
| { | ||||
|     if (!mPackages.empty()) | ||||
|     if(actor != MWBase::Environment::get().getWorld()->getPlayer().getPlayer()) | ||||
|     { | ||||
|         if (mPackages.front()->execute (actor)) | ||||
|         if (!mPackages.empty()) | ||||
|         { | ||||
|             mPackages.erase (mPackages.begin()); | ||||
|             mDone = true; | ||||
|             if (mPackages.front()->execute (actor,duration)) | ||||
|             { | ||||
|                 mPackages.erase (mPackages.begin()); | ||||
|                 mDone = true; | ||||
|             } | ||||
|             else | ||||
|                 mDone = false;     | ||||
|         } | ||||
|         else | ||||
|             mDone = false;     | ||||
|     } | ||||
| } | ||||
| 
 | ||||
|  | @ -76,7 +87,14 @@ void MWMechanics::AiSequence::clear() | |||
| 
 | ||||
| void MWMechanics::AiSequence::stack (const AiPackage& package) | ||||
| { | ||||
|     mPackages.push_front (package.clone()); | ||||
|     for(std::list<AiPackage *>::iterator it = mPackages.begin(); it != mPackages.end(); it++) | ||||
|     { | ||||
|         if(mPackages.front()->getPriority() <= package.getPriority()) | ||||
|             mPackages.insert(it,package.clone()); | ||||
|     } | ||||
| 
 | ||||
|     if(mPackages.empty()) | ||||
|         mPackages.push_front (package.clone()); | ||||
| } | ||||
| 
 | ||||
| void MWMechanics::AiSequence::queue (const AiPackage& package) | ||||
|  |  | |||
|  | @ -18,6 +18,7 @@ namespace MWMechanics | |||
|     class AiSequence | ||||
|     { | ||||
|             std::list<AiPackage *> mPackages; | ||||
| 
 | ||||
|             bool mDone; | ||||
| 
 | ||||
|             void copy (const AiSequence& sequence); | ||||
|  | @ -33,17 +34,17 @@ namespace MWMechanics | |||
|             virtual ~AiSequence(); | ||||
| 
 | ||||
|             int getTypeId() const; | ||||
|             ///< -1: None, 0: Wanter, 1 Travel, 2 Escort, 3 Follow, 4 Activate    
 | ||||
|             ///< -1: None, 0: Wanter, 1 Travel, 2 Escort, 3 Follow, 4 Activate, 5 Combat    
 | ||||
|              | ||||
|             bool isPackageDone() const; | ||||
|             ///< Has a package been completed during the last update?
 | ||||
|              | ||||
|             void execute (const MWWorld::Ptr& actor); | ||||
|             void execute (const MWWorld::Ptr& actor,float duration); | ||||
|             ///< Execute package.
 | ||||
|              | ||||
|             void clear(); | ||||
|             ///< Remove all packages.
 | ||||
|              | ||||
| 
 | ||||
|             void stack (const AiPackage& package); | ||||
|             ///< Add \a package to the front of the sequence (suspends current package)
 | ||||
|              | ||||
|  |  | |||
|  | @ -31,7 +31,7 @@ namespace MWMechanics | |||
|         return new AiTravel(*this); | ||||
|     } | ||||
| 
 | ||||
|     bool AiTravel::execute (const MWWorld::Ptr& actor) | ||||
|     bool AiTravel::execute (const MWWorld::Ptr& actor,float duration) | ||||
|     { | ||||
|         MWBase::World *world = MWBase::Environment::get().getWorld(); | ||||
|         ESM::Position pos = actor.getRefData().getPosition(); | ||||
|  |  | |||
|  | @ -13,7 +13,7 @@ namespace MWMechanics | |||
|             AiTravel(float x, float y, float z); | ||||
|             virtual AiTravel *clone() const; | ||||
| 
 | ||||
|             virtual bool execute (const MWWorld::Ptr& actor); | ||||
|             virtual bool execute (const MWWorld::Ptr& actor,float duration); | ||||
|                     ///< \return Package completed?
 | ||||
| 
 | ||||
|             virtual int getTypeId() const; | ||||
|  |  | |||
|  | @ -63,7 +63,7 @@ namespace MWMechanics | |||
|         return new AiWander(*this); | ||||
|     } | ||||
| 
 | ||||
|     bool AiWander::execute (const MWWorld::Ptr& actor) | ||||
|     bool AiWander::execute (const MWWorld::Ptr& actor,float duration) | ||||
|     { | ||||
|         MWBase::World *world = MWBase::Environment::get().getWorld(); | ||||
|         if(mDuration) | ||||
|  |  | |||
|  | @ -16,7 +16,7 @@ namespace MWMechanics | |||
| 
 | ||||
|             AiWander(int distance, int duration, int timeOfDay, const std::vector<int>& idle, bool repeat); | ||||
|             virtual AiPackage *clone() const; | ||||
|             virtual bool execute (const MWWorld::Ptr& actor); | ||||
|             virtual bool execute (const MWWorld::Ptr& actor,float duration); | ||||
|             ///< \return Package completed?
 | ||||
|             virtual int getTypeId() const; | ||||
|             ///< 0: Wander
 | ||||
|  |  | |||
|  | @ -165,7 +165,7 @@ namespace MWMechanics | |||
| 
 | ||||
|     MechanicsManager::MechanicsManager() | ||||
|     : mUpdatePlayer (true), mClassSelected (false), | ||||
|       mRaceSelected (false) | ||||
|       mRaceSelected (false), mAI(true) | ||||
|     { | ||||
|         //buildPlayer no longer here, needs to be done explicitely after all subsystems are up and running
 | ||||
|     } | ||||
|  | @ -684,4 +684,13 @@ namespace MWMechanics | |||
|         mActors.updateMagicEffects(ptr); | ||||
|     } | ||||
| 
 | ||||
|     void MechanicsManager::toggleAI() | ||||
|     { | ||||
|         mAI = !mAI; | ||||
|     } | ||||
| 
 | ||||
|     bool MechanicsManager::isAIActive() | ||||
|     { | ||||
|         return mAI; | ||||
|     } | ||||
| } | ||||
|  |  | |||
|  | @ -29,6 +29,7 @@ namespace MWMechanics | |||
|             bool mUpdatePlayer; | ||||
|             bool mClassSelected; | ||||
|             bool mRaceSelected; | ||||
|             bool mAI;///< is AI active?
 | ||||
| 
 | ||||
|             Objects mObjects; | ||||
|             Actors mActors; | ||||
|  | @ -89,7 +90,7 @@ namespace MWMechanics | |||
| 
 | ||||
|             virtual int countDeaths (const std::string& id) const; | ||||
|             ///< Return the number of deaths for actors with the given ID.
 | ||||
|              | ||||
| 
 | ||||
|             virtual void getPersuasionDispositionChange (const MWWorld::Ptr& npc, PersuasionType type, | ||||
|                 float currentTemporaryDispositionDelta, bool& success, float& tempChange, float& permChange); | ||||
|             void toLower(std::string npcFaction); | ||||
|  | @ -105,6 +106,8 @@ namespace MWMechanics | |||
|             /// paused we may want to do it manually (after equipping permanent enchantment)
 | ||||
|             virtual void updateMagicEffects (const MWWorld::Ptr& ptr); | ||||
| 
 | ||||
|         virtual void toggleAI(); | ||||
|         virtual bool isAIActive(); | ||||
|     }; | ||||
| } | ||||
| 
 | ||||
|  |  | |||
|  | @ -189,7 +189,7 @@ namespace MWMechanics | |||
|         // This should never happen (programmers should have an if statement checking mIsPathConstructed that prevents this call
 | ||||
|         // if otherwise).
 | ||||
|         if(mPath.empty()) | ||||
|             return 0; | ||||
|             return 0.; | ||||
| 
 | ||||
|         const ESM::Pathgrid::Point &nextPoint = *mPath.begin(); | ||||
|         float directionX = nextPoint.mX - x; | ||||
|  | @ -199,6 +199,21 @@ namespace MWMechanics | |||
|         return Ogre::Radian(acos(directionY / directionResult) * sgn(asin(directionX / directionResult))).valueDegrees(); | ||||
|     } | ||||
| 
 | ||||
|     bool PathFinder::checkWaypoint(float x, float y, float z) | ||||
|     { | ||||
|         if(mPath.empty()) | ||||
|             return true; | ||||
| 
 | ||||
|         ESM::Pathgrid::Point nextPoint = *mPath.begin(); | ||||
|         if(distanceZCorrected(nextPoint, x, y, z) < 64) | ||||
|         { | ||||
|             mPath.pop_front(); | ||||
|             if(mPath.empty()) mIsPathConstructed = false; | ||||
|             return true; | ||||
|         } | ||||
|         return false; | ||||
|     } | ||||
| 
 | ||||
|     bool PathFinder::checkPathCompleted(float x, float y, float z) | ||||
|     { | ||||
|         if(mPath.empty()) | ||||
|  |  | |||
|  | @ -18,6 +18,8 @@ namespace MWMechanics | |||
| 
 | ||||
|             bool checkPathCompleted(float x, float y, float z); | ||||
|             ///< \Returns true if the last point of the path has been reached.
 | ||||
|             bool checkWaypoint(float x, float y, float z); | ||||
|             ///< \Returns true if a way point was reached
 | ||||
|             float getZAngleToNext(float x, float y) const; | ||||
| 
 | ||||
|             bool isPathConstructed() const | ||||
|  | @ -25,6 +27,16 @@ namespace MWMechanics | |||
|                 return mIsPathConstructed; | ||||
|             } | ||||
| 
 | ||||
|             int getPathSize() const | ||||
|             { | ||||
|                 return mPath.size(); | ||||
|             } | ||||
| 
 | ||||
|             std::list<ESM::Pathgrid::Point> getPath() const | ||||
|             { | ||||
|                 return mPath; | ||||
|             } | ||||
| 
 | ||||
|         private: | ||||
|             std::list<ESM::Pathgrid::Point> mPath; | ||||
|             bool mIsPathConstructed; | ||||
|  |  | |||
|  | @ -17,11 +17,16 @@ | |||
| #include "../mwmechanics/aitravel.hpp" | ||||
| #include "../mwmechanics/aiwander.hpp" | ||||
| 
 | ||||
| #include "../mwbase/environment.hpp" | ||||
| #include "../mwbase/world.hpp" | ||||
| 
 | ||||
| #include "interpretercontext.hpp" | ||||
| #include "ref.hpp" | ||||
| 
 | ||||
| #include <iostream> | ||||
| 
 | ||||
| #include "../mwbase/mechanicsmanager.hpp" | ||||
| 
 | ||||
| namespace MWScript | ||||
| { | ||||
|     namespace Ai | ||||
|  | @ -364,6 +369,39 @@ namespace MWScript | |||
|                 } | ||||
|         }; | ||||
| 
 | ||||
|         template<class R> | ||||
|         class OpGetLineOfSight : public Interpreter::Opcode0 | ||||
|         { | ||||
|             public: | ||||
| 
 | ||||
|                 virtual void execute (Interpreter::Runtime& runtime) | ||||
|                 { | ||||
| 
 | ||||
|                     MWWorld::Ptr source = R()(runtime); | ||||
| 
 | ||||
|                     std::string actorID = runtime.getStringLiteral (runtime[0].mInteger); | ||||
|                     runtime.pop(); | ||||
| 
 | ||||
|                     MWWorld::Ptr dest = MWBase::Environment::get().getWorld()->getPtr(actorID,true); | ||||
|                     bool value = false; | ||||
|                     if(dest != MWWorld::Ptr() ) | ||||
|                     { | ||||
|                         value = MWBase::Environment::get().getWorld()->getLOS(source,dest); | ||||
|                     } | ||||
|                     runtime.push (value); | ||||
|                 } | ||||
|         }; | ||||
| 
 | ||||
|         template<class R> | ||||
|         class OpToggleAI : public Interpreter::Opcode0 | ||||
|         { | ||||
|             public: | ||||
| 
 | ||||
|                 virtual void execute (Interpreter::Runtime& runtime) | ||||
|                 { | ||||
|                     MWBase::Environment::get().getMechanicsManager()->toggleAI();    | ||||
|                 } | ||||
|         }; | ||||
| 
 | ||||
|         void installOpcodes (Interpreter::Interpreter& interpreter) | ||||
|         { | ||||
|  | @ -389,6 +427,11 @@ namespace MWScript | |||
|             interpreter.installSegment5 (Compiler::Ai::opcodeGetCurrentAiPackageExplicit, new OpGetCurrentAIPackage<ExplicitRef>); | ||||
|             interpreter.installSegment3 (Compiler::Ai::opcodeGetDetected, new OpGetDetected<ImplicitRef>); | ||||
|             interpreter.installSegment3 (Compiler::Ai::opcodeGetDetectedExplicit, new OpGetDetected<ExplicitRef>); | ||||
|             interpreter.installSegment5 (Compiler::Ai::opcodeGetLineOfSight, new OpGetLineOfSight<ImplicitRef>); | ||||
|             interpreter.installSegment5 (Compiler::Ai::opcodeGetLineOfSightExplicit, new OpGetLineOfSight<ExplicitRef>); | ||||
|             interpreter.installSegment5 (Compiler::Ai::opcodeToggleAI, new OpToggleAI<ImplicitRef>); | ||||
|             interpreter.installSegment5 (Compiler::Ai::opcodeToggleAIExplicit, new OpToggleAI<ExplicitRef>); | ||||
| 
 | ||||
|             interpreter.installSegment5 (Compiler::Ai::opcodeSetHello, new OpSetAiSetting<ImplicitRef>(0)); | ||||
|             interpreter.installSegment5 (Compiler::Ai::opcodeSetHelloExplicit, new OpSetAiSetting<ExplicitRef>(0)); | ||||
|             interpreter.installSegment5 (Compiler::Ai::opcodeSetFight, new OpSetAiSetting<ImplicitRef>(1)); | ||||
|  |  | |||
|  | @ -354,5 +354,9 @@ op 0x200021e: ShowVarsExplicit | |||
| op 0x200021f: ToggleGodMode | ||||
| op 0x2000220: DisableLevitation | ||||
| op 0x2000221: EnableLevitation | ||||
| op 0x2000222: GetLineOfSight | ||||
| op 0x2000223: GetLineOfSightExplicit | ||||
| op 0x2000224: ToggleAI | ||||
| op 0x2000225: ToggleAIExplicit | ||||
| 
 | ||||
| opcodes 0x2000222-0x3ffffff unused | ||||
| opcodes 0x2000226-0x3ffffff unused | ||||
|  |  | |||
|  | @ -1832,6 +1832,21 @@ namespace MWWorld | |||
|         } | ||||
|     } | ||||
| 
 | ||||
|     bool World::getLOS(const MWWorld::Ptr& npc,const MWWorld::Ptr& targetNpc) | ||||
|     { | ||||
|         Ogre::Vector3 halfExt1 = mPhysEngine->getCharacter(npc.getRefData().getHandle())->getHalfExtents(); | ||||
|         float* pos1 = npc.getRefData().getPosition().pos; | ||||
|         Ogre::Vector3 halfExt2 = mPhysEngine->getCharacter(targetNpc.getRefData().getHandle())->getHalfExtents(); | ||||
|         float* pos2 = targetNpc.getRefData().getPosition().pos; | ||||
| 
 | ||||
|         btVector3 from(pos1[0],pos1[1],pos1[2]+halfExt1.z); | ||||
|         btVector3 to(pos2[0],pos2[1],pos2[2]+halfExt2.z); | ||||
| 
 | ||||
|         std::pair<std::string, float> result = mPhysEngine->rayTest(from, to,false); | ||||
|         if(result.first == "") return true; | ||||
|         return false; | ||||
|     } | ||||
| 
 | ||||
|     void World::enableActorCollision(const MWWorld::Ptr& actor, bool enable) | ||||
|     { | ||||
|         OEngine::Physic::PhysicActor *physicActor = mPhysEngine->getCharacter(actor.getRefData().getHandle()); | ||||
|  |  | |||
|  | @ -441,6 +441,9 @@ namespace MWWorld | |||
|             virtual void getItemsOwnedBy (const MWWorld::Ptr& npc, std::vector<MWWorld::Ptr>& out); | ||||
|             ///< get all items in active cells owned by this Npc
 | ||||
| 
 | ||||
|             virtual bool getLOS(const MWWorld::Ptr& npc,const MWWorld::Ptr& targetNpc); | ||||
|             ///< get Line of Sight (morrowind stupid implementation)
 | ||||
| 
 | ||||
|             virtual void enableActorCollision(const MWWorld::Ptr& actor, bool enable); | ||||
| 
 | ||||
|             virtual void setupExternalRendering (MWRender::ExternalRendering& rendering); | ||||
|  |  | |||
|  | @ -59,10 +59,12 @@ namespace Compiler | |||
|             extensions.registerInstruction ("modfight", "l", opcodeModFight, opcodeModFightExplicit); | ||||
|             extensions.registerInstruction ("modflee", "l", opcodeModFlee, opcodeModFleeExplicit); | ||||
|             extensions.registerInstruction ("modalarm", "l", opcodeModAlarm, opcodeModAlarmExplicit); | ||||
|             extensions.registerInstruction ("toggleai", "", opcodeToggleAI, opcodeToggleAI); | ||||
|             extensions.registerFunction ("gethello", 'l', "", opcodeGetHello, opcodeGetHelloExplicit); | ||||
|             extensions.registerFunction ("getfight", 'l', "", opcodeGetFight, opcodeGetFightExplicit); | ||||
|             extensions.registerFunction ("getflee", 'l', "", opcodeGetFlee, opcodeGetFleeExplicit); | ||||
|             extensions.registerFunction ("getalarm", 'l', "", opcodeGetAlarm, opcodeGetAlarmExplicit); | ||||
|             extensions.registerFunction ("getlineofsight", 'l', "c", opcodeGetLineOfSight, opcodeGetLineOfSightExplicit); | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|  |  | |||
|  | @ -49,6 +49,10 @@ namespace Compiler | |||
|         const int opcodeGetFleeExplicit = 0x20001c4; | ||||
|         const int opcodeGetAlarm = 0x20001c5; | ||||
|         const int opcodeGetAlarmExplicit = 0x20001c6; | ||||
|         const int opcodeGetLineOfSight = 0x2000222; | ||||
|         const int opcodeGetLineOfSightExplicit = 0x2000223; | ||||
|         const int opcodeToggleAI = 0x2000224; | ||||
|         const int opcodeToggleAIExplicit = 0x2000225; | ||||
|     } | ||||
| 
 | ||||
|     namespace Animation | ||||
|  |  | |||
		Loading…
	
		Reference in a new issue