Allow targeting non-unique actors with StartScript (bug #2311)

pull/2648/head
unknown 4 years ago
parent 7a6ba8bf7a
commit 3b4782959e

@ -2,6 +2,7 @@
------
Bug #1952: Incorrect particle lighting
Bug #2311: Targeted scripts are not properly supported on non-unique RefIDs
Bug #3676: NiParticleColorModifier isn't applied properly
Bug #5358: ForceGreeting always resets the dialogue window completely
Bug #5363: Enchantment autocalc not always 0/1

@ -35,7 +35,7 @@ namespace MWBase
virtual ~ScriptManager() {}
virtual void run (const std::string& name, Interpreter::Context& interpreterContext) = 0;
virtual bool run (const std::string& name, Interpreter::Context& interpreterContext) = 0;
///< Run the script with the given name (compile first, if not compiled yet)
virtual bool compile (const std::string& name) = 0;

@ -189,6 +189,8 @@ namespace MWBase
virtual MWWorld::Ptr searchPtrViaActorId (int actorId) = 0;
///< Search is limited to the active cells.
virtual MWWorld::Ptr searchPtrViaRefNum (const std::string& id, const ESM::RefNum& refNum) = 0;
virtual MWWorld::Ptr findContainer (const MWWorld::ConstPtr& ptr) = 0;
///< Return a pointer to a liveCellRef which contains \a ptr.
/// \note Search is limited to the active cells.

@ -5,83 +5,171 @@
#include <components/esm/esmwriter.hpp>
#include <components/esm/globalscript.hpp>
#include "../mwworld/class.hpp"
#include "../mwworld/esmstore.hpp"
#include "../mwbase/environment.hpp"
#include "../mwbase/world.hpp"
#include "../mwbase/scriptmanager.hpp"
#include "../mwmechanics/creaturestats.hpp"
#include "interpretercontext.hpp"
namespace
{
struct ScriptCreatingVisitor : public boost::static_visitor<ESM::GlobalScript>
{
ESM::GlobalScript operator()(const MWWorld::Ptr &ptr) const
{
ESM::GlobalScript script;
script.mTargetRef.unset();
if (!ptr.isEmpty())
{
if (ptr.getCellRef().hasContentFile())
{
script.mTargetId = ptr.getCellRef().getRefId();
script.mTargetRef = ptr.getCellRef().getRefNum();
}
else if (MWBase::Environment::get().getWorld()->getPlayerPtr() == ptr)
script.mTargetId = ptr.getCellRef().getRefId();
}
return script;
}
ESM::GlobalScript operator()(const std::pair<ESM::RefNum, std::string> &pair) const
{
ESM::GlobalScript script;
script.mTargetId = pair.second;
script.mTargetRef = pair.first;
return script;
}
};
struct PtrGettingVisitor : public boost::static_visitor<const MWWorld::Ptr*>
{
const MWWorld::Ptr* operator()(const MWWorld::Ptr &ptr) const
{
return &ptr;
}
const MWWorld::Ptr* operator()(const std::pair<ESM::RefNum, std::string> &pair) const
{
return nullptr;
}
};
struct PtrResolvingVisitor : public boost::static_visitor<MWWorld::Ptr>
{
MWWorld::Ptr operator()(const MWWorld::Ptr &ptr) const
{
return ptr;
}
MWWorld::Ptr operator()(const std::pair<ESM::RefNum, std::string> &pair) const
{
if (pair.second.empty())
return MWWorld::Ptr();
else if(pair.first.hasContentFile())
return MWBase::Environment::get().getWorld()->searchPtrViaRefNum(pair.second, pair.first);
return MWBase::Environment::get().getWorld()->searchPtr(pair.second, false);
}
};
class MatchPtrVisitor : public boost::static_visitor<bool>
{
const MWWorld::Ptr& mPtr;
public:
MatchPtrVisitor(const MWWorld::Ptr& ptr) : mPtr(ptr) {}
bool operator()(const MWWorld::Ptr &ptr) const
{
return ptr == mPtr;
}
bool operator()(const std::pair<ESM::RefNum, std::string> &pair) const
{
return false;
}
};
}
namespace MWScript
{
GlobalScriptDesc::GlobalScriptDesc() : mRunning (false) {}
const MWWorld::Ptr* GlobalScriptDesc::getPtrIfPresent() const
{
return boost::apply_visitor(PtrGettingVisitor(), mTarget);
}
MWWorld::Ptr GlobalScriptDesc::getPtr()
{
MWWorld::Ptr ptr = boost::apply_visitor(PtrResolvingVisitor(), mTarget);
mTarget = ptr;
return ptr;
}
GlobalScripts::GlobalScripts (const MWWorld::ESMStore& store)
: mStore (store)
{}
void GlobalScripts::addScript (const std::string& name, const std::string& targetId)
void GlobalScripts::addScript (const std::string& name, const MWWorld::Ptr& target)
{
std::map<std::string, GlobalScriptDesc>::iterator iter =
mScripts.find (::Misc::StringUtils::lowerCase (name));
const auto iter = mScripts.find (::Misc::StringUtils::lowerCase (name));
if (iter==mScripts.end())
{
if (const ESM::Script *script = mStore.get<ESM::Script>().search(name))
{
GlobalScriptDesc desc;
desc.mRunning = true;
desc.mLocals.configure (*script);
desc.mId = targetId;
mScripts.insert (std::make_pair (name, desc));
auto desc = std::make_shared<GlobalScriptDesc>();
MWWorld::Ptr ptr = target;
desc->mTarget = ptr;
desc->mRunning = true;
desc->mLocals.configure (*script);
mScripts.insert (std::make_pair(name, desc));
}
else
{
Log(Debug::Error) << "Failed to add global script " << name << ": script record not found";
}
}
else if (!iter->second.mRunning)
else if (!iter->second->mRunning)
{
iter->second.mRunning = true;
iter->second.mId = targetId;
iter->second->mRunning = true;
MWWorld::Ptr ptr = target;
iter->second->mTarget = ptr;
}
}
void GlobalScripts::removeScript (const std::string& name)
{
std::map<std::string, GlobalScriptDesc>::iterator iter =
mScripts.find (::Misc::StringUtils::lowerCase (name));
const auto iter = mScripts.find (::Misc::StringUtils::lowerCase (name));
if (iter!=mScripts.end())
iter->second.mRunning = false;
iter->second->mRunning = false;
}
bool GlobalScripts::isRunning (const std::string& name) const
{
std::map<std::string, GlobalScriptDesc>::const_iterator iter =
mScripts.find (::Misc::StringUtils::lowerCase (name));
const auto iter = mScripts.find (::Misc::StringUtils::lowerCase (name));
if (iter==mScripts.end())
return false;
return iter->second.mRunning;
return iter->second->mRunning;
}
void GlobalScripts::run()
{
for (std::map<std::string, GlobalScriptDesc>::iterator iter (mScripts.begin());
iter!=mScripts.end(); ++iter)
for (const auto& script : mScripts)
{
if (iter->second.mRunning)
if (script.second->mRunning)
{
MWWorld::Ptr ptr;
MWScript::InterpreterContext interpreterContext (
&iter->second.mLocals, MWWorld::Ptr(), iter->second.mId);
MWBase::Environment::get().getScriptManager()->run (iter->first, interpreterContext);
MWScript::InterpreterContext context(script.second);
if (!MWBase::Environment::get().getScriptManager()->run(script.first, context))
script.second->mRunning = false;
}
}
}
@ -129,18 +217,15 @@ namespace MWScript
void GlobalScripts::write (ESM::ESMWriter& writer, Loading::Listener& progress) const
{
for (std::map<std::string, GlobalScriptDesc>::const_iterator iter (mScripts.begin());
iter!=mScripts.end(); ++iter)
for (const auto& iter : mScripts)
{
ESM::GlobalScript script;
ESM::GlobalScript script = boost::apply_visitor (ScriptCreatingVisitor(), iter.second->mTarget);
script.mId = iter->first;
script.mId = iter.first;
iter->second.mLocals.write (script.mLocals, iter->first);
iter.second->mLocals.write (script.mLocals, iter.first);
script.mRunning = iter->second.mRunning ? 1 : 0;
script.mTargetId = iter->second.mId;
script.mRunning = iter.second->mRunning ? 1 : 0;
writer.startRecord (ESM::REC_GSCR);
script.save (writer);
@ -155,8 +240,7 @@ namespace MWScript
ESM::GlobalScript script;
script.load (reader);
std::map<std::string, GlobalScriptDesc>::iterator iter =
mScripts.find (script.mId);
auto iter = mScripts.find (script.mId);
if (iter==mScripts.end())
{
@ -164,8 +248,12 @@ namespace MWScript
{
try
{
GlobalScriptDesc desc;
desc.mLocals.configure (*scriptRecord);
auto desc = std::make_shared<GlobalScriptDesc>();
if (!script.mTargetId.empty())
{
desc->mTarget = std::make_pair(script.mTargetRef, script.mTargetId);
}
desc->mLocals.configure (*scriptRecord);
iter = mScripts.insert (std::make_pair (script.mId, desc)).first;
}
@ -182,9 +270,8 @@ namespace MWScript
return true;
}
iter->second.mRunning = script.mRunning!=0;
iter->second.mLocals.read (script.mLocals, script.mId);
iter->second.mId = script.mTargetId;
iter->second->mRunning = script.mRunning!=0;
iter->second->mLocals.read (script.mLocals, script.mId);
return true;
}
@ -195,18 +282,28 @@ namespace MWScript
Locals& GlobalScripts::getLocals (const std::string& name)
{
std::string name2 = ::Misc::StringUtils::lowerCase (name);
std::map<std::string, GlobalScriptDesc>::iterator iter = mScripts.find (name2);
auto iter = mScripts.find (name2);
if (iter==mScripts.end())
{
const ESM::Script *script = mStore.get<ESM::Script>().find (name);
GlobalScriptDesc desc;
desc.mLocals.configure (*script);
auto desc = std::make_shared<GlobalScriptDesc>();
desc->mLocals.configure (*script);
iter = mScripts.insert (std::make_pair (name2, desc)).first;
}
return iter->second.mLocals;
return iter->second->mLocals;
}
void GlobalScripts::updatePtrs(const MWWorld::Ptr& base, const MWWorld::Ptr& updated)
{
MatchPtrVisitor visitor(base);
for (const auto& script : mScripts)
{
if (boost::apply_visitor (visitor, script.second->mTarget))
script.second->mTarget = updated;
}
}
}

@ -1,17 +1,24 @@
#ifndef GAME_SCRIPT_GLOBALSCRIPTS_H
#define GAME_SCRIPT_GLOBALSCRIPTS_H
#include <boost/variant/variant.hpp>
#include <string>
#include <map>
#include <memory>
#include <utility>
#include <stdint.h>
#include "locals.hpp"
#include "../mwworld/ptr.hpp"
namespace ESM
{
class ESMWriter;
class ESMReader;
struct RefNum;
}
namespace Loading
@ -30,21 +37,25 @@ namespace MWScript
{
bool mRunning;
Locals mLocals;
std::string mId; // ID used to start targeted script (empty if not a targeted script)
boost::variant<MWWorld::Ptr, std::pair<ESM::RefNum, std::string> > mTarget; // Used to start targeted script
GlobalScriptDesc();
const MWWorld::Ptr* getPtrIfPresent() const; // Returns a Ptr if one has been resolved
MWWorld::Ptr getPtr(); // Resolves mTarget to a Ptr and caches the (potentially empty) result
};
class GlobalScripts
{
const MWWorld::ESMStore& mStore;
std::map<std::string, GlobalScriptDesc> mScripts;
std::map<std::string, std::shared_ptr<GlobalScriptDesc> > mScripts;
public:
GlobalScripts (const MWWorld::ESMStore& store);
void addScript (const std::string& name, const std::string& targetId = "");
void addScript (const std::string& name, const MWWorld::Ptr& target = MWWorld::Ptr());
void removeScript (const std::string& name);
@ -70,6 +81,9 @@ namespace MWScript
Locals& getLocals (const std::string& name);
///< If the script \a name has not been added as a global script yet, it is added
/// automatically, but is not set to running state.
void updatePtrs(const MWWorld::Ptr& base, const MWWorld::Ptr& updated);
///< Update the Ptrs stored in mTarget. Should be called after the reference has been moved to a new cell.
};
}

@ -1,7 +1,6 @@
#include "interpretercontext.hpp"
#include <cmath>
#include <stdexcept>
#include <sstream>
#include <components/compiler/locals.hpp>
@ -28,26 +27,6 @@
namespace MWScript
{
MWWorld::Ptr InterpreterContext::getReferenceImp (
const std::string& id, bool activeOnly, bool doThrow)
{
if (!id.empty())
{
return MWBase::Environment::get().getWorld()->getPtr (id, activeOnly);
}
else
{
if (mReference.isEmpty() && !mTargetId.empty())
mReference =
MWBase::Environment::get().getWorld()->searchPtr (mTargetId, false);
if (mReference.isEmpty() && doThrow)
throw std::runtime_error ("no implicit reference");
return mReference;
}
}
const MWWorld::Ptr InterpreterContext::getReferenceImp (
const std::string& id, bool activeOnly, bool doThrow) const
{
@ -57,12 +36,11 @@ namespace MWScript
}
else
{
if (mReference.isEmpty() && !mTargetId.empty())
mReference =
MWBase::Environment::get().getWorld()->searchPtr (mTargetId, false);
if (mReference.isEmpty() && mGlobalScriptDesc)
mReference = mGlobalScriptDesc->getPtr();
if (mReference.isEmpty() && doThrow)
throw std::runtime_error ("no implicit reference");
throw MissingImplicitRefError();
return mReference;
}
@ -80,7 +58,7 @@ namespace MWScript
{
const MWWorld::Ptr ptr = getReferenceImp (id, false);
id = ptr.getClass().getScript (ptr);
id = ptr.getClass().getScript (ptr);
ptr.getRefData().setLocals (
*MWBase::Environment::get().getWorld()->getStore().get<ESM::Script>().find (id));
@ -109,6 +87,8 @@ namespace MWScript
}
}
MissingImplicitRefError::MissingImplicitRefError() : std::runtime_error("no implicit reference") {}
int InterpreterContext::findLocalVariableIndex (const std::string& scriptId,
const std::string& name, char type) const
{
@ -134,16 +114,21 @@ namespace MWScript
throw std::runtime_error (stream.str().c_str());
}
InterpreterContext::InterpreterContext (MWScript::Locals *locals, const MWWorld::Ptr& reference)
: mLocals (locals), mReference (reference)
{}
InterpreterContext::InterpreterContext (
MWScript::Locals *locals, const MWWorld::Ptr& reference, const std::string& targetId)
: mLocals (locals), mReference (reference), mTargetId (targetId)
InterpreterContext::InterpreterContext (std::shared_ptr<GlobalScriptDesc> globalScriptDesc)
: mLocals (&(globalScriptDesc->mLocals))
{
// 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
// targeted scripts started from this one.
if (targetId.empty() && !reference.isEmpty())
mTargetId = reference.getCellRef().getRefId();
const MWWorld::Ptr* ptr = globalScriptDesc->getPtrIfPresent();
// A nullptr here signifies that the script's target has not yet been resolved after loading the game.
// Script targets are lazily resolved to MWWorld::Ptrs (which can, upon resolution, be empty)
// because scripts started through dialogue often don't use their implicit target.
if (ptr)
mReference = *ptr;
else
mGlobalScriptDesc = globalScriptDesc;
}
int InterpreterContext::getLocalShort (int index) const
@ -437,7 +422,12 @@ namespace MWScript
void InterpreterContext::startScript (const std::string& name, const std::string& targetId)
{
MWBase::Environment::get().getScriptManager()->getGlobalScripts().addScript (name, targetId);
MWWorld::Ptr target;
if (targetId.empty())
target = getReference(false);
else
target = getReferenceImp(targetId);
MWBase::Environment::get().getScriptManager()->getGlobalScripts().addScript (name, target);
}
void InterpreterContext::stopScript (const std::string& name)
@ -449,12 +439,7 @@ namespace MWScript
{
// NOTE: id may be empty, indicating an implicit reference
MWWorld::Ptr ref2;
if (id.empty())
ref2 = getReferenceImp();
else
ref2 = MWBase::Environment::get().getWorld()->getPtr(id, false);
MWWorld::Ptr ref2 = getReferenceImp(id);
if (ref2.getContainerStore()) // is the object contained?
{
@ -578,11 +563,6 @@ namespace MWScript
return getReferenceImp ("", true, required);
}
std::string InterpreterContext::getTargetId() const
{
return mTargetId;
}
void InterpreterContext::updatePtr(const MWWorld::Ptr& base, const MWWorld::Ptr& updated)
{
if (!mReference.isEmpty() && base == mReference)

@ -1,8 +1,13 @@
#ifndef GAME_SCRIPT_INTERPRETERCONTEXT_H
#define GAME_SCRIPT_INTERPRETERCONTEXT_H
#include <memory>
#include <stdexcept>
#include <components/interpreter/context.hpp>
#include "globalscripts.hpp"
#include "../mwworld/ptr.hpp"
namespace MWSound
@ -19,17 +24,17 @@ namespace MWScript
{
class Locals;
class MissingImplicitRefError : public std::runtime_error
{
public:
MissingImplicitRefError();
};
class InterpreterContext : public Interpreter::Context
{
Locals *mLocals;
mutable MWWorld::Ptr mReference;
std::string mTargetId;
/// If \a id is empty, a reference the script is run from is returned or in case
/// of a non-local script the reference derived from the target ID.
MWWorld::Ptr getReferenceImp (const std::string& id = "", bool activeOnly = false,
bool doThrow=true);
std::shared_ptr<GlobalScriptDesc> mGlobalScriptDesc;
/// If \a id is empty, a reference the script is run from is returned or in case
/// of a non-local script the reference derived from the target ID.
@ -47,9 +52,9 @@ namespace MWScript
char type) const;
public:
InterpreterContext (std::shared_ptr<GlobalScriptDesc> globalScriptDesc);
InterpreterContext (MWScript::Locals *locals, const MWWorld::Ptr& reference,
const std::string& targetId = "");
InterpreterContext (MWScript::Locals *locals, const MWWorld::Ptr& reference);
///< The ownership of \a locals is not transferred. 0-pointer allowed.
virtual int getLocalShort (int index) const;
@ -153,8 +158,6 @@ namespace MWScript
void updatePtr(const MWWorld::Ptr& base, const MWWorld::Ptr& updated);
///< Update the Ptr stored in mReference, if there is one stored there. Should be called after the reference has been moved to a new cell.
virtual std::string getTargetId() const;
};
}

@ -19,6 +19,7 @@
#include "../mwworld/esmstore.hpp"
#include "extensions.hpp"
#include "interpretercontext.hpp"
namespace MWScript
{
@ -88,7 +89,7 @@ namespace MWScript
return false;
}
void ScriptManager::run (const std::string& name, Interpreter::Context& interpreterContext)
bool ScriptManager::run (const std::string& name, Interpreter::Context& interpreterContext)
{
// compile script
ScriptCollection::iterator iter = mScripts.find (name);
@ -100,7 +101,7 @@ namespace MWScript
// failed -> ignore script from now on.
std::vector<Interpreter::Type_Code> empty;
mScripts.insert (std::make_pair (name, std::make_pair (empty, Compiler::Locals())));
return;
return false;
}
iter = mScripts.find (name);
@ -118,14 +119,19 @@ namespace MWScript
}
mInterpreter.run (&iter->second.first[0], iter->second.first.size(), interpreterContext);
return true;
}
catch (const MissingImplicitRefError& e)
{
Log(Debug::Error) << "Execution of script " << name << " failed: " << e.what();
}
catch (const std::exception& e)
{
Log(Debug::Error) << "Execution of script " << name << " failed:";
Log(Debug::Error) << e.what();
Log(Debug::Error) << "Execution of script " << name << " failed: " << e.what();
iter->second.first.clear(); // don't execute again.
}
return false;
}
std::pair<int, int> ScriptManager::compileAll()

@ -55,7 +55,7 @@ namespace MWScript
Compiler::Context& compilerContext, int warningsMode,
const std::vector<std::string>& scriptBlacklist);
virtual void run (const std::string& name, Interpreter::Context& interpreterContext);
virtual bool run (const std::string& name, Interpreter::Context& interpreterContext);
///< Run the script with the given name (compile first, if not compiled yet)
virtual bool compile (const std::string& name);

@ -5,6 +5,7 @@
#include <components/esm/esmwriter.hpp>
#include <components/esm/defs.hpp>
#include <components/esm/cellstate.hpp>
#include <components/esm/cellref.hpp>
#include <components/loadinglistener/loadinglistener.hpp>
#include <components/settings/settings.hpp>
@ -270,6 +271,37 @@ MWWorld::Ptr MWWorld::Cells::getPtr (const std::string& name)
return Ptr();
}
MWWorld::Ptr MWWorld::Cells::getPtr (const std::string& id, const ESM::RefNum& refNum)
{
for (auto& pair : mInteriors)
{
Ptr ptr = getPtr(pair.second, id, refNum);
if (!ptr.isEmpty())
return ptr;
}
for (auto& pair : mExteriors)
{
Ptr ptr = getPtr(pair.second, id, refNum);
if (!ptr.isEmpty())
return ptr;
}
return Ptr();
}
MWWorld::Ptr MWWorld::Cells::getPtr(CellStore& cellStore, const std::string& id, const ESM::RefNum& refNum)
{
if (cellStore.getState() == CellStore::State_Unloaded)
cellStore.preload();
if (cellStore.getState() == CellStore::State_Preloaded)
{
if (cellStore.hasId(id))
cellStore.load();
else
return Ptr();
}
return cellStore.searchViaRefNum(refNum);
}
void MWWorld::Cells::getExteriorPtrs(const std::string &name, std::vector<MWWorld::Ptr> &out)
{
const MWWorld::Store<ESM::Cell> &cells = mStore.get<ESM::Cell>();

@ -13,6 +13,7 @@ namespace ESM
class ESMWriter;
struct CellId;
struct Cell;
struct RefNum;
}
namespace Loading
@ -41,6 +42,8 @@ namespace MWWorld
Ptr getPtrAndCache (const std::string& name, CellStore& cellStore);
Ptr getPtr(CellStore& cellStore, const std::string& id, const ESM::RefNum& refNum);
void writeCell (ESM::ESMWriter& writer, CellStore& cell) const;
public:
@ -62,6 +65,8 @@ namespace MWWorld
/// @note name must be lower case
Ptr getPtr (const std::string& name);
Ptr getPtr(const std::string& id, const ESM::RefNum& refNum);
void rest (double hours);
void recharge (float duration);

@ -6,6 +6,7 @@
#include <components/esm/cellstate.hpp>
#include <components/esm/cellid.hpp>
#include <components/esm/cellref.hpp>
#include <components/esm/esmreader.hpp>
#include <components/esm/esmwriter.hpp>
#include <components/esm/objectstate.hpp>
@ -435,6 +436,32 @@ namespace MWWorld
return Ptr();
}
class RefNumSearchVisitor
{
const ESM::RefNum& mRefNum;
public:
RefNumSearchVisitor(const ESM::RefNum& refNum) : mRefNum(refNum) {}
Ptr mFound;
bool operator()(const Ptr& ptr)
{
if (ptr.getCellRef().getRefNum() == mRefNum)
{
mFound = ptr;
return false;
}
return true;
}
};
Ptr CellStore::searchViaRefNum (const ESM::RefNum& refNum)
{
RefNumSearchVisitor searchVisitor(refNum);
forEach(searchVisitor);
return searchVisitor.mFound;
}
float CellStore::getWaterLevel() const
{
if (isExterior())

@ -41,6 +41,7 @@ namespace ESM
struct CellState;
struct FogState;
struct CellId;
struct RefNum;
}
namespace MWWorld
@ -242,6 +243,11 @@ namespace MWWorld
Ptr searchViaActorId (int id);
///< Will return an empty Ptr if cell is not loaded.
Ptr searchViaRefNum (const ESM::RefNum& refNum);
///< Will return an empty Ptr if cell is not loaded. Does not check references in
/// containers.
/// @note Triggers CellStore hasState flag.
float getWaterLevel() const;
bool movedHere(const MWWorld::Ptr& ptr) const;

@ -11,6 +11,7 @@
#include <components/esm/esmreader.hpp>
#include <components/esm/esmwriter.hpp>
#include <components/esm/cellid.hpp>
#include <components/esm/cellref.hpp>
#include <components/misc/constants.hpp>
#include <components/misc/resourcehelpers.hpp>
@ -752,6 +753,11 @@ namespace MWWorld
return mWorldScene->searchPtrViaActorId (actorId);
}
Ptr World::searchPtrViaRefNum (const std::string& id, const ESM::RefNum& refNum)
{
return mCells.getPtr (id, refNum);
}
struct FindContainerVisitor
{
ConstPtr mContainedPtr;
@ -1290,6 +1296,7 @@ namespace MWWorld
mRendering->updatePtr(ptr, newPtr);
MWBase::Environment::get().getSoundManager()->updatePtr (ptr, newPtr);
mPhysics->updatePtr(ptr, newPtr);
MWBase::Environment::get().getScriptManager()->getGlobalScripts().updatePtrs(ptr, newPtr);
MWBase::MechanicsManager *mechMgr = MWBase::Environment::get().getMechanicsManager();
mechMgr->updateCell(ptr, newPtr);

@ -297,6 +297,8 @@ namespace MWWorld
Ptr searchPtrViaActorId (int actorId) override;
///< Search is limited to the active cells.
Ptr searchPtrViaRefNum (const std::string& id, const ESM::RefNum& refNum) override;
MWWorld::Ptr findContainer (const MWWorld::ConstPtr& ptr) override;
///< Return a pointer to a liveCellRef which contains \a ptr.
/// \note Search is limited to the active cells.

@ -12,7 +12,11 @@ void ESM::GlobalScript::load (ESMReader &esm)
mRunning = 0;
esm.getHNOT (mRunning, "RUN_");
mTargetId = esm.getHNOString ("TARG");
mTargetRef.unset();
if (esm.peekNextSub("TARG"))
mTargetId = esm.getHNString ("TARG");
if (esm.peekNextSub("FRMR"))
mTargetRef.load(esm, true, "FRMR");
}
void ESM::GlobalScript::save (ESMWriter &esm) const
@ -24,5 +28,10 @@ void ESM::GlobalScript::save (ESMWriter &esm) const
if (mRunning)
esm.writeHNT ("RUN_", mRunning);
esm.writeHNOString ("TARG", mTargetId);
if (!mTargetId.empty())
{
esm.writeHNOString ("TARG", mTargetId);
if (mTargetRef.hasContentFile())
mTargetRef.save (esm, true, "FRMR");
}
}

@ -2,6 +2,7 @@
#define OPENMW_ESM_GLOBALSCRIPT_H
#include "locals.hpp"
#include "cellref.hpp"
namespace ESM
{
@ -16,6 +17,7 @@ namespace ESM
Locals mLocals;
int mRunning;
std::string mTargetId; // for targeted scripts
RefNum mTargetRef;
void load (ESMReader &esm);
void save (ESMWriter &esm) const;

@ -5,7 +5,7 @@
#include "defs.hpp"
unsigned int ESM::SavedGame::sRecordId = ESM::REC_SAVE;
int ESM::SavedGame::sCurrentFormat = 5;
int ESM::SavedGame::sCurrentFormat = 6;
void ESM::SavedGame::load (ESMReader &esm)
{

@ -108,8 +108,6 @@ namespace Interpreter
virtual void setMemberFloat (const std::string& id, const std::string& name, float value, bool global)
= 0;
virtual std::string getTargetId() const = 0;
};
}

@ -26,7 +26,7 @@ namespace Interpreter
{
std::string name = runtime.getStringLiteral (runtime[0].mInteger);
runtime.pop();
runtime.getContext().startScript (name, runtime.getContext().getTargetId());
runtime.getContext().startScript (name);
}
};

Loading…
Cancel
Save