Make Activate instruction work properly even when onActivate was not called in the same frame.

There are two major differences to the old implementation:
 - Activate can now be called on its own, e.g. in the console. In Vanilla this appears to be a no-op, so it is unlikely to be used and the potential for breakage is low.
 - The Action to execute is now determined when Activate is called, not when OnActivate is called. This however makes sense, since there may be a time difference between the two, and the object (or the player) could have changed in the meantime, requiring a different Action.

Fixes #1166 and #1346.
deque
scrawl 11 years ago
parent 42ea43c3d1
commit e68600eda2

@ -491,10 +491,7 @@ void OMW::Engine::activate()
MWScript::InterpreterContext interpreterContext (&ptr.getRefData().getLocals(), ptr);
boost::shared_ptr<MWWorld::Action> action =
ptr.getClass().activate (ptr, MWBase::Environment::get().getWorld()->getPlayerPtr());
interpreterContext.activate (ptr, action);
interpreterContext.activate (ptr);
std::string script = ptr.getClass().getScript (ptr);
@ -508,7 +505,7 @@ void OMW::Engine::activate()
if (!interpreterContext.hasActivationBeenHandled())
{
interpreterContext.executeActivation();
interpreterContext.executeActivation(ptr);
}
}

@ -392,5 +392,6 @@ op 0x2000240: onKnockout
op 0x2000241: onKnockoutExplicit
op 0x2000242: ModFactionReaction
op 0x2000243: GetFactionReaction
op 0x2000244: Activate, explicit
opcodes 0x2000244-0x3ffffff unused
opcodes 0x2000245-0x3ffffff unused

@ -413,28 +413,25 @@ namespace MWScript
return mActivationHandled;
}
void InterpreterContext::activate (const MWWorld::Ptr& ptr,
boost::shared_ptr<MWWorld::Action> action)
void InterpreterContext::activate (const MWWorld::Ptr& ptr)
{
mActivated = ptr;
mActivationHandled = false;
mAction = action;
}
void InterpreterContext::executeActivation()
void InterpreterContext::executeActivation(MWWorld::Ptr ptr)
{
if (!mAction.get())
throw std::runtime_error ("activation failed, because no action to perform");
mAction->execute (MWBase::Environment::get().getWorld()->getPlayerPtr());
mActivationHandled = true;
MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayerPtr();
boost::shared_ptr<MWWorld::Action> action = (ptr.getClass().activate(ptr, player));
action->execute (player);
if (mActivated == ptr)
mActivationHandled = true;
}
void InterpreterContext::clearActivation()
{
mActivated = MWWorld::Ptr();
mActivationHandled = false;
mAction.reset();
}
float InterpreterContext::getSecondsPassed() const

@ -31,7 +31,6 @@ namespace MWScript
MWWorld::Ptr mActivated;
bool mActivationHandled;
boost::shared_ptr<MWWorld::Action> mAction;
MWWorld::Ptr getReference (const std::string& id, bool activeOnly, bool doThrow=true);
@ -126,12 +125,12 @@ namespace MWScript
bool hasActivationBeenHandled() const;
void activate (const MWWorld::Ptr& ptr, boost::shared_ptr<MWWorld::Action> action);
///< Store reference acted upon and action. The actual execution of the action does not
void activate (const MWWorld::Ptr& ptr);
///< Store reference acted upon. The actual execution of the action does not
/// take place here.
void executeActivation();
///< Execute the action defined by the last activate call.
void executeActivation(MWWorld::Ptr ptr);
///< Execute the activation action for this ptr. If ptr is mActivated, mark activation as handled.
void clearActivation();
///< Discard the action defined by the last activate call.

@ -109,6 +109,7 @@ namespace MWScript
}
};
template <class R>
class OpActivate : public Interpreter::Opcode0
{
public:
@ -118,7 +119,9 @@ namespace MWScript
InterpreterContext& context =
static_cast<InterpreterContext&> (runtime.getContext());
context.executeActivation();
MWWorld::Ptr ptr = R()(runtime);
context.executeActivation(ptr);
}
};
@ -860,7 +863,8 @@ namespace MWScript
{
interpreter.installSegment5 (Compiler::Misc::opcodeXBox, new OpXBox);
interpreter.installSegment5 (Compiler::Misc::opcodeOnActivate, new OpOnActivate);
interpreter.installSegment5 (Compiler::Misc::opcodeActivate, new OpActivate);
interpreter.installSegment5 (Compiler::Misc::opcodeActivate, new OpActivate<ImplicitRef>);
interpreter.installSegment5 (Compiler::Misc::opcodeActivateExplicit, new OpActivate<ExplicitRef>);
interpreter.installSegment3 (Compiler::Misc::opcodeLock, new OpLock<ImplicitRef>);
interpreter.installSegment3 (Compiler::Misc::opcodeLockExplicit, new OpLock<ExplicitRef>);
interpreter.installSegment5 (Compiler::Misc::opcodeUnlock, new OpUnlock<ImplicitRef>);

@ -224,7 +224,7 @@ namespace Compiler
{
extensions.registerFunction ("xbox", 'l', "", opcodeXBox);
extensions.registerFunction ("onactivate", 'l', "", opcodeOnActivate);
extensions.registerInstruction ("activate", "", opcodeActivate);
extensions.registerInstruction ("activate", "", opcodeActivate, opcodeActivateExplicit);
extensions.registerInstruction ("lock", "/l", opcodeLock, opcodeLockExplicit);
extensions.registerInstruction ("unlock", "", opcodeUnlock, opcodeUnlockExplicit);
extensions.registerInstruction ("cast", "SS", opcodeCast, opcodeCastExplicit);

@ -182,6 +182,7 @@ namespace Compiler
const int opcodeXBox = 0x200000c;
const int opcodeOnActivate = 0x200000d;
const int opcodeActivate = 0x2000075;
const int opcodeActivateExplicit = 0x2000244;
const int opcodeLock = 0x20004;
const int opcodeLockExplicit = 0x20005;
const int opcodeUnlock = 0x200008c;

Loading…
Cancel
Save