mirror of
				https://github.com/TES3MP/openmw-tes3mp.git
				synced 2025-10-31 12:26:44 +00:00 
			
		
		
		
	Ai pursue now controls guards pursuit of crimes
Should extend AiActivate in the future
This commit is contained in:
		
							parent
							
								
									50dac98a2b
								
							
						
					
					
						commit
						7c0b51fb7e
					
				
					 11 changed files with 171 additions and 19 deletions
				
			
		|  | @ -67,7 +67,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 | ||||
|     drawstate spells activespells npcstats aipackage aisequence aipersue alchemy aiwander aitravel aifollow | ||||
|     aiescort aiactivate aicombat repair enchanting pathfinding security spellsuccess spellcasting | ||||
|     disease pickpocket levelledlist combat steering | ||||
|     ) | ||||
|  |  | |||
|  | @ -9,11 +9,9 @@ | |||
| 
 | ||||
| #include "steering.hpp" | ||||
| #include "movement.hpp" | ||||
| #include "creaturestats.hpp" | ||||
| 
 | ||||
| MWMechanics::AiActivate::AiActivate(const std::string &objectId, int arg) | ||||
|     : mObjectId(objectId), | ||||
|       mArg(arg) | ||||
| MWMechanics::AiActivate::AiActivate(const std::string &objectId) | ||||
|     : mObjectId(objectId) | ||||
| { | ||||
| } | ||||
| MWMechanics::AiActivate *MWMechanics::AiActivate::clone() const | ||||
|  | @ -27,9 +25,6 @@ bool MWMechanics::AiActivate::execute (const MWWorld::Ptr& actor,float duration) | |||
|     Movement &movement = actor.getClass().getMovementSettings(actor); | ||||
|     const ESM::Cell *cell = actor.getCell()->getCell(); | ||||
| 
 | ||||
|     if (mArg == 1) // run to actor
 | ||||
|         actor.getClass().getCreatureStats(actor).setMovementFlag(CreatureStats::Flag_Run, true); | ||||
| 
 | ||||
