mirror of
				https://github.com/OpenMW/openmw.git
				synced 2025-10-31 20:56:39 +00:00 
			
		
		
		
	Merge remote-tracking branch 'digmaster/master'
This commit is contained in:
		
						commit
						2116f16289
					
				
					 29 changed files with 578 additions and 398 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 aipursue alchemy aiwander aitravel aifollow | ||||
|     drawstate spells activespells npcstats aipackage aisequence aipursue alchemy aiwander aitravel aifollow aiavoiddoor | ||||
|     aiescort aiactivate aicombat repair enchanting pathfinding pathgrid security spellsuccess spellcasting | ||||
|     disease pickpocket levelledlist combat steering obstacle | ||||
|     ) | ||||
|  |  | |||
|  | @ -390,10 +390,14 @@ namespace MWBase | |||
|             virtual void setupPlayer() = 0; | ||||
|             virtual void renderPlayer() = 0; | ||||
| 
 | ||||
|             /// if activated, should this door be opened or closed?
 | ||||
|             virtual bool getOpenOrCloseDoor(const MWWorld::Ptr& door) = 0; | ||||
|             ///< if activated, should this door be opened or closed?
 | ||||
| 
 | ||||
|             /// activate (open or close) an non-teleport door
 | ||||
|             virtual void activateDoor(const MWWorld::Ptr& door) = 0; | ||||
|             ///< activate (open or close) an non-teleport door
 | ||||
| 
 | ||||
|             /// Is door currently opening/closing?
 | ||||
|             virtual bool getIsMovingDoor(const MWWorld::Ptr& door) = 0; | ||||
| 
 | ||||
|             virtual bool getPlayerStandingOn (const MWWorld::Ptr& object) = 0; ///< @return true if the player is standing on \a object
 | ||||
|             virtual bool getActorStandingOn (const MWWorld::Ptr& object) = 0; ///< @return true if any actor is standing on \a object
 | ||||
