forked from mirror/openmw-tes3mp
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);
|
||||
mEnvironment.getScriptManager()->run (script.first, interpreterContext);
|
||||
}
|
||||
|
||||
localScripts.setIgnore (MWWorld::Ptr());
|
||||
}
|
||||
|
||||
void OMW::Engine::frame(float frametime)
|
||||
|
|
|
@ -138,8 +138,7 @@ namespace MWScript
|
|||
|
||||
InterpreterContext::InterpreterContext (
|
||||
MWScript::Locals *locals, MWWorld::Ptr reference, const std::string& targetId)
|
||||
: mLocals (locals), mReference (reference),
|
||||
mActivationHandled (false), mTargetId (targetId)
|
||||
: mLocals (locals), mReference (reference), mTargetId (targetId)
|
||||
{
|
||||
// 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
|
||||
|
@ -477,37 +476,10 @@ namespace MWScript
|
|||
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)
|
||||
{
|
||||
boost::shared_ptr<MWWorld::Action> action = (ptr.getClass().activate(ptr, actor));
|
||||
action->execute (actor);
|
||||
if (mActivated == ptr)
|
||||
{
|
||||
mActivationHandled = true;
|
||||
mActivated = MWWorld::Ptr();
|
||||
}
|
||||
}
|
||||
|
||||
float InterpreterContext::getSecondsPassed() const
|
||||
|
|
|
@ -27,9 +27,6 @@ namespace MWScript
|
|||
Locals *mLocals;
|
||||
mutable MWWorld::Ptr mReference;
|
||||
|
||||
MWWorld::Ptr mActivated;
|
||||
bool mActivationHandled;
|
||||
|
||||
std::string mTargetId;
|
||||
|
||||
/// 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;
|
||||
///< @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);
|
||||
///< 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();
|
||||
|
||||
runtime.push (context.hasBeenActivated (ptr));
|
||||
runtime.push (ptr.getRefData().onActivate());
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -158,7 +158,8 @@ namespace MWScript
|
|||
|
||||
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();
|
||||
}
|
||||
|
||||
void MWWorld::LocalScripts::setIgnore (const ConstPtr& ptr)
|
||||
{
|
||||
mIgnore = ptr;
|
||||
}
|
||||
|
||||
void MWWorld::LocalScripts::startIteration()
|
||||
{
|
||||
mIter = mScripts.begin();
|
||||
|
@ -81,11 +76,8 @@ bool MWWorld::LocalScripts::getNext(std::pair<std::string, Ptr>& script)
|
|||
while (mIter!=mScripts.end())
|
||||
{
|
||||
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;
|
||||
}
|
||||
|
|
|
@ -17,17 +17,12 @@ namespace MWWorld
|
|||
{
|
||||
std::list<std::pair<std::string, Ptr> > mScripts;
|
||||
std::list<std::pair<std::string, Ptr> >::iterator mIter;
|
||||
MWWorld::ConstPtr mIgnore;
|
||||
const MWWorld::ESMStore& mStore;
|
||||
|
||||
public:
|
||||
|
||||
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();
|
||||
///< Set the iterator to the begin of the script list.
|
||||
|
||||
|
|
|
@ -8,8 +8,18 @@
|
|||
#include "../mwbase/environment.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
|
||||
{
|
||||
|
||||
void RefData::copy (const RefData& refData)
|
||||
{
|
||||
mBaseNode = refData.mBaseNode;
|
||||
|
@ -19,6 +29,7 @@ namespace MWWorld
|
|||
mPosition = refData.mPosition;
|
||||
mChanged = refData.mChanged;
|
||||
mDeletedByContentFile = refData.mDeletedByContentFile;
|
||||
mFlags = refData.mFlags;
|
||||
|
||||
mCustomData = refData.mCustomData ? refData.mCustomData->clone() : 0;
|
||||
}
|
||||
|
@ -32,7 +43,7 @@ namespace MWWorld
|
|||
}
|
||||
|
||||
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)
|
||||
{
|
||||
|
@ -45,7 +56,7 @@ namespace MWWorld
|
|||
: mBaseNode(0), mDeletedByContentFile(false), mEnabled (true),
|
||||
mCount (1), mPosition (cellRef.mPos),
|
||||
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),
|
||||
mPosition (objectState.mPosition),
|
||||
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)
|
||||
|
@ -80,6 +95,7 @@ namespace MWWorld
|
|||
objectState.mEnabled = mEnabled;
|
||||
objectState.mCount = mCount;
|
||||
objectState.mPosition = mPosition;
|
||||
objectState.mFlags = mFlags;
|
||||
}
|
||||
|
||||
RefData& RefData::operator= (const RefData& refData)
|
||||
|
@ -219,4 +235,38 @@ namespace MWWorld
|
|||
{
|
||||
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;
|
||||
|
||||
unsigned int mFlags;
|
||||
|
||||
public:
|
||||
|
||||
RefData();
|
||||
|
@ -122,6 +124,12 @@ namespace MWWorld
|
|||
|
||||
const CustomData *getCustomData() const;
|
||||
|
||||
bool activate();
|
||||
|
||||
bool onActivate();
|
||||
|
||||
bool activateByScript();
|
||||
|
||||
bool hasChanged() const;
|
||||
///< Has this RefData changed since it was originally loaded?
|
||||
};
|
||||
|
|
|
@ -3148,25 +3148,16 @@ namespace MWWorld
|
|||
|
||||
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);
|
||||
|
||||
if (mScriptsEnabled)
|
||||
{
|
||||
if (!script.empty())
|
||||
if (object.getRefData().activate())
|
||||
{
|
||||
getLocalScripts().setIgnore (object);
|
||||
MWBase::Environment::get().getScriptManager()->run (script, interpreterContext);
|
||||
boost::shared_ptr<MWWorld::Action> action = (object.getClass().activate(object, actor));
|
||||
action->execute (actor);
|
||||
}
|
||||
if (!interpreterContext.hasActivationBeenHandled())
|
||||
interpreterContext.executeActivation(object, actor);
|
||||
}
|
||||
else
|
||||
interpreterContext.executeActivation(object, actor);
|
||||
}
|
||||
|
||||
struct ResetActorsVisitor
|
||||
|
|
|
@ -27,6 +27,9 @@ void ESM::ObjectState::load (ESMReader &esm)
|
|||
if (esm.isNextSub("LROT"))
|
||||
esm.skipHSub(); // local rotation, no longer used
|
||||
|
||||
mFlags = 0;
|
||||
esm.getHNOT (mFlags, "FLAG");
|
||||
|
||||
// obsolete
|
||||
int unused;
|
||||
esm.getHNOT(unused, "LTIM");
|
||||
|
@ -55,6 +58,9 @@ void ESM::ObjectState::save (ESMWriter &esm, bool inInventory) const
|
|||
if (!inInventory)
|
||||
esm.writeHNT ("POS_", mPosition, 24);
|
||||
|
||||
if (mFlags != 0)
|
||||
esm.writeHNT ("FLAG", mFlags);
|
||||
|
||||
if (!mHasCustomState)
|
||||
esm.writeHNT ("HCUS", false);
|
||||
}
|
||||
|
@ -70,6 +76,7 @@ void ESM::ObjectState::blank()
|
|||
mPosition.pos[i] = 0;
|
||||
mPosition.rot[i] = 0;
|
||||
}
|
||||
mFlags = 0;
|
||||
mHasCustomState = true;
|
||||
}
|
||||
|
||||
|
|
|
@ -24,6 +24,7 @@ namespace ESM
|
|||
unsigned char mEnabled;
|
||||
int mCount;
|
||||
ESM::Position mPosition;
|
||||
unsigned int mFlags;
|
||||
|
||||
// Is there any class-specific state following the ObjectState
|
||||
bool mHasCustomState;
|
||||
|
|
Loading…
Reference in a new issue