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
actorid
Marc Zinnschlag 11 years ago
commit 11e254aac8

@ -72,7 +72,7 @@ add_openmw_dir (mwclass
add_openmw_dir (mwmechanics
mechanicsmanagerimp stat character creaturestats magiceffects movement actors objects
drawstate spells activespells npcstats aipackage aisequence alchemy aiwander aitravel aifollow
aiescort aiactivate repair enchanting pathfinding security spellsuccess spellcasting
aiescort aiactivate aicombat repair enchanting pathfinding security spellsuccess spellcasting
)
add_openmw_dir (mwbase

@ -119,6 +119,8 @@ namespace MWBase
/// paused we may want to do it manually (after equipping permanent enchantment)
virtual void updateMagicEffects (const MWWorld::Ptr& ptr) = 0;
virtual void toggleAI() = 0;
virtual bool isAIActive() = 0;
};
}

@ -362,6 +362,9 @@ namespace MWBase
virtual void getItemsOwnedBy (const MWWorld::Ptr& npc, std::vector<MWWorld::Ptr>& out) = 0;
///< get all items in active cells owned by this Npc
virtual bool getLOS(const MWWorld::Ptr& npc,const MWWorld::Ptr& targetNpc) = 0;
///< get Line of Sight (morrowind stupid implementation)
virtual void enableActorCollision(const MWWorld::Ptr& actor, bool enable) = 0;
virtual void setupExternalRendering (MWRender::ExternalRendering& rendering) = 0;

