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:
Marc Zinnschlag 2013-11-19 09:10:48 +01:00
commit 11e254aac8
29 changed files with 394 additions and 29 deletions

View file

@ -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

View file

@ -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;
}; };
} }

View file

@ -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;

View file

@ -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);

View file

@ -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;

View file

@ -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;

View 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);
}
}

View 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

View file

@ -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.

View file

@ -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;

View file

@ -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;

View file

@ -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;

View file

@ -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)
}; };
} }

View file

@ -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());
} }

View file

@ -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();

View file

@ -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();

View file

@ -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;

View file

@ -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)

View file

@ -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

View file

@ -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;
}
} }

View file

@ -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();
}; };
} }

View file

@ -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())

View file

@ -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;

View file

@ -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));

View file

@ -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

View file

@ -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());

View file

@ -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);

View file

@ -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);
} }
} }

View file

@ -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