1
0
mirror of https://gitlab.com/OpenMW/openmw.git synced 2025-03-12 13:13:27 +00:00

Merge remote-tracking branch 'mrcheko/master'

This commit is contained in:
Marc Zinnschlag 2014-05-18 18:42:23 +02:00
commit 56c4367c1a
13 changed files with 275 additions and 114 deletions

View File

@ -181,55 +181,66 @@ namespace MWMechanics
calculateDynamicStats (ptr);
calculateCreatureStatModifiers (ptr, duration);
// AI
if(MWBase::Environment::get().getMechanicsManager()->isAIActive())
{
CreatureStats& creatureStats = MWWorld::Class::get(ptr).getCreatureStats(ptr);
MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayerPtr();
//engage combat or not?
if(ptr != player && !creatureStats.isHostile())
{
ESM::Position playerpos = player.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(CreatureStats::AI_Fight).getModified();
if( (fight == 100 )
|| (fight >= 95 && d <= 3000)
|| (fight >= 90 && d <= 2000)
|| (fight >= 80 && d <= 1000)
)
{
bool LOS = MWBase::Environment::get().getWorld()->getLOS(ptr,player)
&& MWBase::Environment::get().getMechanicsManager()->awarenessCheck(player, ptr);
if (LOS)
{
MWBase::Environment::get().getMechanicsManager()->startCombat(ptr, player);
}
}
}
updateCrimePersuit(ptr, duration);
creatureStats.getAiSequence().execute (ptr,duration);
}
// fatigue restoration
calculateRestoration(ptr, duration, false);
}
void Actors::updateNpc (const MWWorld::Ptr& ptr, float duration, bool paused)
void Actors::engageCombat (const MWWorld::Ptr& actor1, const MWWorld::Ptr& actor2, bool againstPlayer)
{
if(!paused)
CreatureStats& creatureStats = MWWorld::Class::get(actor1).getCreatureStats(actor1);
if (againstPlayer && creatureStats.isHostile()) return; // already fighting against player
float fight;
if (againstPlayer)
fight = actor1.getClass().getCreatureStats(actor1).getAiSetting(CreatureStats::AI_Fight).getModified();
else
{
fight = 0;
// if one of actors is creature then we should make a decision to start combat or not
// NOTE: function doesn't take into account combat between 2 creatures
if (!actor1.getClass().isNpc())
{
// if creature is hostile then it is necessarily to start combat
if (creatureStats.isHostile()) fight = 100;
else fight = creatureStats.getAiSetting(CreatureStats::AI_Fight).getModified();
}
}
ESM::Position actor1Pos = actor1.getRefData().getPosition();
ESM::Position actor2Pos = actor2.getRefData().getPosition();
float d = Ogre::Vector3(actor1Pos.pos).distance(Ogre::Vector3(actor2Pos.pos));
if( (fight == 100 && d <= 5000)
|| (fight >= 95 && d <= 3000)
|| (fight >= 90 && d <= 2000)
|| (fight >= 80 && d <= 1000))
{
if (againstPlayer || actor2.getClass().getCreatureStats(actor2).getAiSequence().canAddTarget(actor2Pos, d))
{
bool LOS = MWBase::Environment::get().getWorld()->getLOS(actor1, actor2);
if (againstPlayer) LOS &= MWBase::Environment::get().getMechanicsManager()->awarenessCheck(actor2, actor1);
if (LOS)
{
MWBase::Environment::get().getMechanicsManager()->startCombat(actor1, actor2);
if (!againstPlayer) // start combat between each other
{
MWBase::Environment::get().getMechanicsManager()->startCombat(actor2, actor1);
}
}
}
}
}
void Actors::updateNpc (const MWWorld::Ptr& ptr, float duration)
{
updateDrowning(ptr, duration);
calculateNpcStatModifiers(ptr);
updateEquippedLight(ptr, duration);
}
}
void Actors::adjustMagicEffects (const MWWorld::Ptr& creature)
{
@ -861,10 +872,24 @@ namespace MWMechanics
}
}
static Ogre::Vector3 sBasePoint;
bool comparePtrDist (const MWWorld::Ptr& ptr1, const MWWorld::Ptr& ptr2)
{
return (sBasePoint.squaredDistance(Ogre::Vector3(ptr1.getRefData().getPosition().pos))
< sBasePoint.squaredDistance(Ogre::Vector3(ptr2.getRefData().getPosition().pos)));
}
void Actors::update (float duration, bool paused)
{
if(!paused)
{
std::list<MWWorld::Ptr> listGuards; // at the moment only guards certainly will fight with creatures
static float timerUpdateAITargets = 0;
// target lists get updated once every 1.0 sec
if (timerUpdateAITargets >= 1.0f) timerUpdateAITargets = 0;
// Reset data from previous frame
for (PtrControllerMap::iterator iter(mActors.begin()); iter != mActors.end(); ++iter)
{
@ -872,29 +897,63 @@ namespace MWMechanics
// Note, the new hit object for this frame may be set by CharacterController::update -> Animation::runAnimation
// (below)
iter->first.getClass().getCreatureStats(iter->first).setLastHitObject(std::string());
// add guards to list to later make them fight with creatures
if (timerUpdateAITargets == 0 && iter->first.getClass().isClass(iter->first, "Guard"))
listGuards.push_back(iter->first);
}
MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayerPtr();
listGuards.push_back(player);
// AI and magic effects update
for (PtrControllerMap::iterator iter(mActors.begin());iter != mActors.end();++iter)
for(PtrControllerMap::iterator iter(mActors.begin()); iter != mActors.end(); ++iter)
{
if (!iter->first.getClass().getCreatureStats(iter->first).isDead())
{
updateActor(iter->first, duration);
if (iter->first.getTypeName() == typeid(ESM::NPC).name())
updateNpc(iter->first, duration, paused);
if (MWBase::Environment::get().getMechanicsManager()->isAIActive())
{
// make guards and creatures fight each other
if (timerUpdateAITargets == 0 && iter->first.getTypeName() == typeid(ESM::Creature).name() && !listGuards.empty())
{
sBasePoint = Ogre::Vector3(iter->first.getRefData().getPosition().pos);
listGuards.sort(comparePtrDist); // try to engage combat starting from the nearest creature
for (std::list<MWWorld::Ptr>::iterator it = listGuards.begin(); it != listGuards.end(); ++it)
{
engageCombat(iter->first, *it, false);
}
}
if (iter->first != player) engageCombat(iter->first, player, true);
if (iter->first.getClass().isNpc() && iter->first != player)
updateCrimePersuit(iter->first, duration);
if (iter->first != player)
iter->first.getClass().getCreatureStats(iter->first).getAiSequence().execute(iter->first, duration);
}
if(iter->first.getTypeName() == typeid(ESM::NPC).name())
updateNpc(iter->first, duration);
}
}
timerUpdateAITargets += duration;
// Looping magic VFX update
// Note: we need to do this before any of the animations are updated.
// Reaching the text keys may trigger Hit / Spellcast (and as such, particles),
// so updating VFX immediately after that would just remove the particle effects instantly.
// There needs to be a magic effect update in between.
for (PtrControllerMap::iterator iter(mActors.begin());iter != mActors.end();++iter)
for(PtrControllerMap::iterator iter(mActors.begin()); iter != mActors.end(); ++iter)
iter->second->updateContinuousVfx();
// Animation/movement update
for (PtrControllerMap::iterator iter(mActors.begin());iter != mActors.end();++iter)
for(PtrControllerMap::iterator iter(mActors.begin()); iter != mActors.end(); ++iter)
{
if (iter->first.getClass().getCreatureStats(iter->first).getMagicEffects().get(
ESM::MagicEffect::Paralyze).mMagnitude > 0)
@ -903,7 +962,7 @@ namespace MWMechanics
}
// Kill dead actors, update some variables
for (PtrControllerMap::iterator iter(mActors.begin());iter != mActors.end();iter++)
for(PtrControllerMap::iterator iter(mActors.begin()); iter != mActors.end(); ++iter)
{
const MWWorld::Class &cls = MWWorld::Class::get(iter->first);
CreatureStats &stats = cls.getCreatureStats(iter->first);
@ -975,7 +1034,6 @@ namespace MWMechanics
}
// if player is in sneak state see if anyone detects him
const MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayerPtr();
if (player.getClass().getCreatureStats(player).getMovementFlag(MWMechanics::CreatureStats::Flag_Sneak))
{
const MWWorld::ESMStore& esmStore = MWBase::Environment::get().getWorld()->getStore();
@ -1105,9 +1163,7 @@ namespace MWMechanics
if(!stats.isDead() && stats.getAiSequence().getTypeId() == AiPackage::TypeIdCombat)
{
MWMechanics::AiCombat* package = static_cast<MWMechanics::AiCombat*>(stats.getAiSequence().getActivePackage());
// TODO: This is wrong! It's comparing Ref IDs with Ogre handles. The only case where this (coincidentally) works is the player.
// possibly applies to other code using getTargetId.
if(package->getTargetId() == actor.getCellRef().mRefID)
if(package->getTarget() == actor)
list.push_front(*iter);
}
}

View File

@ -27,7 +27,7 @@ namespace MWMechanics
{
std::map<std::string, int> mDeathCount;
void updateNpc(const MWWorld::Ptr &ptr, float duration, bool paused);
void updateNpc(const MWWorld::Ptr &ptr, float duration);
void adjustMagicEffects (const MWWorld::Ptr& creature);
@ -81,6 +81,12 @@ namespace MWMechanics
///< This function is normally called automatically during the update process, but it can
/// also be called explicitly at any time to force an update.
/** Start combat between two actors
@Notes: If againstPlayer = true then actor2 should be the Player.
If one of the combatants is creature it should be actor1.
*/
void engageCombat(const MWWorld::Ptr& actor1, const MWWorld::Ptr& actor2, bool againstPlayer);
void restoreDynamicStats(bool sleep);
///< If the player is sleeping, this should be called every hour.

View File

@ -149,9 +149,7 @@ namespace MWMechanics
bool AiCombat::execute (const MWWorld::Ptr& actor,float duration)
{
//General description
if(!actor.getClass().getCreatureStats(actor).isHostile()
|| actor.getClass().getCreatureStats(actor).getHealth().getCurrent() <= 0)
return true;
if(actor.getClass().getCreatureStats(actor).isDead()) return true;
MWWorld::Ptr target = MWBase::Environment::get().getWorld()->searchPtrViaActorId(mTargetActorId);
@ -629,12 +627,9 @@ namespace MWMechanics
return 1;
}
std::string AiCombat::getTargetId() const
MWWorld::Ptr AiCombat::getTarget() const
{
MWWorld::Ptr target = MWBase::Environment::get().getWorld()->searchPtrViaActorId(mTargetActorId);
if (target.isEmpty())
return "";
return target.getRefData().getHandle();
return MWBase::Environment::get().getWorld()->searchPtrViaActorId(mTargetActorId);
}

View File

@ -31,7 +31,7 @@ namespace MWMechanics
virtual unsigned int getPriority() const;
///Returns target ID
std::string getTargetId() const;
MWWorld::Ptr getTarget() const;
private:
PathFinder mPathFinder;

View File

@ -1,6 +1,5 @@
#include "aipursue.hpp"
#include "../mwbase/world.hpp"
#include "../mwbase/environment.hpp"
#include "../mwworld/class.hpp"
@ -9,23 +8,24 @@
#include "../mwmechanics/creaturestats.hpp"
#include "steering.hpp"
#include "movement.hpp"
#include "creaturestats.hpp"
MWMechanics::AiPursue::AiPursue(const MWWorld::Ptr& actor)
: mActorId(actor.getClass().getCreatureStats(actor).getActorId())
namespace MWMechanics
{
AiPursue::AiPursue(const MWWorld::Ptr& actor)
: mTargetActorId(actor.getClass().getCreatureStats(actor).getActorId())
{
}
MWMechanics::AiPursue *MWMechanics::AiPursue::clone() const
AiPursue *MWMechanics::AiPursue::clone() const
{
return new AiPursue(*this);
}
bool MWMechanics::AiPursue::execute (const MWWorld::Ptr& actor, float duration)
bool AiPursue::execute (const MWWorld::Ptr& actor, float duration)
{
ESM::Position pos = actor.getRefData().getPosition(); //position of the actor
const MWWorld::Ptr target = MWBase::Environment::get().getWorld()->searchPtrViaActorId(mActorId); //The target to follow
const MWWorld::Ptr target = MWBase::Environment::get().getWorld()->searchPtrViaActorId(mTargetActorId); //The target to follow
if(target == MWWorld::Ptr())
return true; //Target doesn't exist
@ -47,7 +47,14 @@ bool MWMechanics::AiPursue::execute (const MWWorld::Ptr& actor, float duration)
return false;
}
int MWMechanics::AiPursue::getTypeId() const
int AiPursue::getTypeId() const
{
return TypeIdPursue;
}
MWWorld::Ptr AiPursue::getTarget() const
{
return MWBase::Environment::get().getWorld()->searchPtrViaActorId(mTargetActorId);
}
} // namespace MWMechanics

View File

@ -2,7 +2,8 @@
#define GAME_MWMECHANICS_AIPURSUE_H
#include "aipackage.hpp"
#include <string>
#include "../mwbase/world.hpp"
#include "pathfinding.hpp"
@ -18,12 +19,16 @@ namespace MWMechanics
///Constructor
/** \param actor Actor to pursue **/
AiPursue(const MWWorld::Ptr& actor);
virtual AiPursue *clone() const;
virtual bool execute (const MWWorld::Ptr& actor,float duration);
virtual int getTypeId() const;
MWWorld::Ptr getTarget() const;
private:
int mActorId; // The actor to pursue
int mTargetActorId; // The actor to pursue
int mCellX;
int mCellY;
};

View File

@ -9,6 +9,7 @@
#include "aifollow.hpp"
#include "aiactivate.hpp"
#include "aicombat.hpp"
#include "aipursue.hpp"
#include "../mwworld/class.hpp"
#include "creaturestats.hpp"
@ -16,21 +17,24 @@
#include "../mwbase/environment.hpp"
#include "../mwbase/world.hpp"
void MWMechanics::AiSequence::copy (const AiSequence& sequence)
namespace MWMechanics
{
void AiSequence::copy (const AiSequence& sequence)
{
for (std::list<AiPackage *>::const_iterator iter (sequence.mPackages.begin());
iter!=sequence.mPackages.end(); ++iter)
mPackages.push_back ((*iter)->clone());
}
MWMechanics::AiSequence::AiSequence() : mDone (false), mLastAiPackage(-1) {}
AiSequence::AiSequence() : mDone (false), mLastAiPackage(-1) {}
MWMechanics::AiSequence::AiSequence (const AiSequence& sequence) : mDone (false)
AiSequence::AiSequence (const AiSequence& sequence) : mDone (false)
{
copy (sequence);
}
MWMechanics::AiSequence& MWMechanics::AiSequence::operator= (const AiSequence& sequence)
AiSequence& AiSequence::operator= (const AiSequence& sequence)
{
if (this!=&sequence)
{
@ -42,12 +46,12 @@ MWMechanics::AiSequence& MWMechanics::AiSequence::operator= (const AiSequence& s
return *this;
}
MWMechanics::AiSequence::~AiSequence()
AiSequence::~AiSequence()
{
clear();
}
int MWMechanics::AiSequence::getTypeId() const
int AiSequence::getTypeId() const
{
if (mPackages.empty())
return -1;
@ -55,16 +59,45 @@ int MWMechanics::AiSequence::getTypeId() const
return mPackages.front()->getTypeId();
}
bool MWMechanics::AiSequence::getCombatTarget(std::string &targetActorId) const
bool AiSequence::getCombatTarget(MWWorld::Ptr &targetActor) const
{
if (getTypeId() != AiPackage::TypeIdCombat)
return false;
const AiCombat *combat = static_cast<const AiCombat *>(mPackages.front());
targetActorId = combat->getTargetId();
targetActor = combat->getTarget();
return true;
}
void MWMechanics::AiSequence::stopCombat()
bool AiSequence::canAddTarget(const ESM::Position& actorPos, float distToTarget) const
{
bool firstCombatFound = false;
MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayerPtr();
for(std::list<AiPackage*>::const_iterator it = mPackages.begin(); it != mPackages.end(); ++it)
{
if ((*it)->getTypeId() == AiPackage::TypeIdCombat)
{
firstCombatFound = true;
const AiCombat *combat = static_cast<const AiCombat *>(*it);
if (combat->getTarget() != player ) return false; // only 1 non-player target allowed
else
{
// add new target only if current target (player) is farther
ESM::Position &targetPos = combat->getTarget().getRefData().getPosition();
float distToCurrTarget = (Ogre::Vector3(targetPos.pos) - Ogre::Vector3(actorPos.pos)).length();
return (distToCurrTarget > distToTarget);
}
}
else if (firstCombatFound) break; // assumes combat packages go one-by-one in packages list
}
return true;
}
void AiSequence::stopCombat()
{
while (getTypeId() == AiPackage::TypeIdCombat)
{
@ -73,7 +106,7 @@ void MWMechanics::AiSequence::stopCombat()
}
}
void MWMechanics::AiSequence::stopPursuit()
void AiSequence::stopPursuit()
{
while (getTypeId() == AiPackage::TypeIdPursue)
{
@ -82,12 +115,12 @@ void MWMechanics::AiSequence::stopPursuit()
}
}
bool MWMechanics::AiSequence::isPackageDone() const
bool AiSequence::isPackageDone() const
{
return mDone;
}
void MWMechanics::AiSequence::execute (const MWWorld::Ptr& actor,float duration)
void AiSequence::execute (const MWWorld::Ptr& actor,float duration)
{
if(actor != MWBase::Environment::get().getWorld()->getPlayerPtr())
{
@ -95,6 +128,36 @@ void MWMechanics::AiSequence::execute (const MWWorld::Ptr& actor,float duration)
{
MWMechanics::AiPackage* package = mPackages.front();
mLastAiPackage = package->getTypeId();
// if active package is combat one, choose nearest target
if (mLastAiPackage == AiPackage::TypeIdCombat)
{
std::list<AiPackage *>::iterator itActualCombat;
float nearestDist = std::numeric_limits<float>::max();
Ogre::Vector3 vActorPos = Ogre::Vector3(actor.getRefData().getPosition().pos);
for(std::list<AiPackage *>::iterator it = mPackages.begin(); it != mPackages.end(); ++it)
{
if ((*it)->getTypeId() != AiPackage::TypeIdCombat) break;
ESM::Position &targetPos = static_cast<const AiCombat *>(*it)->getTarget().getRefData().getPosition();
float distTo = (Ogre::Vector3(targetPos.pos) - vActorPos).length();
if (distTo < nearestDist)
{
nearestDist = distTo;
itActualCombat = it;
}
}
if (mPackages.begin() != itActualCombat)
{
// move combat package with nearest target to the front
mPackages.splice(mPackages.begin(), mPackages, itActualCombat);
}
}
if (package->execute (actor,duration))
{
// To account for the rare case where AiPackage::execute() queued another AI package
@ -113,7 +176,7 @@ void MWMechanics::AiSequence::execute (const MWWorld::Ptr& actor,float duration)
}
}
void MWMechanics::AiSequence::clear()
void AiSequence::clear()
{
for (std::list<AiPackage *>::const_iterator iter (mPackages.begin()); iter!=mPackages.end(); ++iter)
delete *iter;
@ -121,14 +184,19 @@ void MWMechanics::AiSequence::clear()
mPackages.clear();
}
void MWMechanics::AiSequence::stack (const AiPackage& package, const MWWorld::Ptr& actor)
void AiSequence::stack (const AiPackage& package, const MWWorld::Ptr& actor)
{
if (package.getTypeId() == AiPackage::TypeIdCombat || package.getTypeId() == AiPackage::TypeIdPursue)
{
// Notify AiWander of our current position so we can return to it after combat finished
for (std::list<AiPackage *>::const_iterator iter (mPackages.begin()); iter!=mPackages.end(); ++iter)
{
if ((*iter)->getTypeId() == AiPackage::TypeIdWander)
if((*iter)->getTypeId() == AiPackage::TypeIdPursue && package.getTypeId() == AiPackage::TypeIdPursue
&& static_cast<const AiPursue*>(*iter)->getTarget() == static_cast<const AiPursue*>(&package)->getTarget())
{
return; // target is already pursued
}
else if ((*iter)->getTypeId() == AiPackage::TypeIdWander)
static_cast<AiWander*>(*iter)->setReturnPosition(Ogre::Vector3(actor.getRefData().getPosition().pos));
}
}
@ -146,12 +214,12 @@ void MWMechanics::AiSequence::stack (const AiPackage& package, const MWWorld::Pt
mPackages.push_front (package.clone());
}
void MWMechanics::AiSequence::queue (const AiPackage& package)
void AiSequence::queue (const AiPackage& package)
{
mPackages.push_back (package.clone());
}
MWMechanics::AiPackage* MWMechanics::AiSequence::getActivePackage()
AiPackage* MWMechanics::AiSequence::getActivePackage()
{
if(mPackages.empty())
throw std::runtime_error(std::string("No AI Package!"));
@ -159,7 +227,7 @@ MWMechanics::AiPackage* MWMechanics::AiSequence::getActivePackage()
return mPackages.front();
}
void MWMechanics::AiSequence::fill(const ESM::AIPackageList &list)
void AiSequence::fill(const ESM::AIPackageList &list)
{
for (std::vector<ESM::AIPackage>::const_iterator it = list.mList.begin(); it != list.mList.end(); ++it)
{
@ -195,3 +263,5 @@ void MWMechanics::AiSequence::fill(const ESM::AIPackageList &list)
mPackages.push_back(package);
}
}
} // namespace MWMechanics

View File

@ -53,7 +53,10 @@ namespace MWMechanics
int getLastRunTypeId() const { return mLastAiPackage; }
/// Return true and assign target if combat package is currently active, return false otherwise
bool getCombatTarget (std::string &targetActorId) const;
bool getCombatTarget (MWWorld::Ptr &targetActor) const;
bool canAddTarget(const ESM::Position& actorPos, float distToTarget) const;
///< Function assumes that actor can have only 1 target apart player
/// Removes all combat packages until first non-combat or stack empty.
void stopCombat();

View File

@ -1012,7 +1012,16 @@ void CharacterController::update(float duration)
bool flying = world->isFlying(mPtr);
//Ogre::Vector3 vec = cls.getMovementVector(mPtr);
Ogre::Vector3 vec(cls.getMovementSettings(mPtr).mPosition);
if(vec.z > 0.0f) // to avoid slow-down when jumping
{
Ogre::Vector2 vecXY = Ogre::Vector2(vec.x, vec.y);
vecXY.normalise();
vec.x = vecXY.x;
vec.y = vecXY.y;
}
else
vec.normalise();
if(mHitState != CharState_None && mJumpState == JumpState_None)
vec = Ogre::Vector3(0.0f);
Ogre::Vector3 rot = cls.getRotationVector(mPtr);
@ -1113,9 +1122,12 @@ void CharacterController::update(float duration)
if(cls.isNpc())
{
const NpcStats &stats = cls.getNpcStats(mPtr);
mult = gmst.find("fJumpMoveBase")->getFloat() +
static const float fJumpMoveBase = gmst.find("fJumpMoveBase")->getFloat();
static const float fJumpMoveMult = gmst.find("fJumpMoveMult")->getFloat();
mult = fJumpMoveBase +
(stats.getSkill(ESM::Skill::Acrobatics).getModified()/100.0f *
gmst.find("fJumpMoveMult")->getFloat());
fJumpMoveMult);
}
vec.x *= mult;
@ -1125,14 +1137,7 @@ void CharacterController::update(float duration)
else if(vec.z > 0.0f && mJumpState == JumpState_None)
{
// Started a jump.
float z = cls.getJump(mPtr);
if(vec.x == 0 && vec.y == 0)
vec = Ogre::Vector3(0.0f, 0.0f, z);
else
{
Ogre::Vector3 lat = Ogre::Vector3(vec.x, vec.y, 0.0f).normalisedCopy();
vec = Ogre::Vector3(lat.x, lat.y, 1.0f) * z * 0.707f;
}
vec.z = cls.getJump(mPtr);
// advance acrobatics
if (mPtr.getRefData().getHandle() == "player")
@ -1444,14 +1449,14 @@ void CharacterController::updateVisibility()
void CharacterController::determineAttackType()
{
float * move = mPtr.getClass().getMovementSettings(mPtr).mPosition;
float *move = mPtr.getClass().getMovementSettings(mPtr).mPosition;
if(mPtr.getClass().hasInventoryStore(mPtr))
{
if (move[0] && !move[1]) //sideway
mAttackType = "slash";
else if (move[1]) //forward
if (move[1]) // forward-backward
mAttackType = "thrust";
else if (move[0]) //sideway
mAttackType = "slash";
else
mAttackType = "chop";
}

View File

@ -321,12 +321,10 @@ namespace MWMechanics
}
bool CreatureStats::getCreatureTargetted() const
{
std::string target;
if (mAiSequence.getCombatTarget(target))
{
MWWorld::Ptr targetPtr;
targetPtr = MWBase::Environment::get().getWorld()->getPtr(target, true);
if (mAiSequence.getCombatTarget(targetPtr))
{
return targetPtr.getTypeName() == typeid(ESM::Creature).name();
}
return false;

View File

@ -328,6 +328,12 @@ namespace MWMechanics
path.push_front(pt);
current = graphParent[current];
}
// add first node to path explicitly
ESM::Pathgrid::Point pt = mPathgrid->mPoints[start];
pt.mX += xCell;
pt.mY += yCell;
path.push_front(pt);
return path;
}
}

View File

@ -415,9 +415,10 @@ namespace MWScript
std::string currentTargetId;
bool targetsAreEqual = false;
if (creatureStats.getAiSequence().getCombatTarget (currentTargetId))
MWWorld::Ptr targetPtr;
if (creatureStats.getAiSequence().getCombatTarget (targetPtr))
{
if (currentTargetId == testedTargetId)
if (targetPtr.getRefData().getHandle() == testedTargetId)
targetsAreEqual = true;
}
runtime.push(int(targetsAreEqual));

View File

@ -242,6 +242,15 @@ namespace MWWorld
// If falling, add part of the incoming velocity with the current inertia
// TODO: but we could be jumping up?
velocity = velocity * time + physicActor->getInertialForce();
// avoid getting infinite inertia in air
float actorSpeed = ptr.getClass().getSpeed(ptr);
float speedXY = Ogre::Vector2(velocity.x, velocity.y).length();
if (speedXY > actorSpeed)
{
velocity.x *= actorSpeed / speedXY;
velocity.y *= actorSpeed / speedXY;
}
}
inertia = velocity; // NOTE: velocity is for z axis only in this code block