@ -22,6 +22,11 @@
#include "creaturestats.hpp"
#include "movement.hpp"
#include "../mwbase/environment.hpp"
#include "../mwbase/mechanicsmanager.hpp"
#include "aicombat.hpp"
namespace MWMechanics
{
void Actors::updateActor (const MWWorld::Ptr& ptr, float duration)
@ -34,8 +39,47 @@ namespace MWMechanics
if(!MWBase::Environment::get().getWindowManager()->isGuiMode())
{
// AI
CreatureStats& creatureStats = MWWorld::Class::get (ptr).getCreatureStats (ptr);
creatureStats.getAiSequence().execute (ptr);
if(MWBase::Environment::get().getMechanicsManager())//check MechanismsManager is already created
{
if(MWBase::Environment::get().getMechanicsManager()->isAIActive())//MWBase::Environment::get().getMechanicsManager()->isAIActive())
{
CreatureStats& creatureStats = MWWorld::Class::get (ptr).getCreatureStats (ptr);
if(ptr != MWBase::Environment::get().getWorld()->getPlayer().getPlayer()) MWBase::Environment::get().getMechanicsManager()->restoreDynamicStats();
//engage combat or not?
if(ptr != MWBase::Environment::get().getWorld()->getPlayer().getPlayer() && !creatureStats.isHostile())
{
ESM::Position playerpos = MWBase::Environment::get().getWorld()->getPlayer().getPlayer().getRefData().getPosition();
ESM::Position actorpos = ptr.getRefData().getPosition();
float d = sqrt((actorpos.pos[0] - playerpos.pos[0])*(actorpos.pos[0] - playerpos.pos[0])
+(actorpos.pos[1] - playerpos.pos[1])*(actorpos.pos[1] - playerpos.pos[1])
+(actorpos.pos[2] - playerpos.pos[2])*(actorpos.pos[2] - playerpos.pos[2]));
float fight = ptr.getClass().getCreatureStats(ptr).getAiSetting(1);
float disp = 100; //creatures don't have disposition, so set it to 100 by default
if(ptr.getTypeName() == typeid(ESM::NPC).name())
{
disp = MWBase::Environment::get().getMechanicsManager()->getDerivedDisposition(ptr);
}
bool LOS = MWBase::Environment::get().getWorld()->getLOS(ptr,MWBase::Environment::get().getWorld()->getPlayer().getPlayer());
if( ( (fight == 100 )
|| (fight >= 95 && d <= 3000)
|| (fight >= 90 && d <= 2000)
|| (fight >= 80 && d <= 1000)
|| (fight >= 80 && disp <= 40)
|| (fight >= 70 && disp <= 35 && d <= 1000)
|| (fight >= 60 && disp <= 30 && d <= 1000)
|| (fight >= 50 && disp == 0)
|| (fight >= 40 && disp <= 10 && d <= 500) )
&& LOS
)
{
creatureStats.getAiSequence().stack(AiCombat("player"));
creatureStats.setHostile(true);
}
}
creatureStats.getAiSequence().execute (ptr,duration);
}
}
// fatigue restoration
calculateRestoration(ptr, duration);

@ -9,7 +9,7 @@ MWMechanics::AiActivate *MWMechanics::AiActivate::clone() const
{
return new AiActivate(*this);
}
bool MWMechanics::AiActivate::execute (const MWWorld::Ptr& actor)
bool MWMechanics::AiActivate::execute (const MWWorld::Ptr& actor,float duration)
{
std::cout << "AiActivate completed.\n";
return true;

@ -12,7 +12,7 @@ namespace MWMechanics
public:
AiActivate(const std::string &objectId);
virtual AiActivate *clone() const;
virtual bool execute (const MWWorld::Ptr& actor);
virtual bool execute (const MWWorld::Ptr& actor,float duration);
///< \return Package completed?
virtual int getTypeId() const;

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

@ -0,0 +1,36 @@
#ifndef GAME_MWMECHANICS_AICOMBAT_H
#define GAME_MWMECHANICS_AICOMBAT_H
#include "aipackage.hpp"
#include "pathfinding.hpp"
#include "movement.hpp"
namespace MWMechanics
{
class AiCombat : public AiPackage
{
public:
AiCombat(const std::string &targetId);
virtual AiCombat *clone() const;
virtual bool execute (const MWWorld::Ptr& actor,float duration);
///< \return Package completed?
virtual int getTypeId() const;
virtual unsigned int getPriority() const;
private:
std::string mTargetId;
PathFinder mPathFinder;
PathFinder mPathFinder2;
float mTimer;
float mTimer2;
};
}
#endif

@ -71,7 +71,7 @@ namespace MWMechanics
return new AiEscort(*this);
}
bool AiEscort::execute (const MWWorld::Ptr& actor)
bool AiEscort::execute (const MWWorld::Ptr& actor,float duration)
{
// If AiEscort has ran for as long or longer then the duration specified
// and the duration is not infinite, the package is complete.

@ -18,7 +18,7 @@ namespace MWMechanics
virtual AiEscort *clone() const;
virtual bool execute (const MWWorld::Ptr& actor);
virtual bool execute (const MWWorld::Ptr& actor,float duration);
///< \return Package completed?
virtual int getTypeId() const;

@ -15,7 +15,7 @@ MWMechanics::AiFollow *MWMechanics::AiFollow::clone() const
return new AiFollow(*this);
}
bool MWMechanics::AiFollow::execute (const MWWorld::Ptr& actor)
bool MWMechanics::AiFollow::execute (const MWWorld::Ptr& actor,float duration)
{
std::cout << "AiFollow completed.\n";
return true;

@ -13,7 +13,7 @@ namespace MWMechanics
AiFollow(const std::string &ActorId,float duration, float X, float Y, float Z);
AiFollow(const std::string &ActorId,const std::string &CellId,float duration, float X, float Y, float Z);
virtual AiFollow *clone() const;
virtual bool execute (const MWWorld::Ptr& actor);
virtual bool execute (const MWWorld::Ptr& actor,float duration);
///< \return Package completed?
virtual int getTypeId() const;

@ -17,11 +17,14 @@ namespace MWMechanics
virtual AiPackage *clone() const = 0;
virtual bool execute (const MWWorld::Ptr& actor) = 0;
virtual bool execute (const MWWorld::Ptr& actor,float duration) = 0;
///< \return Package completed?
virtual int getTypeId() const = 0;
///< 0: Wanter, 1 Travel, 2 Escort, 3 Follow, 4 Activate
virtual unsigned int getPriority() const {return 0;}
///< higher number is higher priority (0 beeing the lowest)
};
}

@ -8,6 +8,14 @@
#include "aitravel.hpp"
#include "aifollow.hpp"
#include "aiactivate.hpp"
#include "aicombat.hpp"
#include "../mwworld/class.hpp"
#include "creaturestats.hpp"
#include "npcstats.hpp"
#include "../mwbase/environment.hpp"
#include "../mwbase/world.hpp"
#include "../mwworld/player.hpp"
void MWMechanics::AiSequence::copy (const AiSequence& sequence)
{
@ -52,17 +60,20 @@ bool MWMechanics::AiSequence::isPackageDone() const
return mDone;
}
void MWMechanics::AiSequence::execute (const MWWorld::Ptr& actor)
void MWMechanics::AiSequence::execute (const MWWorld::Ptr& actor,float duration)
{
if (!mPackages.empty())
if(actor != MWBase::Environment::get().getWorld()->getPlayer().getPlayer())
{
if (mPackages.front()->execute (actor))
if (!mPackages.empty())
{
mPackages.erase (mPackages.begin());
mDone = true;
if (mPackages.front()->execute (actor,duration))
{
mPackages.erase (mPackages.begin());
mDone = true;
}
else
mDone = false;
}
else
mDone = false;
}
}
@ -76,7 +87,14 @@ void MWMechanics::AiSequence::clear()
void MWMechanics::AiSequence::stack (const AiPackage& package)
{
mPackages.push_front (package.clone());
for(std::list<AiPackage *>::iterator it = mPackages.begin(); it != mPackages.end(); it++)
{
if(mPackages.front()->getPriority() <= package.getPriority())
mPackages.insert(it,package.clone());
}
if(mPackages.empty())
mPackages.push_front (package.clone());
}
void MWMechanics::AiSequence::queue (const AiPackage& package)

@ -18,6 +18,7 @@ namespace MWMechanics
class AiSequence
{
std::list<AiPackage *> mPackages;
bool mDone;
void copy (const AiSequence& sequence);
@ -33,17 +34,17 @@ namespace MWMechanics
virtual ~AiSequence();
int getTypeId() const;
///< -1: None, 0: Wanter, 1 Travel, 2 Escort, 3 Follow, 4 Activate
///< -1: None, 0: Wanter, 1 Travel, 2 Escort, 3 Follow, 4 Activate, 5 Combat
bool isPackageDone() const;
///< Has a package been completed during the last update?
void execute (const MWWorld::Ptr& actor);
void execute (const MWWorld::Ptr& actor,float duration);
///< Execute package.
void clear();
///< Remove all packages.
void stack (const AiPackage& package);
///< Add \a package to the front of the sequence (suspends current package)

@ -31,7 +31,7 @@ namespace MWMechanics
return new AiTravel(*this);
}
bool AiTravel::execute (const MWWorld::Ptr& actor)
bool AiTravel::execute (const MWWorld::Ptr& actor,float duration)
{
MWBase::World *world = MWBase::Environment::get().getWorld();
ESM::Position pos = actor.getRefData().getPosition();

@ -13,7 +13,7 @@ namespace MWMechanics
AiTravel(float x, float y, float z);
virtual AiTravel *clone() const;
virtual bool execute (const MWWorld::Ptr& actor);
virtual bool execute (const MWWorld::Ptr& actor,float duration);
///< \return Package completed?
virtual int getTypeId() const;

@ -63,7 +63,7 @@ namespace MWMechanics
return new AiWander(*this);
}
bool AiWander::execute (const MWWorld::Ptr& actor)
bool AiWander::execute (const MWWorld::Ptr& actor,float duration)
{
MWBase::World *world = MWBase::Environment::get().getWorld();
if(mDuration)

@ -16,7 +16,7 @@ namespace MWMechanics
AiWander(int distance, int duration, int timeOfDay, const std::vector<int>& idle, bool repeat);
virtual AiPackage *clone() const;
virtual bool execute (const MWWorld::Ptr& actor);
virtual bool execute (const MWWorld::Ptr& actor,float duration);
///< \return Package completed?
virtual int getTypeId() const;
///< 0: Wander

@ -165,7 +165,7 @@ namespace MWMechanics
MechanicsManager::MechanicsManager()
: mUpdatePlayer (true), mClassSelected (false),
mRaceSelected (false)
mRaceSelected (false), mAI(true)
{
//buildPlayer no longer here, needs to be done explicitely after all subsystems are up and running
}
@ -684,4 +684,13 @@ namespace MWMechanics
mActors.updateMagicEffects(ptr);
}
void MechanicsManager::toggleAI()
{
mAI = !mAI;
}
bool MechanicsManager::isAIActive()
{
return mAI;
}
}

