Vanilla-compatible activate / onActivate (Fixes #1629)

See https://forum.openmw.org/viewtopic.php?f=6&t=3074&p=34618#p34635
move
scrawl 9 years ago
parent 195c3b9967
commit f99cd15f00

@ -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…
Cancel
Save