mirror of
https://github.com/TES3MP/openmw-tes3mp.git
synced 2025-01-16 19:19:56 +00:00
Vanilla-compatible activate / onActivate (Fixes #1629)
See https://forum.openmw.org/viewtopic.php?f=6&t=3074&p=34618#p34635
This commit is contained in:
parent
195c3b9967
commit
f99cd15f00
11 changed files with 78 additions and 76 deletions
|
@ -76,8 +76,6 @@ void OMW::Engine::executeLocalScripts()
|
||||||
&script.second.getRefData().getLocals(), script.second);
|
&script.second.getRefData().getLocals(), script.second);
|
||||||
mEnvironment.getScriptManager()->run (script.first, interpreterContext);
|
mEnvironment.getScriptManager()->run (script.first, interpreterContext);
|
||||||
}
|
}
|
||||||
|
|
||||||
localScripts.setIgnore (MWWorld::Ptr());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void OMW::Engine::frame(float frametime)
|
void OMW::Engine::frame(float frametime)
|
||||||
|
|
|
@ -138,8 +138,7 @@ namespace MWScript
|
||||||
|
|
||||||
InterpreterContext::InterpreterContext (
|
InterpreterContext::InterpreterContext (
|
||||||
MWScript::Locals *locals, MWWorld::Ptr reference, const std::string& targetId)
|
MWScript::Locals *locals, MWWorld::Ptr reference, const std::string& targetId)
|
||||||
: mLocals (locals), mReference (reference),
|
: mLocals (locals), mReference (reference), mTargetId (targetId)
|
||||||
mActivationHandled (false), mTargetId (targetId)
|
|
||||||
{
|
{
|
||||||
// If we run on a reference (local script, dialogue script or console with object
|
// If we run on a reference (local script, dialogue script or console with object
|
||||||
// selected), store the ID of that reference store it so it can be inherited by
|
// selected), store the ID of that reference store it so it can be inherited by
|
||||||
|
@ -477,37 +476,10 @@ namespace MWScript
|
||||||
return static_cast<float>(std::sqrt(diff[0] * diff[0] + diff[1] * diff[1] + diff[2] * diff[2]));
|
return static_cast<float>(std::sqrt(diff[0] * diff[0] + diff[1] * diff[1] + diff[2] * diff[2]));
|
||||||
}
|
}
|
||||||
|
|
||||||
bool InterpreterContext::hasBeenActivated (const MWWorld::Ptr& ptr)
|
|
||||||
{
|
|
||||||
if (!mActivated.isEmpty() && mActivated==ptr)
|
|
||||||
{
|
|
||||||
mActivationHandled = true;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool InterpreterContext::hasActivationBeenHandled() const
|
|
||||||
{
|
|
||||||
return mActivationHandled;
|
|
||||||
}
|
|
||||||
|
|
||||||
void InterpreterContext::activate (const MWWorld::Ptr& ptr)
|
|
||||||
{
|
|
||||||
mActivated = ptr;
|
|
||||||
mActivationHandled = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
void InterpreterContext::executeActivation(MWWorld::Ptr ptr, MWWorld::Ptr actor)
|
void InterpreterContext::executeActivation(MWWorld::Ptr ptr, MWWorld::Ptr actor)
|
||||||
{
|
{
|
||||||
boost::shared_ptr<MWWorld::Action> action = (ptr.getClass().activate(ptr, actor));
|
boost::shared_ptr<MWWorld::Action> action = (ptr.getClass().activate(ptr, actor));
|
||||||
action->execute (actor);
|
action->execute (actor);
|
||||||
if (mActivated == ptr)
|
|
||||||
{
|
|
||||||
mActivationHandled = true;
|
|
||||||
mActivated = MWWorld::Ptr();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
float InterpreterContext::getSecondsPassed() const
|
float InterpreterContext::getSecondsPassed() const
|
||||||
|
|
|
@ -27,9 +27,6 @@ namespace MWScript
|
||||||
Locals *mLocals;
|
Locals *mLocals;
|
||||||
mutable MWWorld::Ptr mReference;
|
mutable MWWorld::Ptr mReference;
|
||||||
|
|
||||||
MWWorld::Ptr mActivated;
|
|
||||||
bool mActivationHandled;
|
|
||||||
|
|
||||||
std::string mTargetId;
|
std::string mTargetId;
|
||||||
|
|
||||||
/// If \a id is empty, a reference the script is run from is returned or in case
|
/// If \a id is empty, a reference the script is run from is returned or in case
|
||||||
|
@ -131,16 +128,6 @@ namespace MWScript
|
||||||
virtual float getDistance (const std::string& name, const std::string& id = "") const;
|
virtual float getDistance (const std::string& name, const std::string& id = "") const;
|
||||||
///< @note if \a id is empty, assumes an implicit reference
|
///< @note if \a id is empty, assumes an implicit reference
|
||||||
|
|
||||||
bool hasBeenActivated (const MWWorld::Ptr& ptr);
|
|
||||||
///< \attention Calling this function for the right reference will mark the action as
|
|
||||||
/// been handled.
|
|
||||||
|
|
||||||
bool hasActivationBeenHandled() const;
|
|
||||||
|
|
||||||
void activate (const MWWorld::Ptr& ptr);
|
|
||||||
///< Store reference acted upon. The actual execution of the action does not
|
|
||||||
/// take place here.
|
|
||||||
|
|
||||||
void executeActivation(MWWorld::Ptr ptr, MWWorld::Ptr actor);
|
void executeActivation(MWWorld::Ptr ptr, MWWorld::Ptr actor);
|
||||||
///< Execute the activation action for this ptr. If ptr is mActivated, mark activation as handled.
|
///< Execute the activation action for this ptr. If ptr is mActivated, mark activation as handled.
|
||||||
|
|
||||||
|
|
|
@ -142,7 +142,7 @@ namespace MWScript
|
||||||
|
|
||||||
MWWorld::Ptr ptr = context.getReference();
|
MWWorld::Ptr ptr = context.getReference();
|
||||||
|
|
||||||
runtime.push (context.hasBeenActivated (ptr));
|
runtime.push (ptr.getRefData().onActivate());
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -158,7 +158,8 @@ namespace MWScript
|
||||||
|
|
||||||
MWWorld::Ptr ptr = R()(runtime);
|
MWWorld::Ptr ptr = R()(runtime);
|
||||||
|
|
||||||
context.executeActivation(ptr, MWMechanics::getPlayer());
|
if (ptr.getRefData().activateByScript())
|
||||||
|
context.executeActivation(ptr, MWMechanics::getPlayer());
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -66,11 +66,6 @@ MWWorld::LocalScripts::LocalScripts (const MWWorld::ESMStore& store) : mStore (s
|
||||||
mIter = mScripts.end();
|
mIter = mScripts.end();
|
||||||
}
|
}
|
||||||
|
|
||||||
void MWWorld::LocalScripts::setIgnore (const ConstPtr& ptr)
|
|
||||||
{
|
|
||||||
mIgnore = ptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
void MWWorld::LocalScripts::startIteration()
|
void MWWorld::LocalScripts::startIteration()
|
||||||
{
|
{
|
||||||
mIter = mScripts.begin();
|
mIter = mScripts.begin();
|
||||||
|
@ -81,11 +76,8 @@ bool MWWorld::LocalScripts::getNext(std::pair<std::string, Ptr>& script)
|
||||||
while (mIter!=mScripts.end())
|
while (mIter!=mScripts.end())
|
||||||
{
|
{
|
||||||
std::list<std::pair<std::string, Ptr> >::iterator iter = mIter++;
|
std::list<std::pair<std::string, Ptr> >::iterator iter = mIter++;
|
||||||
if (mIgnore.isEmpty() || iter->second!=mIgnore)
|
script = *iter;
|
||||||
{
|
return true;
|
||||||
script = *iter;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
|
@ -17,17 +17,12 @@ namespace MWWorld
|
||||||
{
|
{
|
||||||
std::list<std::pair<std::string, Ptr> > mScripts;
|
std::list<std::pair<std::string, Ptr> > mScripts;
|
||||||
std::list<std::pair<std::string, Ptr> >::iterator mIter;
|
std::list<std::pair<std::string, Ptr> >::iterator mIter;
|
||||||
MWWorld::ConstPtr mIgnore;
|
|
||||||
const MWWorld::ESMStore& mStore;
|
const MWWorld::ESMStore& mStore;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
LocalScripts (const MWWorld::ESMStore& store);
|
LocalScripts (const MWWorld::ESMStore& store);
|
||||||
|
|
||||||
void setIgnore (const ConstPtr& ptr);
|
|
||||||
///< Mark a single reference for ignoring during iteration over local scripts (will revoke
|
|
||||||
/// previous ignores).
|
|
||||||
|
|
||||||
void startIteration();
|
void startIteration();
|
||||||
///< Set the iterator to the begin of the script list.
|
///< Set the iterator to the begin of the script list.
|
||||||
|
|
||||||
|
|
|
@ -8,8 +8,18 @@
|
||||||
#include "../mwbase/environment.hpp"
|
#include "../mwbase/environment.hpp"
|
||||||
#include "../mwbase/world.hpp"
|
#include "../mwbase/world.hpp"
|
||||||
|
|
||||||
|
namespace
|
||||||
|
{
|
||||||
|
enum RefDataFlags
|
||||||
|
{
|
||||||
|
Flag_SuppressActivate = 1, // If set, activation will be suppressed and redirected to the OnActivate flag, which can then be handled by a script.
|
||||||
|
Flag_OnActivate = 2
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
namespace MWWorld
|
namespace MWWorld
|
||||||
{
|
{
|
||||||
|
|
||||||
void RefData::copy (const RefData& refData)
|
void RefData::copy (const RefData& refData)
|
||||||
{
|
{
|
||||||
mBaseNode = refData.mBaseNode;
|
mBaseNode = refData.mBaseNode;
|
||||||
|
@ -19,6 +29,7 @@ namespace MWWorld
|
||||||
mPosition = refData.mPosition;
|
mPosition = refData.mPosition;
|
||||||
mChanged = refData.mChanged;
|
mChanged = refData.mChanged;
|
||||||
mDeletedByContentFile = refData.mDeletedByContentFile;
|
mDeletedByContentFile = refData.mDeletedByContentFile;
|
||||||
|
mFlags = refData.mFlags;
|
||||||
|
|
||||||
mCustomData = refData.mCustomData ? refData.mCustomData->clone() : 0;
|
mCustomData = refData.mCustomData ? refData.mCustomData->clone() : 0;
|
||||||
}
|
}
|
||||||
|
@ -32,7 +43,7 @@ namespace MWWorld
|
||||||
}
|
}
|
||||||
|
|
||||||
RefData::RefData()
|
RefData::RefData()
|
||||||
: mBaseNode(0), mDeletedByContentFile(false), mEnabled (true), mCount (1), mCustomData (0), mChanged(false)
|
: mBaseNode(0), mDeletedByContentFile(false), mEnabled (true), mCount (1), mCustomData (0), mChanged(false), mFlags(0)
|
||||||
{
|
{
|
||||||
for (int i=0; i<3; ++i)
|
for (int i=0; i<3; ++i)
|
||||||
{
|
{
|
||||||
|
@ -45,7 +56,7 @@ namespace MWWorld
|
||||||
: mBaseNode(0), mDeletedByContentFile(false), mEnabled (true),
|
: mBaseNode(0), mDeletedByContentFile(false), mEnabled (true),
|
||||||
mCount (1), mPosition (cellRef.mPos),
|
mCount (1), mPosition (cellRef.mPos),
|
||||||
mCustomData (0),
|
mCustomData (0),
|
||||||
mChanged(false) // Loading from ESM/ESP files -> assume unchanged
|
mChanged(false), mFlags(0) // Loading from ESM/ESP files -> assume unchanged
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -55,8 +66,12 @@ namespace MWWorld
|
||||||
mCount (objectState.mCount),
|
mCount (objectState.mCount),
|
||||||
mPosition (objectState.mPosition),
|
mPosition (objectState.mPosition),
|
||||||
mCustomData (0),
|
mCustomData (0),
|
||||||
mChanged(true) // Loading from a savegame -> assume changed
|
mChanged(true), mFlags(objectState.mFlags) // Loading from a savegame -> assume changed
|
||||||
{
|
{
|
||||||
|
// "Note that the ActivationFlag_UseEnabled is saved to the reference,
|
||||||
|
// which will result in permanently suppressed activation if the reference script is removed.
|
||||||
|
// This occurred when removing the animated containers mod, and the fix in MCP is to reset UseEnabled to true on loading a game."
|
||||||
|
mFlags &= (~Flag_SuppressActivate);
|
||||||
}
|
}
|
||||||
|
|
||||||
RefData::RefData (const RefData& refData)
|
RefData::RefData (const RefData& refData)
|
||||||
|
@ -80,6 +95,7 @@ namespace MWWorld
|
||||||
objectState.mEnabled = mEnabled;
|
objectState.mEnabled = mEnabled;
|
||||||
objectState.mCount = mCount;
|
objectState.mCount = mCount;
|
||||||
objectState.mPosition = mPosition;
|
objectState.mPosition = mPosition;
|
||||||
|
objectState.mFlags = mFlags;
|
||||||
}
|
}
|
||||||
|
|
||||||
RefData& RefData::operator= (const RefData& refData)
|
RefData& RefData::operator= (const RefData& refData)
|
||||||
|
@ -219,4 +235,38 @@ namespace MWWorld
|
||||||
{
|
{
|
||||||
return mChanged;
|
return mChanged;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool RefData::activate()
|
||||||
|
{
|
||||||
|
if (!(mFlags & Flag_SuppressActivate))
|
||||||
|
return true;
|
||||||
|
else
|
||||||
|
{
|
||||||
|
mFlags |= Flag_OnActivate;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool RefData::onActivate()
|
||||||
|
{
|
||||||
|
mFlags |= Flag_SuppressActivate;
|
||||||
|
|
||||||
|
if (mFlags & Flag_OnActivate)
|
||||||
|
{
|
||||||
|
mFlags &= (~Flag_OnActivate);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool RefData::activateByScript()
|
||||||
|
{
|
||||||
|
if (mFlags & Flag_SuppressActivate)
|
||||||
|
{
|
||||||
|
mFlags &= (~Flag_SuppressActivate);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
return false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -50,6 +50,8 @@ namespace MWWorld
|
||||||
|
|
||||||
bool mChanged;
|
bool mChanged;
|
||||||
|
|
||||||
|
unsigned int mFlags;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
RefData();
|
RefData();
|
||||||
|
@ -122,6 +124,12 @@ namespace MWWorld
|
||||||
|
|
||||||
const CustomData *getCustomData() const;
|
const CustomData *getCustomData() const;
|
||||||
|
|
||||||
|
bool activate();
|
||||||
|
|
||||||
|
bool onActivate();
|
||||||
|
|
||||||
|
bool activateByScript();
|
||||||
|
|
||||||
bool hasChanged() const;
|
bool hasChanged() const;
|
||||||
///< Has this RefData changed since it was originally loaded?
|
///< Has this RefData changed since it was originally loaded?
|
||||||
};
|
};
|
||||||
|
|
|
@ -3148,25 +3148,16 @@ namespace MWWorld
|
||||||
|
|
||||||
void World::activate(const Ptr &object, const Ptr &actor)
|
void World::activate(const Ptr &object, const Ptr &actor)
|
||||||
{
|
{
|
||||||
MWScript::InterpreterContext interpreterContext (&object.getRefData().getLocals(), object);
|
|
||||||
interpreterContext.activate (object);
|
|
||||||
|
|
||||||
std::string script = object.getClass().getScript (object);
|
|
||||||
|
|
||||||
breakInvisibility(actor);
|
breakInvisibility(actor);
|
||||||
|
|
||||||
if (mScriptsEnabled)
|
if (mScriptsEnabled)
|
||||||
{
|
{
|
||||||
if (!script.empty())
|
if (object.getRefData().activate())
|
||||||
{
|
{
|
||||||
getLocalScripts().setIgnore (object);
|
boost::shared_ptr<MWWorld::Action> action = (object.getClass().activate(object, actor));
|
||||||
MWBase::Environment::get().getScriptManager()->run (script, interpreterContext);
|
action->execute (actor);
|
||||||
}
|
}
|
||||||
if (!interpreterContext.hasActivationBeenHandled())
|
|
||||||
interpreterContext.executeActivation(object, actor);
|
|
||||||
}
|
}
|
||||||
else
|
|
||||||
interpreterContext.executeActivation(object, actor);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
struct ResetActorsVisitor
|
struct ResetActorsVisitor
|
||||||
|
|
|
@ -27,6 +27,9 @@ void ESM::ObjectState::load (ESMReader &esm)
|
||||||
if (esm.isNextSub("LROT"))
|
if (esm.isNextSub("LROT"))
|
||||||
esm.skipHSub(); // local rotation, no longer used
|
esm.skipHSub(); // local rotation, no longer used
|
||||||
|
|
||||||
|
mFlags = 0;
|
||||||
|
esm.getHNOT (mFlags, "FLAG");
|
||||||
|
|
||||||
// obsolete
|
// obsolete
|
||||||
int unused;
|
int unused;
|
||||||
esm.getHNOT(unused, "LTIM");
|
esm.getHNOT(unused, "LTIM");
|
||||||
|
@ -55,6 +58,9 @@ void ESM::ObjectState::save (ESMWriter &esm, bool inInventory) const
|
||||||
if (!inInventory)
|
if (!inInventory)
|
||||||
esm.writeHNT ("POS_", mPosition, 24);
|
esm.writeHNT ("POS_", mPosition, 24);
|
||||||
|
|
||||||
|
if (mFlags != 0)
|
||||||
|
esm.writeHNT ("FLAG", mFlags);
|
||||||
|
|
||||||
if (!mHasCustomState)
|
if (!mHasCustomState)
|
||||||
esm.writeHNT ("HCUS", false);
|
esm.writeHNT ("HCUS", false);
|
||||||
}
|
}
|
||||||
|
@ -70,6 +76,7 @@ void ESM::ObjectState::blank()
|
||||||
mPosition.pos[i] = 0;
|
mPosition.pos[i] = 0;
|
||||||
mPosition.rot[i] = 0;
|
mPosition.rot[i] = 0;
|
||||||
}
|
}
|
||||||
|
mFlags = 0;
|
||||||
mHasCustomState = true;
|
mHasCustomState = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -24,6 +24,7 @@ namespace ESM
|
||||||
unsigned char mEnabled;
|
unsigned char mEnabled;
|
||||||
int mCount;
|
int mCount;
|
||||||
ESM::Position mPosition;
|
ESM::Position mPosition;
|
||||||
|
unsigned int mFlags;
|
||||||
|
|
||||||
// Is there any class-specific state following the ObjectState
|
// Is there any class-specific state following the ObjectState
|
||||||
bool mHasCustomState;
|
bool mHasCustomState;
|
||||||
|
|
Loading…
Reference in a new issue