|  |  | |||
|  | @ -19,83 +19,26 @@ MWMechanics::AiActivate *MWMechanics::AiActivate::clone() const | |||
|     return new AiActivate(*this); | ||||
| } | ||||
| bool MWMechanics::AiActivate::execute (const MWWorld::Ptr& actor,float duration) | ||||
| { | ||||
|     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(); | ||||
| 
 | ||||
|     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->searchPtr(mObjectId,false); | ||||
|     if(target == MWWorld::Ptr()) return true; | ||||
| 
 | ||||
|     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; | ||||
| 
 | ||||
| { | ||||
|     ESM::Position pos = actor.getRefData().getPosition(); //position of the actor
 | ||||
|     const MWWorld::Ptr target = MWBase::Environment::get().getWorld()->searchPtr(mObjectId, false); //The target to follow
 | ||||
| 
 | ||||
|     if(target == MWWorld::Ptr()) | ||||
|         return true;   //Target doesn't exist
 | ||||
| 
 | ||||
|     //Set the target desition from the actor
 | ||||
|     ESM::Pathgrid::Point dest = target.getRefData().getPosition().pos; | ||||
| 
 | ||||
|     if(distance(dest, pos.pos[0], pos.pos[1], pos.pos[2]) < 200) { //Stop when you get close
 | ||||
|         actor.getClass().getMovementSettings(actor).mPosition[1] = 0; | ||||
|         MWWorld::Ptr target = MWBase::Environment::get().getWorld()->getPtr(mObjectId,false); | ||||
|         MWWorld::Class::get(target).activate(target,actor).get()->execute(actor); //Arrest player
 | ||||
|         return true; | ||||
|     } | ||||
|     else { | ||||
|         pathTo(actor, dest, duration); //Go to the destination
 | ||||
|     } | ||||
| 
 | ||||
|     return false; | ||||
| } | ||||
| 
 | ||||
|  |  | |||
|  | @ -7,21 +7,21 @@ | |||
| #include "pathfinding.hpp" | ||||
| 
 | ||||
| namespace MWMechanics | ||||
| { | ||||
| 
 | ||||
| { | ||||
|     /// \brief Causes actor to walk to activatable object and activate it
 | ||||
|     /** Will activate when close to object **/ | ||||
|     class AiActivate : public AiPackage | ||||
|     { | ||||
|         public: | ||||
|         public: | ||||
|             /// Constructor
 | ||||
|             /** \param objectId Reference to object to activate **/ | ||||
|             AiActivate(const std::string &objectId); | ||||
|             virtual AiActivate *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; | ||||
|     }; | ||||
|  |  | |||
							
								
								
									
										90
									
								
								apps/openmw/mwmechanics/aiavoiddoor.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										90
									
								
								apps/openmw/mwmechanics/aiavoiddoor.cpp
									
									
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,90 @@ | |||
| #include "aiavoiddoor.hpp" | ||||
| #include <iostream> | ||||
| #include "../mwbase/world.hpp" | ||||
| #include "../mwbase/environment.hpp" | ||||
| #include "../mwworld/class.hpp" | ||||
| #include "../mwworld/cellstore.hpp" | ||||
| #include "creaturestats.hpp" | ||||
| #include "movement.hpp" | ||||
| #include "mechanicsmanagerimp.hpp" | ||||
| 
 | ||||
| #include <OgreMath.h> | ||||
| 
 | ||||
| #include "steering.hpp" | ||||
| 
 | ||||
| MWMechanics::AiAvoidDoor::AiAvoidDoor(const MWWorld::Ptr& doorPtr) | ||||
| : AiPackage(), mDoorPtr(doorPtr), mDuration(1), mAdjAngle(0) | ||||
| { | ||||
| 
 | ||||
| } | ||||
| 
 | ||||
| bool MWMechanics::AiAvoidDoor::execute (const MWWorld::Ptr& actor,float duration) | ||||
| { | ||||
| 
 | ||||
|     ESM::Position pos = actor.getRefData().getPosition(); | ||||
|     if(mDuration == 1) //If it just started, get the actor position as the stuck detection thing
 | ||||
|         mLastPos = pos; | ||||
| 
 | ||||
|     mDuration -= duration; //Update timer
 | ||||
| 
 | ||||
|     if(mDuration < 0) { | ||||
|         float x = pos.pos[0] - mLastPos.pos[0]; | ||||
|         float y = pos.pos[1] - mLastPos.pos[1]; | ||||
|         float z = pos.pos[2] - mLastPos.pos[2]; | ||||
|         int distance = x * x + y * y + z * z; | ||||
|         if(distance < 10 * 10) { //Got stuck, didn't move
 | ||||
|             if(mAdjAngle == 0) //Try going in various directions
 | ||||
|                 mAdjAngle = 1.57079632679f; //pi/2
 | ||||
|             else if (mAdjAngle == 1.57079632679f) | ||||
|                 mAdjAngle = -1.57079632679; | ||||
|             else | ||||
|                 mAdjAngle = 0; | ||||
|             mDuration = 1; //reset timer
 | ||||
|         } | ||||
|         else //Not stuck
 | ||||
|             return true; // We have tried backing up for more than one second, we've probably cleared it
 | ||||
|     } | ||||
| 
 | ||||
|     if(!MWBase::Environment::get().getWorld()->getIsMovingDoor(mDoorPtr)) | ||||
|         return true; //Door is no longer opening
 | ||||
| 
 | ||||
|     ESM::Position tPos = mDoorPtr.getRefData().getPosition(); //Position of the door
 | ||||
|     float x = pos.pos[0] - tPos.pos[0]; | ||||
|     float y = pos.pos[1] - tPos.pos[1]; | ||||
|     float dirToDoor = std::atan2(x,y) + pos.rot[2] + mAdjAngle; //Calculates the direction to the door, relative to the direction of the NPC
 | ||||
|                                                     // For example, if the NPC is directly facing the door this will be pi/2
 | ||||
| 
 | ||||
|     // Make actor move away from the door
 | ||||
|     actor.getClass().getMovementSettings(actor).mPosition[1] = -1 * std::sin(dirToDoor); //I knew I'd use trig someday
 | ||||
|     actor.getClass().getMovementSettings(actor).mPosition[0] = -1 * std::cos(dirToDoor); | ||||
| 
 | ||||
|     //Make all nearby actors also avoid the door
 | ||||
|     std::vector<MWWorld::Ptr> actors; | ||||
|     MWBase::Environment::get().getMechanicsManager()->getActorsInRange(Ogre::Vector3(pos.pos[0],pos.pos[1],pos.pos[2]),100,actors); | ||||
|     for(std::vector<MWWorld::Ptr>::iterator it = actors.begin(); it != actors.end(); it++) { | ||||
|         if(*it != MWBase::Environment::get().getWorld()->getPlayerPtr()) { //Not the player
 | ||||
|             MWMechanics::AiSequence& seq = MWWorld::Class::get(*it).getCreatureStats(*it).getAiSequence(); | ||||
|             if(seq.getTypeId() != MWMechanics::AiPackage::TypeIdAvoidDoor) { //Only add it once
 | ||||
|                 seq.stack(MWMechanics::AiAvoidDoor(mDoorPtr),*it); | ||||
|             } | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     return false; | ||||
| } | ||||
| 
 | ||||
| std::string MWMechanics::AiAvoidDoor::getAvoidedDoor() | ||||
| { | ||||
|     return mDoorPtr.getCellRef().mRefID; | ||||
| } | ||||
| 
 | ||||
| MWMechanics::AiAvoidDoor *MWMechanics::AiAvoidDoor::clone() const | ||||
| { | ||||
|     return new AiAvoidDoor(*this); | ||||
| } | ||||
| 
 | ||||
|  int MWMechanics::AiAvoidDoor::getTypeId() const | ||||
| { | ||||
|     return TypeIdAvoidDoor; | ||||
| } | ||||
| 
 | ||||
							
								
								
									
										38
									
								
								apps/openmw/mwmechanics/aiavoiddoor.hpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										38
									
								
								apps/openmw/mwmechanics/aiavoiddoor.hpp
									
									
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,38 @@ | |||
| #ifndef GAME_MWMECHANICS_AIAVOIDDOOR_H | ||||
| #define GAME_MWMECHANICS_AIAVOIDDOOR_H | ||||
| 
 | ||||
| #include "aipackage.hpp" | ||||
| #include <string> | ||||
| #include "pathfinding.hpp" | ||||
| #include <components/esm/defs.hpp> | ||||
| #include "../mwworld/class.hpp" | ||||
| 
 | ||||
| namespace MWMechanics | ||||
| { | ||||
|     /// \brief AiPackage to have an actor avoid an opening door
 | ||||
|     /** The AI will retreat from the door until it has finished opening, walked far away from it, or one second has passed, in an attempt to avoid it
 | ||||
|     **/ | ||||
|     class AiAvoidDoor : public AiPackage | ||||
|     { | ||||
|         public: | ||||
|             /// Avoid door until the door is fully open
 | ||||
|             AiAvoidDoor(const MWWorld::Ptr& doorPtr); | ||||
| 
 | ||||
|             virtual AiAvoidDoor *clone() const; | ||||
| 
 | ||||
|             virtual bool execute (const MWWorld::Ptr& actor,float duration); | ||||
| 
 | ||||
|             virtual int getTypeId() const; | ||||
| 
 | ||||
|             /// Returns the door being avoided
 | ||||
|             std::string getAvoidedDoor(); | ||||
| 
 | ||||
|         private: | ||||
|             float mDuration; | ||||
|             const MWWorld::Ptr& mDoorPtr; | ||||
|             ESM::Position mLastPos; | ||||
|             float mAdjAngle; | ||||
|     }; | ||||
| } | ||||
| #endif | ||||
| 
 | ||||
|  | @ -14,20 +14,23 @@ | |||
| 
 | ||||
| namespace MWMechanics | ||||
| { | ||||
|     /// \brief Causes the actor to fight another actor
 | ||||
|     class AiCombat : public AiPackage | ||||
|     { | ||||
|         public: | ||||
|             ///Constructor
 | ||||
|             /** \param actor Actor to fight **/ | ||||
|             AiCombat(const MWWorld::Ptr& actor); | ||||
| 
 | ||||
|             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; | ||||
| 
 | ||||
|             ///Returns target ID
 | ||||
|             const std::string &getTargetId() const; | ||||
| 
 | ||||
|         private: | ||||
|  |  | |||
|  | @ -75,58 +75,6 @@ namespace MWMechanics | |||
|                 return true; | ||||
|         } | ||||
| 
 | ||||
|         MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayerPtr(); | ||||
|         ESM::Position pos = actor.getRefData().getPosition(); | ||||
|         bool cellChange = actor.getCell()->getCell()->mData.mX != mCellX || actor.getCell()->getCell()->mData.mY != mCellY; | ||||
| 
 | ||||
|         if(actor.getCell()->getCell()->mData.mX != player.getCell()->getCell()->mData.mX) | ||||
|         { | ||||
|             int sideX = PathFinder::sgn(actor.getCell()->getCell()->mData.mX - player.getCell()->getCell()->mData.mX); | ||||
|             // Check if actor is near the border of an inactive cell. If so, pause walking.
 | ||||
|             if(sideX * (pos.pos[0] - actor.getCell()->getCell()->mData.mX * ESM::Land::REAL_SIZE) > sideX * (ESM::Land::REAL_SIZE / | ||||
|                 2.0 - 200)) | ||||
|             { | ||||
|                 MWWorld::Class::get(actor).getMovementSettings(actor).mPosition[1] = 0; | ||||
|                 return false; | ||||
|             } | ||||
|         } | ||||
|         if(actor.getCell()->getCell()->mData.mY != player.getCell()->getCell()->mData.mY) | ||||
|         { | ||||
|             int sideY = PathFinder::sgn(actor.getCell()->getCell()->mData.mY - player.getCell()->getCell()->mData.mY); | ||||
|             // Check if actor is near the border of an inactive cell. If so, pause walking.
 | ||||
|             if(sideY*(pos.pos[1] - actor.getCell()->getCell()->mData.mY * ESM::Land::REAL_SIZE) > sideY * (ESM::Land::REAL_SIZE / | ||||
|                 2.0 - 200)) | ||||
|             { | ||||
|                 MWWorld::Class::get(actor).getMovementSettings(actor).mPosition[1] = 0; | ||||
|                 return false; | ||||
|             } | ||||
|         } | ||||
| 
 | ||||
| 
 | ||||
|         if(!mPathFinder.isPathConstructed() || cellChange) | ||||
|         { | ||||
|             mCellX = actor.getCell()->getCell()->mData.mX; | ||||
|             mCellY = actor.getCell()->getCell()->mData.mY; | ||||
| 
 | ||||
|             ESM::Pathgrid::Point dest; | ||||
|             dest.mX = mX; | ||||
|             dest.mY = mY; | ||||
|             dest.mZ = mZ; | ||||
| 
 | ||||
|             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(mPathFinder.checkPathCompleted(pos.pos[0],pos.pos[1],pos.pos[2])) | ||||
|         { | ||||
|             MWWorld::Class::get(actor).getMovementSettings(actor).mPosition[1] = 0; | ||||
|             return true; | ||||
|         } | ||||
| 
 | ||||
|         const MWWorld::Ptr follower = MWBase::Environment::get().getWorld()->getPtr(mActorId, false); | ||||
|         const float* const leaderPos = actor.getRefData().getPosition().pos; | ||||
|         const float* const followerPos = follower.getRefData().getPosition().pos; | ||||
|  | @ -141,9 +89,8 @@ namespace MWMechanics | |||
| 
 | ||||
|         if(distanceBetweenResult <= mMaxDist * mMaxDist) | ||||
|         { | ||||
|             float zAngle = mPathFinder.getZAngleToNext(pos.pos[0], pos.pos[1]); | ||||
|             zTurn(actor, Ogre::Degree(zAngle)); | ||||
|             MWWorld::Class::get(actor).getMovementSettings(actor).mPosition[1] = 1; | ||||
|             if(pathTo(actor,ESM::Pathgrid::Point(mX,mY,mZ),duration)) //Returns true on path complete
 | ||||
|                 return true; | ||||
|             mMaxDist = 470; | ||||
|         } | ||||
|         else | ||||
|  |  | |||
|  | @ -8,18 +8,22 @@ | |||
| 
 | ||||
| namespace MWMechanics | ||||
| { | ||||
|     /// \brief AI Package to have an NPC lead the player to a specific point
 | ||||
|     class AiEscort : public AiPackage | ||||
|     { | ||||
|         public: | ||||
|             /// Implementation of AiEscort
 | ||||
|             /** The Actor will escort the specified actor to the world position x, y, z until they reach their position, or they run out of time
 | ||||
|                 \implement AiEscort **/ | ||||
|             AiEscort(const std::string &actorId,int duration, float x, float y, float z); | ||||
|             ///< \implement AiEscort
 | ||||
|             /// Implementation of AiEscortCell
 | ||||
|             /** The Actor will escort the specified actor to the cell position x, y, z until they reach their position, or they run out of time
 | ||||
|                 \implement AiEscortCell **/ | ||||
|             AiEscort(const std::string &actorId,const std::string &cellId,int duration, float x, float y, float z); | ||||
|             ///< \implement AiEscortCell
 | ||||
| 
 | ||||
|             virtual AiEscort *clone() const; | ||||
| 
 | ||||
|             virtual bool execute (const MWWorld::Ptr& actor,float duration); | ||||
|             ///< \return Package completed?
 | ||||
| 
 | ||||
|             virtual int getTypeId() const; | ||||
| 
 | ||||
|  |  | |||
|  | @ -12,16 +12,16 @@ | |||
| #include "steering.hpp" | ||||
| 
 | ||||
| MWMechanics::AiFollow::AiFollow(const std::string &actorId,float duration, float x, float y, float z) | ||||
| : mAlwaysFollow(false), mDuration(duration), mX(x), mY(y), mZ(z), mActorId(actorId), mCellId(""), mTimer(0), mStuckTimer(0) | ||||
| : mAlwaysFollow(false), mDuration(duration), mX(x), mY(y), mZ(z), mActorId(actorId), mCellId(""), AiPackage() | ||||
| { | ||||
| } | ||||
| MWMechanics::AiFollow::AiFollow(const std::string &actorId,const std::string &cellId,float duration, float x, float y, float z) | ||||
| : mAlwaysFollow(false), mDuration(duration), mX(x), mY(y), mZ(z), mActorId(actorId), mCellId(cellId), mTimer(0), mStuckTimer(0) | ||||
| : mAlwaysFollow(false), mDuration(duration), mX(x), mY(y), mZ(z), mActorId(actorId), mCellId(cellId), AiPackage() | ||||
| { | ||||
| } | ||||
| 
 | ||||
| MWMechanics::AiFollow::AiFollow(const std::string &actorId) | ||||
| : mAlwaysFollow(true), mDuration(0), mX(0), mY(0), mZ(0), mActorId(actorId), mCellId(""), mTimer(0), mStuckTimer(0) | ||||
| : mAlwaysFollow(true), mDuration(0), mX(0), mY(0), mZ(0), mActorId(actorId), mCellId(""), AiPackage() | ||||
| { | ||||
| } | ||||
| 
 | ||||
|  | @ -31,10 +31,6 @@ bool MWMechanics::AiFollow::execute (const MWWorld::Ptr& actor,float duration) | |||
| 
 | ||||
|     if(target == MWWorld::Ptr()) return true;   //Target doesn't exist
 | ||||
| 
 | ||||
|     mTimer = mTimer + duration; //Update timer
 | ||||
|     mStuckTimer = mStuckTimer + duration;   //Update stuck timer
 | ||||
|     mTotalTime = mTotalTime + duration; //Update total time following
 | ||||
| 
 | ||||
|     ESM::Position pos = actor.getRefData().getPosition(); //position of the actor
 | ||||
| 
 | ||||
|     if(!mAlwaysFollow) //Update if you only follow for a bit
 | ||||
|  | @ -60,74 +56,18 @@ bool MWMechanics::AiFollow::execute (const MWWorld::Ptr& actor,float duration) | |||
|     } | ||||
| 
 | ||||
|     //Set the target desition from the actor
 | ||||
|     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 dest = target.getRefData().getPosition().pos; | ||||
| 
 | ||||
|     //Current position, for pathfilding stuff
 | ||||
|     ESM::Pathgrid::Point start; | ||||
|     start.mX = pos.pos[0]; | ||||
|     start.mY = pos.pos[1]; | ||||
|     start.mZ = pos.pos[2]; | ||||
| 
 | ||||
|     //Build the path to get to the destination
 | ||||
|     if(mPathFinder.getPath().empty()) | ||||
|         mPathFinder.buildPath(start, dest, actor.getCell(), true); | ||||
| 
 | ||||
|     //***********************
 | ||||
|     // Checks if you can't get to the end position at all
 | ||||
|     //***********************
 | ||||
|     if(mTimer > 0.25) | ||||
|     { | ||||
|         if(!mPathFinder.getPath().empty()) //Path has points in it
 | ||||
|         { | ||||
|             ESM::Pathgrid::Point lastPos = mPathFinder.getPath().back(); //Get the end of the proposed path
 | ||||
| 
 | ||||
|             if((dest.mX - lastPos.mX)*(dest.mX - lastPos.mX) | ||||
|                 +(dest.mY - lastPos.mY)*(dest.mY - lastPos.mY) | ||||
|                 +(dest.mZ - lastPos.mZ)*(dest.mZ - lastPos.mZ) | ||||
|             > 100*100) //End of the path is far from the destination
 | ||||
|                 mPathFinder.addPointToPath(dest); //Adds the final destination to the path, to try to get to where you want to go
 | ||||
|         } | ||||
| 
 | ||||
|         mTimer = 0; | ||||
|     } | ||||
| 
 | ||||
|     //************************
 | ||||
|     // Checks if you aren't moving; you're stuck
 | ||||
|     //************************
 | ||||
|     if(mStuckTimer>0.5) //Checks every half of a second
 | ||||
|     { | ||||
|         if((mStuckPos.pos[0] - pos.pos[0])*(mStuckPos.pos[0] - pos.pos[0]) | ||||
|             +(mStuckPos.pos[1] - pos.pos[1])*(mStuckPos.pos[1] - pos.pos[1]) | ||||
|             +(mStuckPos.pos[2] - pos.pos[2])*(mStuckPos.pos[2] - pos.pos[2]) < 100) //NPC is stuck
 | ||||
|             mPathFinder.buildPath(start, dest, actor.getCell(), true); | ||||
| 
 | ||||
|         mStuckTimer = 0; | ||||
|         mStuckPos = pos; | ||||
|     } | ||||
| 
 | ||||
|     //Checks if the path isn't over, turn tomards the direction that you're going
 | ||||
|     if(!mPathFinder.checkPathCompleted(pos.pos[0],pos.pos[1],pos.pos[2])) | ||||
|     { | ||||
|         zTurn(actor, Ogre::Degree(mPathFinder.getZAngleToNext(pos.pos[0], pos.pos[1]))); | ||||
|     } | ||||
| 
 | ||||
|     if((dest.mX - pos.pos[0])*(dest.mX - pos.pos[0])+(dest.mY - pos.pos[1])*(dest.mY - pos.pos[1])+(dest.mZ - pos.pos[2])*(dest.mZ - pos.pos[2]) | ||||
|         < 100*100) | ||||
|     if(distance(dest, pos.pos[0], pos.pos[1], pos.pos[2]) < 100) //Stop when you get close
 | ||||
|         actor.getClass().getMovementSettings(actor).mPosition[1] = 0; | ||||
|     else | ||||
|         actor.getClass().getMovementSettings(actor).mPosition[1] = 1; | ||||
|     else { | ||||
|         pathTo(actor, dest, duration); //Go to the destination
 | ||||
|     } | ||||
| 
 | ||||
|     //Check if you're far away
 | ||||
|     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) > 1000*1000) | ||||
|     if(distance(dest, pos.pos[0], pos.pos[1], pos.pos[2]) > 1000) | ||||
|         actor.getClass().getCreatureStats(actor).setMovementFlag(MWMechanics::CreatureStats::Flag_Run, true); //Make NPC run
 | ||||
|     else if((dest.mX - start.mX)*(dest.mX - start.mX) //Have a bit of a dead zone, otherwise npc will constantly flip between running and not when right on the edge of the running threshhold
 | ||||
|                 +(dest.mY - start.mY)*(dest.mY - start.mY) | ||||
|                 +(dest.mZ - start.mZ)*(dest.mZ - start.mZ) < 800*800) | ||||
|     else if(distance(dest, pos.pos[0], pos.pos[1], pos.pos[2])  < 800) //Have a bit of a dead zone, otherwise npc will constantly flip between running and not when right on the edge of the running threshhold
 | ||||
|         actor.getClass().getCreatureStats(actor).setMovementFlag(MWMechanics::CreatureStats::Flag_Run, false); //make NPC walk
 | ||||
| 
 | ||||
|     return false; | ||||
|  |  | |||
|  | @ -1,43 +1,45 @@ | |||
| #ifndef GAME_MWMECHANICS_AIFALLOW_H | ||||
| #define GAME_MWMECHANICS_AIFALLOW_H | ||||
| #ifndef GAME_MWMECHANICS_AIFOLLOW_H | ||||
| #define GAME_MWMECHANICS_AIFOLLOW_H | ||||
| 
 | ||||
| #include "aipackage.hpp" | ||||
| #include <string> | ||||
| #include "pathfinding.hpp" | ||||
| #include "../../../components/esm/defs.hpp" | ||||
| #include <components/esm/defs.hpp> | ||||
| 
 | ||||
| namespace MWMechanics | ||||
| { | ||||
| 
 | ||||
|     /// \brief AiPackage for an actor to follow another actor/the PC
 | ||||
|     /** The AI will follow the target until a condition (time, or position) are set. Both can be disabled to cause the actor to follow the other indefinitely
 | ||||
|     **/ | ||||
|     class AiFollow : public AiPackage | ||||
|     { | ||||
|         public: | ||||
|             /// Follow Actor for duration or until you arrive at a world position
 | ||||
|             AiFollow(const std::string &ActorId,float duration, float X, float Y, float Z); | ||||
|             /// Follow Actor for duration or until you arrive at a position in a cell
 | ||||
|             AiFollow(const std::string &ActorId,const std::string &CellId,float duration, float X, float Y, float Z); | ||||
|             /// Follow Actor indefinitively
 | ||||
|             AiFollow(const std::string &ActorId); | ||||
| 
 | ||||
|             virtual AiFollow *clone() const; | ||||
| 
 | ||||
|             virtual bool execute (const MWWorld::Ptr& actor,float duration); | ||||
|                     ///< \return Package completed?
 | ||||
| 
 | ||||
|             virtual int getTypeId() const; | ||||
| 
 | ||||
|             /// Returns the actor being followed
 | ||||
|             std::string getFollowedActor(); | ||||
| 
 | ||||
|         private: | ||||
|             bool mAlwaysFollow; //this will make the actor always follow, thus ignoring mDuration and mX,mY,mZ (used for summoned creatures).
 | ||||
|             /// This will make the actor always follow.
 | ||||
|             /** Thus ignoring mDuration and mX,mY,mZ (used for summoned creatures). **/ | ||||
|             bool mAlwaysFollow; | ||||
|             float mDuration; | ||||
|             float mX; | ||||
|             float mY; | ||||
|             float mZ; | ||||
|             std::string mActorId; | ||||
|             std::string mCellId; | ||||
| 
 | ||||
|             float mTimer; | ||||
|             float mStuckTimer; | ||||
|             float mTotalTime; | ||||
| 
 | ||||
|             ESM::Position mStuckPos; | ||||
| 
 | ||||
|             PathFinder mPathFinder; | ||||
|     }; | ||||
| } | ||||
| #endif | ||||
|  |  | |||
|  | @ -1,4 +1,131 @@ | |||
| 
 | ||||
| #include "aipackage.hpp" | ||||
| 
 | ||||
| #include <cmath> | ||||
| #include "../mwbase/world.hpp" | ||||
| #include "../mwbase/environment.hpp" | ||||
| #include "../mwworld/class.hpp" | ||||
| #include "../mwworld/cellstore.hpp" | ||||
| #include "creaturestats.hpp" | ||||
| #include "movement.hpp" | ||||
| #include "../mwworld/action.hpp" | ||||
| 
 | ||||
| #include <OgreMath.h> | ||||
| 
 | ||||
| #include "steering.hpp" | ||||
| 
 | ||||
| MWMechanics::AiPackage::~AiPackage() {} | ||||
| 
 | ||||
| MWMechanics::AiPackage::AiPackage() : mLastDoorChecked(MWWorld::Ptr()), mTimer(.26), mStuckTimer(0) { //mTimer starts at .26 to force initial pathbuild
 | ||||
| 
 | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| bool MWMechanics::AiPackage::pathTo(const MWWorld::Ptr& actor, ESM::Pathgrid::Point dest, float duration) | ||||
| { | ||||
|     //Update various Timers
 | ||||
|     mTimer += duration; //Update timer
 | ||||
|     mStuckTimer += duration;   //Update stuck timer
 | ||||
|     mTotalTime += duration; //Update total time following
 | ||||
| 
 | ||||
| 
 | ||||
|     ESM::Position pos = actor.getRefData().getPosition(); //position of the actor
 | ||||
| 
 | ||||
|     /// Stops the actor when it gets too close to a unloaded cell
 | ||||
|     { | ||||
|         MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayerPtr(); | ||||
|         const ESM::Cell *cell = actor.getCell()->getCell(); | ||||
|         Movement &movement = actor.getClass().getMovementSettings(actor); | ||||
| 
 | ||||
|         //Ensure pursuer doesn't leave loaded cells
 | ||||
|         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; | ||||
|             } | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     //Start position
 | ||||
|     ESM::Pathgrid::Point start = pos.pos; | ||||
| 
 | ||||
|     //***********************
 | ||||
|     /// Checks if you can't get to the end position at all, adds end position to end of path
 | ||||
|     /// Rebuilds path every quarter of a second, in case the target has moved
 | ||||
|     //***********************
 | ||||
|     if(mTimer > 0.25) | ||||
|     { | ||||
|         if(distance(mPrevDest, dest) > 10) { //Only rebuild path if it's moved
 | ||||
|             mPathFinder.buildPath(start, dest, actor.getCell(), true); //Rebuild path, in case the target has moved
 | ||||
|             mPrevDest = dest; | ||||
|         } | ||||
| 
 | ||||
|         if(!mPathFinder.getPath().empty()) //Path has points in it
 | ||||
|         { | ||||
|             ESM::Pathgrid::Point lastPos = mPathFinder.getPath().back(); //Get the end of the proposed path
 | ||||
| 
 | ||||
|             if(distance(dest, lastPos) > 100) //End of the path is far from the destination
 | ||||
|                 mPathFinder.addPointToPath(dest); //Adds the final destination to the path, to try to get to where you want to go
 | ||||
|         } | ||||
| 
 | ||||
|         mTimer = 0; | ||||
|     } | ||||
| 
 | ||||
|     //************************
 | ||||
|     /// Checks if you aren't moving; attempts to unstick you
 | ||||
|     //************************
 | ||||
|     if(mPathFinder.checkPathCompleted(pos.pos[0],pos.pos[1],pos.pos[2])) //Path finished?
 | ||||
|         return true; | ||||
|     else if(mStuckTimer>0.5) //Every half second see if we need to take action to avoid something
 | ||||
|     { | ||||
| /// TODO (tluppi#1#): Use ObstacleCheck here. Not working for some reason
 | ||||
|         //if(mObstacleCheck.check(actor, duration)) {
 | ||||
|         if(distance(start, mStuckPos.pos[0], mStuckPos.pos[1], mStuckPos.pos[2]) < 10 && distance(dest, start) > 20) { //Actually stuck, and far enough away from destination to care
 | ||||
|             // first check if we're walking into a door
 | ||||
|             MWWorld::Ptr door = getNearbyDoor(actor); | ||||
|             if(door != MWWorld::Ptr()) // NOTE: checks interior cells only
 | ||||
|             { | ||||
|                 if(door.getCellRef().mTrap.empty() && mLastDoorChecked != door) { //Open the door if untrapped
 | ||||
|                     door.getClass().activate(door, actor).get()->execute(actor); | ||||
|                     mLastDoorChecked = door; | ||||
|                 } | ||||
|             } | ||||
|             else // probably walking into another NPC
 | ||||
|             { | ||||
|                 // TODO: diagonal should have same animation as walk forward
 | ||||
|                 //       but doesn't seem to do that?
 | ||||
|                 actor.getClass().getMovementSettings(actor).mPosition[0] = 1; | ||||
|                 actor.getClass().getMovementSettings(actor).mPosition[1] = 0.1f; | ||||
|                 // change the angle a bit, too
 | ||||
|                 zTurn(actor, Ogre::Degree(mPathFinder.getZAngleToNext(pos.pos[0] + 1, pos.pos[1]))); | ||||
|             } | ||||
|         } | ||||
|         else { //Not stuck, so reset things
 | ||||
|             mStuckTimer = 0; | ||||
|             mStuckPos = pos; | ||||
|             mLastDoorChecked = MWWorld::Ptr(); //Resets it, in case he gets stuck behind the door again
 | ||||
|             actor.getClass().getMovementSettings(actor).mPosition[1] = 1; //Just run forward
 | ||||
|         } | ||||
|     } | ||||
|     else { | ||||
|         actor.getClass().getMovementSettings(actor).mPosition[1] = 1; //Just run forward the rest of the time
 | ||||
|     } | ||||
| 
 | ||||
|     zTurn(actor, Ogre::Degree(mPathFinder.getZAngleToNext(pos.pos[0], pos.pos[1]))); | ||||
| 
 | ||||
|     return false; | ||||
| } | ||||
|  |  | |||
|  | @ -1,6 +1,12 @@ | |||
| #ifndef GAME_MWMECHANICS_AIPACKAGE_H | ||||
| #define GAME_MWMECHANICS_AIPACKAGE_H | ||||
| 
 | ||||
| #include "pathfinding.hpp" | ||||
| #include <components/esm/defs.hpp> | ||||
| #include "../mwbase/world.hpp" | ||||
| 
 | ||||
| #include "obstacle.hpp" | ||||
| 
 | ||||
| namespace MWWorld | ||||
| { | ||||
|     class Ptr; | ||||
|  | @ -12,6 +18,7 @@ namespace MWMechanics | |||
|     class AiPackage | ||||
|     { | ||||
|         public: | ||||
|             ///Enumerates the various AITypes availible.
 | ||||
|             enum TypeId { | ||||
|                 TypeIdNone = -1, | ||||
|                 TypeIdWander = 0, | ||||
|  | @ -20,21 +27,47 @@ namespace MWMechanics | |||
|                 TypeIdFollow = 3, | ||||
|                 TypeIdActivate = 4, | ||||
|                 TypeIdCombat = 5, | ||||
|                 TypeIdPursue = 6 | ||||
|                 TypeIdPursue = 6, | ||||
|                 TypeIdAvoidDoor = 7 | ||||
|             }; | ||||
| 
 | ||||
|             virtual ~AiPackage(); | ||||
|        | ||||
|             virtual AiPackage *clone() const = 0; | ||||
|              | ||||
|             virtual bool execute (const MWWorld::Ptr& actor,float duration) = 0; | ||||
|             ///< \return Package completed?
 | ||||
|              | ||||
|             virtual int getTypeId() const = 0; | ||||
|             ///< @see enum TypeId
 | ||||
|             ///Default constructor
 | ||||
|             AiPackage(); | ||||
| 
 | ||||
|             ///Default Deconstructor
 | ||||
|             virtual ~AiPackage(); | ||||
| 
 | ||||
|             ///Clones the package
 | ||||
|             virtual AiPackage *clone() const = 0; | ||||
| 
 | ||||
|             /// Updates and runs the package (Should run every frame)
 | ||||
|             /// \return Package completed?
 | ||||
|             virtual bool execute (const MWWorld::Ptr& actor,float duration) = 0; | ||||
| 
 | ||||
|             /// Returns the TypeID of the AiPackage
 | ||||
|             /// \see enum TypeId
 | ||||
|             virtual int getTypeId() const = 0; | ||||
| 
 | ||||
|             /// Higher number is higher priority (0 being the lowest)
 | ||||
|             virtual unsigned int getPriority() const {return 0;} | ||||
|             ///< higher number is higher priority (0 beeing the lowest)
 | ||||
| 
 | ||||
|         protected: | ||||
|             /// Causes the actor to attempt to walk to the specified location
 | ||||
|             /** \return If the actor has arrived at his destination **/ | ||||
|             bool pathTo(const MWWorld::Ptr& actor, ESM::Pathgrid::Point dest, float duration); | ||||
| 
 | ||||
|             PathFinder mPathFinder; | ||||
|             ObstacleCheck mObstacleCheck; | ||||
| 
 | ||||
|             float mDoorCheckDuration; | ||||
|             float mTimer; | ||||
|             float mStuckTimer; | ||||
|             float mTotalTime; | ||||
| 
 | ||||
|             MWWorld::Ptr mLastDoorChecked; //Used to ensure we don't try to CONSTANTLY open a door
 | ||||
| 
 | ||||
|             ESM::Position mStuckPos; | ||||
|             ESM::Pathgrid::Point mPrevDest; | ||||
|     }; | ||||
| } | ||||
| 
 | ||||
|  |  | |||
|  | @ -21,75 +21,27 @@ MWMechanics::AiPursue *MWMechanics::AiPursue::clone() const | |||
| } | ||||
| bool MWMechanics::AiPursue::execute (const MWWorld::Ptr& actor, float duration) | ||||
| { | ||||
|     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); | ||||
|     ESM::Position pos = actor.getRefData().getPosition(); //position of the actor
 | ||||
|     const MWWorld::Ptr target = MWBase::Environment::get().getWorld()->searchPtr(mObjectId, false); //The target to follow
 | ||||
| 
 | ||||
|     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; | ||||
|         } | ||||
|     } | ||||
|     if(target == MWWorld::Ptr()) | ||||
|         return true;   //Target doesn't exist
 | ||||
| 
 | ||||
|     // Big TODO: Sync this with current AiFollow. Move common code to a shared base class or helpers (applies to all AI packages, way too much duplicated code)
 | ||||
|     //Set the target desition from the actor
 | ||||
|     ESM::Pathgrid::Point dest = target.getRefData().getPosition().pos; | ||||
| 
 | ||||
|     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 || mPathFinder.checkPathCompleted(pos.pos[0], pos.pos[1], pos.pos[2])) | ||||
|     { | ||||
|         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]) < 100*100) | ||||
|     { | ||||
|         movement.mPosition[1] = 0; | ||||
|         MWWorld::Ptr target = world->getPtr(mObjectId,false); | ||||
|         MWWorld::Class::get(target).activate(target,actor).get()->execute(actor); | ||||
|     if(distance(dest, pos.pos[0], pos.pos[1], pos.pos[2]) < 100) { //Stop when you get close
 | ||||
|         actor.getClass().getMovementSettings(actor).mPosition[1] = 0; | ||||
|         MWWorld::Ptr target = MWBase::Environment::get().getWorld()->getPtr(mObjectId,false); | ||||
|         MWWorld::Class::get(target).activate(target,actor).get()->execute(actor); //Arrest player
 | ||||
|         return true; | ||||
|     } | ||||
|     else { | ||||
|         pathTo(actor, dest, duration); //Go to the destination
 | ||||
|     } | ||||
| 
 | ||||
|     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; | ||||
|     actor.getClass().getCreatureStats(actor).setMovementFlag(MWMechanics::CreatureStats::Flag_Run, true); //Make NPC run
 | ||||
| 
 | ||||
|     return false; | ||||
| } | ||||
|  |  | |||
|  | @ -8,20 +8,22 @@ | |||
| 
 | ||||
| namespace MWMechanics | ||||
| { | ||||
| 
 | ||||
|     /// \brief Makes the actor very closely follow the actor
 | ||||
|     /** Used for arresting players. Causes the actor to run to the pursued actor and activate them, to arrest them.
 | ||||
|         Note that while very similar to AiActivate, it will ONLY activate when evry close to target (Not also when the | ||||
|         path is completed). **/ | ||||
|     class AiPursue : public AiPackage | ||||
|     { | ||||
|         public: | ||||
|             ///Constructor
 | ||||
|             /** \param objectId Actor to pursue **/ | ||||
|             AiPursue(const std::string &objectId); | ||||
|             virtual AiPursue *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; | ||||
|     }; | ||||
|  |  | |||
|  | @ -13,66 +13,79 @@ namespace MWWorld | |||
| namespace MWMechanics | ||||
| { | ||||
|     class AiPackage; | ||||
|      | ||||
| 
 | ||||
|     /// \brief Sequence of AI-packages for a single actor
 | ||||
|     /** The top-most AI package is run each frame. When completed, it is removed from the stack. **/ | ||||
|     class AiSequence | ||||
|     { | ||||
|             ///AiPackages to run though
 | ||||
|             std::list<AiPackage *> mPackages; | ||||
| 
 | ||||
|             ///Finished with top AIPackage, set for one frame
 | ||||
|             bool mDone; | ||||
| 
 | ||||
|             ///Copy AiSequence
 | ||||
|             void copy (const AiSequence& sequence); | ||||
| 
 | ||||
|             // The type of AI package that ran last
 | ||||
|             /// The type of AI package that ran last
 | ||||
|             int mLastAiPackage; | ||||
| 
 | ||||
|         public: | ||||
|          | ||||
|             ///Default constructor
 | ||||
|             AiSequence(); | ||||
|              | ||||
| 
 | ||||
|             /// Copy Constructor
 | ||||
|             AiSequence (const AiSequence& sequence); | ||||
|              | ||||
| 
 | ||||
|             /// Assignment operator
 | ||||
|             AiSequence& operator= (const AiSequence& sequence); | ||||
|              | ||||
| 
 | ||||
|             virtual ~AiSequence(); | ||||
| 
 | ||||
|             /// Returns currently executing AiPackage type
 | ||||
|             /** \see enum AiPackage::TypeId **/ | ||||
|             int getTypeId() const; | ||||
|             ///< @see enum AiPackage::TypeId
 | ||||
| 
 | ||||
|             /// Get the typeid of the Ai package that ran last
 | ||||
|             /** NOT the currently "active" Ai package that will be run in the next frame.
 | ||||
|                 This difference is important when an Ai package has just finished and been removed. | ||||
|                 \see enum AiPackage::TypeId **/ | ||||
|             int getLastRunTypeId() const { return mLastAiPackage; } | ||||
|             ///< Get the typeid of the Ai package that ran last, NOT the currently "active" Ai package that will be run in the next frame.
 | ||||
|             /// This difference is important when an Ai package has just finished and been removed.
 | ||||
| 
 | ||||
|             /// Return true and assign target if combat package is currently active, return false otherwise
 | ||||
|             bool getCombatTarget (std::string &targetActorId) const; | ||||
|             ///< Return true and assign target if combat package is currently
 | ||||
|             /// active, return false otherwise
 | ||||
| 
 | ||||
|             /// Removes all combat packages until first non-combat or stack empty.
 | ||||
|             void stopCombat(); | ||||
|             ///< Removes all combat packages until first non-combat or stack empty.
 | ||||
| 
 | ||||
|             void stopPursuit(); | ||||
|             ///< Removes all pursue packages until first non-pursue or stack empty.
 | ||||
|              | ||||
|             /// Has a package been completed during the last update?
 | ||||
|             bool isPackageDone() const; | ||||
|             ///< Has a package been completed during the last update?
 | ||||
|              | ||||
| 
 | ||||
|             /// Removes all pursue packages until first non-pursue or stack empty.
 | ||||
|             void stopPursuit(); | ||||
| 
 | ||||
|             /// Execute current package, switching if needed.
 | ||||
|             void execute (const MWWorld::Ptr& actor,float duration); | ||||
|             ///< Execute package.
 | ||||
|              | ||||
| 
 | ||||
|             /// Remove all packages.
 | ||||
|             void clear(); | ||||
|             ///< Remove all packages.
 | ||||
| 
 | ||||
|             ///< Add \a package to the front of the sequence
 | ||||
|             /** Suspends current package
 | ||||
|                 @param actor The actor that owns this AiSequence **/ | ||||
|             void stack (const AiPackage& package, const MWWorld::Ptr& actor); | ||||
|             ///< Add \a package to the front of the sequence (suspends current package)
 | ||||
|             /// @param actor The actor that owns this AiSequence
 | ||||
|              | ||||
| 
 | ||||
|             /// Add \a package to the end of the sequence
 | ||||
|             /** Executed after all other packages have been completed **/ | ||||
|             void queue (const AiPackage& package); | ||||
|             ///< Add \a package to the end of the sequence (executed after all other packages have been
 | ||||
|             /// completed)
 | ||||
| 
 | ||||
|             /// Return the current active package.
 | ||||
|             /** If there is no active package, it will throw an exception **/ | ||||
|             AiPackage* getActivePackage(); | ||||
|             ///< return the current active package. If there is no active package, throw an exeption
 | ||||
| 
 | ||||
|             /// Fills the AiSequence with packages
 | ||||
|             /** Typically used for loading from the ESM
 | ||||
|                 \see ESM::AIPackageList **/ | ||||
|             void fill (const ESM::AIPackageList& list); | ||||
|     }; | ||||
| } | ||||
|  |  | |||
|  | @ -6,15 +6,16 @@ | |||
| #include "pathfinding.hpp" | ||||
| 
 | ||||
| namespace MWMechanics | ||||
| { | ||||
| { | ||||
|     /// \brief Causes the AI to travel to the specified point
 | ||||
|     class AiTravel : public AiPackage | ||||
|     { | ||||
|         public: | ||||
|         public: | ||||
|             /// Default constructor
 | ||||
|             AiTravel(float x, float y, float z); | ||||
|             virtual AiTravel *clone() const; | ||||
| 
 | ||||
|             virtual bool execute (const MWWorld::Ptr& actor,float duration); | ||||
|                     ///< \return Package completed?
 | ||||
| 
 | ||||
|             virtual int getTypeId() const; | ||||
| 
 | ||||
|  |  | |||
|  | @ -14,20 +14,27 @@ | |||
| 
 | ||||
| namespace MWMechanics | ||||
| { | ||||
|     /// \brief Causes the Actor to wander within a specified range
 | ||||
|     class AiWander : public AiPackage | ||||
|     { | ||||
|         public: | ||||
| 
 | ||||
|             /// Constructor
 | ||||
|             /** \param distance Max distance the ACtor will wander
 | ||||
|                 \param duration Time, in hours, that this package will be preformed | ||||
|                 \param timeOfDay Start time of the package, if it has a duration. Currently unimplemented | ||||
|                 \param idle Chances of each idle to play (9 in total) | ||||
|                 \param repeat Repeat wander or not **/ | ||||
|             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,float duration); | ||||
|             ///< \return Package completed?
 | ||||
|             virtual int getTypeId() const; | ||||
|             ///< 0: Wander
 | ||||
| 
 | ||||
|             virtual AiPackage *clone() const; | ||||
| 
 | ||||
|             virtual bool execute (const MWWorld::Ptr& actor,float duration); | ||||
| 
 | ||||
|             virtual int getTypeId() const; | ||||
| 
 | ||||
|             /// Set the position to return to for a stationary (non-wandering) actor
 | ||||
|             /** In case another AI package moved the actor elsewhere **/ | ||||
|             void setReturnPosition (const Ogre::Vector3& position); | ||||
|             ///< Set the position to return to for a stationary (non-wandering) actor, in case
 | ||||
|             /// another AI package moved the actor elsewhere
 | ||||
| 
 | ||||
|         private: | ||||
|             void stopWalking(const MWWorld::Ptr& actor); | ||||
|  |  | |||
|  | @ -19,11 +19,19 @@ namespace MWMechanics | |||
|     // Limitation: there can be false detections, and does not test whether the
 | ||||
|     // actor is facing the door.
 | ||||
|     bool proximityToDoor(const MWWorld::Ptr& actor, float minSqr, bool closed) | ||||
|     { | ||||
|         if(getNearbyDoor(actor, minSqr, closed)!=MWWorld::Ptr()) | ||||
|             return true; | ||||
|         else | ||||
|             return false; | ||||
|     } | ||||
| 
 | ||||
|     MWWorld::Ptr getNearbyDoor(const MWWorld::Ptr& actor, float minSqr, bool closed) | ||||
|     { | ||||
|         MWWorld::CellStore *cell = actor.getCell(); | ||||
| 
 | ||||
|         if(cell->getCell()->isExterior()) | ||||
|             return false; // check interior cells only
 | ||||
|             return MWWorld::Ptr(); // check interior cells only
 | ||||
| 
 | ||||
|         // Check all the doors in this cell
 | ||||
|         MWWorld::CellRefList<ESM::Door>& doors = cell->get<ESM::Door>(); | ||||
|  | @ -31,14 +39,14 @@ namespace MWMechanics | |||
|         MWWorld::CellRefList<ESM::Door>::List::iterator it = refList.begin(); | ||||
|         Ogre::Vector3 pos(actor.getRefData().getPosition().pos); | ||||
| 
 | ||||
|         // TODO: How to check whether the actor is facing a door? Below code is for
 | ||||
|         //       the player, perhaps it can be adapted.
 | ||||
|         /// TODO: How to check whether the actor is facing a door? Below code is for
 | ||||
|         ///       the player, perhaps it can be adapted.
 | ||||
|         //MWWorld::Ptr ptr = MWBase::Environment::get().getWorld()->getFacedObject();
 | ||||
|         //if(!ptr.isEmpty())
 | ||||
|             //std::cout << "faced door " << ptr.getClass().getName(ptr) << std::endl;
 | ||||
| 
 | ||||
|         // TODO: The in-game observation of rot[2] value seems to be the
 | ||||
|         //       opposite of the code in World::activateDoor() ::confused::
 | ||||
|         /// TODO: The in-game observation of rot[2] value seems to be the
 | ||||
|         ///       opposite of the code in World::activateDoor() ::confused::
 | ||||
|         for (; it != refList.end(); ++it) | ||||
|         { | ||||
|             MWWorld::LiveCellRef<ESM::Door>& ref = *it; | ||||
|  | @ -46,10 +54,10 @@ namespace MWMechanics | |||
|                 if((closed && ref.mData.getLocalRotation().rot[2] == 0) || | ||||
|                    (!closed && ref.mData.getLocalRotation().rot[2] >= 1)) | ||||
|                 { | ||||
|                     return true; // found, stop searching
 | ||||
|                     return MWWorld::Ptr(&ref, actor.getCell()); // found, stop searching
 | ||||
|                 } | ||||
|         } | ||||
|         return false; // none found
 | ||||
|         return MWWorld::Ptr(); // none found
 | ||||
|     } | ||||
| 
 | ||||
|     ObstacleCheck::ObstacleCheck(): | ||||
|  |  | |||
|  | @ -1,6 +1,10 @@ | |||
| #ifndef OPENMW_MECHANICS_OBSTACLE_H | ||||
| #define OPENMW_MECHANICS_OBSTACLE_H | ||||
| 
 | ||||
| //#include "../mwbase/world.hpp"
 | ||||
| //#include "../mwworld/class.hpp"
 | ||||
| #include "../mwworld/cellstore.hpp" | ||||
| 
 | ||||
| namespace MWWorld | ||||
| { | ||||
|     class Ptr; | ||||
|  | @ -8,14 +12,20 @@ namespace MWWorld | |||
| 
 | ||||
| namespace MWMechanics | ||||
| { | ||||
|     // NOTE: determined empirically based on in-game behaviour
 | ||||
|     /// NOTE: determined empirically based on in-game behaviour
 | ||||
|     static const float MIN_DIST_TO_DOOR_SQUARED = 128*128; | ||||
| 
 | ||||
|     // tests actor's proximity to a closed door by default
 | ||||
|     /// tests actor's proximity to a closed door by default
 | ||||
|     bool proximityToDoor(const MWWorld::Ptr& actor, | ||||
|                          float minSqr = MIN_DIST_TO_DOOR_SQUARED, | ||||
|                          bool closed = true); | ||||
| 
 | ||||
|     /// Returns door pointer within range. No guarentee is given as too which one
 | ||||
|     /** \return Pointer to the door, or NULL if none exists **/ | ||||
|     MWWorld::Ptr getNearbyDoor(const MWWorld::Ptr& actor, | ||||
|                          float minSqr = MIN_DIST_TO_DOOR_SQUARED, | ||||
|                          bool closed = true); | ||||
| 
 | ||||
|     class ObstacleCheck | ||||
|     { | ||||
|         public: | ||||
|  |  | |||
|  | @ -11,30 +11,6 @@ | |||
| 
 | ||||
| namespace | ||||
| { | ||||
|     float distanceZCorrected(ESM::Pathgrid::Point point, float x, float y, float z) | ||||
|     { | ||||
|         x -= point.mX; | ||||
|         y -= point.mY; | ||||
|         z -= point.mZ; | ||||
|         return sqrt(x * x + y * y + 0.1 * z * z); | ||||
|     } | ||||
| 
 | ||||
|     float distance(ESM::Pathgrid::Point point, float x, float y, float z) | ||||
|     { | ||||
|         x -= point.mX; | ||||
|         y -= point.mY; | ||||
|         z -= point.mZ; | ||||
|         return sqrt(x * x + y * y + z * z); | ||||
|     } | ||||
| 
 | ||||
|     float distance(ESM::Pathgrid::Point a, ESM::Pathgrid::Point b) | ||||
|     { | ||||
|         float x = a.mX - b.mX; | ||||
|         float y = a.mY - b.mY; | ||||
|         float z = a.mZ - b.mZ; | ||||
|         return sqrt(x * x + y * y + z * z); | ||||
|     } | ||||
| 
 | ||||
|     // Slightly cheaper version for comparisons.
 | ||||
|     // Caller needs to be careful for very short distances (i.e. less than 1)
 | ||||
|     // or when accumuating the results i.e. (a + b)^2 != a^2 + b^2
 | ||||
|  | @ -114,6 +90,30 @@ namespace | |||
| 
 | ||||
| namespace MWMechanics | ||||
| { | ||||
|     float distanceZCorrected(ESM::Pathgrid::Point point, float x, float y, float z) | ||||
|     { | ||||
|         x -= point.mX; | ||||
|         y -= point.mY; | ||||
|         z -= point.mZ; | ||||
|         return sqrt(x * x + y * y + 0.1 * z * z); | ||||
|     } | ||||
| 
 | ||||
|     float distance(ESM::Pathgrid::Point point, float x, float y, float z) | ||||
|     { | ||||
|         x -= point.mX; | ||||
|         y -= point.mY; | ||||
|         z -= point.mZ; | ||||
|         return sqrt(x * x + y * y + z * z); | ||||
|     } | ||||
| 
 | ||||
|     float distance(ESM::Pathgrid::Point a, ESM::Pathgrid::Point b) | ||||
|     { | ||||
|         float x = a.mX - b.mX; | ||||
|         float y = a.mY - b.mY; | ||||
|         float z = a.mZ - b.mZ; | ||||
|         return sqrt(x * x + y * y + z * z); | ||||
|     } | ||||
| 
 | ||||
|     PathFinder::PathFinder() | ||||
|         : mIsPathConstructed(false), | ||||
|           mPathgrid(NULL), | ||||
|  |  | |||
|  | @ -13,6 +13,8 @@ namespace MWWorld | |||
| 
 | ||||
| namespace MWMechanics | ||||
| { | ||||
|     float distance(ESM::Pathgrid::Point point, float x, float y, float); | ||||
|     float distance(ESM::Pathgrid::Point a, ESM::Pathgrid::Point b); | ||||
|     class PathFinder | ||||
|     { | ||||
|         public: | ||||
|  |  | |||
|  | @ -30,6 +30,7 @@ | |||
| #include "../mwmechanics/spellcasting.hpp" | ||||
| #include "../mwmechanics/levelledlist.hpp" | ||||
| #include "../mwmechanics/combat.hpp" | ||||
| #include "../mwmechanics/aiavoiddoor.hpp" //Used to tell actors to avoid doors
 | ||||
| 
 | ||||
| #include "../mwrender/sky.hpp" | ||||
| #include "../mwrender/animation.hpp" | ||||
|  | @ -1210,9 +1211,16 @@ namespace MWWorld | |||
|                     MWWorld::Ptr ptr = getPtrViaHandle(*cit); | ||||
|                     if (MWWorld::Class::get(ptr).isActor()) | ||||
|                     { | ||||
|                         // we collided with an actor, we need to undo the rotation
 | ||||
|                         // Collided with actor, ask actor to try to avoid door
 | ||||
|                         if(ptr != MWBase::Environment::get().getWorld()->getPlayerPtr() ) { | ||||
|                             MWMechanics::AiSequence& seq = MWWorld::Class::get(ptr).getCreatureStats(ptr).getAiSequence(); | ||||
|                             if(seq.getTypeId() != MWMechanics::AiPackage::TypeIdAvoidDoor) //Only add it once
 | ||||
|                                 seq.stack(MWMechanics::AiAvoidDoor(it->first),ptr); | ||||
|                         } | ||||
| 
 | ||||
|                         // we need to undo the rotation
 | ||||
|                         localRotateObject(it->first, 0, 0, oldRot); | ||||
|                         break; | ||||
|                         //break; //Removed in case multiple actors are touching
 | ||||
|                     } | ||||
|                 } | ||||
| 
 | ||||
|  | @ -1856,6 +1864,12 @@ namespace MWWorld | |||
|         return door.getRefData().getLocalRotation().rot[2] == 0; | ||||
|     } | ||||
| 
 | ||||
|     bool World::getIsMovingDoor(const Ptr& door) | ||||
|     { | ||||
|         bool result = mDoorStates.find(door) != mDoorStates.end(); | ||||
|         return result; | ||||
|     } | ||||
| 
 | ||||
|     bool World::getPlayerStandingOn (const MWWorld::Ptr& object) | ||||
|     { | ||||
|         MWWorld::Ptr player = mPlayer->getPlayer(); | ||||
|  | @ -1922,7 +1936,7 @@ namespace MWWorld | |||
|                     out.push_back(searchPtrViaHandle(*it)); | ||||
|         } | ||||
|     } | ||||
|      | ||||
| 
 | ||||
|     bool World::getLOS(const MWWorld::Ptr& npc,const MWWorld::Ptr& targetNpc) | ||||
|     { | ||||
|         if (!targetNpc.getRefData().isEnabled() || !npc.getRefData().isEnabled()) | ||||
|  |  | |||
|  | @ -493,10 +493,13 @@ namespace MWWorld | |||
|             virtual void setupPlayer(); | ||||
|             virtual void renderPlayer(); | ||||
| 
 | ||||
|             /// if activated, should this door be opened or closed?
 | ||||
|             virtual bool getOpenOrCloseDoor(const MWWorld::Ptr& door); | ||||
|             ///< if activated, should this door be opened or closed?
 | ||||
| 
 | ||||
|             /// activate (open or close) an non-teleport door
 | ||||
|             virtual void activateDoor(const MWWorld::Ptr& door); | ||||
|             ///< activate (open or close) an non-teleport door
 | ||||
| 
 | ||||
|             virtual bool getIsMovingDoor(const MWWorld::Ptr& door); | ||||
| 
 | ||||
|             virtual bool getPlayerStandingOn (const MWWorld::Ptr& object); ///< @return true if the player is standing on \a object
 | ||||
|             virtual bool getActorStandingOn (const MWWorld::Ptr& object); ///< @return true if any actor is standing on \a object
 | ||||
|  |  | |||
|  | @ -98,10 +98,8 @@ namespace Compiler | |||
|             int parseArguments (const std::string& arguments, Scanner& scanner, | ||||
|                 std::vector<Interpreter::Type_Code>& code, bool invert = false); | ||||
|             ///< Parse sequence of arguments specified by \a arguments.
 | ||||
|             /// \param arguments Each character represents one arguments ('l': integer,
 | ||||
|             /// 'f': float, 'S': string, 'c': string (case smashed), '/': following arguments are
 | ||||
|             /// optional)
 | ||||
|             /// 'x': optional string that will be ignored (die in a fire, MW script compiler!)
 | ||||
|             /// \param arguments Uses ScriptArgs typedef
 | ||||
|             /// \see Compiler::ScriptArgs
 | ||||
|             /// \param invert Store arguments in reverted order.
 | ||||
|             /// \return number of optional arguments
 | ||||
|     }; | ||||
|  |  | |||
|  | @ -21,7 +21,7 @@ namespace Compiler | |||
|         return iter->second; | ||||
|     } | ||||
| 
 | ||||
|     bool Extensions::isFunction (int keyword, char& returnType, std::string& argumentType, | ||||
|     bool Extensions::isFunction (int keyword, ScriptReturn& returnType, ScriptArgs& argumentType, | ||||
|         bool& explicitReference) const | ||||
|     { | ||||
|         std::map<int, Function>::const_iterator iter = mFunctions.find (keyword); | ||||
|  | @ -37,7 +37,7 @@ namespace Compiler | |||
|         return true; | ||||
|     } | ||||
| 
 | ||||
|     bool Extensions::isInstruction (int keyword, std::string& argumentType, | ||||
|     bool Extensions::isInstruction (int keyword, ScriptArgs& argumentType, | ||||
|         bool& explicitReference) const | ||||
|     { | ||||
|         std::map<int, Instruction>::const_iterator iter = mInstructions.find (keyword); | ||||
|  | @ -52,8 +52,8 @@ namespace Compiler | |||
|         return true; | ||||
|     } | ||||
| 
 | ||||
|     void Extensions::registerFunction (const std::string& keyword, char returnType, | ||||
|         const std::string& argumentType, int code, int codeExplicit) | ||||
|     void Extensions::registerFunction (const std::string& keyword, ScriptReturn returnType, | ||||
|         const ScriptArgs& argumentType, int code, int codeExplicit) | ||||
|     { | ||||
|         Function function; | ||||
| 
 | ||||
|  | @ -83,7 +83,7 @@ namespace Compiler | |||
|     } | ||||
| 
 | ||||
|     void Extensions::registerInstruction (const std::string& keyword, | ||||
|         const std::string& argumentType, int code, int codeExplicit) | ||||
|         const ScriptArgs& argumentType, int code, int codeExplicit) | ||||
|     { | ||||
|         Instruction instruction; | ||||
| 
 | ||||
|  |  | |||
|  | @ -11,14 +11,35 @@ namespace Compiler | |||
| { | ||||
|     class Literals; | ||||
| 
 | ||||
|     /// \brief Collection of compiler extensions
 | ||||
|     /// Typedef for script arguments string
 | ||||
|     /** Every character reperesents an argument to the command. All arguments are required until a /, after which
 | ||||
|         every argument is optional. <BR> | ||||
|         Eg: fff/f represents 3 required floats followed by one optional float <BR> | ||||
|         f - Float <BR> | ||||
|         c - String, case smashed <BR> | ||||
|         l - Integer <BR> | ||||
|         s - Short <BR> | ||||
|         S - String, case preserved <BR> | ||||
|         x - Optional, ignored argument | ||||
|     **/ | ||||
|     typedef std::string ScriptArgs; | ||||
| 
 | ||||
|     /// Typedef for script return char
 | ||||
|     /** The character represents the type of data being returned. <BR>
 | ||||
|         f - float <BR> | ||||
|         S - String (Cell names) <BR> | ||||
|         l - Integer | ||||
|     **/ | ||||
|     typedef char ScriptReturn; | ||||
| 
 | ||||
|     /// \brief Collection of compiler extensions
 | ||||
|     class Extensions | ||||
|     { | ||||
| 
 | ||||
|             struct Function | ||||
|             { | ||||
|                 char mReturn; | ||||
|                 std::string mArguments; | ||||
|                 ScriptArgs mArguments; | ||||
|                 int mCode; | ||||
|                 int mCodeExplicit; | ||||
|                 int mSegment; | ||||
|  | @ -26,7 +47,7 @@ namespace Compiler | |||
| 
 | ||||
|             struct Instruction | ||||
|             { | ||||
|                 std::string mArguments; | ||||
|                 ScriptArgs mArguments; | ||||
|                 int mCode; | ||||
|                 int mCodeExplicit; | ||||
|                 int mSegment; | ||||
|  | @ -46,21 +67,21 @@ namespace Compiler | |||
|             /// - if no match is found 0 is returned.
 | ||||
|             /// - keyword must be all lower case.
 | ||||
| 
 | ||||
|             bool isFunction (int keyword, char& returnType, std::string& argumentType, | ||||
|             bool isFunction (int keyword, ScriptReturn& returnType, ScriptArgs& argumentType, | ||||
|                 bool& explicitReference) const; | ||||
|             ///< Is this keyword registered with a function? If yes, return return and argument
 | ||||
|             /// types.
 | ||||
|             /// \param explicitReference In: has explicit reference; Out: set to false, if
 | ||||
|             /// explicit reference is not available for this instruction.
 | ||||
| 
 | ||||
|             bool isInstruction (int keyword, std::string& argumentType, | ||||
|             bool isInstruction (int keyword, ScriptArgs& argumentType, | ||||
|                 bool& explicitReference) const; | ||||
|             ///< Is this keyword registered with a function? If yes, return argument types.
 | ||||
|             /// \param explicitReference In: has explicit reference; Out: set to false, if
 | ||||
|             /// explicit reference is not available for this instruction.
 | ||||
| 
 | ||||
|             void registerFunction (const std::string& keyword, char returnType, | ||||
|                 const std::string& argumentType, int code, int codeExplicit = -1); | ||||
|             void registerFunction (const std::string& keyword, ScriptReturn returnType, | ||||
|                 const ScriptArgs& argumentType, int code, int codeExplicit = -1); | ||||
|             ///< Register a custom function
 | ||||
|             /// - keyword must be all lower case.
 | ||||
|             /// - keyword must be unique
 | ||||
|  | @ -68,7 +89,7 @@ namespace Compiler | |||
|             /// \note Currently only segment 3 and segment 5 opcodes are supported.
 | ||||
| 
 | ||||
|             void registerInstruction (const std::string& keyword, | ||||
|                 const std::string& argumentType, int code, int codeExplicit = -1); | ||||
|                 const ScriptArgs& argumentType, int code, int codeExplicit = -1); | ||||
|             ///< Register a custom instruction
 | ||||
|             /// - keyword must be all lower case.
 | ||||
|             /// - keyword must be unique
 | ||||
|  |  | |||
|  | @ -8,6 +8,20 @@ namespace ESM | |||
| { | ||||
|     unsigned int Pathgrid::sRecordId = REC_PGRD; | ||||
| 
 | ||||
|     Pathgrid::Point& Pathgrid::Point::operator=(const float rhs[3]) { | ||||
|         mX = rhs[0]; | ||||
|         mY = rhs[1]; | ||||
|         mZ = rhs[2]; | ||||
|         return *this; | ||||
|     } | ||||
|     Pathgrid::Point::Point(const float rhs[3]) { | ||||
|         mX = rhs[0]; | ||||
|         mY = rhs[1]; | ||||
|         mZ = rhs[2]; | ||||
|     } | ||||
|     Pathgrid::Point::Point():mX(0),mY(0),mZ(0) { | ||||
|     } | ||||
| 
 | ||||
| void Pathgrid::load(ESMReader &esm) | ||||
| { | ||||
|     esm.getHNT(mData, "DATA", 12); | ||||
|  |  | |||
|  | @ -31,6 +31,10 @@ struct Pathgrid | |||
|         unsigned char mAutogenerated; // autogenerated vs. user coloring flag?
 | ||||
|         unsigned char mConnectionNum; // number of connections for this point
 | ||||
|         short mUnknown; | ||||
|         Point& operator=(const float[3]); | ||||
|         Point(const float[3]); | ||||
|         Point(); | ||||
|         Point(int x, int y, int z) : mX(x), mY(y), mZ(z) {} | ||||
|     }; // 16 bytes
 | ||||
| 
 | ||||
|     struct Edge // path grid edge
 | ||||
|  |  | |||
		Loading…
	
		Reference in a new issue