@ -29,6 +29,7 @@ namespace MWMechanics
bool mUpdatePlayer;
bool mClassSelected;
bool mRaceSelected;
bool mAI;///< is AI active?
Objects mObjects;
Actors mActors;
@ -89,7 +90,7 @@ namespace MWMechanics
virtual int countDeaths (const std::string& id) const;
///< Return the number of deaths for actors with the given ID.
virtual void getPersuasionDispositionChange (const MWWorld::Ptr& npc, PersuasionType type,
float currentTemporaryDispositionDelta, bool& success, float& tempChange, float& permChange);
void toLower(std::string npcFaction);
@ -105,6 +106,8 @@ namespace MWMechanics
/// paused we may want to do it manually (after equipping permanent enchantment)
virtual void updateMagicEffects (const MWWorld::Ptr& ptr);
virtual void toggleAI();
virtual bool isAIActive();
};
}

@ -189,7 +189,7 @@ namespace MWMechanics
// This should never happen (programmers should have an if statement checking mIsPathConstructed that prevents this call
// if otherwise).
if(mPath.empty())
return 0;
return 0.;
const ESM::Pathgrid::Point &nextPoint = *mPath.begin();
float directionX = nextPoint.mX - x;
@ -199,6 +199,21 @@ namespace MWMechanics
return Ogre::Radian(acos(directionY / directionResult) * sgn(asin(directionX / directionResult))).valueDegrees();
}
bool PathFinder::checkWaypoint(float x, float y, float z)
{
if(mPath.empty())
return true;
ESM::Pathgrid::Point nextPoint = *mPath.begin();
if(distanceZCorrected(nextPoint, x, y, z) < 64)
{
mPath.pop_front();
if(mPath.empty()) mIsPathConstructed = false;
return true;
}
return false;
}
bool PathFinder::checkPathCompleted(float x, float y, float z)
{
if(mPath.empty())

@ -18,6 +18,8 @@ namespace MWMechanics
bool checkPathCompleted(float x, float y, float z);
///< \Returns true if the last point of the path has been reached.
bool checkWaypoint(float x, float y, float z);
///< \Returns true if a way point was reached
float getZAngleToNext(float x, float y) const;
bool isPathConstructed() const
@ -25,6 +27,16 @@ namespace MWMechanics
return mIsPathConstructed;
}
int getPathSize() const
{
return mPath.size();
}
std::list<ESM::Pathgrid::Point> getPath() const
{
return mPath;
}
private:
std::list<ESM::Pathgrid::Point> mPath;
bool mIsPathConstructed;

