mirror of
https://github.com/TES3MP/openmw-tes3mp.git
synced 2025-01-16 19:19:56 +00:00
Store integer actor ID in AI packages (bug #4036)
This commit is contained in:
parent
9d0ce25052
commit
fed10e87aa
16 changed files with 93 additions and 72 deletions
|
@ -1,6 +1,7 @@
|
|||
0.45.0
|
||||
------
|
||||
Bug #2835: Player able to slowly move when overencumbered
|
||||
Bug #4036: Weird behaviour of AI packages if package target has non-unique ID
|
||||
Bug #4221: Characters get stuck in V-shaped terrain
|
||||
Bug #4293: Faction members are not aware of faction ownerships in barter
|
||||
Bug #4327: Missing animations during spell/weapon stance switching
|
||||
|
|
|
@ -103,9 +103,10 @@ namespace MWMechanics
|
|||
bool isFleeing();
|
||||
};
|
||||
|
||||
AiCombat::AiCombat(const MWWorld::Ptr& actor) :
|
||||
mTargetActorId(actor.getClass().getCreatureStats(actor).getActorId())
|
||||
{}
|
||||
AiCombat::AiCombat(const MWWorld::Ptr& actor)
|
||||
{
|
||||
mTargetActorId = actor.getClass().getCreatureStats(actor).getActorId();
|
||||
}
|
||||
|
||||
AiCombat::AiCombat(const ESM::AiSequence::AiCombat *combat)
|
||||
{
|
||||
|
|
|
@ -54,9 +54,6 @@ namespace MWMechanics
|
|||
virtual bool shouldCancelPreviousAi() const { return false; }
|
||||
|
||||
private:
|
||||
|
||||
int mTargetActorId;
|
||||
|
||||
/// Returns true if combat should end
|
||||
bool attack(const MWWorld::Ptr& actor, const MWWorld::Ptr& target, AiCombatStorage& storage, CharacterController& characterController);
|
||||
|
||||
|
|
|
@ -22,28 +22,32 @@
|
|||
namespace MWMechanics
|
||||
{
|
||||
AiEscort::AiEscort(const std::string &actorId, int duration, float x, float y, float z)
|
||||
: mActorId(actorId), mX(x), mY(y), mZ(z), mDuration(duration), mRemainingDuration(static_cast<float>(duration))
|
||||
: mX(x), mY(y), mZ(z), mDuration(duration), mRemainingDuration(static_cast<float>(duration))
|
||||
, mCellX(std::numeric_limits<int>::max())
|
||||
, mCellY(std::numeric_limits<int>::max())
|
||||
{
|
||||
mTargetActorRefId = actorId;
|
||||
mMaxDist = 450;
|
||||
}
|
||||
|
||||
AiEscort::AiEscort(const std::string &actorId, const std::string &cellId,int duration, float x, float y, float z)
|
||||
: mActorId(actorId), mCellId(cellId), mX(x), mY(y), mZ(z), mDuration(duration), mRemainingDuration(static_cast<float>(duration))
|
||||
AiEscort::AiEscort(const std::string &actorId, const std::string &cellId, int duration, float x, float y, float z)
|
||||
: mCellId(cellId), mX(x), mY(y), mZ(z), mDuration(duration), mRemainingDuration(static_cast<float>(duration))
|
||||
, mCellX(std::numeric_limits<int>::max())
|
||||
, mCellY(std::numeric_limits<int>::max())
|
||||
{
|
||||
mTargetActorRefId = actorId;
|
||||
mMaxDist = 450;
|
||||
}
|
||||
|
||||
AiEscort::AiEscort(const ESM::AiSequence::AiEscort *escort)
|
||||
: mActorId(escort->mTargetId), mCellId(escort->mCellId), mX(escort->mData.mX), mY(escort->mData.mY), mZ(escort->mData.mZ)
|
||||
: mCellId(escort->mCellId), mX(escort->mData.mX), mY(escort->mData.mY), mZ(escort->mData.mZ)
|
||||
, mMaxDist(450)
|
||||
, mRemainingDuration(escort->mRemainingDuration)
|
||||
, mCellX(std::numeric_limits<int>::max())
|
||||
, mCellY(std::numeric_limits<int>::max())
|
||||
{
|
||||
mTargetActorRefId = escort->mTargetId;
|
||||
mTargetActorId = escort->mTargetActorId;
|
||||
// mDuration isn't saved in the save file, so just giving it "1" for now if the package has a duration.
|
||||
// The exact value of mDuration only matters for repeating packages.
|
||||
if (mRemainingDuration > 0) // Previously mRemainingDuration could be negative even when mDuration was 0. Checking for > 0 should fix old saves.
|
||||
|
@ -78,7 +82,7 @@ namespace MWMechanics
|
|||
actor.getClass().getCreatureStats(actor).setDrawState(DrawState_Nothing);
|
||||
actor.getClass().getCreatureStats(actor).setMovementFlag(CreatureStats::Flag_Run, false);
|
||||
|
||||
const MWWorld::Ptr follower = MWBase::Environment::get().getWorld()->getPtr(mActorId, false);
|
||||
const MWWorld::Ptr follower = MWBase::Environment::get().getWorld()->getPtr(mTargetActorRefId, false);
|
||||
const float* const leaderPos = actor.getRefData().getPosition().pos;
|
||||
const float* const followerPos = follower.getRefData().getPosition().pos;
|
||||
double differenceBetween[3];
|
||||
|
@ -119,18 +123,14 @@ namespace MWMechanics
|
|||
return TypeIdEscort;
|
||||
}
|
||||
|
||||
MWWorld::Ptr AiEscort::getTarget() const
|
||||
{
|
||||
return MWBase::Environment::get().getWorld()->getPtr(mActorId, false);
|
||||
}
|
||||
|
||||
void AiEscort::writeState(ESM::AiSequence::AiSequence &sequence) const
|
||||
{
|
||||
std::unique_ptr<ESM::AiSequence::AiEscort> escort(new ESM::AiSequence::AiEscort());
|
||||
escort->mData.mX = mX;
|
||||
escort->mData.mY = mY;
|
||||
escort->mData.mZ = mZ;
|
||||
escort->mTargetId = mActorId;
|
||||
escort->mTargetId = mTargetActorRefId;
|
||||
escort->mTargetActorId = mTargetActorId;
|
||||
escort->mRemainingDuration = mRemainingDuration;
|
||||
escort->mCellId = mCellId;
|
||||
|
||||
|
|
|
@ -24,11 +24,11 @@ namespace MWMechanics
|
|||
/// Implementation of AiEscort
|
||||
/** The Actor will escort the specified actor to the world position x, y, z until they reach their position, or they run out of time
|
||||
\implement AiEscort **/
|
||||
AiEscort(const std::string &actorId,int duration, float x, float y, float z);
|
||||
AiEscort(const std::string &actorId, int duration, float x, float y, float z);
|
||||
/// Implementation of AiEscortCell
|
||||
/** The Actor will escort the specified actor to the cell position x, y, z until they reach their position, or they run out of time
|
||||
\implement AiEscortCell **/
|
||||
AiEscort(const std::string &actorId,const std::string &cellId,int duration, float x, float y, float z);
|
||||
AiEscort(const std::string &actorId, const std::string &cellId, int duration, float x, float y, float z);
|
||||
|
||||
AiEscort(const ESM::AiSequence::AiEscort* escort);
|
||||
|
||||
|
@ -38,7 +38,6 @@ namespace MWMechanics
|
|||
|
||||
virtual int getTypeId() const;
|
||||
|
||||
MWWorld::Ptr getTarget() const;
|
||||
virtual bool sideWithTarget() const { return true; }
|
||||
|
||||
void writeState(ESM::AiSequence::AiSequence &sequence) const;
|
||||
|
@ -46,7 +45,6 @@ namespace MWMechanics
|
|||
void fastForward(const MWWorld::Ptr& actor, AiState& state);
|
||||
|
||||
private:
|
||||
std::string mActorId;
|
||||
std::string mCellId;
|
||||
float mX;
|
||||
float mY;
|
||||
|
|
|
@ -35,32 +35,53 @@ struct AiFollowStorage : AiTemporaryBase
|
|||
|
||||
int AiFollow::mFollowIndexCounter = 0;
|
||||
|
||||
AiFollow::AiFollow(const std::string &actorId,float duration, float x, float y, float z)
|
||||
AiFollow::AiFollow(const std::string &actorId, float duration, float x, float y, float z)
|
||||
: mAlwaysFollow(false), mCommanded(false), mDuration(duration), mRemainingDuration(duration), mX(x), mY(y), mZ(z)
|
||||
, mActorRefId(actorId), mActorId(-1), mCellId(""), mActive(false), mFollowIndex(mFollowIndexCounter++)
|
||||
, mCellId(""), mActive(false), mFollowIndex(mFollowIndexCounter++)
|
||||
{
|
||||
mTargetActorRefId = actorId;
|
||||
}
|
||||
|
||||
AiFollow::AiFollow(const std::string &actorId,const std::string &cellId,float duration, float x, float y, float z)
|
||||
AiFollow::AiFollow(const std::string &actorId, const std::string &cellId, float duration, float x, float y, float z)
|
||||
: mAlwaysFollow(false), mCommanded(false), mDuration(duration), mRemainingDuration(duration), mX(x), mY(y), mZ(z)
|
||||
, mActorRefId(actorId), mActorId(-1), mCellId(cellId), mActive(false), mFollowIndex(mFollowIndexCounter++)
|
||||
, mCellId(cellId), mActive(false), mFollowIndex(mFollowIndexCounter++)
|
||||
{
|
||||
mTargetActorRefId = actorId;
|
||||
}
|
||||
|
||||
AiFollow::AiFollow(const std::string &actorId, bool commanded)
|
||||
AiFollow::AiFollow(const MWWorld::Ptr& actor, float duration, float x, float y, float z)
|
||||
: mAlwaysFollow(false), mCommanded(false), mDuration(duration), mRemainingDuration(duration), mX(x), mY(y), mZ(z)
|
||||
, mCellId(""), mActive(false), mFollowIndex(mFollowIndexCounter++)
|
||||
{
|
||||
mTargetActorRefId = actor.getCellRef().getRefId();
|
||||
mTargetActorId = actor.getClass().getCreatureStats(actor).getActorId();
|
||||
}
|
||||
|
||||
AiFollow::AiFollow(const MWWorld::Ptr& actor, const std::string &cellId, float duration, float x, float y, float z)
|
||||
: mAlwaysFollow(false), mCommanded(false), mDuration(duration), mRemainingDuration(duration), mX(x), mY(y), mZ(z)
|
||||
, mCellId(cellId), mActive(false), mFollowIndex(mFollowIndexCounter++)
|
||||
{
|
||||
mTargetActorRefId = actor.getCellRef().getRefId();
|
||||
mTargetActorId = actor.getClass().getCreatureStats(actor).getActorId();
|
||||
}
|
||||
|
||||
AiFollow::AiFollow(const MWWorld::Ptr& actor, bool commanded)
|
||||
: mAlwaysFollow(true), mCommanded(commanded), mDuration(0), mRemainingDuration(0), mX(0), mY(0), mZ(0)
|
||||
, mActorRefId(actorId), mActorId(-1), mCellId(""), mActive(false), mFollowIndex(mFollowIndexCounter++)
|
||||
, mCellId(""), mActive(false), mFollowIndex(mFollowIndexCounter++)
|
||||
{
|
||||
mTargetActorRefId = actor.getCellRef().getRefId();
|
||||
mTargetActorId = actor.getClass().getCreatureStats(actor).getActorId();
|
||||
}
|
||||
|
||||
AiFollow::AiFollow(const ESM::AiSequence::AiFollow *follow)
|
||||
: mAlwaysFollow(follow->mAlwaysFollow), mCommanded(follow->mCommanded), mRemainingDuration(follow->mRemainingDuration)
|
||||
, mX(follow->mData.mX), mY(follow->mData.mY), mZ(follow->mData.mZ)
|
||||
, mActorRefId(follow->mTargetId), mActorId(-1)
|
||||
, mCellId(follow->mCellId), mActive(follow->mActive), mFollowIndex(mFollowIndexCounter++)
|
||||
{
|
||||
// mDuration isn't saved in the save file, so just giving it "1" for now if the package had a duration.
|
||||
// The exact value of mDuration only matters for repeating packages.
|
||||
mTargetActorRefId = follow->mTargetId;
|
||||
mTargetActorId = follow->mTargetActorId;
|
||||
// mDuration isn't saved in the save file, so just giving it "1" for now if the package had a duration.
|
||||
// The exact value of mDuration only matters for repeating packages.
|
||||
if (mRemainingDuration > 0) // Previously mRemainingDuration could be negative even when mDuration was 0. Checking for > 0 should fix old saves.
|
||||
mDuration = 1;
|
||||
else
|
||||
|
@ -204,7 +225,7 @@ bool AiFollow::execute (const MWWorld::Ptr& actor, CharacterController& characte
|
|||
|
||||
std::string AiFollow::getFollowedActor()
|
||||
{
|
||||
return mActorRefId;
|
||||
return mTargetActorRefId;
|
||||
}
|
||||
|
||||
AiFollow *MWMechanics::AiFollow::clone() const
|
||||
|
@ -228,7 +249,8 @@ void AiFollow::writeState(ESM::AiSequence::AiSequence &sequence) const
|
|||
follow->mData.mX = mX;
|
||||
follow->mData.mY = mY;
|
||||
follow->mData.mZ = mZ;
|
||||
follow->mTargetId = mActorRefId;
|
||||
follow->mTargetId = mTargetActorRefId;
|
||||
follow->mTargetActorId = mTargetActorId;
|
||||
follow->mRemainingDuration = mRemainingDuration;
|
||||
follow->mCellId = mCellId;
|
||||
follow->mAlwaysFollow = mAlwaysFollow;
|
||||
|
@ -241,29 +263,6 @@ void AiFollow::writeState(ESM::AiSequence::AiSequence &sequence) const
|
|||
sequence.mPackages.push_back(package);
|
||||
}
|
||||
|
||||
MWWorld::Ptr AiFollow::getTarget() const
|
||||
{
|
||||
if (mActorId == -2)
|
||||
return MWWorld::Ptr();
|
||||
|
||||
if (mActorId == -1)
|
||||
{
|
||||
MWWorld::Ptr target = MWBase::Environment::get().getWorld()->searchPtr(mActorRefId, false);
|
||||
if (target.isEmpty())
|
||||
{
|
||||
mActorId = -2;
|
||||
return target;
|
||||
}
|
||||
else
|
||||
mActorId = target.getClass().getCreatureStats(target).getActorId();
|
||||
}
|
||||
|
||||
if (mActorId != -1)
|
||||
return MWBase::Environment::get().getWorld()->searchPtrViaActorId(mActorId);
|
||||
else
|
||||
return MWWorld::Ptr();
|
||||
}
|
||||
|
||||
int AiFollow::getFollowIndex() const
|
||||
{
|
||||
return mFollowIndex;
|
||||
|
|
|
@ -25,16 +25,17 @@ namespace MWMechanics
|
|||
class AiFollow : public AiPackage
|
||||
{
|
||||
public:
|
||||
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);
|
||||
/// Follow Actor for duration or until you arrive at a world position
|
||||
AiFollow(const std::string &ActorId,float duration, float X, float Y, float Z);
|
||||
AiFollow(const MWWorld::Ptr& actor, float duration, float X, float Y, float Z);
|
||||
/// Follow Actor for duration or until you arrive at a position in a cell
|
||||
AiFollow(const std::string &ActorId,const std::string &CellId,float duration, float X, float Y, float Z);
|
||||
AiFollow(const MWWorld::Ptr& actor, const std::string &CellId, float duration, float X, float Y, float Z);
|
||||
/// Follow Actor indefinitively
|
||||
AiFollow(const std::string &ActorId, bool commanded=false);
|
||||
AiFollow(const MWWorld::Ptr& actor, bool commanded=false);
|
||||
|
||||
AiFollow(const ESM::AiSequence::AiFollow* follow);
|
||||
|
||||
MWWorld::Ptr getTarget() const;
|
||||
virtual bool sideWithTarget() const { return true; }
|
||||
virtual bool followTargetThroughDoors() const { return true; }
|
||||
virtual bool shouldCancelPreviousAi() const { return !mCommanded; }
|
||||
|
@ -66,8 +67,6 @@ namespace MWMechanics
|
|||
float mX;
|
||||
float mY;
|
||||
float mZ;
|
||||
std::string mActorRefId;
|
||||
mutable int mActorId;
|
||||
std::string mCellId;
|
||||
bool mActive; // have we spotted the target?
|
||||
int mFollowIndex;
|
||||
|
|
|
@ -27,15 +27,36 @@ MWMechanics::AiPackage::~AiPackage() {}
|
|||
|
||||
MWMechanics::AiPackage::AiPackage() :
|
||||
mTimer(AI_REACTION_TIME + 1.0f), // to force initial pathbuild
|
||||
mTargetActorRefId(""),
|
||||
mTargetActorId(-1),
|
||||
mRotateOnTheRunChecks(0),
|
||||
mIsShortcutting(false),
|
||||
mShortcutProhibited(false), mShortcutFailPos()
|
||||
mShortcutProhibited(false),
|
||||
mShortcutFailPos()
|
||||
{
|
||||
}
|
||||
|
||||
MWWorld::Ptr MWMechanics::AiPackage::getTarget() const
|
||||
{
|
||||
return MWWorld::Ptr();
|
||||
if (mTargetActorId == -2)
|
||||
return MWWorld::Ptr();
|
||||
|
||||
if (mTargetActorId == -1)
|
||||
{
|
||||
MWWorld::Ptr target = MWBase::Environment::get().getWorld()->searchPtr(mTargetActorRefId, false);
|
||||
if (target.isEmpty())
|
||||
{
|
||||
mTargetActorId = -2;
|
||||
return target;
|
||||
}
|
||||
else
|
||||
mTargetActorId = target.getClass().getCreatureStats(target).getActorId();
|
||||
}
|
||||
|
||||
if (mTargetActorId != -1)
|
||||
return MWBase::Environment::get().getWorld()->searchPtrViaActorId(mTargetActorId);
|
||||
else
|
||||
return MWWorld::Ptr();
|
||||
}
|
||||
|
||||
bool MWMechanics::AiPackage::sideWithTarget() const
|
||||
|
|
|
@ -128,6 +128,9 @@ namespace MWMechanics
|
|||
|
||||
float mTimer;
|
||||
|
||||
std::string mTargetActorRefId;
|
||||
mutable int mTargetActorId;
|
||||
|
||||
osg::Vec3f mLastActorPos;
|
||||
|
||||
short mRotateOnTheRunChecks; // attempts to check rotation to the pathpoint on the run possibility
|
||||
|
|
|
@ -15,13 +15,13 @@ namespace MWMechanics
|
|||
{
|
||||
|
||||
AiPursue::AiPursue(const MWWorld::Ptr& actor)
|
||||
: mTargetActorId(actor.getClass().getCreatureStats(actor).getActorId())
|
||||
{
|
||||
mTargetActorId = actor.getClass().getCreatureStats(actor).getActorId();
|
||||
}
|
||||
|
||||
AiPursue::AiPursue(const ESM::AiSequence::AiPursue *pursue)
|
||||
: mTargetActorId(pursue->mTargetActorId)
|
||||
{
|
||||
mTargetActorId = pursue->mTargetActorId;
|
||||
}
|
||||
|
||||
AiPursue *MWMechanics::AiPursue::clone() const
|
||||
|
|
|
@ -40,10 +40,6 @@ namespace MWMechanics
|
|||
|
||||
virtual bool canCancel() const { return false; }
|
||||
virtual bool shouldCancelPreviousAi() const { return false; }
|
||||
|
||||
private:
|
||||
|
||||
int mTargetActorId; // The actor to pursue
|
||||
};
|
||||
}
|
||||
#endif
|
||||
|
|
|
@ -547,7 +547,7 @@ namespace MWMechanics
|
|||
|| (effectIt->mEffectID == ESM::MagicEffect::CommandCreature && target.getTypeName() == typeid(ESM::Creature).name()))
|
||||
&& !caster.isEmpty() && caster.getClass().isActor() && target != getPlayer() && magnitude >= target.getClass().getCreatureStats(target).getLevel())
|
||||
{
|
||||
MWMechanics::AiFollow package(caster.getCellRef().getRefId(), true);
|
||||
MWMechanics::AiFollow package(caster, true);
|
||||
target.getClass().getCreatureStats(target).getAiSequence().stack(package, target);
|
||||
}
|
||||
|
||||
|
|
|
@ -59,7 +59,7 @@ namespace MWMechanics
|
|||
MWMechanics::CreatureStats& summonedCreatureStats = ref.getPtr().getClass().getCreatureStats(ref.getPtr());
|
||||
|
||||
// Make the summoned creature follow its master and help in fights
|
||||
AiFollow package(mActor.getCellRef().getRefId());
|
||||
AiFollow package(mActor);
|
||||
summonedCreatureStats.getAiSequence().stack(package, ref.getPtr());
|
||||
creatureActorId = summonedCreatureStats.getActorId();
|
||||
|
||||
|
|
|
@ -46,6 +46,7 @@ namespace AiSequence
|
|||
{
|
||||
esm.getHNT (mData, "DATA");
|
||||
mTargetId = esm.getHNString("TARG");
|
||||
esm.getHNOT (mTargetActorId, "TAID");
|
||||
esm.getHNT (mRemainingDuration, "DURA");
|
||||
mCellId = esm.getHNOString ("CELL");
|
||||
}
|
||||
|
@ -54,6 +55,7 @@ namespace AiSequence
|
|||
{
|
||||
esm.writeHNT ("DATA", mData);
|
||||
esm.writeHNString ("TARG", mTargetId);
|
||||
esm.writeHNT ("TAID", mTargetActorId);
|
||||
esm.writeHNT ("DURA", mRemainingDuration);
|
||||
if (!mCellId.empty())
|
||||
esm.writeHNString ("CELL", mCellId);
|
||||
|
@ -63,6 +65,7 @@ namespace AiSequence
|
|||
{
|
||||
esm.getHNT (mData, "DATA");
|
||||
mTargetId = esm.getHNString("TARG");
|
||||
esm.getHNOT (mTargetActorId, "TAID");
|
||||
esm.getHNT (mRemainingDuration, "DURA");
|
||||
mCellId = esm.getHNOString ("CELL");
|
||||
esm.getHNT (mAlwaysFollow, "ALWY");
|
||||
|
@ -76,6 +79,7 @@ namespace AiSequence
|
|||
{
|
||||
esm.writeHNT ("DATA", mData);
|
||||
esm.writeHNString("TARG", mTargetId);
|
||||
esm.writeHNT ("TAID", mTargetActorId);
|
||||
esm.writeHNT ("DURA", mRemainingDuration);
|
||||
if (!mCellId.empty())
|
||||
esm.writeHNString ("CELL", mCellId);
|
||||
|
|
|
@ -89,6 +89,7 @@ namespace ESM
|
|||
{
|
||||
AiEscortData mData;
|
||||
|
||||
int mTargetActorId;
|
||||
std::string mTargetId;
|
||||
std::string mCellId;
|
||||
float mRemainingDuration;
|
||||
|
@ -101,6 +102,7 @@ namespace ESM
|
|||
{
|
||||
AiEscortData mData;
|
||||
|
||||
int mTargetActorId;
|
||||
std::string mTargetId;
|
||||
std::string mCellId;
|
||||
float mRemainingDuration;
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
#include "defs.hpp"
|
||||
|
||||
unsigned int ESM::SavedGame::sRecordId = ESM::REC_SAVE;
|
||||
int ESM::SavedGame::sCurrentFormat = 3;
|
||||
int ESM::SavedGame::sCurrentFormat = 4;
|
||||
|
||||
void ESM::SavedGame::load (ESMReader &esm)
|
||||
{
|
||||
|
|
Loading…
Reference in a new issue