pull/196/head
scrawl 11 years ago
commit 45af34d189

@ -74,9 +74,6 @@ option(BUILD_OPENCS "build OpenMW Construction Set" ON)
option(BUILD_WITH_CODE_COVERAGE "Enable code coverage with gconv" OFF)
option(BUILD_UNITTESTS "Enable Unittests with Google C++ Unittest ang GMock frameworks" OFF)
# Sound source selection
option(USE_FFMPEG "use ffmpeg for sound" ON)
# OS X deployment
option(OPENMW_OSX_DEPLOYMENT OFF)
@ -138,32 +135,10 @@ set(OPENMW_LIBS ${OENGINE_ALL})
set(OPENMW_LIBS_HEADER)
# Sound setup
set(GOT_SOUND_INPUT 0)
set(SOUND_INPUT_INCLUDES "")
set(SOUND_INPUT_LIBRARY "")
set(SOUND_DEFINE "")
if (USE_FFMPEG)
set(FFmpeg_FIND_COMPONENTS AVCODEC AVFORMAT AVUTIL SWSCALE)
find_package(FFmpeg)
if (FFMPEG_FOUND)
set(SOUND_INPUT_INCLUDES ${SOUND_INPUT_INCLUDES} ${FFMPEG_INCLUDE_DIRS})
set(SOUND_INPUT_LIBRARY ${SOUND_INPUT_LIBRARY} ${FFMPEG_LIBRARIES} ${SWSCALE_LIBRARIES})
set(SOUND_DEFINE ${SOUND_DEFINE} -DOPENMW_USE_FFMPEG)
set(GOT_SOUND_INPUT 1)
endif (FFMPEG_FOUND)
endif (USE_FFMPEG)
if (NOT GOT_SOUND_INPUT)
message(WARNING "--------------------")
message(WARNING "Failed to find any sound input packages")
message(WARNING "--------------------")
endif (NOT GOT_SOUND_INPUT)
if (NOT FFMPEG_FOUND)
message(WARNING "--------------------")
message(WARNING "FFmpeg not found, video playback will be disabled")
message(WARNING "--------------------")
endif (NOT FFMPEG_FOUND)
set(FFmpeg_FIND_COMPONENTS AVCODEC AVFORMAT AVUTIL SWSCALE)
find_package(FFmpeg REQUIRED)
set(SOUND_INPUT_INCLUDES ${FFMPEG_INCLUDE_DIRS})
set(SOUND_INPUT_LIBRARY ${FFMPEG_LIBRARIES} ${SWSCALE_LIBRARIES})
# TinyXML
option(USE_SYSTEM_TINYXML "Use system TinyXML library instead of internal." OFF)

@ -9,7 +9,7 @@ opencs_units (model/doc
)
opencs_units_noqt (model/doc
stage savingstate savingstages
stage savingstate savingstages blacklist
)
opencs_hdrs_noqt (model/doc

@ -86,7 +86,11 @@ std::pair<Files::PathContainer, std::vector<std::string> > CS::Editor::readConfi
("encoding", boost::program_options::value<std::string>()->default_value("win1252"))
("resources", boost::program_options::value<std::string>()->default_value("resources"))
("fallback-archive", boost::program_options::value<std::vector<std::string> >()->
default_value(std::vector<std::string>(), "fallback-archive")->multitoken());
default_value(std::vector<std::string>(), "fallback-archive")->multitoken())
("script-blacklist", boost::program_options::value<std::vector<std::string> >()->default_value(std::vector<std::string>(), "")
->multitoken(), "exclude specified script from the verifier (if the use of the blacklist is enabled)")
("script-blacklist-use", boost::program_options::value<bool>()->implicit_value(true)
->default_value(true), "enable script blacklisting");
boost::program_options::notify(variables);
@ -97,6 +101,10 @@ std::pair<Files::PathContainer, std::vector<std::string> > CS::Editor::readConfi
mDocumentManager.setResourceDir (mResources = variables["resources"].as<std::string>());
if (variables["script-blacklist-use"].as<bool>())
mDocumentManager.setBlacklistedScripts (
variables["script-blacklist"].as<std::vector<std::string> >());
mFsStrict = variables["fs-strict"].as<bool>();
Files::PathContainer dataDirs, dataLocal;

@ -0,0 +1,31 @@
#include "blacklist.hpp"
#include <algorithm>
#include <components/misc/stringops.hpp>
bool CSMDoc::Blacklist::isBlacklisted (const CSMWorld::UniversalId& id) const
{
std::map<CSMWorld::UniversalId::Type, std::vector<std::string> >::const_iterator iter =
mIds.find (id.getType());
if (iter==mIds.end())
return false;
return std::binary_search (iter->second.begin(), iter->second.end(),
Misc::StringUtils::lowerCase (id.getId()));
}
void CSMDoc::Blacklist::add (CSMWorld::UniversalId::Type type,
const std::vector<std::string>& ids)
{
std::vector<std::string>& list = mIds[type];
int size = list.size();
list.resize (size+ids.size());
std::transform (ids.begin(), ids.end(), list.begin()+size, Misc::StringUtils::lowerCase);
std::sort (list.begin(), list.end());
}

@ -0,0 +1,25 @@
#ifndef CSM_DOC_BLACKLIST_H
#define CSM_DOC_BLACKLIST_H
#include <map>
#include <vector>
#include <string>
#include "../world/universalid.hpp"
namespace CSMDoc
{
/// \brief ID blacklist sorted by UniversalId type
class Blacklist
{
std::map<CSMWorld::UniversalId::Type, std::vector<std::string> > mIds;
public:
bool isBlacklisted (const CSMWorld::UniversalId& id) const;
void add (CSMWorld::UniversalId::Type type, const std::vector<std::string>& ids);
};
}
#endif

@ -2205,9 +2205,10 @@ void CSMDoc::Document::createBase()
CSMDoc::Document::Document (const Files::ConfigurationManager& configuration,
const std::vector< boost::filesystem::path >& files, bool new_,
const boost::filesystem::path& savePath, const boost::filesystem::path& resDir,
ToUTF8::FromType encoding, const CSMWorld::ResourcesManager& resourcesManager)
ToUTF8::FromType encoding, const CSMWorld::ResourcesManager& resourcesManager,
const std::vector<std::string>& blacklistedScripts)
: mSavePath (savePath), mContentFiles (files), mNew (new_), mData (encoding, resourcesManager),
mTools (mData), mResDir(resDir),
mTools (*this), mResDir(resDir),
mProjectPath ((configuration.getUserDataPath() / "projects") /
(savePath.filename().string() + ".project")),
mSaving (*this, mProjectPath, encoding)
@ -2239,6 +2240,8 @@ CSMDoc::Document::Document (const Files::ConfigurationManager& configuration,
createBase();
}
mBlacklist.add (CSMWorld::UniversalId::Type_Script, blacklistedScripts);
addOptionalGmsts();
addOptionalGlobals();
@ -2358,6 +2361,13 @@ CSMTools::ReportModel *CSMDoc::Document::getReport (const CSMWorld::UniversalId&
return mTools.getReport (id);
}
bool CSMDoc::Document::isBlacklisted (const CSMWorld::UniversalId& id)
const
{
return mBlacklist.isBlacklisted (id);
}
void CSMDoc::Document::progress (int current, int max, int type)
{
emit progress (current, max, type, 1, this);

@ -17,6 +17,7 @@
#include "state.hpp"
#include "saving.hpp"
#include "blacklist.hpp"
class QAbstractItemModel;
@ -52,6 +53,7 @@ namespace CSMDoc
boost::filesystem::path mProjectPath;
Saving mSaving;
boost::filesystem::path mResDir;
Blacklist mBlacklist;
// It is important that the undo stack is declared last, because on desctruction it fires a signal, that is connected to a slot, that is
// using other member variables. Unfortunately this connection is cut only in the QObject destructor, which is way too late.
@ -78,7 +80,8 @@ namespace CSMDoc
Document (const Files::ConfigurationManager& configuration,
const std::vector< boost::filesystem::path >& files, bool new_,
const boost::filesystem::path& savePath, const boost::filesystem::path& resDir,
ToUTF8::FromType encoding, const CSMWorld::ResourcesManager& resourcesManager);
ToUTF8::FromType encoding, const CSMWorld::ResourcesManager& resourcesManager,
const std::vector<std::string>& blacklistedScripts);
~Document();
@ -110,6 +113,8 @@ namespace CSMDoc
CSMTools::ReportModel *getReport (const CSMWorld::UniversalId& id);
///< The ownership of the returned report is not transferred.
bool isBlacklisted (const CSMWorld::UniversalId& id) const;
signals:
void stateChanged (int state, CSMDoc::Document *document);

@ -52,7 +52,7 @@ CSMDoc::DocumentManager::~DocumentManager()
void CSMDoc::DocumentManager::addDocument (const std::vector<boost::filesystem::path>& files, const boost::filesystem::path& savePath,
bool new_)
{
Document *document = new Document (mConfiguration, files, new_, savePath, mResDir, mEncoding, mResourcesManager);
Document *document = new Document (mConfiguration, files, new_, savePath, mResDir, mEncoding, mResourcesManager, mBlacklistedScripts);
mDocuments.push_back (document);
@ -85,6 +85,11 @@ void CSMDoc::DocumentManager::setEncoding (ToUTF8::FromType encoding)
mEncoding = encoding;
}
void CSMDoc::DocumentManager::setBlacklistedScripts (const std::vector<std::string>& scriptIds)
{
mBlacklistedScripts = scriptIds;
}
void CSMDoc::DocumentManager::listResources()
{
mResourcesManager.listResources();

@ -34,6 +34,7 @@ namespace CSMDoc
Loader mLoader;
ToUTF8::FromType mEncoding;
CSMWorld::ResourcesManager mResourcesManager;
std::vector<std::string> mBlacklistedScripts;
DocumentManager (const DocumentManager&);
DocumentManager& operator= (const DocumentManager&);
@ -53,6 +54,8 @@ namespace CSMDoc
void setEncoding (ToUTF8::FromType encoding);
void setBlacklistedScripts (const std::vector<std::string>& scriptIds);
/// Ask OGRE for a list of available resources.
void listResources();

@ -7,6 +7,8 @@
#include <components/compiler/exception.hpp>
#include <components/compiler/extensions0.hpp>
#include "../doc/document.hpp"
#include "../world/data.hpp"
void CSMTools::ScriptCheckStage::report (const std::string& message, const Compiler::TokenLoc& loc,
@ -37,8 +39,8 @@ void CSMTools::ScriptCheckStage::report (const std::string& message, Type type)
(type==ErrorMessage ? "error: " : "warning: ") + message));
}
CSMTools::ScriptCheckStage::ScriptCheckStage (const CSMWorld::Data& data)
: mData (data), mContext (data), mMessages (0)
CSMTools::ScriptCheckStage::ScriptCheckStage (const CSMDoc::Document& document)
: mDocument (document), mContext (document.getData()), mMessages (0)
{
/// \todo add an option to configure warning mode
setWarningsMode (0);
@ -53,18 +55,25 @@ int CSMTools::ScriptCheckStage::setup()
mMessages = 0;
mId.clear();
return mData.getScripts().getSize();
return mDocument.getData().getScripts().getSize();
}
void CSMTools::ScriptCheckStage::perform (int stage, Messages& messages)
{
mId = mDocument.getData().getScripts().getId (stage);
if (mDocument.isBlacklisted (
CSMWorld::UniversalId (CSMWorld::UniversalId::Type_Script, mId)))
return;
mMessages = &messages;
mId = mData.getScripts().getId (stage);
try
{
mFile = mData.getScripts().getRecord (stage).get().mId;
std::istringstream input (mData.getScripts().getRecord (stage).get().mScriptText);
const CSMWorld::Data& data = mDocument.getData();
mFile = data.getScripts().getRecord (stage).get().mId;
std::istringstream input (data.getScripts().getRecord (stage).get().mScriptText);
Compiler::Scanner scanner (*this, input, mContext.getExtensions());

@ -8,12 +8,17 @@
#include "../world/scriptcontext.hpp"
namespace CSMDoc
{
class Document;
}
namespace CSMTools
{
/// \brief VerifyStage: make sure that scripts compile
class ScriptCheckStage : public CSMDoc::Stage, private Compiler::ErrorHandler
{
const CSMWorld::Data& mData;
const CSMDoc::Document& mDocument;
Compiler::Extensions mExtensions;
CSMWorld::ScriptContext mContext;
std::string mId;
@ -28,7 +33,7 @@ namespace CSMTools
public:
ScriptCheckStage (const CSMWorld::Data& data);
ScriptCheckStage (const CSMDoc::Document& document);
virtual int setup();
///< \return number of steps

@ -5,6 +5,7 @@
#include "../doc/state.hpp"
#include "../doc/operation.hpp"
#include "../doc/document.hpp"
#include "../world/data.hpp"
#include "../world/universalid.hpp"
@ -80,13 +81,14 @@ CSMDoc::Operation *CSMTools::Tools::getVerifier()
mVerifier->appendStage (new ReferenceableCheckStage (mData.getReferenceables().getDataSet(), mData.getRaces(), mData.getClasses(), mData.getFactions()));
mVerifier->appendStage (new ScriptCheckStage (mData));
mVerifier->appendStage (new ScriptCheckStage (mDocument));
}
return mVerifier;
}
CSMTools::Tools::Tools (CSMWorld::Data& data) : mData (data), mVerifier (0), mNextReportNumber (0)
CSMTools::Tools::Tools (CSMDoc::Document& document)
: mDocument (document), mData (document.getData()), mVerifier (0), mNextReportNumber (0)
{
// index 0: load error log
mReports.insert (std::make_pair (mNextReportNumber++, new ReportModel));

@ -14,6 +14,7 @@ namespace CSMWorld
namespace CSMDoc
{
class Operation;
class Document;
}
namespace CSMTools
@ -24,6 +25,7 @@ namespace CSMTools
{
Q_OBJECT
CSMDoc::Document& mDocument;
CSMWorld::Data& mData;
CSMDoc::Operation *mVerifier;
std::map<int, ReportModel *> mReports;
@ -44,7 +46,7 @@ namespace CSMTools
public:
Tools (CSMWorld::Data& data);
Tools (CSMDoc::Document& document);
virtual ~Tools();

@ -99,7 +99,6 @@ add_executable(openmw
# Sound stuff - here so CMake doesn't stupidly recompile EVERYTHING
# when we change the backend.
include_directories(${SOUND_INPUT_INCLUDES} ${BULLET_INCLUDE_DIRS})
add_definitions(${SOUND_DEFINE})
target_link_libraries(openmw
${OGRE_LIBRARIES}

@ -180,6 +180,7 @@ OMW::Engine::Engine(Files::ConfigurationManager& configurationManager)
, mEncoder(NULL)
, mActivationDistanceOverride(-1)
, mGrab(true)
, mScriptBlacklistUse (true)
{
std::srand ( std::time(NULL) );
@ -406,7 +407,8 @@ void OMW::Engine::prepareEngine (Settings::Manager & settings)
mScriptContext->setExtensions (&mExtensions);
mEnvironment.setScriptManager (new MWScript::ScriptManager (MWBase::Environment::get().getWorld()->getStore(),
mVerboseScripts, *mScriptContext, mWarningsMode));
mVerboseScripts, *mScriptContext, mWarningsMode,
mScriptBlacklistUse ? mScriptBlacklist : std::vector<std::string>()));
// Create game mechanics system
MWMechanics::MechanicsManager* mechanics = new MWMechanics::MechanicsManager;
@ -565,3 +567,13 @@ void OMW::Engine::setWarningsMode (int mode)
{
mWarningsMode = mode;
}
void OMW::Engine::setScriptBlacklist (const std::vector<std::string>& list)
{
mScriptBlacklist = list;
}
void OMW::Engine::setScriptBlacklistUse (bool use)
{
mScriptBlacklistUse = use;
}

@ -89,6 +89,8 @@ namespace OMW
Files::Collections mFileCollections;
bool mFSStrict;
Translation::Storage mTranslationDataStorage;
std::vector<std::string> mScriptBlacklist;
bool mScriptBlacklistUse;
// not implemented
Engine (const Engine&);
@ -181,6 +183,10 @@ namespace OMW
void setWarningsMode (int mode);
void setScriptBlacklist (const std::vector<std::string>& list);
void setScriptBlacklistUse (bool use);
private:
Files::ConfigurationManager& mCfgMgr;
};

@ -144,6 +144,12 @@ bool parseOptions (int argc, char** argv, OMW::Engine& engine, Files::Configurat
"\t1 - show warning but consider script as correctly compiled anyway\n"
"\t2 - treat warnings as errors")
("script-blacklist", bpo::value<StringsVector>()->default_value(StringsVector(), "")
->multitoken(), "ignore the specified script (if the use of the blacklist is enabled)")
("script-blacklist-use", bpo::value<bool>()->implicit_value(true)
->default_value(true), "enable script blacklisting")
("skip-menu", bpo::value<bool>()->implicit_value(true)
->default_value(false), "skip main menu on game startup")
@ -184,6 +190,14 @@ bool parseOptions (int argc, char** argv, OMW::Engine& engine, Files::Configurat
if (variables.count ("version"))
{
std::cout << "OpenMW version " << OPENMW_VERSION << std::endl;
std::string rev = OPENMW_VERSION_COMMITHASH;
std::string tag = OPENMW_VERSION_TAGHASH;
if (!rev.empty() && !tag.empty())
{
rev = rev.substr(0, 10);
std::cout << "Revision " << rev << std::endl;
}
run = false;
}
@ -241,15 +255,19 @@ bool parseOptions (int argc, char** argv, OMW::Engine& engine, Files::Configurat
engine.setCell(variables["start"].as<std::string>());
engine.setSkipMenu (variables["skip-menu"].as<bool>());
// other settings
engine.setSoundUsage(!variables["no-sound"].as<bool>());
engine.setScriptsVerbosity(variables["script-verbose"].as<bool>());
// scripts
engine.setCompileAll(variables["script-all"].as<bool>());
engine.setFallbackValues(variables["fallback"].as<FallbackMap>().mMap);
engine.setScriptsVerbosity(variables["script-verbose"].as<bool>());
engine.setScriptConsoleMode (variables["script-console"].as<bool>());
engine.setStartupScript (variables["script-run"].as<std::string>());
engine.setActivationDistanceOverride (variables["activate-dist"].as<int>());
engine.setWarningsMode (variables["script-warn"].as<int>());
engine.setScriptBlacklist (variables["script-blacklist"].as<StringsVector>());
engine.setScriptBlacklistUse (variables["script-blacklist-use"].as<bool>());
// other settings
engine.setSoundUsage(!variables["no-sound"].as<bool>());
engine.setFallbackValues(variables["fallback"].as<FallbackMap>().mMap);
engine.setActivationDistanceOverride (variables["activate-dist"].as<int>());
return true;
}

@ -46,17 +46,11 @@ namespace MWBase
///< Compile all scripts
/// \return count, success
virtual Compiler::Locals& getLocals (const std::string& name) = 0;
virtual const Compiler::Locals& getLocals (const std::string& name) = 0;
///< Return locals for script \a name.
virtual MWScript::GlobalScripts& getGlobalScripts() = 0;
virtual int getLocalIndex (const std::string& scriptId, const std::string& variable,
char type) = 0;
///< Return index of the variable of the given name and type in the given script. Will
/// throw an exception, if there is no such script or variable or the type does not match.
};
};
}
#endif

@ -25,6 +25,11 @@
namespace MWClass
{
std::string Activator::getId (const MWWorld::Ptr& ptr) const
{
return ptr.get<ESM::Activator>()->mBase->mId;
}
void Activator::insertObjectRendering (const MWWorld::Ptr& ptr, MWRender::RenderingInterface& renderingInterface) const
{
const std::string model = getModel(ptr);

@ -13,6 +13,9 @@ namespace MWClass
public:
/// Return ID of \a ptr
virtual std::string getId (const MWWorld::Ptr& ptr) const;
virtual void insertObjectRendering (const MWWorld::Ptr& ptr, MWRender::RenderingInterface& renderingInterface) const;
///< Add reference into a cell for rendering

@ -21,6 +21,11 @@
namespace MWClass
{
std::string Apparatus::getId (const MWWorld::Ptr& ptr) const
{
return ptr.get<ESM::Apparatus>()->mBase->mId;
}
void Apparatus::insertObjectRendering (const MWWorld::Ptr& ptr, MWRender::RenderingInterface& renderingInterface) const
{
const std::string model = getModel(ptr);

@ -13,6 +13,9 @@ namespace MWClass
public:
/// Return ID of \a ptr
virtual std::string getId (const MWWorld::Ptr& ptr) const;
virtual float getWeight (const MWWorld::Ptr& ptr) const;
virtual void insertObjectRendering (const MWWorld::Ptr& ptr, MWRender::RenderingInterface& renderingInterface) const;

@ -25,6 +25,11 @@
namespace MWClass
{
std::string Armor::getId (const MWWorld::Ptr& ptr) const
{
return ptr.get<ESM::Armor>()->mBase->mId;
}
void Armor::insertObjectRendering (const MWWorld::Ptr& ptr, MWRender::RenderingInterface& renderingInterface) const
{
const std::string model = getModel(ptr);

@ -12,6 +12,9 @@ namespace MWClass
public:
/// Return ID of \a ptr
virtual std::string getId (const MWWorld::Ptr& ptr) const;
virtual float getWeight (const MWWorld::Ptr& ptr) const;
virtual void insertObjectRendering (const MWWorld::Ptr& ptr, MWRender::RenderingInterface& renderingInterface) const;

@ -22,6 +22,11 @@
namespace MWClass
{
std::string Book::getId (const MWWorld::Ptr& ptr) const
{
return ptr.get<ESM::Book>()->mBase->mId;
}
void Book::insertObjectRendering (const MWWorld::Ptr& ptr, MWRender::RenderingInterface& renderingInterface) const
{
const std::string model = getModel(ptr);

@ -12,6 +12,9 @@ namespace MWClass
public:
/// Return ID of \a ptr
virtual std::string getId (const MWWorld::Ptr& ptr) const;
virtual void insertObjectRendering (const MWWorld::Ptr& ptr, MWRender::RenderingInterface& renderingInterface) const;
///< Add reference into a cell for rendering

@ -22,6 +22,11 @@
namespace MWClass
{
std::string Clothing::getId (const MWWorld::Ptr& ptr) const
{
return ptr.get<ESM::Clothing>()->mBase->mId;
}
void Clothing::insertObjectRendering (const MWWorld::Ptr& ptr, MWRender::RenderingInterface& renderingInterface) const
{
const std::string model = getModel(ptr);

@ -12,6 +12,9 @@ namespace MWClass
public:
/// Return ID of \a ptr
virtual std::string getId (const MWWorld::Ptr& ptr) const;
virtual void insertObjectRendering (const MWWorld::Ptr& ptr, MWRender::RenderingInterface& renderingInterface) const;
///< Add reference into a cell for rendering

@ -43,6 +43,11 @@ namespace
namespace MWClass
{
std::string Container::getId (const MWWorld::Ptr& ptr) const
{
return ptr.get<ESM::Container>()->mBase->mId;
}
void Container::ensureCustomData (const MWWorld::Ptr& ptr) const
{
if (!ptr.getRefData().getCustomData())

@ -15,6 +15,9 @@ namespace MWClass
public:
/// Return ID of \a ptr
virtual std::string getId (const MWWorld::Ptr& ptr) const;
virtual void insertObjectRendering (const MWWorld::Ptr& ptr, MWRender::RenderingInterface& renderingInterface) const;
///< Add reference into a cell for rendering

@ -27,6 +27,11 @@ namespace
namespace MWClass
{
std::string CreatureLevList::getId (const MWWorld::Ptr& ptr) const
{
return ptr.get<ESM::CreatureLevList>()->mBase->mId;
}
std::string CreatureLevList::getName (const MWWorld::Ptr& ptr) const
{
return "";

@ -11,6 +11,9 @@ namespace MWClass
public:
/// Return ID of \a ptr
virtual std::string getId (const MWWorld::Ptr& ptr) const;
virtual std::string getName (const MWWorld::Ptr& ptr) const;
///< \return name (the one that is to be presented to the user; not the internal one);
/// can return an empty string.

@ -42,6 +42,11 @@ namespace
namespace MWClass
{
std::string Door::getId (const MWWorld::Ptr& ptr) const
{
return ptr.get<ESM::Door>()->mBase->mId;
}
void Door::insertObjectRendering (const MWWorld::Ptr& ptr, MWRender::RenderingInterface& renderingInterface) const
{
const std::string model = getModel(ptr);

@ -16,6 +16,9 @@ namespace MWClass
public:
/// Return ID of \a ptr
virtual std::string getId (const MWWorld::Ptr& ptr) const;
virtual void insertObjectRendering (const MWWorld::Ptr& ptr, MWRender::RenderingInterface& renderingInterface) const;
///< Add reference into a cell for rendering

@ -5,6 +5,11 @@
namespace MWClass
{
std::string ItemLevList::getId (const MWWorld::Ptr& ptr) const
{
return ptr.get<ESM::ItemLevList>()->mBase->mId;
}
std::string ItemLevList::getName (const MWWorld::Ptr& ptr) const
{
return "";

@ -9,6 +9,9 @@ namespace MWClass
{
public:
/// Return ID of \a ptr
virtual std::string getId (const MWWorld::Ptr& ptr) const;
virtual std::string getName (const MWWorld::Ptr& ptr) const;
///< \return name (the one that is to be presented to the user; not the internal one);
/// can return an empty string.

@ -47,6 +47,11 @@ namespace
namespace MWClass
{
std::string Light::getId (const MWWorld::Ptr& ptr) const
{
return ptr.get<ESM::Light>()->mBase->mId;
}
void Light::insertObjectRendering (const MWWorld::Ptr& ptr, MWRender::RenderingInterface& renderingInterface) const
{
const std::string model = getModel(ptr);

@ -14,6 +14,9 @@ namespace MWClass
public:
/// Return ID of \a ptr
virtual std::string getId (const MWWorld::Ptr& ptr) const;
virtual void insertObjectRendering (const MWWorld::Ptr& ptr, MWRender::RenderingInterface& renderingInterface) const;
///< Add reference into a cell for rendering

@ -22,6 +22,11 @@
namespace MWClass
{
std::string Lockpick::getId (const MWWorld::Ptr& ptr) const
{
return ptr.get<ESM::Lockpick>()->mBase->mId;
}
void Lockpick::insertObjectRendering (const MWWorld::Ptr& ptr, MWRender::RenderingInterface& renderingInterface) const
{
const std::string model = getModel(ptr);

@ -12,6 +12,9 @@ namespace MWClass
public:
/// Return ID of \a ptr
virtual std::string getId (const MWWorld::Ptr& ptr) const;
virtual void insertObjectRendering (const MWWorld::Ptr& ptr, MWRender::RenderingInterface& renderingInterface) const;
///< Add reference into a cell for rendering

@ -38,6 +38,11 @@ bool isGold (const MWWorld::Ptr& ptr)
namespace MWClass
{
std::string Miscellaneous::getId (const MWWorld::Ptr& ptr) const
{
return ptr.get<ESM::Miscellaneous>()->mBase->mId;
}
void Miscellaneous::insertObjectRendering (const MWWorld::Ptr& ptr, MWRender::RenderingInterface& renderingInterface) const
{
const std::string model = getModel(ptr);

@ -12,6 +12,9 @@ namespace MWClass
public:
/// Return ID of \a ptr
virtual std::string getId (const MWWorld::Ptr& ptr) const;
virtual void insertObjectRendering (const MWWorld::Ptr& ptr, MWRender::RenderingInterface& renderingInterface) const;
///< Add reference into a cell for rendering

@ -24,6 +24,11 @@
namespace MWClass
{
std::string Potion::getId (const MWWorld::Ptr& ptr) const
{
return ptr.get<ESM::Potion>()->mBase->mId;
}
void Potion::insertObjectRendering (const MWWorld::Ptr& ptr, MWRender::RenderingInterface& renderingInterface) const
{
const std::string model = getModel(ptr);

@ -12,6 +12,9 @@ namespace MWClass
public:
/// Return ID of \a ptr
virtual std::string getId (const MWWorld::Ptr& ptr) const;
virtual void insertObjectRendering (const MWWorld::Ptr& ptr, MWRender::RenderingInterface& renderingInterface) const;
///< Add reference into a cell for rendering

@ -22,6 +22,11 @@
namespace MWClass
{
std::string Probe::getId (const MWWorld::Ptr& ptr) const
{
return ptr.get<ESM::Probe>()->mBase->mId;
}
void Probe::insertObjectRendering (const MWWorld::Ptr& ptr, MWRender::RenderingInterface& renderingInterface) const
{
const std::string model = getModel(ptr);

@ -12,6 +12,9 @@ namespace MWClass
public:
/// Return ID of \a ptr
virtual std::string getId (const MWWorld::Ptr& ptr) const;
virtual void insertObjectRendering (const MWWorld::Ptr& ptr, MWRender::RenderingInterface& renderingInterface) const;
///< Add reference into a cell for rendering

@ -21,6 +21,11 @@
namespace MWClass
{
std::string Repair::getId (const MWWorld::Ptr& ptr) const
{
return ptr.get<ESM::Repair>()->mBase->mId;
}
void Repair::insertObjectRendering (const MWWorld::Ptr& ptr, MWRender::RenderingInterface& renderingInterface) const
{
const std::string model = getModel(ptr);

@ -12,6 +12,9 @@ namespace MWClass
public:
/// Return ID of \a ptr
virtual std::string getId (const MWWorld::Ptr& ptr) const;
virtual void insertObjectRendering (const MWWorld::Ptr& ptr, MWRender::RenderingInterface& renderingInterface) const;
///< Add reference into a cell for rendering

@ -12,6 +12,11 @@
namespace MWClass
{
std::string Static::getId (const MWWorld::Ptr& ptr) const
{
return ptr.get<ESM::Static>()->mBase->mId;
}
void Static::insertObjectRendering (const MWWorld::Ptr& ptr, MWRender::RenderingInterface& renderingInterface) const
{
MWWorld::LiveCellRef<ESM::Static> *ref =

@ -12,6 +12,9 @@ namespace MWClass
public:
/// Return ID of \a ptr
virtual std::string getId (const MWWorld::Ptr& ptr) const;
virtual void insertObjectRendering (const MWWorld::Ptr& ptr, MWRender::RenderingInterface& renderingInterface) const;
///< Add reference into a cell for rendering

@ -1,11 +1,14 @@
#include "filter.hpp"
#include <components/compiler/locals.hpp>
#include "../mwbase/environment.hpp"
#include "../mwbase/world.hpp"
#include "../mwbase/journal.hpp"
#include "../mwbase/mechanicsmanager.hpp"
#include "../mwbase/dialoguemanager.hpp"
#include "../mwbase/scriptmanager.hpp"
#include "../mwworld/class.hpp"
#include "../mwworld/inventorystore.hpp"
@ -197,33 +200,28 @@ bool MWDialogue::Filter::testSelectStructNumeric (const SelectWrapper& select) c
if (scriptName.empty())
return false; // no script
const ESM::Script *script =
MWBase::Environment::get().getWorld()->getStore().get<ESM::Script>().find (scriptName);
std::string name = Misc::StringUtils::lowerCase (select.getName());
std::string name = select.getName();
const Compiler::Locals& localDefs =
MWBase::Environment::get().getScriptManager()->getLocals (scriptName);
int i = 0;
char type = localDefs.getType (name);
for (; i<static_cast<int> (script->mVarNames.size()); ++i)
if (Misc::StringUtils::ciEqual(script->mVarNames[i], name))
break;
if (type==' ')
return false; // script does not have a variable of this name.
if (i>=static_cast<int> (script->mVarNames.size()))
return false; // script does not have a variable of this name
int index = localDefs.getIndex (name);
const MWScript::Locals& locals = mActor.getRefData().getLocals();
if (i<script->mData.mNumShorts)
return select.selectCompare (static_cast<int> (locals.mShorts[i]));
i -= script->mData.mNumShorts;
if (i<script->mData.mNumLongs)
return select.selectCompare (locals.mLongs[i]);
i -= script->mData.mNumLongs;
switch (type)
{
case 's': return select.selectCompare (static_cast<int> (locals.mShorts[index]));
case 'l': return select.selectCompare (locals.mLongs[index]);
case 'f': return select.selectCompare (locals.mFloats[index]);
}
return select.selectCompare (locals.mFloats.at (i));
throw std::logic_error ("unknown local variable type in dialogue filter");
}
case SelectWrapper::Function_PcHealthPercent:
@ -463,20 +461,10 @@ bool MWDialogue::Filter::getSelectStructBoolean (const SelectWrapper& select) co
// This actor has no attached script, so there is no local variable
return true;
const ESM::Script *script =
MWBase::Environment::get().getWorld()->getStore().get<ESM::Script>().find (scriptName);
std::string name = select.getName();
int i = 0;
for (; i < static_cast<int> (script->mVarNames.size()); ++i)
if (Misc::StringUtils::ciEqual(script->mVarNames[i], name))
break;
if (i >= static_cast<int> (script->mVarNames.size()))
return true; // script does not have a variable of this name
const Compiler::Locals& localDefs =
MWBase::Environment::get().getScriptManager()->getLocals (scriptName);
return false;
return localDefs.getIndex (Misc::StringUtils::lowerCase (select.getName()))==-1;
}
case SelectWrapper::Function_SameGender:

@ -22,6 +22,9 @@ namespace MWMechanics
{
static const int COUNT_BEFORE_RESET = 200; // TODO: maybe no longer needed
static const float DOOR_CHECK_INTERVAL = 1.5f;
static const float REACTION_INTERVAL = 0.25f;
static const int GREETING_SHOULD_START = 4; //how many reaction intervals should pass before NPC can greet player
static const int GREETING_SHOULD_END = 10;
AiWander::AiWander(int distance, int duration, int timeOfDay, const std::vector<unsigned char>& idle, bool repeat):
mDistance(distance), mDuration(duration), mTimeOfDay(timeOfDay), mIdle(idle), mRepeat(repeat)
@ -43,7 +46,8 @@ namespace MWMechanics
mReaction = 0;
mRotate = false;
mTargetAngle = 0;
mSaidGreeting = false;
mSaidGreeting = Greet_None;
greetingTimer = 0;
mHasReturnPosition = false;
mReturnPosition = Ogre::Vector3(0,0,0);
@ -221,14 +225,14 @@ namespace MWMechanics
}
mReaction += duration;
if(mReaction < 0.25f) // FIXME: hard coded constant
if(mReaction < REACTION_INTERVAL)
{
return false;
}
else
mReaction = 0;
// NOTE: everything below get updated every 0.25 seconds
// NOTE: everything below get updated every REACTION_INTERVAL seconds
MWBase::World *world = MWBase::Environment::get().getWorld();
if(mDuration)
@ -407,7 +411,7 @@ namespace MWMechanics
}
// Allow interrupting a walking actor to trigger a greeting
if(mIdleNow || (mWalking && !mObstacleCheck.isNormalState() && mDistance))
if(mIdleNow || mWalking)
{
// Play a random voice greeting if the player gets too close
int hello = cStats.getAiSetting(CreatureStats::AI_Hello).getModified();
@ -421,9 +425,25 @@ namespace MWMechanics
Ogre::Vector3 playerPos(player.getRefData().getPosition().pos);
Ogre::Vector3 actorPos(actor.getRefData().getPosition().pos);
float playerDistSqr = playerPos.squaredDistance(actorPos);
if(playerDistSqr <= helloDistance*helloDistance)
if (mSaidGreeting == Greet_None)
{
if (playerDistSqr <= helloDistance*helloDistance)
greetingTimer++;
// TODO: check if actor is aware / has line of sight
if (greetingTimer >= GREETING_SHOULD_START)
{
mSaidGreeting = Greet_InProgress;
MWBase::Environment::get().getDialogueManager()->say(actor, "hello");
greetingTimer = 0;
}
}
if(mSaidGreeting == Greet_InProgress)
{
greetingTimer++;
if(mWalking)
{
stopWalking(actor);
@ -449,31 +469,25 @@ namespace MWMechanics
mRotate = true;
}
}
}
if (!mSaidGreeting)
{
// TODO: check if actor is aware / has line of sight
if (playerDistSqr <= helloDistance*helloDistance
// Only play a greeting if the player is not moving
&& Ogre::Vector3(player.getClass().getMovementSettings(player).mPosition).squaredLength() == 0)
if (greetingTimer >= GREETING_SHOULD_END)
{
mSaidGreeting = true;
MWBase::Environment::get().getDialogueManager()->say(actor, "hello");
mSaidGreeting = Greet_Done;
greetingTimer = 0;
}
}
else
if (mSaidGreeting == MWMechanics::AiWander::Greet_Done)
{
static float fGreetDistanceReset = MWBase::Environment::get().getWorld()->getStore()
.get<ESM::GameSetting>().find("fGreetDistanceReset")->getFloat();
if (playerDistSqr >= fGreetDistanceReset*fGreetDistanceReset * iGreetDistanceMultiplier*iGreetDistanceMultiplier)
mSaidGreeting = false;
if (playerDistSqr >= fGreetDistanceReset*fGreetDistanceReset)
mSaidGreeting = Greet_None;
}
// Check if idle animation finished
// FIXME: don't stay forever
if(!checkIdle(actor, mPlayedIdle) && playerDistSqr > helloDistance*helloDistance)
if(!checkIdle(actor, mPlayedIdle) && (playerDistSqr > helloDistance*helloDistance || mSaidGreeting == MWMechanics::AiWander::Greet_Done))
{
mPlayedIdle = 0;
mIdleNow = false;

@ -62,7 +62,13 @@ namespace MWMechanics
std::vector<unsigned char> mIdle;
bool mRepeat;
bool mSaidGreeting;
enum GreetingState {
Greet_None,
Greet_InProgress,
Greet_Done
};
GreetingState mSaidGreeting;
int greetingTimer;
bool mHasReturnPosition; // NOTE: Could be removed if mReturnPosition was initialized to actor position,
// if we had the actor in the AiWander constructor...

@ -26,8 +26,6 @@ typedef SSIZE_T ssize_t;
namespace MWRender
{
#ifdef OPENMW_USE_FFMPEG
extern "C"
{
#include <libavcodec/avcodec.h>
@ -1073,27 +1071,6 @@ void VideoState::deinit()
}
}
#else // defined OPENMW_USE_FFMPEG
class VideoState
{
public:
VideoState() { }
void init(const std::string& resourceName)
{
throw std::runtime_error("FFmpeg not supported, cannot play \""+resourceName+"\"");
}
void deinit() { }
void close() { }
bool update()
{ return false; }
};
#endif // defined OPENMW_USE_FFMPEG
VideoPlayer::VideoPlayer()
: mState(NULL)

@ -15,61 +15,69 @@
namespace MWScript
{
GlobalScriptDesc::GlobalScriptDesc() : mRunning (false) {}
GlobalScripts::GlobalScripts (const MWWorld::ESMStore& store)
: mStore (store)
{
addStartup();
}
{}
void GlobalScripts::addScript (const std::string& name)
void GlobalScripts::addScript (const std::string& name, const std::string& targetId)
{
std::map<std::string, std::pair<bool, Locals> >::iterator iter =
std::map<std::string, GlobalScriptDesc>::iterator iter =
mScripts.find (::Misc::StringUtils::lowerCase (name));
if (iter==mScripts.end())
{
if (const ESM::Script *script = mStore.get<ESM::Script>().find (name))
{
Locals locals;
locals.configure (*script);
GlobalScriptDesc desc;
desc.mRunning = true;
desc.mLocals.configure (*script);
desc.mId = targetId;
mScripts.insert (std::make_pair (name, std::make_pair (true, locals)));
mScripts.insert (std::make_pair (name, desc));
}
}
else
iter->second.first = true;
else if (!iter->second.mRunning)
{
iter->second.mRunning = true;
iter->second.mId = targetId;
}
}
void GlobalScripts::removeScript (const std::string& name)
{
std::map<std::string, std::pair<bool, Locals> >::iterator iter =
std::map<std::string, GlobalScriptDesc>::iterator iter =
mScripts.find (::Misc::StringUtils::lowerCase (name));
if (iter!=mScripts.end())
iter->second.first = false;
iter->second.mRunning = false;
}
bool GlobalScripts::isRunning (const std::string& name) const
{
std::map<std::string, std::pair<bool, Locals> >::const_iterator iter =
std::map<std::string, GlobalScriptDesc>::const_iterator iter =
mScripts.find (::Misc::StringUtils::lowerCase (name));
if (iter==mScripts.end())
return false;
return iter->second.first;
return iter->second.mRunning;
}
void GlobalScripts::run()
{
for (std::map<std::string, std::pair<bool, Locals> >::iterator iter (mScripts.begin());
for (std::map<std::string, GlobalScriptDesc>::iterator iter (mScripts.begin());
iter!=mScripts.end(); ++iter)
{
if (iter->second.first)
if (iter->second.mRunning)
{
MWWorld::Ptr ptr;
MWScript::InterpreterContext interpreterContext (
&iter->second.second, MWWorld::Ptr());
&iter->second.mLocals, MWWorld::Ptr(), iter->second.mId);
MWBase::Environment::get().getScriptManager()->run (iter->first, interpreterContext);
}
}
@ -99,16 +107,18 @@ namespace MWScript
void GlobalScripts::write (ESM::ESMWriter& writer, Loading::Listener& progress) const
{
for (std::map<std::string, std::pair<bool, Locals> >::const_iterator iter (mScripts.begin());
for (std::map<std::string, GlobalScriptDesc>::const_iterator iter (mScripts.begin());
iter!=mScripts.end(); ++iter)
{
ESM::GlobalScript script;
script.mId = iter->first;
iter->second.second.write (script.mLocals, iter->first);
iter->second.mLocals.write (script.mLocals, iter->first);
script.mRunning = iter->second.first ? 1 : 0;
script.mRunning = iter->second.mRunning ? 1 : 0;
script.mTargetId = iter->second.mId;
writer.startRecord (ESM::REC_GSCR);
script.save (writer);
@ -124,25 +134,25 @@ namespace MWScript
ESM::GlobalScript script;
script.load (reader);
std::map<std::string, std::pair<bool, Locals> >::iterator iter =
std::map<std::string, GlobalScriptDesc>::iterator iter =
mScripts.find (script.mId);
if (iter==mScripts.end())
{
if (const ESM::Script *scriptRecord = mStore.get<ESM::Script>().search (script.mId))
{
std::pair<bool, Locals> data (false, Locals());
data.second.configure (*scriptRecord);
GlobalScriptDesc desc;
desc.mLocals.configure (*scriptRecord);
iter = mScripts.insert (std::make_pair (script.mId, data)).first;
iter = mScripts.insert (std::make_pair (script.mId, desc)).first;
}
else // script does not exist anymore
return true;
}
iter->second.first = script.mRunning!=0;
iter->second.second.read (script.mLocals, script.mId);
iter->second.mRunning = script.mRunning!=0;
iter->second.mLocals.read (script.mLocals, script.mId);
iter->second.mId = script.mTargetId;
return true;
}
@ -153,21 +163,19 @@ namespace MWScript
Locals& GlobalScripts::getLocals (const std::string& name)
{
std::string name2 = ::Misc::StringUtils::lowerCase (name);
std::map<std::string, std::pair<bool, Locals> >::iterator iter =
mScripts.find (name2);
std::map<std::string, GlobalScriptDesc>::iterator iter = mScripts.find (name2);
if (iter==mScripts.end())
{
if (const ESM::Script *script = mStore.get<ESM::Script>().find (name))
{
Locals locals;
locals.configure (*script);
GlobalScriptDesc desc;
desc.mLocals.configure (*script);
iter = mScripts.insert (std::make_pair (name, std::make_pair (false, locals))).first;
iter = mScripts.insert (std::make_pair (name, desc)).first;
}
}
return iter->second.second;
return iter->second.mLocals;
}
}

@ -26,16 +26,25 @@ namespace MWWorld
namespace MWScript
{
struct GlobalScriptDesc
{
bool mRunning;
Locals mLocals;
std::string mId; // ID used to start targeted script (empty if not a targeted script)
GlobalScriptDesc();
};
class GlobalScripts
{
const MWWorld::ESMStore& mStore;
std::map<std::string, std::pair<bool, Locals> > mScripts; // running, local variables
std::map<std::string, GlobalScriptDesc> mScripts;
public:
GlobalScripts (const MWWorld::ESMStore& store);
void addScript (const std::string& name);
void addScript (const std::string& name, const std::string& targetId = "");
void removeScript (const std::string& name);

@ -3,8 +3,12 @@
#include <cmath>
#include <stdexcept>
#include <sstream>
#include <components/interpreter/types.hpp>
#include <components/compiler/locals.hpp>
#include "../mwworld/esmstore.hpp"
#include "../mwbase/environment.hpp"
@ -22,7 +26,7 @@
namespace MWScript
{
MWWorld::Ptr InterpreterContext::getReference (
MWWorld::Ptr InterpreterContext::getReferenceImp (
const std::string& id, bool activeOnly, bool doThrow)
{
if (!id.empty())
@ -31,6 +35,10 @@ namespace MWScript
}
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");
@ -38,7 +46,7 @@ namespace MWScript
}
}
const MWWorld::Ptr InterpreterContext::getReference (
const MWWorld::Ptr InterpreterContext::getReferenceImp (
const std::string& id, bool activeOnly, bool doThrow) const
{
if (!id.empty())
@ -47,6 +55,10 @@ namespace MWScript
}
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");
@ -64,7 +76,7 @@ namespace MWScript
}
else
{
const MWWorld::Ptr ptr = getReference (id, false);
const MWWorld::Ptr ptr = getReferenceImp (id, false);
id = ptr.getClass().getScript (ptr);
@ -84,7 +96,7 @@ namespace MWScript
}
else
{
const MWWorld::Ptr ptr = getReference (id, false);
const MWWorld::Ptr ptr = getReferenceImp (id, false);
id = ptr.getClass().getScript (ptr);
@ -95,11 +107,43 @@ namespace MWScript
}
}
int InterpreterContext::findLocalVariableIndex (const std::string& scriptId,
const std::string& name, char type) const
{
int index = MWBase::Environment::get().getScriptManager()->getLocals (scriptId).
search (type, name);
if (index!=-1)
return index;
std::ostringstream stream;
stream << "Failed to access ";
switch (type)
{
case 's': stream << "short"; break;
case 'l': stream << "long"; break;
case 'f': stream << "float"; break;
}
stream << " member variable " << name << " in script " << scriptId;
throw std::runtime_error (stream.str().c_str());
}
InterpreterContext::InterpreterContext (
MWScript::Locals *locals, MWWorld::Ptr reference)
MWScript::Locals *locals, MWWorld::Ptr reference, const std::string& targetId)
: mLocals (locals), mReference (reference),
mActivationHandled (false)
{}
mActivationHandled (false), 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
// targeted scripts started from this one.
if (targetId.empty() && !reference.isEmpty())
mTargetId = reference.getClass().getId (reference);
}
int InterpreterContext::getLocalShort (int index) const
{
@ -236,34 +280,34 @@ namespace MWScript
std::string InterpreterContext::getNPCName() const
{
ESM::NPC npc = *mReference.get<ESM::NPC>()->mBase;
ESM::NPC npc = *getReferenceImp().get<ESM::NPC>()->mBase;
return npc.mName;
}
std::string InterpreterContext::getNPCRace() const
{
ESM::NPC npc = *mReference.get<ESM::NPC>()->mBase;
ESM::NPC npc = *getReferenceImp().get<ESM::NPC>()->mBase;
const ESM::Race* race = MWBase::Environment::get().getWorld()->getStore().get<ESM::Race>().find(npc.mRace);
return race->mName;
}
std::string InterpreterContext::getNPCClass() const
{
ESM::NPC npc = *mReference.get<ESM::NPC>()->mBase;
ESM::NPC npc = *getReferenceImp().get<ESM::NPC>()->mBase;
const ESM::Class* class_ = MWBase::Environment::get().getWorld()->getStore().get<ESM::Class>().find(npc.mClass);
return class_->mName;
}
std::string InterpreterContext::getNPCFaction() const
{
ESM::NPC npc = *mReference.get<ESM::NPC>()->mBase;
ESM::NPC npc = *getReferenceImp().get<ESM::NPC>()->mBase;
const ESM::Faction* faction = MWBase::Environment::get().getWorld()->getStore().get<ESM::Faction>().find(npc.mFaction);
return faction->mName;
}
std::string InterpreterContext::getNPCRank() const
{
std::map<std::string, int> ranks = mReference.getClass().getNpcStats (mReference).getFactionRanks();
std::map<std::string, int> ranks = getReferenceImp().getClass().getNpcStats (getReferenceImp()).getFactionRanks();
std::map<std::string, int>::const_iterator it = ranks.begin();
MWBase::World *world = MWBase::Environment::get().getWorld();
@ -299,7 +343,7 @@ namespace MWScript
MWBase::World *world = MWBase::Environment::get().getWorld();
MWWorld::Ptr player = world->getPlayerPtr();
std::string factionId = mReference.getClass().getNpcStats (mReference).getFactionRanks().begin()->first;
std::string factionId = getReferenceImp().getClass().getNpcStats (getReferenceImp()).getFactionRanks().begin()->first;
std::map<std::string, int> ranks = player.getClass().getNpcStats (player).getFactionRanks();
std::map<std::string, int>::const_iterator it = ranks.find(factionId);
@ -326,7 +370,7 @@ namespace MWScript
MWBase::World *world = MWBase::Environment::get().getWorld();
MWWorld::Ptr player = world->getPlayerPtr();
std::string factionId = mReference.getClass().getNpcStats (mReference).getFactionRanks().begin()->first;
std::string factionId = getReferenceImp().getClass().getNpcStats (getReferenceImp()).getFactionRanks().begin()->first;
std::map<std::string, int> ranks = player.getClass().getNpcStats (player).getFactionRanks();
std::map<std::string, int>::const_iterator it = ranks.find(factionId);
@ -366,9 +410,9 @@ namespace MWScript
return MWBase::Environment::get().getScriptManager()->getGlobalScripts().isRunning (name);
}
void InterpreterContext::startScript (const std::string& name)
void InterpreterContext::startScript (const std::string& name, const std::string& targetId)
{
MWBase::Environment::get().getScriptManager()->getGlobalScripts().addScript (name);
MWBase::Environment::get().getScriptManager()->getGlobalScripts().addScript (name, targetId);
}
void InterpreterContext::stopScript (const std::string& name)
@ -383,7 +427,7 @@ namespace MWScript
MWWorld::Ptr ref2;
if (id.empty())
ref2 = getReference("", true, true);
ref2 = getReferenceImp();
else
ref2 = MWBase::Environment::get().getWorld()->searchPtr(id, true);
@ -448,19 +492,19 @@ namespace MWScript
bool InterpreterContext::isDisabled (const std::string& id) const
{
const MWWorld::Ptr ref = getReference (id, false);
const MWWorld::Ptr ref = getReferenceImp (id, false);
return !ref.getRefData().isEnabled();
}
void InterpreterContext::enable (const std::string& id)
{
MWWorld::Ptr ref = getReference (id, false);
MWWorld::Ptr ref = getReferenceImp (id, false);
MWBase::Environment::get().getWorld()->enable (ref);
}
void InterpreterContext::disable (const std::string& id)
{
MWWorld::Ptr ref = getReference (id, false);
MWWorld::Ptr ref = getReferenceImp (id, false);
MWBase::Environment::get().getWorld()->disable (ref);
}
@ -471,10 +515,7 @@ namespace MWScript
const Locals& locals = getMemberLocals (scriptId, global);
int index = MWBase::Environment::get().getScriptManager()->getLocalIndex (
scriptId, name, 's');
return locals.mShorts[index];
return locals.mShorts[findLocalVariableIndex (scriptId, name, 's')];
}
int InterpreterContext::getMemberLong (const std::string& id, const std::string& name,
@ -484,10 +525,7 @@ namespace MWScript
const Locals& locals = getMemberLocals (scriptId, global);
int index = MWBase::Environment::get().getScriptManager()->getLocalIndex (
scriptId, name, 'l');
return locals.mLongs[index];
return locals.mLongs[findLocalVariableIndex (scriptId, name, 'l')];
}
float InterpreterContext::getMemberFloat (const std::string& id, const std::string& name,
@ -497,10 +535,7 @@ namespace MWScript
const Locals& locals = getMemberLocals (scriptId, global);
int index = MWBase::Environment::get().getScriptManager()->getLocalIndex (
scriptId, name, 'f');
return locals.mFloats[index];
return locals.mFloats[findLocalVariableIndex (scriptId, name, 'f')];
}
void InterpreterContext::setMemberShort (const std::string& id, const std::string& name,
@ -510,10 +545,7 @@ namespace MWScript
Locals& locals = getMemberLocals (scriptId, global);
int index =
MWBase::Environment::get().getScriptManager()->getLocalIndex (scriptId, name, 's');
locals.mShorts[index] = value;
locals.mShorts[findLocalVariableIndex (scriptId, name, 's')] = value;
}
void InterpreterContext::setMemberLong (const std::string& id, const std::string& name, int value, bool global)
@ -522,10 +554,7 @@ namespace MWScript
Locals& locals = getMemberLocals (scriptId, global);
int index =
MWBase::Environment::get().getScriptManager()->getLocalIndex (scriptId, name, 'l');
locals.mLongs[index] = value;
locals.mLongs[findLocalVariableIndex (scriptId, name, 'l')] = value;
}
void InterpreterContext::setMemberFloat (const std::string& id, const std::string& name, float value, bool global)
@ -534,14 +563,16 @@ namespace MWScript
Locals& locals = getMemberLocals (scriptId, global);
int index =
MWBase::Environment::get().getScriptManager()->getLocalIndex (scriptId, name, 'f');
locals.mFloats[index] = value;
locals.mFloats[findLocalVariableIndex (scriptId, name, 'f')] = value;
}
MWWorld::Ptr InterpreterContext::getReference(bool required)
{
return getReference ("", true, required);
return getReferenceImp ("", true, required);
}
std::string InterpreterContext::getTargetId() const
{
return mTargetId;
}
}

@ -27,14 +27,22 @@ namespace MWScript
class InterpreterContext : public Interpreter::Context
{
Locals *mLocals;
MWWorld::Ptr mReference;
mutable MWWorld::Ptr mReference;
MWWorld::Ptr mActivated;
bool mActivationHandled;
MWWorld::Ptr getReference (const std::string& id, bool activeOnly, bool doThrow=true);
std::string mTargetId;
const MWWorld::Ptr getReference (const std::string& id, bool activeOnly, bool doThrow=true) const;
/// 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);
/// 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.
const MWWorld::Ptr getReferenceImp (const std::string& id = "",
bool activeOnly = false, bool doThrow=true) const;
const Locals& getMemberLocals (std::string& id, bool global) const;
///< \a id is changed to the respective script ID, if \a id wasn't a script ID before
@ -42,9 +50,14 @@ namespace MWScript
Locals& getMemberLocals (std::string& id, bool global);
///< \a id is changed to the respective script ID, if \a id wasn't a script ID before
/// Throws an exception if local variable can't be found.
int findLocalVariableIndex (const std::string& scriptId, const std::string& name,
char type) const;
public:
InterpreterContext (MWScript::Locals *locals, MWWorld::Ptr reference);
InterpreterContext (MWScript::Locals *locals, MWWorld::Ptr reference,
const std::string& targetId = "");
///< The ownership of \a locals is not transferred. 0-pointer allowed.
virtual int getLocalShort (int index) const;
@ -113,7 +126,7 @@ namespace MWScript
virtual bool isScriptRunning (const std::string& name) const;
virtual void startScript (const std::string& name);
virtual void startScript (const std::string& name, const std::string& targetId = "");
virtual void stopScript (const std::string& name);
@ -158,6 +171,8 @@ namespace MWScript
MWWorld::Ptr getReference(bool required=true);
///< Reference, that the script is running from (can be empty)
virtual std::string getTargetId() const;
};
}

@ -14,12 +14,15 @@ namespace MWScript
{
void Locals::configure (const ESM::Script& script)
{
const Compiler::Locals& locals =
MWBase::Environment::get().getScriptManager()->getLocals (script.mId);
mShorts.clear();
mShorts.resize (script.mData.mNumShorts, 0);
mShorts.resize (locals.get ('s').size(), 0);
mLongs.clear();
mLongs.resize (script.mData.mNumLongs, 0);
mLongs.resize (locals.get ('l').size(), 0);
mFloats.clear();
mFloats.resize (script.mData.mNumFloats, 0);
mFloats.resize (locals.get ('f').size(), 0);
}
bool Locals::isEmpty() const
@ -29,7 +32,7 @@ namespace MWScript
int Locals::getIntVar(const std::string &script, const std::string &var)
{
Compiler::Locals locals = MWBase::Environment::get().getScriptManager()->getLocals(script);
const Compiler::Locals& locals = MWBase::Environment::get().getScriptManager()->getLocals(script);
int index = locals.getIndex(var);
char type = locals.getType(var);
if(index != -1)
@ -53,7 +56,7 @@ namespace MWScript
bool Locals::setVarByInt(const std::string& script, const std::string& var, int val)
{
Compiler::Locals locals = MWBase::Environment::get().getScriptManager()->getLocals(script);
const Compiler::Locals& locals = MWBase::Environment::get().getScriptManager()->getLocals(script);
int index = locals.getIndex(var);
char type = locals.getType(var);
if(index != -1)

@ -5,6 +5,7 @@
#include <iostream>
#include <sstream>
#include <exception>
#include <algorithm>
#include <components/esm/loadscpt.hpp>
@ -22,12 +23,19 @@
namespace MWScript
{
ScriptManager::ScriptManager (const MWWorld::ESMStore& store, bool verbose,
Compiler::Context& compilerContext, int warningsMode)
Compiler::Context& compilerContext, int warningsMode,
const std::vector<std::string>& scriptBlacklist)
: mErrorHandler (std::cerr), mStore (store), mVerbose (verbose),
mCompilerContext (compilerContext), mParser (mErrorHandler, mCompilerContext),
mOpcodesInstalled (false), mGlobalScripts (store)
{
mErrorHandler.setWarningsMode (warningsMode);
mScriptBlacklist.resize (scriptBlacklist.size());
std::transform (scriptBlacklist.begin(), scriptBlacklist.end(),
mScriptBlacklist.begin(), Misc::StringUtils::lowerCase);
std::sort (mScriptBlacklist.begin(), mScriptBlacklist.end());
}
bool ScriptManager::compile (const std::string& name)
@ -133,16 +141,22 @@ namespace MWScript
int success = 0;
const MWWorld::Store<ESM::Script>& scripts = mStore.get<ESM::Script>();
MWWorld::Store<ESM::Script>::iterator it = scripts.begin();
for (; it != scripts.end(); ++it, ++count)
if (compile (it->mId))
++success;
for (MWWorld::Store<ESM::Script>::iterator iter = scripts.begin();
iter != scripts.end(); ++iter)
if (!std::binary_search (mScriptBlacklist.begin(), mScriptBlacklist.end(),
Misc::StringUtils::lowerCase (iter->mId)))
{
++count;
if (compile (iter->mId))
++success;
}
return std::make_pair (count, success);
}
Compiler::Locals& ScriptManager::getLocals (const std::string& name)
const Compiler::Locals& ScriptManager::getLocals (const std::string& name)
{
std::string name2 = Misc::StringUtils::lowerCase (name);
@ -182,46 +196,4 @@ namespace MWScript
{
return mGlobalScripts;
}
int ScriptManager::getLocalIndex (const std::string& scriptId, const std::string& variable,
char type)
{
const ESM::Script *script = mStore.get<ESM::Script>().find (scriptId);
int offset = 0;
int size = 0;
switch (type)
{
case 's':
offset = 0;
size = script->mData.mNumShorts;
break;
case 'l':
offset = script->mData.mNumShorts;
size = script->mData.mNumLongs;
break;
case 'f':
offset = script->mData.mNumShorts+script->mData.mNumLongs;
size = script->mData.mNumFloats;
break;
default:
throw std::runtime_error ("invalid variable type");
}
std::string variable2 = Misc::StringUtils::lowerCase (variable);
for (int i=0; i<size; ++i)
if (Misc::StringUtils::lowerCase (script->mVarNames.at (i+offset))==variable2)
return i;
throw std::runtime_error ("unable to access local variable " + variable + " of " + scriptId);
}
}

@ -48,11 +48,13 @@ namespace MWScript
ScriptCollection mScripts;
GlobalScripts mGlobalScripts;
std::map<std::string, Compiler::Locals> mOtherLocals;
std::vector<std::string> mScriptBlacklist;
public:
ScriptManager (const MWWorld::ESMStore& store, bool verbose,
Compiler::Context& compilerContext, int warningsMode);
Compiler::Context& compilerContext, int warningsMode,
const std::vector<std::string>& scriptBlacklist);
virtual void run (const std::string& name, Interpreter::Context& interpreterContext);
///< Run the script with the given name (compile first, if not compiled yet)
@ -65,15 +67,10 @@ namespace MWScript
///< Compile all scripts
/// \return count, success
virtual Compiler::Locals& getLocals (const std::string& name);
virtual const Compiler::Locals& getLocals (const std::string& name);
///< Return locals for script \a name.
virtual GlobalScripts& getGlobalScripts();
virtual int getLocalIndex (const std::string& scriptId, const std::string& variable,
char type);
///< Return index of the variable of the given name and type in the given script. Will
/// throw an exception, if there is no such script or variable or the type does not match.
};
}

@ -1,6 +1,3 @@
#ifdef OPENMW_USE_FFMPEG
#include "ffmpeg_decoder.hpp"
// auto_ptr
@ -375,5 +372,3 @@ FFmpeg_Decoder::~FFmpeg_Decoder()
}
}
#endif

@ -17,15 +17,10 @@
#include "openal_output.hpp"
#define SOUND_OUT "OpenAL"
/* Set up the sound manager to use FFMPEG for input.
* The OPENMW_USE_x macros are set in CMakeLists.txt.
*/
#ifdef OPENMW_USE_FFMPEG
#include "ffmpeg_decoder.hpp"
#ifndef SOUND_IN
#define SOUND_IN "FFmpeg"
#endif
#endif
namespace MWSound

@ -132,12 +132,12 @@ void MWState::StateManager::newGame (bool bypass)
{
cleanup();
MWBase::Environment::get().getWorld()->startNewGame (bypass);
if (!bypass)
MWBase::Environment::get().getWindowManager()->setNewGame (true);
else
MWBase::Environment::get().getWorld()->setGlobalInt ("chargenstate", -1);
MWBase::Environment::get().getScriptManager()->getGlobalScripts().addStartup();
MWBase::Environment::get().getWorld()->startNewGame (bypass);
mState = State_Running;
}
@ -401,6 +401,8 @@ void MWState::StateManager::loadGame (const Character *character, const Slot *sl
// Use detectWorldSpaceChange=false, otherwise some of the data we just loaded would be cleared again
MWBase::Environment::get().getWorld()->changeToCell (cellId, ptr.getRefData().getPosition(), false);
MWBase::Environment::get().getScriptManager()->getGlobalScripts().addStartup();
// Do not trigger erroneous cellChanged events
MWBase::Environment::get().getWorld()->markCellAsUnchanged();
}

@ -211,9 +211,9 @@ namespace MWWorld
// set new game mark
mGlobalVariables["chargenstate"].setInteger (1);
mGlobalVariables["pcrace"].setInteger (3);
MWBase::Environment::get().getScriptManager()->getGlobalScripts().addStartup();
}
else
mGlobalVariables["chargenstate"].setInteger (-1);
if (bypass && !mStartCell.empty())
{

@ -58,7 +58,7 @@ add_component_dir (compiler
context controlparser errorhandler exception exprparser extensions fileparser generator
lineparser literals locals output parser scanner scriptparser skipparser streamerrorhandler
stringparser tokenloc nullerrorhandler opcodes extensions0 declarationparser
quickfileparser
quickfileparser discardparser
)
add_component_dir (interpreter

@ -0,0 +1,70 @@
#include "discardparser.hpp"
#include "scanner.hpp"
namespace Compiler
{
DiscardParser::DiscardParser (ErrorHandler& errorHandler, const Context& context)
: Parser (errorHandler, context), mState (StartState)
{
}
bool DiscardParser::parseInt (int value, const TokenLoc& loc, Scanner& scanner)
{
if (mState==StartState || mState==CommaState || mState==MinusState)
{
start();
return false;
}
return Parser::parseInt (value, loc, scanner);
}
bool DiscardParser::parseFloat (float value, const TokenLoc& loc, Scanner& scanner)
{
if (mState==StartState || mState==CommaState || mState==MinusState)
{
start();
return false;
}
return Parser::parseFloat (value, loc, scanner);
}
bool DiscardParser::parseName (const std::string& name, const TokenLoc& loc,
Scanner& scanner)
{
if (mState==StartState || mState==CommaState)
{
start();
return false;
}
return Parser::parseName (name, loc, scanner);
}
bool DiscardParser::parseSpecial (int code, const TokenLoc& loc, Scanner& scanner)
{
if (code==Scanner::S_comma && mState==StartState)
{
mState = CommaState;
return true;
}
if (code==Scanner::S_minus && (mState==StartState || mState==CommaState))
{
mState = MinusState;
return true;
}
return Parser::parseSpecial (code, loc, scanner);
}
void DiscardParser::reset()
{
mState = StartState;
Parser::reset();
}
}

@ -0,0 +1,45 @@
#ifndef COMPILER_DISCARDPARSER_H_INCLUDED
#define COMPILER_DISCARDPARSER_H_INCLUDED
#include "parser.hpp"
namespace Compiler
{
/// \brief Parse a single optional numeric value or string and discard it
class DiscardParser : public Parser
{
enum State
{
StartState, CommaState, MinusState
};
State mState;
public:
DiscardParser (ErrorHandler& errorHandler, const Context& context);
virtual bool parseInt (int value, const TokenLoc& loc, Scanner& scanner);
///< Handle an int token.
/// \return fetch another token?
virtual bool parseFloat (float value, const TokenLoc& loc, Scanner& scanner);
///< Handle a float token.
/// \return fetch another token?
virtual bool parseName (const std::string& name, const TokenLoc& loc,
Scanner& scanner);
///< Handle a name token.
/// \return fetch another token?
virtual bool parseSpecial (int code, const TokenLoc& loc, Scanner& scanner);
///< Handle a special character token.
/// \return fetch another token?
virtual void reset();
///< Reset parser to clean state.
};
}
#endif

@ -3,11 +3,8 @@
namespace Compiler
{
// constructor
ErrorHandler::ErrorHandler() : mWarnings (0), mErrors (0), mWarningsMode (1) {}
// destructor
ErrorHandler::ErrorHandler()
: mWarnings (0), mErrors (0), mWarningsMode (1), mDowngradeErrors (false) {}
ErrorHandler::~ErrorHandler() {}
@ -49,6 +46,12 @@ namespace Compiler
void ErrorHandler::error (const std::string& message, const TokenLoc& loc)
{
if (mDowngradeErrors)
{
warning (message, loc);
return;
}
++mErrors;
report (message, loc, ErrorMessage);
}
@ -72,4 +75,21 @@ namespace Compiler
{
mWarningsMode = mode;
}
void ErrorHandler::downgradeErrors (bool downgrade)
{
mDowngradeErrors = downgrade;
}
ErrorDowngrade::ErrorDowngrade (ErrorHandler& handler) : mHandler (handler)
{
mHandler.downgradeErrors (true);
}
ErrorDowngrade::~ErrorDowngrade()
{
mHandler.downgradeErrors (false);
}
}

@ -17,6 +17,7 @@ namespace Compiler
int mWarnings;
int mErrors;
int mWarningsMode;
bool mDowngradeErrors;
protected:
@ -66,6 +67,26 @@ namespace Compiler
void setWarningsMode (int mode);
///< // 0 ignore, 1 rate as warning, 2 rate as error
/// Treat errors as warnings.
void downgradeErrors (bool downgrade);
};
class ErrorDowngrade
{
ErrorHandler& mHandler;
/// not implemented
ErrorDowngrade (const ErrorDowngrade&);
/// not implemented
ErrorDowngrade& operator= (const ErrorDowngrade&);
public:
ErrorDowngrade (ErrorHandler& handler);
~ErrorDowngrade();
};
}

@ -16,6 +16,7 @@
#include "stringparser.hpp"
#include "extensions.hpp"
#include "context.hpp"
#include "discardparser.hpp"
namespace Compiler
{
@ -386,6 +387,9 @@ namespace Compiler
mExplicit.clear();
mRefOp = false;
std::vector<Interpreter::Type_Code> ignore;
parseArguments ("x", scanner, ignore);
mNextOperand = false;
return true;
}
@ -404,6 +408,21 @@ namespace Compiler
mNextOperand = false;
return true;
}
else if (keyword==Scanner::K_scriptrunning)
{
start();
mTokenLoc = loc;
parseArguments ("c", scanner);
Generator::scriptRunning (mCode);
mOperands.push_back ('l');
mExplicit.clear();
mRefOp = false;
mNextOperand = false;
return true;
}
// check for custom extensions
if (const Extensions *extensions = getContext().getExtensions())
@ -527,6 +546,9 @@ namespace Compiler
Generator::getDisabled (mCode, mLiterals, "");
mOperands.push_back ('l');
std::vector<Interpreter::Type_Code> ignore;
parseArguments ("x", scanner, ignore);
mNextOperand = false;
return true;
}
@ -737,6 +759,7 @@ namespace Compiler
ExprParser parser (getErrorHandler(), getContext(), mLocals, mLiterals, true);
StringParser stringParser (getErrorHandler(), getContext(), mLiterals);
DiscardParser discardParser (getErrorHandler(), getContext());
std::stack<std::vector<Interpreter::Type_Code> > stack;
@ -771,11 +794,32 @@ namespace Compiler
++optionalCount;
}
}
else if (*iter=='X')
{
parser.reset();
parser.setOptional (true);
scanner.scan (parser);
if (parser.isEmpty())
break;
}
else if (*iter=='z')
{
discardParser.reset();
discardParser.setOptional (true);
scanner.scan (discardParser);
if (discardParser.isEmpty())
break;
}
else
{
parser.reset();
if (optional || *iter == 'X')
if (optional)
parser.setOptional (true);
scanner.scan (parser);
@ -783,20 +827,17 @@ namespace Compiler
if (optional && parser.isEmpty())
break;
if (*iter != 'X')
{
std::vector<Interpreter::Type_Code> tmp;
std::vector<Interpreter::Type_Code> tmp;
char type = parser.append (tmp);
char type = parser.append (tmp);
if (type!=*iter)
Generator::convert (tmp, type, *iter);
if (type!=*iter)
Generator::convert (tmp, type, *iter);
stack.push (tmp);
stack.push (tmp);
if (optional)
++optionalCount;
}
if (optional)
++optionalCount;
}
}

@ -21,7 +21,8 @@ namespace Compiler
s - Short <BR>
S - String, case preserved <BR>
x - Optional, ignored string argument
X - Optional, ignored integer argument
X - Optional, ignored numeric expression
z - Optional, ignored string or numeric argument
**/
typedef std::string ScriptArgs;

@ -118,7 +118,7 @@ namespace Compiler
opcodeGetItemCountExplicit);
extensions.registerInstruction ("removeitem", "cl", opcodeRemoveItem,
opcodeRemoveItemExplicit);
extensions.registerInstruction ("equip", "c", opcodeEquip, opcodeEquipExplicit);
extensions.registerInstruction ("equip", "cX", opcodeEquip, opcodeEquipExplicit);
extensions.registerFunction ("getarmortype", 'l', "l", opcodeGetArmorType, opcodeGetArmorTypeExplicit);
extensions.registerFunction ("hasitemequipped", 'l', "c", opcodeHasItemEquipped, opcodeHasItemEquippedExplicit);
extensions.registerFunction ("hassoulgem", 'l', "c", opcodeHasSoulGem, opcodeHasSoulGemExplicit);
@ -410,7 +410,7 @@ namespace Compiler
extensions.registerInstruction ("setpccrimelevel", "f", opcodeSetPCCrimeLevel);
extensions.registerInstruction ("modpccrimelevel", "f", opcodeModPCCrimeLevel);
extensions.registerInstruction ("addspell", "cxX", opcodeAddSpell, opcodeAddSpellExplicit);
extensions.registerInstruction ("addspell", "cz", opcodeAddSpell, opcodeAddSpellExplicit);
extensions.registerInstruction ("removespell", "c", opcodeRemoveSpell,
opcodeRemoveSpellExplicit);
extensions.registerInstruction ("removespelleffects", "c", opcodeRemoveSpellEffects,

@ -51,6 +51,12 @@ namespace Compiler
/// \todo allow this workaround to be disabled for newer scripts
}
if (mState==BeginCompleteState)
{
reportWarning ("Stray string (" + name + ") after begin statement", loc);
return true;
}
return Parser::parseName (name, loc, scanner);
}

@ -300,9 +300,9 @@ namespace
code.push_back (Compiler::Generator::segment5 (46));
}
void opStartScript (Compiler::Generator::CodeContainer& code)
void opStartScript (Compiler::Generator::CodeContainer& code, bool targeted)
{
code.push_back (Compiler::Generator::segment5 (47));
code.push_back (Compiler::Generator::segment5 (targeted ? 71 : 47));
}
void opStopScript (Compiler::Generator::CodeContainer& code)
@ -830,9 +830,16 @@ namespace Compiler
opScriptRunning (code);
}
void startScript (CodeContainer& code)
void startScript (CodeContainer& code, Literals& literals, const std::string& id)
{
opStartScript (code);
if (id.empty())
opStartScript (code, false);
else
{
int index = literals.addString (id);
opPushInt (code, index);
opStartScript (code, true);
}
}
void stopScript (CodeContainer& code)

@ -113,7 +113,7 @@ namespace Compiler
void scriptRunning (CodeContainer& code);
void startScript (CodeContainer& code);
void startScript (CodeContainer& code, Literals& literals, const std::string& id);
void stopScript (CodeContainer& code);

@ -11,6 +11,7 @@
#include "generator.hpp"
#include "extensions.hpp"
#include "declarationparser.hpp"
#include "exception.hpp"
namespace Compiler
{
@ -262,6 +263,20 @@ namespace Compiler
Generator::disable (mCode, mLiterals, mExplicit);
mState = PotentialEndState;
return true;
case Scanner::K_startscript:
mExprParser.parseArguments ("c", scanner, mCode);
Generator::startScript (mCode, mLiterals, mExplicit);
mState = EndState;
return true;
case Scanner::K_stopscript:
mExprParser.parseArguments ("c", scanner, mCode);
Generator::stopScript (mCode);
mState = EndState;
return true;
}
// check for custom extensions
@ -278,9 +293,31 @@ namespace Compiler
mExplicit.clear();
}
int optionals = mExprParser.parseArguments (argumentType, scanner, mCode);
int optionals = 0;
try
{
ErrorDowngrade errorDowngrade (getErrorHandler());
std::vector<Interpreter::Type_Code> code;
optionals = mExprParser.parseArguments (argumentType, scanner, code);
mCode.insert (mCode.begin(), code.begin(), code.end());
extensions->generateInstructionCode (keyword, mCode, mLiterals,
mExplicit, optionals);
}
catch (const SourceException& exception)
{
// Ignore argument exceptions for positioncell.
/// \todo add option to disable this
if (Misc::StringUtils::lowerCase (loc.mLiteral)=="positioncell")
{
SkipParser skip (getErrorHandler(), getContext());
scanner.scan (skip);
return false;
}
throw;
}
extensions->generateInstructionCode (keyword, mCode, mLiterals, mExplicit, optionals);
mState = EndState;
return true;
}
@ -349,7 +386,7 @@ namespace Compiler
if (declaration.parseKeyword (keyword, loc, scanner))
scanner.scan (declaration);
return true;
return false;
}
case Scanner::K_set: mState = SetState; return true;
@ -361,13 +398,6 @@ namespace Compiler
mState = EndState;
return true;
case Scanner::K_startscript:
mExprParser.parseArguments ("c", scanner, mCode);
Generator::startScript (mCode);
mState = EndState;
return true;
case Scanner::K_stopscript:
mExprParser.parseArguments ("c", scanner, mCode);

@ -17,8 +17,6 @@ namespace Compiler
int searchIndex (char type, const std::string& name) const;
bool search (char type, const std::string& name) const;
std::vector<std::string>& get (char type);
public:
@ -29,6 +27,10 @@ namespace Compiler
int getIndex (const std::string& name) const;
///< return index for local variable \a name (-1: does not exist).
/// Return index for local variable \a name of type \a type (-1: variable does not
/// exit).
bool search (char type, const std::string& name) const;
const std::vector<std::string>& get (char type) const;
void write (std::ostream& localFile) const;

@ -343,17 +343,13 @@ namespace Compiler
}
else if (!(c=='"' && name.empty()))
{
if (!(std::isalpha (c) || std::isdigit (c) || c=='_' || c=='`' ||
/// \todo add an option to disable the following hack. Also, find out who is
/// responsible for allowing it in the first place and meet up with that person in
/// a dark alley.
(c=='-' && !name.empty() && std::isalpha (mStream.peek()))))
if (!isStringCharacter (c))
{
putback (c);
break;
}
if (first && std::isdigit (c))
if (first && (std::isdigit (c) || c=='`' || c=='-'))
error = true;
}
@ -499,6 +495,17 @@ namespace Compiler
return true;
}
bool Scanner::isStringCharacter (char c, bool lookAhead)
{
return std::isalpha (c) || std::isdigit (c) || c=='_' ||
/// \todo disable this when doing more stricter compiling
c=='`' ||
/// \todo disable this when doing more stricter compiling. Also, find out who is
/// responsible for allowing it in the first place and meet up with that person in
/// a dark alley.
(c=='-' && (!lookAhead || isStringCharacter (mStream.peek(), false)));
}
bool Scanner::isWhitespace (char c)
{
return c==' ' || c=='\t';

@ -92,6 +92,8 @@ namespace Compiler
bool scanSpecial (char c, Parser& parser, bool& cont);
bool isStringCharacter (char c, bool lookAhead = true);
static bool isWhitespace (char c);
public:

@ -12,6 +12,8 @@ void ESM::GlobalScript::load (ESMReader &esm)
mRunning = 0;
esm.getHNOT (mRunning, "RUN_");
mTargetId = esm.getHNOString ("TARG");
}
void ESM::GlobalScript::save (ESMWriter &esm) const
@ -22,4 +24,6 @@ void ESM::GlobalScript::save (ESMWriter &esm) const
if (mRunning)
esm.writeHNT ("RUN_", mRunning);
esm.writeHNOString ("TARG", mTargetId);
}

@ -15,6 +15,7 @@ namespace ESM
std::string mId;
Locals mLocals;
int mRunning;
std::string mTargetId; // for targeted scripts
void load (ESMReader &esm);
void save (ESMWriter &esm) const;

@ -23,29 +23,8 @@ public:
struct SCHDstruct
{
/* Script name.
NOTE: You should handle the name "Main" (case insensitive) with
care. With tribunal, modders got the ability to add 'start
scripts' to their mods, which is a script that is run at
startup and which runs throughout the game (I think.)
However, before Tribunal, there was only one startup script,
called "Main". If mods wanted to make their own start scripts,
they had to overwrite Main. This is obviously problem if
multiple mods to this at the same time.
Although most mods have switched to using Trib-style startup
scripts, some legacy mods might still overwrite Main, and this
can cause problems if several mods do it. I think the best
course of action is to NEVER overwrite main, but instead add
each with a separate unique name and add them to the start
script list. But there might be other problems with this
approach though.
*/
// These describe the sizes we need to allocate for the script
// data.
/// Data from script-precompling in the editor.
/// \warning Do not use them. OpenCS currently does not precompile scripts.
int mNumShorts, mNumLongs, mNumFloats, mScriptDataSize, mStringTableSize;
}; // 52 bytes
@ -53,9 +32,16 @@ public:
SCHDstruct mData;
std::vector<std::string> mVarNames; // Variable names
std::vector<unsigned char> mScriptData; // Compiled bytecode
std::string mScriptText; // Uncompiled script
/// Variable names generated by script-precompiling in the editor.
/// \warning Do not use this field. OpenCS currently does not precompile scripts.
std::vector<std::string> mVarNames;
/// Bytecode generated from script-precompiling in the editor.
/// \warning Do not use this field. OpenCS currently does not precompile scripts.
std::vector<unsigned char> mScriptData;
/// Script source code
std::string mScriptText;
void load(ESMReader &esm);
void save(ESMWriter &esm) const;

@ -16,13 +16,19 @@ namespace Files
static const char* const openmwCfgFile = "openmw.cfg";
#if defined(_WIN32) || defined(__WINDOWS__)
static const char* const applicationName = "OpenMW";
#else
static const char* const applicationName = "openmw";
#endif
const char* const mwToken = "?mw?";
const char* const localToken = "?local?";
const char* const userDataToken = "?userdata?";
const char* const globalToken = "?global?";
ConfigurationManager::ConfigurationManager()
: mFixedPath("openmw")
: mFixedPath(applicationName)
{
setupTokensMapping();

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

@ -133,5 +133,6 @@ op 67: store stack[0] in member float stack[2] of global script with ID stack[1]
op 68: replace stack[0] with member short stack[1] of global script with ID stack[0]
op 69: replace stack[0] with member short stack[1] of global script with ID stack[0]
op 70: replace stack[0] with member short stack[1] of global script with ID stack[0]
opcodes 71-33554431 unused
op 71: explicit reference (target) = stack[0]; pop; start script stack[0] and pop
opcodes 72-33554431 unused
opcodes 33554432-67108863 reserved for extensions

@ -113,6 +113,7 @@ namespace Interpreter
interpreter.installSegment5 (46, new OpScriptRunning);
interpreter.installSegment5 (47, new OpStartScript);
interpreter.installSegment5 (48, new OpStopScript);
interpreter.installSegment5 (71, new OpStartScriptExplicit);
// spacial
interpreter.installSegment5 (49, new OpGetDistance);

@ -10,36 +10,52 @@ namespace Interpreter
class OpScriptRunning : public Opcode0
{
public:
virtual void execute (Runtime& runtime)
{
std::string name = runtime.getStringLiteral (runtime[0].mInteger);
runtime[0].mInteger = runtime.getContext().isScriptRunning (name);
}
}
};
class OpStartScript : public Opcode0
{
public:
virtual void execute (Runtime& runtime)
{
std::string name = runtime.getStringLiteral (runtime[0].mInteger);
runtime.pop();
runtime.getContext().startScript (name);
}
runtime.getContext().startScript (name, runtime.getContext().getTargetId());
}
};
class OpStartScriptExplicit : public Opcode0
{
public:
virtual void execute (Runtime& runtime)
{
std::string targetId = runtime.getStringLiteral (runtime[0].mInteger);
runtime.pop();
std::string name = runtime.getStringLiteral (runtime[0].mInteger);
runtime.pop();
runtime.getContext().startScript (name, targetId);
}
};
class OpStopScript : public Opcode0
{
public:
virtual void execute (Runtime& runtime)
{
std::string name = runtime.getStringLiteral (runtime[0].mInteger);
runtime.pop();
runtime.getContext().stopScript (name);
}
}
};
}

@ -72,6 +72,7 @@ Sandy Carter (bwrsandman)
Sebastian Wick (swick)
Sergey Shambir
sir_herrbatka
Stefan Galowicz (bogglez)
Sylvain Thesnieres (Garvek)
Thomas Luppi (Digmaster)
Tom Mason (wheybags)

@ -2,3 +2,6 @@ data="?global?data"
data="?mw?Data Files"
data-local="?userdata?data"
resources=${OPENMW_RESOURCE_FILES}
script-blacklist=Museum
script-blacklist=MockChangeScript
script-blacklist=doortestwarp

@ -3,3 +3,6 @@ data="?mw?Data Files"
data=./data
data-local="?userdata?data"
resources=./resources
script-blacklist=Museum
script-blacklist=MockChangeScript
script-blacklist=doortestwarp

@ -130,6 +130,7 @@ Bug #1179: Crash after trying to load game after being killed
Bug #1180: Changing footstep sound location
Bug #1196: Jumping not disabled when showing messageboxes
Bug #1202: "strange" keys are not shown in binding menu, and are not saved either, but works
Bug #1216: Broken dialog topics in russian Morrowind
Bug #1217: Container content changes based on the current position of the mouse
Bug #1234: Loading/saving issues with dynamic records
Bug #1277: Text pasted into the console appears twice
@ -248,6 +249,8 @@ Bug #1590: Failed to save game: compile error
Bug #1598: Segfault when making Drain/Fortify Skill spells
Bug #1599: Unable to switch to fullscreen
Bug #1613: Morrowind Rebirth duplicate objects / vanilla objects not removed
Bug #1618: Death notice fails to show up
Bug #1628: Alt+Tab Segfault
Feature #32: Periodic Cleanup/Refill
Feature #41: Precipitation and weather particles
Feature #568: Editor: Configuration setup

Loading…
Cancel
Save