|     MWWorld::Ptr player = world->getPlayerPtr(); | ||||
|     if(cell->mData.mX != player.getCell()->getCell()->mData.mX) | ||||
|     { | ||||
|  |  | |||
|  | @ -12,7 +12,7 @@ namespace MWMechanics | |||
|     class AiActivate : public AiPackage | ||||
|     { | ||||
|         public: | ||||
|             AiActivate(const std::string &objectId, int arg); | ||||
|             AiActivate(const std::string &objectId); | ||||
|             virtual AiActivate *clone() const; | ||||
|             virtual bool execute (const MWWorld::Ptr& actor,float duration); | ||||
|                     ///< \return Package completed?
 | ||||
|  | @ -20,7 +20,6 @@ namespace MWMechanics | |||
| 
 | ||||
|         private: | ||||
|             std::string mObjectId; | ||||
|             int mArg; | ||||
| 
 | ||||
|             PathFinder mPathFinder; | ||||
|             int mCellX; | ||||
|  |  | |||
|  | @ -19,7 +19,8 @@ namespace MWMechanics | |||
|                 TypeIdEscort = 2, | ||||
|                 TypeIdFollow = 3, | ||||
|                 TypeIdActivate = 4, | ||||
|                 TypeIdCombat = 5 | ||||
|                 TypeIdCombat = 5, | ||||
|                 TypeIdPersue = 6 | ||||
|             }; | ||||
| 
 | ||||
|             virtual ~AiPackage(); | ||||
|  |  | |||
							
								
								
									
										108
									
								
								apps/openmw/mwmechanics/aipersue.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										108
									
								
								apps/openmw/mwmechanics/aipersue.cpp
									
									
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,108 @@ | |||
| #include "aipersue.hpp" | ||||
| 
 | ||||
| #include "../mwbase/world.hpp" | ||||
| #include "../mwbase/environment.hpp" | ||||
| 
 | ||||
| #include "../mwworld/class.hpp" | ||||
| #include "../mwworld/action.hpp" | ||||
| #include "../mwworld/cellstore.hpp" | ||||
| 
 | ||||
| #include "steering.hpp" | ||||
| #include "movement.hpp" | ||||
| #include "creaturestats.hpp" | ||||
| 
 | ||||
| MWMechanics::AiPersue::AiPersue(const std::string &objectId) | ||||
|     : mObjectId(objectId) | ||||
| { | ||||
| } | ||||
| MWMechanics::AiPersue *MWMechanics::AiPersue::clone() const | ||||
| { | ||||
|     return new AiPersue(*this); | ||||
| } | ||||
| bool MWMechanics::AiPersue::execute (const MWWorld::Ptr& actor,float duration) | ||||
| { | ||||
|     //TODO: Guards should not dialague with player after crime reset
 | ||||
| 
 | ||||
|     MWBase::World *world = MWBase::Environment::get().getWorld(); | ||||
|     ESM::Position pos = actor.getRefData().getPosition(); | ||||
|     Movement &movement = actor.getClass().getMovementSettings(actor); | ||||
|     const ESM::Cell *cell = actor.getCell()->getCell(); | ||||
| 
 | ||||
|     actor.getClass().getCreatureStats(actor).setMovementFlag(CreatureStats::Flag_Run, true); | ||||
| 
 | ||||
|     MWWorld::Ptr player = world->getPlayerPtr(); | ||||
|     if(cell->mData.mX != player.getCell()->getCell()->mData.mX) | ||||
|     { | ||||
|         int sideX = PathFinder::sgn(cell->mData.mX - player.getCell()->getCell()->mData.mX); | ||||
|         //check if actor is near the border of an inactive cell. If so, stop walking.
 | ||||
|         if(sideX * (pos.pos[0] - cell->mData.mX*ESM::Land::REAL_SIZE) > | ||||
|             sideX * (ESM::Land::REAL_SIZE/2.0f - 200.0f)) | ||||
|         { | ||||
|             movement.mPosition[1] = 0; | ||||
|             return false; | ||||
|         } | ||||
|     } | ||||
|     if(cell->mData.mY != player.getCell()->getCell()->mData.mY) | ||||
|     { | ||||
|         int sideY = PathFinder::sgn(cell->mData.mY - player.getCell()->getCell()->mData.mY); | ||||
|         //check if actor is near the border of an inactive cell. If so, stop walking.
 | ||||
|         if(sideY * (pos.pos[1] - cell->mData.mY*ESM::Land::REAL_SIZE) > | ||||
|             sideY * (ESM::Land::REAL_SIZE/2.0f - 200.0f)) | ||||
|         { | ||||
|             movement.mPosition[1] = 0; | ||||
|             return false; | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     MWWorld::Ptr target = world->getPtr(mObjectId,false); | ||||
|     ESM::Position targetPos = target.getRefData().getPosition(); | ||||
| 
 | ||||
|     bool cellChange = cell->mData.mX != mCellX || cell->mData.mY != mCellY; | ||||
|     if(!mPathFinder.isPathConstructed() || cellChange) | ||||
|     { | ||||
|         mCellX = cell->mData.mX; | ||||
|         mCellY = cell->mData.mY; | ||||
| 
 | ||||
|         ESM::Pathgrid::Point dest; | ||||
|         dest.mX = targetPos.pos[0]; | ||||
|         dest.mY = targetPos.pos[1]; | ||||
|         dest.mZ = targetPos.pos[2]; | ||||
| 
 | ||||
|         ESM::Pathgrid::Point start; | ||||
|         start.mX = pos.pos[0]; | ||||
|         start.mY = pos.pos[1]; | ||||
|         start.mZ = pos.pos[2]; | ||||
| 
 | ||||
|         mPathFinder.buildPath(start, dest, actor.getCell(), true); | ||||
|     } | ||||
| 
 | ||||
|     if((pos.pos[0]-targetPos.pos[0])*(pos.pos[0]-targetPos.pos[0])+ | ||||
|         (pos.pos[1]-targetPos.pos[1])*(pos.pos[1]-targetPos.pos[1])+ | ||||
|         (pos.pos[2]-targetPos.pos[2])*(pos.pos[2]-targetPos.pos[2]) < 200*200) | ||||
|     { | ||||
|         movement.mPosition[1] = 0; | ||||
|         MWWorld::Ptr target = world->getPtr(mObjectId,false); | ||||
|         MWWorld::Class::get(target).activate(target,actor).get()->execute(actor); | ||||
|         return true; | ||||
|     } | ||||
| 
 | ||||
|     if(mPathFinder.checkPathCompleted(pos.pos[0], pos.pos[1], pos.pos[2])) | ||||
|     { | ||||
|         movement.mPosition[1] = 0; | ||||
|         MWWorld::Ptr target = world->getPtr(mObjectId,false); | ||||
|         MWWorld::Class::get(target).activate(target,actor).get()->execute(actor); | ||||
|         return true; | ||||
|     } | ||||
| 
 | ||||
|     float zAngle = mPathFinder.getZAngleToNext(pos.pos[0], pos.pos[1]); | ||||
|     zTurn(actor, Ogre::Degree(zAngle)); | ||||
|     MWWorld::Class::get(actor).getMovementSettings(actor).mPosition[1] = 1; | ||||
|     movement.mPosition[1] = 1; | ||||
| 
 | ||||
|     return false; | ||||
| } | ||||
| 
 | ||||
| int MWMechanics::AiPersue::getTypeId() const | ||||
| { | ||||
|     return TypeIdPersue; | ||||
| } | ||||
							
								
								
									
										29
									
								
								apps/openmw/mwmechanics/aipersue.hpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										29
									
								
								apps/openmw/mwmechanics/aipersue.hpp
									
									
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,29 @@ | |||
| #ifndef GAME_MWMECHANICS_AIPERSUE_H | ||||
| #define GAME_MWMECHANICS_AIPERSUE_H | ||||
| 
 | ||||
| #include "aipackage.hpp" | ||||
| #include <string> | ||||
| 
 | ||||
| #include "pathfinding.hpp" | ||||
| 
 | ||||
| namespace MWMechanics | ||||
| { | ||||
| 
 | ||||
|     class AiPersue : public AiPackage | ||||
|     { | ||||
|         public: | ||||
|             AiPersue(const std::string &objectId); | ||||
|             virtual AiPersue *clone() const; | ||||
|             virtual bool execute (const MWWorld::Ptr& actor,float duration); | ||||
|                     ///< \return Package completed?
 | ||||
|             virtual int getTypeId() const; | ||||
| 
 | ||||
|         private: | ||||
|             std::string mObjectId; | ||||
| 
 | ||||
|             PathFinder mPathFinder; | ||||
|             int mCellX; | ||||
|             int mCellY; | ||||
|     }; | ||||
| } | ||||
| #endif | ||||
|  | @ -73,6 +73,15 @@ void MWMechanics::AiSequence::stopCombat() | |||
|     } | ||||
| } | ||||
| 
 | ||||
| void MWMechanics::AiSequence::stopPersue() | ||||
| { | ||||
|     while (getTypeId() == AiPackage::TypeIdPersue) | ||||
|     { | ||||
|         delete *mPackages.begin(); | ||||
|         mPackages.erase (mPackages.begin()); | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| bool MWMechanics::AiSequence::isPackageDone() const | ||||
| { | ||||
|     return mDone; | ||||
|  | @ -161,7 +170,7 @@ void MWMechanics::AiSequence::fill(const ESM::AIPackageList &list) | |||
|         else if (it->mType == ESM::AI_Activate) | ||||
|         { | ||||
|             ESM::AIActivate data = it->mActivate; | ||||
|             package = new MWMechanics::AiActivate(data.mName.toString(), 0); | ||||
|             package = new MWMechanics::AiActivate(data.mName.toString()); | ||||
|         } | ||||
|         else //if (it->mType == ESM::AI_Follow)
 | ||||
|         { | ||||
|  |  | |||
|  | @ -49,6 +49,9 @@ namespace MWMechanics | |||
| 
 | ||||
|             void stopCombat(); | ||||
|             ///< Removes all combat packages until first non-combat or stack empty.
 | ||||
| 
 | ||||
|             void stopPersue(); | ||||
|             ///< Removes all persue packages until first non-persue or stack empty.
 | ||||
|              | ||||
|             bool isPackageDone() const; | ||||
|             ///< Has a package been completed during the last update?
 | ||||
|  |  | |||
|  | @ -13,6 +13,7 @@ | |||
| #include "../mwworld/player.hpp" | ||||
| 
 | ||||
| #include "aicombat.hpp" | ||||
| #include "aipersue.hpp" | ||||
| #include "aiactivate.hpp" | ||||
| 
 | ||||
| #include <OgreSceneNode.h> | ||||
|  | @ -838,8 +839,6 @@ namespace MWMechanics | |||
|         std::vector<MWWorld::Ptr> neighbors; | ||||
|         mActors.getObjectsInRange(Ogre::Vector3(ptr.getRefData().getPosition().pos),  | ||||
|             esmStore.get<ESM::GameSetting>().find("fAlarmRadius")->getInt(), neighbors); | ||||
|          | ||||
|         // Did anyone see the crime?
 | ||||
|         for (std::vector<MWWorld::Ptr>::iterator it = neighbors.begin(); it != neighbors.end(); ++it) | ||||
|         {  | ||||
|             if (*it == ptr) // Not the player
 | ||||
|  | @ -880,12 +879,12 @@ namespace MWMechanics | |||
|                             { | ||||
|                                 creatureStats1.getAiSequence().stack(AiCombat(ptr)); | ||||
|                                 creatureStats1.setHostile(true); | ||||
|                                 creatureStats1.getAiSequence().execute(*it,0); | ||||
|                                 creatureStats1.getAiSequence().execute(*it1,0); | ||||
|                             } | ||||
|                             else // will the guard persue the player?
 | ||||
|                             { | ||||
|                                 creatureStats1.getAiSequence().stack(AiActivate(ptr.getClass().getId(ptr), 1)); | ||||
|                                 creatureStats1.getAiSequence().execute(*it,0); | ||||
|                                 creatureStats1.getAiSequence().stack(AiPersue(ptr.getClass().getId(ptr))); | ||||
|                                 creatureStats1.getAiSequence().execute(*it1,0); | ||||
|                             }  | ||||
|                         } | ||||
|                         // will the witness fight the player?
 | ||||
|  |  | |||
|  | @ -47,7 +47,7 @@ namespace MWScript | |||
|                     // discard additional arguments (reset), because we have no idea what they mean.
 | ||||
|                     for (unsigned int i=0; i<arg0; ++i) runtime.pop(); | ||||
| 
 | ||||
|                     MWMechanics::AiActivate activatePackage(objectID, 0); | ||||
|                     MWMechanics::AiActivate activatePackage(objectID); | ||||
|                     MWWorld::Class::get (ptr).getCreatureStats (ptr).getAiSequence().stack(activatePackage); | ||||
|                     std::cout << "AiActivate" << std::endl; | ||||
|                 } | ||||
|  |  | |||
|  | @ -29,6 +29,7 @@ | |||
| #include "../mwmechanics/spellcasting.hpp" | ||||
| #include "../mwmechanics/levelledlist.hpp" | ||||
| #include "../mwmechanics/combat.hpp" | ||||
| #include "../mwmechanics/actors.hpp" | ||||
| 
 | ||||
| #include "../mwrender/sky.hpp" | ||||
| #include "../mwrender/animation.hpp" | ||||
|  | @ -2762,6 +2763,9 @@ namespace MWWorld | |||
|                 message += "\n" + skillMsg; | ||||
|             } | ||||
| 
 | ||||
|             // sleep the player, this doesn't work
 | ||||
|             //player.getClass().calculateRestoration(player, days, true);
 | ||||
| 
 | ||||
|             resetCrimes(player); | ||||
| 
 | ||||
|             std::vector<std::string> buttons; | ||||
|  | @ -2776,10 +2780,15 @@ namespace MWWorld | |||
|         std::vector<MWWorld::Ptr> neighbors = ptr.getClass().getCreatureStats(ptr).getPlayerWitnesses(); | ||||
|         for (std::vector<MWWorld::Ptr>::iterator it = neighbors.begin(); it != neighbors.end(); ++it) | ||||
|         { | ||||
|             // This to reset for each witness: 
 | ||||
|             // Reset states
 | ||||
|             // TODO: More research is needed to complete this list
 | ||||
|             it->getClass().getCreatureStats(*it).setHostile(false); | ||||
|             it->getClass().getCreatureStats(*it).setAlarmed(false); | ||||
| 
 | ||||
|             // Stop guard persue
 | ||||
|             if(it->getClass().isClass(*it, "Guard")) | ||||
|                 it->getClass().getCreatureStats(*it).getAiSequence().stopPersue(); | ||||
| 
 | ||||
|         } | ||||
|         ptr.getClass().getCreatureStats(ptr).resetPlayerWitnesses(); | ||||
|     } | ||||
|  |  | |||
		Loading…
	
		Reference in a new issue