@ -17,11 +17,16 @@
#include "../mwmechanics/aitravel.hpp"
#include "../mwmechanics/aiwander.hpp"
#include "../mwbase/environment.hpp"
#include "../mwbase/world.hpp"
#include "interpretercontext.hpp"
#include "ref.hpp"
#include <iostream>
#include "../mwbase/mechanicsmanager.hpp"
namespace MWScript
{
namespace Ai
@ -364,6 +369,39 @@ namespace MWScript
}
};
template<class R>
class OpGetLineOfSight : public Interpreter::Opcode0
{
public:
virtual void execute (Interpreter::Runtime& runtime)
{
MWWorld::Ptr source = R()(runtime);
std::string actorID = runtime.getStringLiteral (runtime[0].mInteger);
runtime.pop();
MWWorld::Ptr dest = MWBase::Environment::get().getWorld()->getPtr(actorID,true);
bool value = false;
if(dest != MWWorld::Ptr() )
{
value = MWBase::Environment::get().getWorld()->getLOS(source,dest);
}
runtime.push (value);
}
};
template<class R>
class OpToggleAI : public Interpreter::Opcode0
{
public:
virtual void execute (Interpreter::Runtime& runtime)
{
MWBase::Environment::get().getMechanicsManager()->toggleAI();
}
};
void installOpcodes (Interpreter::Interpreter& interpreter)
{
@ -389,6 +427,11 @@ namespace MWScript
interpreter.installSegment5 (Compiler::Ai::opcodeGetCurrentAiPackageExplicit, new OpGetCurrentAIPackage<ExplicitRef>);
interpreter.installSegment3 (Compiler::Ai::opcodeGetDetected, new OpGetDetected<ImplicitRef>);
interpreter.installSegment3 (Compiler::Ai::opcodeGetDetectedExplicit, new OpGetDetected<ExplicitRef>);
interpreter.installSegment5 (Compiler::Ai::opcodeGetLineOfSight, new OpGetLineOfSight<ImplicitRef>);
interpreter.installSegment5 (Compiler::Ai::opcodeGetLineOfSightExplicit, new OpGetLineOfSight<ExplicitRef>);
interpreter.installSegment5 (Compiler::Ai::opcodeToggleAI, new OpToggleAI<ImplicitRef>);
interpreter.installSegment5 (Compiler::Ai::opcodeToggleAIExplicit, new OpToggleAI<ExplicitRef>);
interpreter.installSegment5 (Compiler::Ai::opcodeSetHello, new OpSetAiSetting<ImplicitRef>(0));
interpreter.installSegment5 (Compiler::Ai::opcodeSetHelloExplicit, new OpSetAiSetting<ExplicitRef>(0));
interpreter.installSegment5 (Compiler::Ai::opcodeSetFight, new OpSetAiSetting<ImplicitRef>(1));

@ -354,5 +354,9 @@ op 0x200021e: ShowVarsExplicit
op 0x200021f: ToggleGodMode
op 0x2000220: DisableLevitation
op 0x2000221: EnableLevitation
op 0x2000222: GetLineOfSight
op 0x2000223: GetLineOfSightExplicit
op 0x2000224: ToggleAI
op 0x2000225: ToggleAIExplicit
opcodes 0x2000222-0x3ffffff unused
opcodes 0x2000226-0x3ffffff unused

@ -1832,6 +1832,21 @@ namespace MWWorld
}
}
bool World::getLOS(const MWWorld::Ptr& npc,const MWWorld::Ptr& targetNpc)
{
Ogre::Vector3 halfExt1 = mPhysEngine->getCharacter(npc.getRefData().getHandle())->getHalfExtents();
float* pos1 = npc.getRefData().getPosition().pos;
Ogre::Vector3 halfExt2 = mPhysEngine->getCharacter(targetNpc.getRefData().getHandle())->getHalfExtents();
float* pos2 = targetNpc.getRefData().getPosition().pos;
btVector3 from(pos1[0],pos1[1],pos1[2]+halfExt1.z);
btVector3 to(pos2[0],pos2[1],pos2[2]+halfExt2.z);
std::pair<std::string, float> result = mPhysEngine->rayTest(from, to,false);
if(result.first == "") return true;
return false;
}
void World::enableActorCollision(const MWWorld::Ptr& actor, bool enable)
{
OEngine::Physic::PhysicActor *physicActor = mPhysEngine->getCharacter(actor.getRefData().getHandle());

@ -441,6 +441,9 @@ namespace MWWorld
virtual void getItemsOwnedBy (const MWWorld::Ptr& npc, std::vector<MWWorld::Ptr>& out);
///< get all items in active cells owned by this Npc
virtual bool getLOS(const MWWorld::Ptr& npc,const MWWorld::Ptr& targetNpc);
///< get Line of Sight (morrowind stupid implementation)
virtual void enableActorCollision(const MWWorld::Ptr& actor, bool enable);
virtual void setupExternalRendering (MWRender::ExternalRendering& rendering);

@ -59,10 +59,12 @@ namespace Compiler
extensions.registerInstruction ("modfight", "l", opcodeModFight, opcodeModFightExplicit);
extensions.registerInstruction ("modflee", "l", opcodeModFlee, opcodeModFleeExplicit);
extensions.registerInstruction ("modalarm", "l", opcodeModAlarm, opcodeModAlarmExplicit);
extensions.registerInstruction ("toggleai", "", opcodeToggleAI, opcodeToggleAI);
extensions.registerFunction ("gethello", 'l', "", opcodeGetHello, opcodeGetHelloExplicit);
extensions.registerFunction ("getfight", 'l', "", opcodeGetFight, opcodeGetFightExplicit);
extensions.registerFunction ("getflee", 'l', "", opcodeGetFlee, opcodeGetFleeExplicit);
extensions.registerFunction ("getalarm", 'l', "", opcodeGetAlarm, opcodeGetAlarmExplicit);
extensions.registerFunction ("getlineofsight", 'l', "c", opcodeGetLineOfSight, opcodeGetLineOfSightExplicit);
}
}

@ -49,6 +49,10 @@ namespace Compiler
const int opcodeGetFleeExplicit = 0x20001c4;
const int opcodeGetAlarm = 0x20001c5;
const int opcodeGetAlarmExplicit = 0x20001c6;
const int opcodeGetLineOfSight = 0x2000222;
const int opcodeGetLineOfSightExplicit = 0x2000223;
const int opcodeToggleAI = 0x2000224;
const int opcodeToggleAIExplicit = 0x2000225;
}
namespace Animation

Loading…
Cancel
Save