forked from mirror/openmw-tes3mp
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
|
add_openmw_dir (mwmechanics
|
||||||
mechanicsmanagerimp stat character creaturestats magiceffects movement actors objects
|
mechanicsmanagerimp stat character creaturestats magiceffects movement actors objects
|
||||||
drawstate spells activespells npcstats aipackage aisequence alchemy aiwander aitravel aifollow
|
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
|
add_openmw_dir (mwbase
|
||||||
|
|
|
@ -119,6 +119,8 @@ namespace MWBase
|
||||||
/// paused we may want to do it manually (after equipping permanent enchantment)
|
/// paused we may want to do it manually (after equipping permanent enchantment)
|
||||||
virtual void updateMagicEffects (const MWWorld::Ptr& ptr) = 0;
|
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;
|
virtual void getItemsOwnedBy (const MWWorld::Ptr& npc, std::vector<MWWorld::Ptr>& out) = 0;
|
||||||
///< get all items in active cells owned by this Npc
|
///< 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 enableActorCollision(const MWWorld::Ptr& actor, bool enable) = 0;
|
||||||
|
|
||||||
virtual void setupExternalRendering (MWRender::ExternalRendering& rendering) = 0;
|
virtual void setupExternalRendering (MWRender::ExternalRendering& rendering) = 0;
|
||||||
|
|
|
@ -22,6 +22,11 @@
|
||||||
#include "creaturestats.hpp"
|
#include "creaturestats.hpp"
|
||||||
#include "movement.hpp"
|
#include "movement.hpp"
|
||||||
|
|
||||||
|
#include "../mwbase/environment.hpp"
|
||||||
|
#include "../mwbase/mechanicsmanager.hpp"
|
||||||
|
|
||||||
|
#include "aicombat.hpp"
|
||||||
|
|
||||||
namespace MWMechanics
|
namespace MWMechanics
|
||||||
{
|
{
|
||||||
void Actors::updateActor (const MWWorld::Ptr& ptr, float duration)
|
void Actors::updateActor (const MWWorld::Ptr& ptr, float duration)
|
||||||
|
@ -34,8 +39,47 @@ namespace MWMechanics
|
||||||
if(!MWBase::Environment::get().getWindowManager()->isGuiMode())
|
if(!MWBase::Environment::get().getWindowManager()->isGuiMode())
|
||||||
{
|
{
|
||||||
// AI
|
// AI
|
||||||
|
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);
|
CreatureStats& creatureStats = MWWorld::Class::get (ptr).getCreatureStats (ptr);
|
||||||
creatureStats.getAiSequence().execute (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
|
// fatigue restoration
|
||||||
calculateRestoration(ptr, duration);
|
calculateRestoration(ptr, duration);
|
||||||
|
|
|
@ -9,7 +9,7 @@ MWMechanics::AiActivate *MWMechanics::AiActivate::clone() const
|
||||||
{
|
{
|
||||||
return new AiActivate(*this);
|
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";
|
std::cout << "AiActivate completed.\n";
|
||||||
return true;
|
return true;
|
||||||
|
|
|
@ -12,7 +12,7 @@ namespace MWMechanics
|
||||||
public:
|
public:
|
||||||
AiActivate(const std::string &objectId);
|
AiActivate(const std::string &objectId);
|
||||||
virtual AiActivate *clone() const;
|
virtual AiActivate *clone() const;
|
||||||
virtual bool execute (const MWWorld::Ptr& actor);
|
virtual bool execute (const MWWorld::Ptr& actor,float duration);
|
||||||
///< \return Package completed?
|
///< \return Package completed?
|
||||||
virtual int getTypeId() const;
|
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);
|
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
|
// If AiEscort has ran for as long or longer then the duration specified
|
||||||
// and the duration is not infinite, the package is complete.
|
// and the duration is not infinite, the package is complete.
|
||||||
|
|
|
@ -18,7 +18,7 @@ namespace MWMechanics
|
||||||
|
|
||||||
virtual AiEscort *clone() const;
|
virtual AiEscort *clone() const;
|
||||||
|
|
||||||
virtual bool execute (const MWWorld::Ptr& actor);
|
virtual bool execute (const MWWorld::Ptr& actor,float duration);
|
||||||
///< \return Package completed?
|
///< \return Package completed?
|
||||||
|
|
||||||
virtual int getTypeId() const;
|
virtual int getTypeId() const;
|
||||||
|
|
|
@ -15,7 +15,7 @@ MWMechanics::AiFollow *MWMechanics::AiFollow::clone() const
|
||||||
return new AiFollow(*this);
|
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";
|
std::cout << "AiFollow completed.\n";
|
||||||
return true;
|
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,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);
|
AiFollow(const std::string &ActorId,const std::string &CellId,float duration, float X, float Y, float Z);
|
||||||
virtual AiFollow *clone() const;
|
virtual AiFollow *clone() const;
|
||||||
virtual bool execute (const MWWorld::Ptr& actor);
|
virtual bool execute (const MWWorld::Ptr& actor,float duration);
|
||||||
///< \return Package completed?
|
///< \return Package completed?
|
||||||
virtual int getTypeId() const;
|
virtual int getTypeId() const;
|
||||||
|
|
||||||
|
|
|
@ -17,11 +17,14 @@ namespace MWMechanics
|
||||||
|
|
||||||
virtual AiPackage *clone() const = 0;
|
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?
|
///< \return Package completed?
|
||||||
|
|
||||||
virtual int getTypeId() const = 0;
|
virtual int getTypeId() const = 0;
|
||||||
///< 0: Wanter, 1 Travel, 2 Escort, 3 Follow, 4 Activate
|
///< 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 "aitravel.hpp"
|
||||||
#include "aifollow.hpp"
|
#include "aifollow.hpp"
|
||||||
#include "aiactivate.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)
|
void MWMechanics::AiSequence::copy (const AiSequence& sequence)
|
||||||
{
|
{
|
||||||
|
@ -52,11 +60,13 @@ bool MWMechanics::AiSequence::isPackageDone() const
|
||||||
return mDone;
|
return mDone;
|
||||||
}
|
}
|
||||||
|
|
||||||
void MWMechanics::AiSequence::execute (const MWWorld::Ptr& actor)
|
void MWMechanics::AiSequence::execute (const MWWorld::Ptr& actor,float duration)
|
||||||
{
|
{
|
||||||
|
if(actor != MWBase::Environment::get().getWorld()->getPlayer().getPlayer())
|
||||||
|
{
|
||||||
if (!mPackages.empty())
|
if (!mPackages.empty())
|
||||||
{
|
{
|
||||||
if (mPackages.front()->execute (actor))
|
if (mPackages.front()->execute (actor,duration))
|
||||||
{
|
{
|
||||||
mPackages.erase (mPackages.begin());
|
mPackages.erase (mPackages.begin());
|
||||||
mDone = true;
|
mDone = true;
|
||||||
|
@ -64,6 +74,7 @@ void MWMechanics::AiSequence::execute (const MWWorld::Ptr& actor)
|
||||||
else
|
else
|
||||||
mDone = false;
|
mDone = false;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void MWMechanics::AiSequence::clear()
|
void MWMechanics::AiSequence::clear()
|
||||||
|
@ -76,6 +87,13 @@ void MWMechanics::AiSequence::clear()
|
||||||
|
|
||||||
void MWMechanics::AiSequence::stack (const AiPackage& package)
|
void MWMechanics::AiSequence::stack (const AiPackage& package)
|
||||||
{
|
{
|
||||||
|
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());
|
mPackages.push_front (package.clone());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -18,6 +18,7 @@ namespace MWMechanics
|
||||||
class AiSequence
|
class AiSequence
|
||||||
{
|
{
|
||||||
std::list<AiPackage *> mPackages;
|
std::list<AiPackage *> mPackages;
|
||||||
|
|
||||||
bool mDone;
|
bool mDone;
|
||||||
|
|
||||||
void copy (const AiSequence& sequence);
|
void copy (const AiSequence& sequence);
|
||||||
|
@ -33,12 +34,12 @@ namespace MWMechanics
|
||||||
virtual ~AiSequence();
|
virtual ~AiSequence();
|
||||||
|
|
||||||
int getTypeId() const;
|
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;
|
bool isPackageDone() const;
|
||||||
///< Has a package been completed during the last update?
|
///< 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.
|
///< Execute package.
|
||||||
|
|
||||||
void clear();
|
void clear();
|
||||||
|
|
|
@ -31,7 +31,7 @@ namespace MWMechanics
|
||||||
return new AiTravel(*this);
|
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();
|
MWBase::World *world = MWBase::Environment::get().getWorld();
|
||||||
ESM::Position pos = actor.getRefData().getPosition();
|
ESM::Position pos = actor.getRefData().getPosition();
|
||||||
|
|
|
@ -13,7 +13,7 @@ namespace MWMechanics
|
||||||
AiTravel(float x, float y, float z);
|
AiTravel(float x, float y, float z);
|
||||||
virtual AiTravel *clone() const;
|
virtual AiTravel *clone() const;
|
||||||
|
|
||||||
virtual bool execute (const MWWorld::Ptr& actor);
|
virtual bool execute (const MWWorld::Ptr& actor,float duration);
|
||||||
///< \return Package completed?
|
///< \return Package completed?
|
||||||
|
|
||||||
virtual int getTypeId() const;
|
virtual int getTypeId() const;
|
||||||
|
|
|
@ -63,7 +63,7 @@ namespace MWMechanics
|
||||||
return new AiWander(*this);
|
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();
|
MWBase::World *world = MWBase::Environment::get().getWorld();
|
||||||
if(mDuration)
|
if(mDuration)
|
||||||
|
|
|
@ -16,7 +16,7 @@ namespace MWMechanics
|
||||||
|
|
||||||
AiWander(int distance, int duration, int timeOfDay, const std::vector<int>& idle, bool repeat);
|
AiWander(int distance, int duration, int timeOfDay, const std::vector<int>& idle, bool repeat);
|
||||||
virtual AiPackage *clone() const;
|
virtual AiPackage *clone() const;
|
||||||
virtual bool execute (const MWWorld::Ptr& actor);
|
virtual bool execute (const MWWorld::Ptr& actor,float duration);
|
||||||
///< \return Package completed?
|
///< \return Package completed?
|
||||||
virtual int getTypeId() const;
|
virtual int getTypeId() const;
|
||||||
///< 0: Wander
|
///< 0: Wander
|
||||||
|
|
|
@ -165,7 +165,7 @@ namespace MWMechanics
|
||||||
|
|
||||||
MechanicsManager::MechanicsManager()
|
MechanicsManager::MechanicsManager()
|
||||||
: mUpdatePlayer (true), mClassSelected (false),
|
: 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
|
//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);
|
mActors.updateMagicEffects(ptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void MechanicsManager::toggleAI()
|
||||||
|
{
|
||||||
|
mAI = !mAI;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool MechanicsManager::isAIActive()
|
||||||
|
{
|
||||||
|
return mAI;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -29,6 +29,7 @@ namespace MWMechanics
|
||||||
bool mUpdatePlayer;
|
bool mUpdatePlayer;
|
||||||
bool mClassSelected;
|
bool mClassSelected;
|
||||||
bool mRaceSelected;
|
bool mRaceSelected;
|
||||||
|
bool mAI;///< is AI active?
|
||||||
|
|
||||||
Objects mObjects;
|
Objects mObjects;
|
||||||
Actors mActors;
|
Actors mActors;
|
||||||
|
@ -105,6 +106,8 @@ namespace MWMechanics
|
||||||
/// paused we may want to do it manually (after equipping permanent enchantment)
|
/// paused we may want to do it manually (after equipping permanent enchantment)
|
||||||
virtual void updateMagicEffects (const MWWorld::Ptr& ptr);
|
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
|
// This should never happen (programmers should have an if statement checking mIsPathConstructed that prevents this call
|
||||||
// if otherwise).
|
// if otherwise).
|
||||||
if(mPath.empty())
|
if(mPath.empty())
|
||||||
return 0;
|
return 0.;
|
||||||
|
|
||||||
const ESM::Pathgrid::Point &nextPoint = *mPath.begin();
|
const ESM::Pathgrid::Point &nextPoint = *mPath.begin();
|
||||||
float directionX = nextPoint.mX - x;
|
float directionX = nextPoint.mX - x;
|
||||||
|
@ -199,6 +199,21 @@ namespace MWMechanics
|
||||||
return Ogre::Radian(acos(directionY / directionResult) * sgn(asin(directionX / directionResult))).valueDegrees();
|
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)
|
bool PathFinder::checkPathCompleted(float x, float y, float z)
|
||||||
{
|
{
|
||||||
if(mPath.empty())
|
if(mPath.empty())
|
||||||
|
|
|
@ -18,6 +18,8 @@ namespace MWMechanics
|
||||||
|
|
||||||
bool checkPathCompleted(float x, float y, float z);
|
bool checkPathCompleted(float x, float y, float z);
|
||||||
///< \Returns true if the last point of the path has been reached.
|
///< \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;
|
float getZAngleToNext(float x, float y) const;
|
||||||
|
|
||||||
bool isPathConstructed() const
|
bool isPathConstructed() const
|
||||||
|
@ -25,6 +27,16 @@ namespace MWMechanics
|
||||||
return mIsPathConstructed;
|
return mIsPathConstructed;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int getPathSize() const
|
||||||
|
{
|
||||||
|
return mPath.size();
|
||||||
|
}
|
||||||
|
|
||||||
|
std::list<ESM::Pathgrid::Point> getPath() const
|
||||||
|
{
|
||||||
|
return mPath;
|
||||||
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
std::list<ESM::Pathgrid::Point> mPath;
|
std::list<ESM::Pathgrid::Point> mPath;
|
||||||
bool mIsPathConstructed;
|
bool mIsPathConstructed;
|
||||||
|
|
|
@ -17,11 +17,16 @@
|
||||||
#include "../mwmechanics/aitravel.hpp"
|
#include "../mwmechanics/aitravel.hpp"
|
||||||
#include "../mwmechanics/aiwander.hpp"
|
#include "../mwmechanics/aiwander.hpp"
|
||||||
|
|
||||||
|
#include "../mwbase/environment.hpp"
|
||||||
|
#include "../mwbase/world.hpp"
|
||||||
|
|
||||||
#include "interpretercontext.hpp"
|
#include "interpretercontext.hpp"
|
||||||
#include "ref.hpp"
|
#include "ref.hpp"
|
||||||
|
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
|
|
||||||
|
#include "../mwbase/mechanicsmanager.hpp"
|
||||||
|
|
||||||
namespace MWScript
|
namespace MWScript
|
||||||
{
|
{
|
||||||
namespace Ai
|
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)
|
void installOpcodes (Interpreter::Interpreter& interpreter)
|
||||||
{
|
{
|
||||||
|
@ -389,6 +427,11 @@ namespace MWScript
|
||||||
interpreter.installSegment5 (Compiler::Ai::opcodeGetCurrentAiPackageExplicit, new OpGetCurrentAIPackage<ExplicitRef>);
|
interpreter.installSegment5 (Compiler::Ai::opcodeGetCurrentAiPackageExplicit, new OpGetCurrentAIPackage<ExplicitRef>);
|
||||||
interpreter.installSegment3 (Compiler::Ai::opcodeGetDetected, new OpGetDetected<ImplicitRef>);
|
interpreter.installSegment3 (Compiler::Ai::opcodeGetDetected, new OpGetDetected<ImplicitRef>);
|
||||||
interpreter.installSegment3 (Compiler::Ai::opcodeGetDetectedExplicit, new OpGetDetected<ExplicitRef>);
|
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::opcodeSetHello, new OpSetAiSetting<ImplicitRef>(0));
|
||||||
interpreter.installSegment5 (Compiler::Ai::opcodeSetHelloExplicit, new OpSetAiSetting<ExplicitRef>(0));
|
interpreter.installSegment5 (Compiler::Ai::opcodeSetHelloExplicit, new OpSetAiSetting<ExplicitRef>(0));
|
||||||
interpreter.installSegment5 (Compiler::Ai::opcodeSetFight, new OpSetAiSetting<ImplicitRef>(1));
|
interpreter.installSegment5 (Compiler::Ai::opcodeSetFight, new OpSetAiSetting<ImplicitRef>(1));
|
||||||
|
|
|
@ -354,5 +354,9 @@ op 0x200021e: ShowVarsExplicit
|
||||||
op 0x200021f: ToggleGodMode
|
op 0x200021f: ToggleGodMode
|
||||||
op 0x2000220: DisableLevitation
|
op 0x2000220: DisableLevitation
|
||||||
op 0x2000221: EnableLevitation
|
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)
|
void World::enableActorCollision(const MWWorld::Ptr& actor, bool enable)
|
||||||
{
|
{
|
||||||
OEngine::Physic::PhysicActor *physicActor = mPhysEngine->getCharacter(actor.getRefData().getHandle());
|
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);
|
virtual void getItemsOwnedBy (const MWWorld::Ptr& npc, std::vector<MWWorld::Ptr>& out);
|
||||||
///< get all items in active cells owned by this Npc
|
///< 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 enableActorCollision(const MWWorld::Ptr& actor, bool enable);
|
||||||
|
|
||||||
virtual void setupExternalRendering (MWRender::ExternalRendering& rendering);
|
virtual void setupExternalRendering (MWRender::ExternalRendering& rendering);
|
||||||
|
|
|
@ -59,10 +59,12 @@ namespace Compiler
|
||||||
extensions.registerInstruction ("modfight", "l", opcodeModFight, opcodeModFightExplicit);
|
extensions.registerInstruction ("modfight", "l", opcodeModFight, opcodeModFightExplicit);
|
||||||
extensions.registerInstruction ("modflee", "l", opcodeModFlee, opcodeModFleeExplicit);
|
extensions.registerInstruction ("modflee", "l", opcodeModFlee, opcodeModFleeExplicit);
|
||||||
extensions.registerInstruction ("modalarm", "l", opcodeModAlarm, opcodeModAlarmExplicit);
|
extensions.registerInstruction ("modalarm", "l", opcodeModAlarm, opcodeModAlarmExplicit);
|
||||||
|
extensions.registerInstruction ("toggleai", "", opcodeToggleAI, opcodeToggleAI);
|
||||||
extensions.registerFunction ("gethello", 'l', "", opcodeGetHello, opcodeGetHelloExplicit);
|
extensions.registerFunction ("gethello", 'l', "", opcodeGetHello, opcodeGetHelloExplicit);
|
||||||
extensions.registerFunction ("getfight", 'l', "", opcodeGetFight, opcodeGetFightExplicit);
|
extensions.registerFunction ("getfight", 'l', "", opcodeGetFight, opcodeGetFightExplicit);
|
||||||
extensions.registerFunction ("getflee", 'l', "", opcodeGetFlee, opcodeGetFleeExplicit);
|
extensions.registerFunction ("getflee", 'l', "", opcodeGetFlee, opcodeGetFleeExplicit);
|
||||||
extensions.registerFunction ("getalarm", 'l', "", opcodeGetAlarm, opcodeGetAlarmExplicit);
|
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 opcodeGetFleeExplicit = 0x20001c4;
|
||||||
const int opcodeGetAlarm = 0x20001c5;
|
const int opcodeGetAlarm = 0x20001c5;
|
||||||
const int opcodeGetAlarmExplicit = 0x20001c6;
|
const int opcodeGetAlarmExplicit = 0x20001c6;
|
||||||
|
const int opcodeGetLineOfSight = 0x2000222;
|
||||||
|
const int opcodeGetLineOfSightExplicit = 0x2000223;
|
||||||
|
const int opcodeToggleAI = 0x2000224;
|
||||||
|
const int opcodeToggleAIExplicit = 0x2000225;
|
||||||
}
|
}
|
||||||
|
|
||||||
namespace Animation
|
namespace Animation
|
||||||
|
|
Loading…
Reference in a new issue