Commit 5be37f04 authored by mrcheko's avatar mrcheko

Feature 1314: make npc fight creatures

parent 725f6cac
This diff is collapsed.
......@@ -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.
......
......@@ -149,11 +149,8 @@ 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(mTarget.getClass().getCreatureStats(mTarget).isDead())
if(actor.getClass().getCreatureStats(actor).isDead()
|| mTarget.getClass().getCreatureStats(mTarget).isDead() )
return true;
//Update every frame
......@@ -627,9 +624,9 @@ namespace MWMechanics
return 1;
}
const std::string &AiCombat::getTargetId() const
const MWWorld::Ptr &AiCombat::getTarget() const
{
return mTarget.getRefData().getHandle();
return mTarget;
}
......
......@@ -28,7 +28,7 @@ namespace MWMechanics
virtual unsigned int getPriority() const;
const std::string &getTargetId() const;
const MWWorld::Ptr &getTarget() const;
private:
PathFinder mPathFinder;
......
......@@ -61,7 +61,35 @@ bool MWMechanics::AiSequence::getCombatTarget(std::string &targetActorId) const
if (getTypeId() != AiPackage::TypeIdCombat)
return false;
const AiCombat *combat = static_cast<const AiCombat *>(mPackages.front());
targetActorId = combat->getTargetId();
targetActorId = combat->getTarget().getRefData().getHandle();
return true;
}
bool MWMechanics::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;
}
......@@ -96,6 +124,40 @@ 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 *>::const_iterator itActualCombat;
float nearestDist = std::numeric_limits<float>::max();
Ogre::Vector3 vActorPos = Ogre::Vector3(actor.getRefData().getPosition().pos);
const AiCombat *package;
for(std::list<AiPackage *>::const_iterator it = mPackages.begin(); it != mPackages.end(); ++it)
{
package = static_cast<const AiCombat *>(*it);
if ((*it)->getTypeId() != AiPackage::TypeIdCombat) break;
ESM::Position &targetPos = package->getTarget().getRefData().getPosition();
float distTo = (Ogre::Vector3(targetPos.pos) - vActorPos).length();
if (distTo < nearestDist)
{
nearestDist = distTo;
itActualCombat = it;
}
}
if (mPackages.cbegin() != 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
......
......@@ -47,6 +47,9 @@ namespace MWMechanics
///< Return true and assign target if combat package is currently
/// active, return false otherwise
bool canAddTarget(const ESM::Position& actorPos, float distToTarget) const;
///< Function assumes that actor can have only 1 target apart player
void stopCombat();
///< Removes all combat packages until first non-combat or stack empty.
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment