forked from mirror/openmw-tes3mp
Merged pull request #1477
This commit is contained in:
commit
7d9de93fd3
11 changed files with 98 additions and 62 deletions
|
@ -1,16 +1,20 @@
|
||||||
0.45.0
|
0.45.0
|
||||||
------
|
------
|
||||||
|
|
||||||
Bug #2835: Player able to slowly move when overencumbered
|
Bug #2835: Player able to slowly move when overencumbered
|
||||||
Bug #3374: Touch spells not hitting kwama foragers
|
Bug #3374: Touch spells not hitting kwama foragers
|
||||||
Bug #3591: Angled hit distance too low
|
Bug #3591: Angled hit distance too low
|
||||||
Bug #3897: Have Goodbye give all choices the effects of Goodbye
|
Bug #3897: Have Goodbye give all choices the effects of Goodbye
|
||||||
|
Bug #3997: Almalexia doesn't pace
|
||||||
Bug #4036: Weird behaviour of AI packages if package target has non-unique ID
|
Bug #4036: Weird behaviour of AI packages if package target has non-unique ID
|
||||||
Bug #4221: Characters get stuck in V-shaped terrain
|
Bug #4221: Characters get stuck in V-shaped terrain
|
||||||
|
Bug #4251: Stationary NPCs do not return to their position after combat
|
||||||
Bug #4293: Faction members are not aware of faction ownerships in barter
|
Bug #4293: Faction members are not aware of faction ownerships in barter
|
||||||
Bug #4327: Missing animations during spell/weapon stance switching
|
Bug #4327: Missing animations during spell/weapon stance switching
|
||||||
Bug #4419: MRK NiStringExtraData is handled incorrectly
|
Bug #4419: MRK NiStringExtraData is handled incorrectly
|
||||||
Bug #4426: RotateWorld behavior is incorrect
|
Bug #4426: RotateWorld behavior is incorrect
|
||||||
Bug #4429: [Windows] Error on build INSTALL.vcxproj project (debug) with cmake 3.7.2
|
Bug #4429: [Windows] Error on build INSTALL.vcxproj project (debug) with cmake 3.7.2
|
||||||
|
Bug #4432: Guards behaviour is incorrect if they do not have AI packages
|
||||||
Bug #4433: Guard behaviour is incorrect with Alarm = 0
|
Bug #4433: Guard behaviour is incorrect with Alarm = 0
|
||||||
Feature #4444: Per-group KF-animation files support
|
Feature #4444: Per-group KF-animation files support
|
||||||
|
|
||||||
|
|
|
@ -48,7 +48,8 @@ namespace MWMechanics
|
||||||
TypeIdPursue = 6,
|
TypeIdPursue = 6,
|
||||||
TypeIdAvoidDoor = 7,
|
TypeIdAvoidDoor = 7,
|
||||||
TypeIdFace = 8,
|
TypeIdFace = 8,
|
||||||
TypeIdBreathe = 9
|
TypeIdBreathe = 9,
|
||||||
|
TypeIdInternalTravel = 10
|
||||||
};
|
};
|
||||||
|
|
||||||
///Default constructor
|
///Default constructor
|
||||||
|
@ -79,6 +80,9 @@ namespace MWMechanics
|
||||||
/// Get the target actor the AI is targeted at (not applicable to all AI packages, default return empty Ptr)
|
/// Get the target actor the AI is targeted at (not applicable to all AI packages, default return empty Ptr)
|
||||||
virtual MWWorld::Ptr getTarget() const;
|
virtual MWWorld::Ptr getTarget() const;
|
||||||
|
|
||||||
|
/// Get the destination point of the AI package (not applicable to all AI packages, default return (0, 0, 0))
|
||||||
|
virtual osg::Vec3f getDestination(const MWWorld::Ptr& actor) const { return osg::Vec3f(0, 0, 0); };
|
||||||
|
|
||||||
/// Return true if having this AiPackage makes the actor side with the target in fights (default false)
|
/// Return true if having this AiPackage makes the actor side with the target in fights (default false)
|
||||||
virtual bool sideWithTarget() const;
|
virtual bool sideWithTarget() const;
|
||||||
|
|
||||||
|
|
|
@ -184,7 +184,8 @@ bool isActualAiPackage(int packageTypeId)
|
||||||
&& packageTypeId != AiPackage::TypeIdPursue
|
&& packageTypeId != AiPackage::TypeIdPursue
|
||||||
&& packageTypeId != AiPackage::TypeIdAvoidDoor
|
&& packageTypeId != AiPackage::TypeIdAvoidDoor
|
||||||
&& packageTypeId != AiPackage::TypeIdFace
|
&& packageTypeId != AiPackage::TypeIdFace
|
||||||
&& packageTypeId != AiPackage::TypeIdBreathe);
|
&& packageTypeId != AiPackage::TypeIdBreathe
|
||||||
|
&& packageTypeId != AiPackage::TypeIdInternalTravel);
|
||||||
}
|
}
|
||||||
|
|
||||||
void AiSequence::execute (const MWWorld::Ptr& actor, CharacterController& characterController, AiState& state, float duration)
|
void AiSequence::execute (const MWWorld::Ptr& actor, CharacterController& characterController, AiState& state, float duration)
|
||||||
|
@ -298,7 +299,7 @@ void AiSequence::clear()
|
||||||
mPackages.clear();
|
mPackages.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
void AiSequence::stack (const AiPackage& package, const MWWorld::Ptr& actor)
|
void AiSequence::stack (const AiPackage& package, const MWWorld::Ptr& actor, bool cancelOther)
|
||||||
{
|
{
|
||||||
if (actor == getPlayer())
|
if (actor == getPlayer())
|
||||||
throw std::runtime_error("Can't add AI packages to player");
|
throw std::runtime_error("Can't add AI packages to player");
|
||||||
|
@ -307,8 +308,33 @@ void AiSequence::stack (const AiPackage& package, const MWWorld::Ptr& actor)
|
||||||
if (isActualAiPackage(package.getTypeId()))
|
if (isActualAiPackage(package.getTypeId()))
|
||||||
stopCombat();
|
stopCombat();
|
||||||
|
|
||||||
|
// We should return a wandering actor back after combat or pursuit.
|
||||||
|
// The same thing for actors without AI packages.
|
||||||
|
// Also there is no point to stack return packages.
|
||||||
|
int currentTypeId = getTypeId();
|
||||||
|
int newTypeId = package.getTypeId();
|
||||||
|
if (currentTypeId <= MWMechanics::AiPackage::TypeIdWander
|
||||||
|
&& !hasPackage(MWMechanics::AiPackage::TypeIdInternalTravel)
|
||||||
|
&& (newTypeId <= MWMechanics::AiPackage::TypeIdCombat
|
||||||
|
|| newTypeId == MWMechanics::AiPackage::TypeIdPursue))
|
||||||
|
{
|
||||||
|
osg::Vec3f dest;
|
||||||
|
if (currentTypeId == MWMechanics::AiPackage::TypeIdWander)
|
||||||
|
{
|
||||||
|
AiPackage* activePackage = getActivePackage();
|
||||||
|
dest = activePackage->getDestination(actor);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
dest = actor.getRefData().getPosition().asVec3();
|
||||||
|
}
|
||||||
|
|
||||||
|
MWMechanics::AiTravel travelPackage(dest.x(), dest.y(), dest.z(), true);
|
||||||
|
stack(travelPackage, actor, false);
|
||||||
|
}
|
||||||
|
|
||||||
// remove previous packages if required
|
// remove previous packages if required
|
||||||
if (package.shouldCancelPreviousAi())
|
if (cancelOther && package.shouldCancelPreviousAi())
|
||||||
{
|
{
|
||||||
for(std::list<AiPackage *>::iterator it = mPackages.begin(); it != mPackages.end();)
|
for(std::list<AiPackage *>::iterator it = mPackages.begin(); it != mPackages.end();)
|
||||||
{
|
{
|
||||||
|
@ -392,6 +418,8 @@ void AiSequence::writeState(ESM::AiSequence::AiSequence &sequence) const
|
||||||
{
|
{
|
||||||
(*iter)->writeState(sequence);
|
(*iter)->writeState(sequence);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
sequence.mLastAiPackage = mLastAiPackage;
|
||||||
}
|
}
|
||||||
|
|
||||||
void AiSequence::readState(const ESM::AiSequence::AiSequence &sequence)
|
void AiSequence::readState(const ESM::AiSequence::AiSequence &sequence)
|
||||||
|
@ -462,6 +490,8 @@ void AiSequence::readState(const ESM::AiSequence::AiSequence &sequence)
|
||||||
|
|
||||||
mPackages.push_back(package.release());
|
mPackages.push_back(package.release());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
mLastAiPackage = sequence.mLastAiPackage;
|
||||||
}
|
}
|
||||||
|
|
||||||
void AiSequence::fastForward(const MWWorld::Ptr& actor, AiState& state)
|
void AiSequence::fastForward(const MWWorld::Ptr& actor, AiState& state)
|
||||||
|
|
|
@ -115,7 +115,7 @@ namespace MWMechanics
|
||||||
///< Add \a package to the front of the sequence
|
///< Add \a package to the front of the sequence
|
||||||
/** Suspends current package
|
/** Suspends current package
|
||||||
@param actor The actor that owns this AiSequence **/
|
@param actor The actor that owns this AiSequence **/
|
||||||
void stack (const AiPackage& package, const MWWorld::Ptr& actor);
|
void stack (const AiPackage& package, const MWWorld::Ptr& actor, bool cancelOther=true);
|
||||||
|
|
||||||
/// Return the current active package.
|
/// Return the current active package.
|
||||||
/** If there is no active package, it will throw an exception **/
|
/** If there is no active package, it will throw an exception **/
|
||||||
|
|
|
@ -28,15 +28,14 @@ bool isWithinMaxRange(const osg::Vec3f& pos1, const osg::Vec3f& pos2)
|
||||||
|
|
||||||
namespace MWMechanics
|
namespace MWMechanics
|
||||||
{
|
{
|
||||||
AiTravel::AiTravel(float x, float y, float z)
|
AiTravel::AiTravel(float x, float y, float z, bool hidden)
|
||||||
: mX(x),mY(y),mZ(z)
|
: mX(x),mY(y),mZ(z),mHidden(hidden)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
AiTravel::AiTravel(const ESM::AiSequence::AiTravel *travel)
|
AiTravel::AiTravel(const ESM::AiSequence::AiTravel *travel)
|
||||||
: mX(travel->mData.mX), mY(travel->mData.mY), mZ(travel->mData.mZ)
|
: mX(travel->mData.mX), mY(travel->mData.mY), mZ(travel->mData.mZ), mHidden(travel->mHidden)
|
||||||
{
|
{
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
AiTravel *MWMechanics::AiTravel::clone() const
|
AiTravel *MWMechanics::AiTravel::clone() const
|
||||||
|
@ -64,7 +63,7 @@ namespace MWMechanics
|
||||||
|
|
||||||
int AiTravel::getTypeId() const
|
int AiTravel::getTypeId() const
|
||||||
{
|
{
|
||||||
return TypeIdTravel;
|
return mHidden ? TypeIdInternalTravel : TypeIdTravel;
|
||||||
}
|
}
|
||||||
|
|
||||||
void AiTravel::fastForward(const MWWorld::Ptr& actor, AiState& state)
|
void AiTravel::fastForward(const MWWorld::Ptr& actor, AiState& state)
|
||||||
|
@ -83,6 +82,7 @@ namespace MWMechanics
|
||||||
travel->mData.mX = mX;
|
travel->mData.mX = mX;
|
||||||
travel->mData.mY = mY;
|
travel->mData.mY = mY;
|
||||||
travel->mData.mZ = mZ;
|
travel->mData.mZ = mZ;
|
||||||
|
travel->mHidden = mHidden;
|
||||||
|
|
||||||
ESM::AiSequence::AiPackageContainer package;
|
ESM::AiSequence::AiPackageContainer package;
|
||||||
package.mType = ESM::AiSequence::Ai_Travel;
|
package.mType = ESM::AiSequence::Ai_Travel;
|
||||||
|
|
|
@ -20,7 +20,7 @@ namespace MWMechanics
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
/// Default constructor
|
/// Default constructor
|
||||||
AiTravel(float x, float y, float z);
|
AiTravel(float x, float y, float z, bool hidden = false);
|
||||||
AiTravel(const ESM::AiSequence::AiTravel* travel);
|
AiTravel(const ESM::AiSequence::AiTravel* travel);
|
||||||
|
|
||||||
/// Simulates the passing of time
|
/// Simulates the passing of time
|
||||||
|
@ -38,6 +38,8 @@ namespace MWMechanics
|
||||||
float mX;
|
float mX;
|
||||||
float mY;
|
float mY;
|
||||||
float mZ;
|
float mZ;
|
||||||
|
|
||||||
|
bool mHidden;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -298,13 +298,6 @@ namespace MWMechanics
|
||||||
if(mDistance && cellChange)
|
if(mDistance && cellChange)
|
||||||
mDistance = 0;
|
mDistance = 0;
|
||||||
|
|
||||||
// For stationary NPCs, move back to the starting location if another AiPackage moved us elsewhere
|
|
||||||
if (mDistance == 0 && !cellChange
|
|
||||||
&& (pos.asVec3() - mInitialActorPosition).length2() > (DESTINATION_TOLERANCE * DESTINATION_TOLERANCE))
|
|
||||||
{
|
|
||||||
returnToStartLocation(actor, storage, pos);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Allow interrupting a walking actor to trigger a greeting
|
// Allow interrupting a walking actor to trigger a greeting
|
||||||
WanderState& wanderState = storage.mState;
|
WanderState& wanderState = storage.mState;
|
||||||
if ((wanderState == Wander_IdleNow) || (wanderState == Wander_Walking))
|
if ((wanderState == Wander_IdleNow) || (wanderState == Wander_Walking))
|
||||||
|
@ -334,6 +327,15 @@ namespace MWMechanics
|
||||||
return mRepeat;
|
return mRepeat;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
osg::Vec3f AiWander::getDestination(const MWWorld::Ptr& actor) const
|
||||||
|
{
|
||||||
|
if (mHasDestination)
|
||||||
|
return mDestination;
|
||||||
|
|
||||||
|
const ESM::Pathgrid::Point currentPosition = actor.getRefData().getPosition().pos;
|
||||||
|
const osg::Vec3f currentPositionVec3f = osg::Vec3f(currentPosition.mX, currentPosition.mY, currentPosition.mZ);
|
||||||
|
return currentPositionVec3f;
|
||||||
|
}
|
||||||
|
|
||||||
bool AiWander::isPackageCompleted(const MWWorld::Ptr& actor, AiWanderStorage& storage)
|
bool AiWander::isPackageCompleted(const MWWorld::Ptr& actor, AiWanderStorage& storage)
|
||||||
{
|
{
|
||||||
|
@ -350,27 +352,6 @@ namespace MWMechanics
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
void AiWander::returnToStartLocation(const MWWorld::Ptr& actor, AiWanderStorage& storage, ESM::Position& pos)
|
|
||||||
{
|
|
||||||
if (!mPathFinder.isPathConstructed())
|
|
||||||
{
|
|
||||||
mDestination = mInitialActorPosition;
|
|
||||||
ESM::Pathgrid::Point dest(PathFinder::MakePathgridPoint(mDestination));
|
|
||||||
|
|
||||||
// actor position is already in world coordinates
|
|
||||||
ESM::Pathgrid::Point start(PathFinder::MakePathgridPoint(pos));
|
|
||||||
|
|
||||||
// don't take shortcuts for wandering
|
|
||||||
mPathFinder.buildSyncedPath(start, dest, actor.getCell(), getPathGridGraph(actor.getCell()));
|
|
||||||
|
|
||||||
if (mPathFinder.isPathConstructed())
|
|
||||||
{
|
|
||||||
storage.setState(Wander_Walking);
|
|
||||||
mHasDestination = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Commands actor to walk to a random location near original spawn location.
|
* Commands actor to walk to a random location near original spawn location.
|
||||||
*/
|
*/
|
||||||
|
@ -1041,4 +1022,3 @@ namespace MWMechanics
|
||||||
init();
|
init();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -50,6 +50,8 @@ namespace MWMechanics
|
||||||
|
|
||||||
bool getRepeat() const;
|
bool getRepeat() const;
|
||||||
|
|
||||||
|
osg::Vec3f getDestination(const MWWorld::Ptr& actor) const;
|
||||||
|
|
||||||
enum GreetingState {
|
enum GreetingState {
|
||||||
Greet_None,
|
Greet_None,
|
||||||
Greet_InProgress,
|
Greet_InProgress,
|
||||||
|
@ -85,7 +87,6 @@ namespace MWMechanics
|
||||||
bool reactionTimeActions(const MWWorld::Ptr& actor, AiWanderStorage& storage,
|
bool reactionTimeActions(const MWWorld::Ptr& actor, AiWanderStorage& storage,
|
||||||
const MWWorld::CellStore*& currentCell, bool cellChange, ESM::Position& pos, float duration);
|
const MWWorld::CellStore*& currentCell, bool cellChange, ESM::Position& pos, float duration);
|
||||||
bool isPackageCompleted(const MWWorld::Ptr& actor, AiWanderStorage& storage);
|
bool isPackageCompleted(const MWWorld::Ptr& actor, AiWanderStorage& storage);
|
||||||
void returnToStartLocation(const MWWorld::Ptr& actor, AiWanderStorage& storage, ESM::Position& pos);
|
|
||||||
void wanderNearStart(const MWWorld::Ptr &actor, AiWanderStorage &storage, int wanderDistance);
|
void wanderNearStart(const MWWorld::Ptr &actor, AiWanderStorage &storage, int wanderDistance);
|
||||||
bool destinationIsAtWater(const MWWorld::Ptr &actor, const osg::Vec3f& destination);
|
bool destinationIsAtWater(const MWWorld::Ptr &actor, const osg::Vec3f& destination);
|
||||||
bool destinationThroughGround(const osg::Vec3f& startPoint, const osg::Vec3f& destination);
|
bool destinationThroughGround(const osg::Vec3f& startPoint, const osg::Vec3f& destination);
|
||||||
|
|
|
@ -22,6 +22,7 @@
|
||||||
|
|
||||||
#include "aicombat.hpp"
|
#include "aicombat.hpp"
|
||||||
#include "aipursue.hpp"
|
#include "aipursue.hpp"
|
||||||
|
#include "aitravel.hpp"
|
||||||
#include "spellcasting.hpp"
|
#include "spellcasting.hpp"
|
||||||
#include "autocalcspell.hpp"
|
#include "autocalcspell.hpp"
|
||||||
#include "npcstats.hpp"
|
#include "npcstats.hpp"
|
||||||
|
@ -1598,9 +1599,12 @@ namespace MWMechanics
|
||||||
|
|
||||||
void MechanicsManager::startCombat(const MWWorld::Ptr &ptr, const MWWorld::Ptr &target)
|
void MechanicsManager::startCombat(const MWWorld::Ptr &ptr, const MWWorld::Ptr &target)
|
||||||
{
|
{
|
||||||
if (ptr.getClass().getCreatureStats(ptr).getAiSequence().isInCombat(target))
|
MWMechanics::AiSequence& aiSequence = ptr.getClass().getCreatureStats(ptr).getAiSequence();
|
||||||
|
|
||||||
|
if (aiSequence.isInCombat(target))
|
||||||
return;
|
return;
|
||||||
ptr.getClass().getCreatureStats(ptr).getAiSequence().stack(MWMechanics::AiCombat(target), ptr);
|
|
||||||
|
aiSequence.stack(MWMechanics::AiCombat(target), ptr);
|
||||||
if (target == getPlayer())
|
if (target == getPlayer())
|
||||||
{
|
{
|
||||||
// if guard starts combat with player, guards pursuing player should do the same
|
// if guard starts combat with player, guards pursuing player should do the same
|
||||||
|
|
|
@ -35,11 +35,13 @@ namespace AiSequence
|
||||||
void AiTravel::load(ESMReader &esm)
|
void AiTravel::load(ESMReader &esm)
|
||||||
{
|
{
|
||||||
esm.getHNT (mData, "DATA");
|
esm.getHNT (mData, "DATA");
|
||||||
|
esm.getHNOT (mHidden, "HIDD");
|
||||||
}
|
}
|
||||||
|
|
||||||
void AiTravel::save(ESMWriter &esm) const
|
void AiTravel::save(ESMWriter &esm) const
|
||||||
{
|
{
|
||||||
esm.writeHNT ("DATA", mData);
|
esm.writeHNT ("DATA", mData);
|
||||||
|
esm.writeHNT ("HIDD", mHidden);
|
||||||
}
|
}
|
||||||
|
|
||||||
void AiEscort::load(ESMReader &esm)
|
void AiEscort::load(ESMReader &esm)
|
||||||
|
@ -158,6 +160,8 @@ namespace AiSequence
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
esm.writeHNT ("LAST", mLastAiPackage);
|
||||||
}
|
}
|
||||||
|
|
||||||
void AiSequence::load(ESMReader &esm)
|
void AiSequence::load(ESMReader &esm)
|
||||||
|
@ -225,6 +229,8 @@ namespace AiSequence
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
esm.getHNOT (mLastAiPackage, "LAST");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -80,6 +80,7 @@ namespace ESM
|
||||||
struct AiTravel : AiPackage
|
struct AiTravel : AiPackage
|
||||||
{
|
{
|
||||||
AiTravelData mData;
|
AiTravelData mData;
|
||||||
|
bool mHidden;
|
||||||
|
|
||||||
void load(ESMReader &esm);
|
void load(ESMReader &esm);
|
||||||
void save(ESMWriter &esm) const;
|
void save(ESMWriter &esm) const;
|
||||||
|
@ -149,10 +150,14 @@ namespace ESM
|
||||||
|
|
||||||
struct AiSequence
|
struct AiSequence
|
||||||
{
|
{
|
||||||
AiSequence() {}
|
AiSequence()
|
||||||
|
{
|
||||||
|
mLastAiPackage = -1;
|
||||||
|
}
|
||||||
~AiSequence();
|
~AiSequence();
|
||||||
|
|
||||||
std::vector<AiPackageContainer> mPackages;
|
std::vector<AiPackageContainer> mPackages;
|
||||||
|
int mLastAiPackage;
|
||||||
|
|
||||||
void load (ESMReader &esm);
|
void load (ESMReader &esm);
|
||||||
void save (ESMWriter &esm) const;
|
void save (ESMWriter &esm) const;
|
||||||
|
|
Loading…
Reference in a new issue