mirror of
https://gitlab.com/OpenMW/openmw.git
synced 2025-05-09 12:07:51 +03:00
Merge branch 'script'
Conflicts: readme.txt
This commit is contained in:
commit
6ac64bbe15
54 changed files with 1129 additions and 286 deletions
|
@ -38,7 +38,7 @@ opencs_units (model/tools
|
|||
|
||||
opencs_units_noqt (model/tools
|
||||
mandatoryid skillcheck classcheck factioncheck racecheck soundcheck regioncheck
|
||||
birthsigncheck spellcheck referenceablecheck
|
||||
birthsigncheck spellcheck referenceablecheck scriptcheck
|
||||
)
|
||||
|
||||
|
||||
|
|
103
apps/opencs/model/tools/scriptcheck.cpp
Normal file
103
apps/opencs/model/tools/scriptcheck.cpp
Normal file
|
@ -0,0 +1,103 @@
|
|||
|
||||
#include "scriptcheck.hpp"
|
||||
|
||||
#include <components/compiler/tokenloc.hpp>
|
||||
#include <components/compiler/scanner.hpp>
|
||||
#include <components/compiler/fileparser.hpp>
|
||||
#include <components/compiler/exception.hpp>
|
||||
#include <components/compiler/extensions0.hpp>
|
||||
|
||||
#include "../world/data.hpp"
|
||||
|
||||
void CSMTools::ScriptCheckStage::report (const std::string& message, const Compiler::TokenLoc& loc,
|
||||
Type type)
|
||||
{
|
||||
std::ostringstream stream;
|
||||
|
||||
CSMWorld::UniversalId id (CSMWorld::UniversalId::Type_Script, mId);
|
||||
|
||||
stream << id.toString() << "|";
|
||||
|
||||
if (type==ErrorMessage)
|
||||
stream << "error ";
|
||||
else
|
||||
stream << "warning ";
|
||||
|
||||
stream
|
||||
<< "script " << mFile
|
||||
<< ", line " << loc.mLine << ", column " << loc.mColumn
|
||||
<< " (" << loc.mLiteral << "): " << message;
|
||||
|
||||
mMessages->push_back (stream.str());
|
||||
}
|
||||
|
||||
void CSMTools::ScriptCheckStage::report (const std::string& message, Type type)
|
||||
{
|
||||
std::ostringstream stream;
|
||||
|
||||
CSMWorld::UniversalId id (CSMWorld::UniversalId::Type_Script, mId);
|
||||
|
||||
stream << id.toString() << "|";
|
||||
|
||||
if (type==ErrorMessage)
|
||||
stream << "error: ";
|
||||
else
|
||||
stream << "warning: ";
|
||||
|
||||
stream << message;
|
||||
|
||||
mMessages->push_back (stream.str());
|
||||
}
|
||||
|
||||
CSMTools::ScriptCheckStage::ScriptCheckStage (const CSMWorld::Data& data)
|
||||
: mData (data), mContext (data), mMessages (0)
|
||||
{
|
||||
/// \todo add an option to configure warning mode
|
||||
setWarningsMode (0);
|
||||
|
||||
Compiler::registerExtensions (mExtensions);
|
||||
mContext.setExtensions (&mExtensions);
|
||||
}
|
||||
|
||||
int CSMTools::ScriptCheckStage::setup()
|
||||
{
|
||||
mContext.clear();
|
||||
mMessages = 0;
|
||||
mId.clear();
|
||||
|
||||
return mData.getScripts().getSize();
|
||||
}
|
||||
|
||||
void CSMTools::ScriptCheckStage::perform (int stage, std::vector<std::string>& messages)
|
||||
{
|
||||
mMessages = &messages;
|
||||
mId = mData.getScripts().getId (stage);
|
||||
|
||||
try
|
||||
{
|
||||
mFile = mData.getScripts().getRecord (stage).get().mId;
|
||||
std::istringstream input (mData.getScripts().getRecord (stage).get().mScriptText);
|
||||
|
||||
Compiler::Scanner scanner (*this, input, mContext.getExtensions());
|
||||
|
||||
Compiler::FileParser parser (*this, mContext);
|
||||
|
||||
scanner.scan (parser);
|
||||
}
|
||||
catch (const Compiler::SourceException&)
|
||||
{
|
||||
// error has already been reported via error handler
|
||||
}
|
||||
catch (const std::exception& error)
|
||||
{
|
||||
std::ostringstream stream;
|
||||
|
||||
CSMWorld::UniversalId id (CSMWorld::UniversalId::Type_Script, mId);
|
||||
|
||||
stream << id.toString() << "|Critical compile error: " << error.what();
|
||||
|
||||
messages.push_back (stream.str());
|
||||
}
|
||||
|
||||
mMessages = 0;
|
||||
}
|
41
apps/opencs/model/tools/scriptcheck.hpp
Normal file
41
apps/opencs/model/tools/scriptcheck.hpp
Normal file
|
@ -0,0 +1,41 @@
|
|||
#ifndef CSM_TOOLS_SCRIPTCHECK_H
|
||||
#define CSM_TOOLS_SCRIPTCHECK_H
|
||||
|
||||
#include <components/compiler/errorhandler.hpp>
|
||||
#include <components/compiler/extensions.hpp>
|
||||
|
||||
#include "../doc/stage.hpp"
|
||||
|
||||
#include "../world/scriptcontext.hpp"
|
||||
|
||||
namespace CSMTools
|
||||
{
|
||||
/// \brief VerifyStage: make sure that scripts compile
|
||||
class ScriptCheckStage : public CSMDoc::Stage, private Compiler::ErrorHandler
|
||||
{
|
||||
const CSMWorld::Data& mData;
|
||||
Compiler::Extensions mExtensions;
|
||||
CSMWorld::ScriptContext mContext;
|
||||
std::string mId;
|
||||
std::string mFile;
|
||||
std::vector<std::string> *mMessages;
|
||||
|
||||
virtual void report (const std::string& message, const Compiler::TokenLoc& loc, Type type);
|
||||
///< Report error to the user.
|
||||
|
||||
virtual void report (const std::string& message, Type type);
|
||||
///< Report a file related error
|
||||
|
||||
public:
|
||||
|
||||
ScriptCheckStage (const CSMWorld::Data& data);
|
||||
|
||||
virtual int setup();
|
||||
///< \return number of steps
|
||||
|
||||
virtual void perform (int stage, std::vector<std::string>& messages);
|
||||
///< Messages resulting from this tage will be appended to \a messages.
|
||||
};
|
||||
}
|
||||
|
||||
#endif
|
|
@ -20,6 +20,7 @@
|
|||
#include "birthsigncheck.hpp"
|
||||
#include "spellcheck.hpp"
|
||||
#include "referenceablecheck.hpp"
|
||||
#include "scriptcheck.hpp"
|
||||
|
||||
CSMDoc::Operation *CSMTools::Tools::get (int type)
|
||||
{
|
||||
|
@ -77,6 +78,8 @@ CSMDoc::Operation *CSMTools::Tools::getVerifier()
|
|||
mVerifier->appendStage (new SpellCheckStage (mData.getSpells()));
|
||||
|
||||
mVerifier->appendStage (new ReferenceableCheckStage (mData.getReferenceables().getDataSet(), mData.getRaces(), mData.getClasses(), mData.getFactions()));
|
||||
|
||||
mVerifier->appendStage (new ScriptCheckStage (mData));
|
||||
}
|
||||
|
||||
return mVerifier;
|
||||
|
|
|
@ -5,23 +5,92 @@
|
|||
|
||||
#include <components/misc/stringops.hpp>
|
||||
|
||||
#include <components/compiler/quickfileparser.hpp>
|
||||
#include <components/compiler/nullerrorhandler.hpp>
|
||||
#include <components/compiler/scanner.hpp>
|
||||
|
||||
#include "data.hpp"
|
||||
|
||||
CSMWorld::ScriptContext::ScriptContext (const Data& data) : mData (data), mIdsUpdated (false) {}
|
||||
|
||||
bool CSMWorld::ScriptContext::canDeclareLocals() const
|
||||
{
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
char CSMWorld::ScriptContext::getGlobalType (const std::string& name) const
|
||||
{
|
||||
int index = mData.getGlobals().searchId (name);
|
||||
|
||||
if (index!=-1)
|
||||
{
|
||||
switch (mData.getGlobals().getRecord (index).get().mValue.getType())
|
||||
{
|
||||
case ESM::VT_Short: return 's';
|
||||
case ESM::VT_Long: return 'l';
|
||||
case ESM::VT_Float: return 'f';
|
||||
|
||||
default: return ' ';
|
||||
}
|
||||
}
|
||||
|
||||
return ' ';
|
||||
}
|
||||
|
||||
char CSMWorld::ScriptContext::getMemberType (const std::string& name, const std::string& id) const
|
||||
std::pair<char, bool> CSMWorld::ScriptContext::getMemberType (const std::string& name,
|
||||
const std::string& id) const
|
||||
{
|
||||
return ' ';
|
||||
/// \todo invalidate locals cache on change to scripts
|
||||
|
||||
std::string id2 = Misc::StringUtils::lowerCase (id);
|
||||
|
||||
int index = mData.getScripts().searchId (id2);
|
||||
bool reference = false;
|
||||
|
||||
if (index!=-1)
|
||||
{
|
||||
// ID is not a script ID. Search for a matching referenceable instead.
|
||||
index = mData.getReferenceables().searchId (id2);
|
||||
|
||||
if (index!=-1)
|
||||
{
|
||||
// Referenceable found.
|
||||
int columnIndex = mData.getReferenceables().searchColumnIndex (Columns::ColumnId_Script);
|
||||
|
||||
if (columnIndex!=-1)
|
||||
{
|
||||
id2 = Misc::StringUtils::lowerCase (mData.getReferenceables().
|
||||
getData (index, columnIndex).toString().toUtf8().constData());
|
||||
|
||||
if (!id2.empty())
|
||||
{
|
||||
// Referenceable has a script -> use it.
|
||||
index = mData.getScripts().searchId (id2);
|
||||
reference = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (index==-1)
|
||||
return std::make_pair (' ', false);
|
||||
|
||||
std::map<std::string, Compiler::Locals>::iterator iter = mLocals.find (id2);
|
||||
|
||||
if (iter==mLocals.end())
|
||||
{
|
||||
Compiler::Locals locals;
|
||||
|
||||
Compiler::NullErrorHandler errorHandler;
|
||||
std::istringstream stream (mData.getScripts().getRecord (index).get().mScriptText);
|
||||
Compiler::QuickFileParser parser (errorHandler, *this, locals);
|
||||
Compiler::Scanner scanner (errorHandler, stream, getExtensions());
|
||||
scanner.scan (parser);
|
||||
|
||||
iter = mLocals.insert (std::make_pair (id2, locals)).first;
|
||||
}
|
||||
|
||||
return std::make_pair (iter->second.getType (Misc::StringUtils::lowerCase (name)), reference);
|
||||
}
|
||||
|
||||
bool CSMWorld::ScriptContext::isId (const std::string& name) const
|
||||
|
@ -31,6 +100,7 @@ bool CSMWorld::ScriptContext::isId (const std::string& name) const
|
|||
mIds = mData.getIds();
|
||||
|
||||
std::for_each (mIds.begin(), mIds.end(), &Misc::StringUtils::lowerCase);
|
||||
std::sort (mIds.begin(), mIds.end());
|
||||
|
||||
mIdsUpdated = true;
|
||||
}
|
||||
|
@ -38,7 +108,19 @@ bool CSMWorld::ScriptContext::isId (const std::string& name) const
|
|||
return std::binary_search (mIds.begin(), mIds.end(), Misc::StringUtils::lowerCase (name));
|
||||
}
|
||||
|
||||
bool CSMWorld::ScriptContext::isJournalId (const std::string& name) const
|
||||
{
|
||||
return mData.getJournals().searchId (name)!=-1;
|
||||
}
|
||||
|
||||
void CSMWorld::ScriptContext::invalidateIds()
|
||||
{
|
||||
mIdsUpdated = false;
|
||||
}
|
||||
|
||||
void CSMWorld::ScriptContext::clear()
|
||||
{
|
||||
mIds.clear();
|
||||
mIdsUpdated = false;
|
||||
mLocals.clear();
|
||||
}
|
|
@ -3,8 +3,10 @@
|
|||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <map>
|
||||
|
||||
#include <components/compiler/context.hpp>
|
||||
#include <components/compiler/locals.hpp>
|
||||
|
||||
namespace CSMWorld
|
||||
{
|
||||
|
@ -15,6 +17,7 @@ namespace CSMWorld
|
|||
const Data& mData;
|
||||
mutable std::vector<std::string> mIds;
|
||||
mutable bool mIdsUpdated;
|
||||
mutable std::map<std::string, Compiler::Locals> mLocals;
|
||||
|
||||
public:
|
||||
|
||||
|
@ -26,13 +29,23 @@ namespace CSMWorld
|
|||
virtual char getGlobalType (const std::string& name) const;
|
||||
///< 'l: long, 's': short, 'f': float, ' ': does not exist.
|
||||
|
||||
virtual char getMemberType (const std::string& name, const std::string& id) const;
|
||||
///< 'l: long, 's': short, 'f': float, ' ': does not exist.
|
||||
virtual std::pair<char, bool> getMemberType (const std::string& name,
|
||||
const std::string& id) const;
|
||||
///< Return type of member variable \a name in script \a id or in script of reference of
|
||||
/// \a id
|
||||
/// \return first: 'l: long, 's': short, 'f': float, ' ': does not exist.
|
||||
/// second: true: script of reference
|
||||
|
||||
virtual bool isId (const std::string& name) const;
|
||||
///< Does \a name match an ID, that can be referenced?
|
||||
|
||||
virtual bool isJournalId (const std::string& name) const;
|
||||
///< Does \a name match a journal ID?
|
||||
|
||||
void invalidateIds();
|
||||
|
||||
void clear();
|
||||
///< Remove all cached data.
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
@ -155,6 +155,7 @@ OMW::Engine::Engine(Files::ConfigurationManager& configurationManager)
|
|||
, mSkipMenu (false)
|
||||
, mUseSound (true)
|
||||
, mCompileAll (false)
|
||||
, mWarningsMode (1)
|
||||
, mScriptContext (0)
|
||||
, mFSStrict (false)
|
||||
, mScriptConsoleMode (false)
|
||||
|
@ -424,7 +425,7 @@ void OMW::Engine::prepareEngine (Settings::Manager & settings)
|
|||
mScriptContext->setExtensions (&mExtensions);
|
||||
|
||||
mEnvironment.setScriptManager (new MWScript::ScriptManager (MWBase::Environment::get().getWorld()->getStore(),
|
||||
mVerboseScripts, *mScriptContext));
|
||||
mVerboseScripts, *mScriptContext, mWarningsMode));
|
||||
|
||||
// Create game mechanics system
|
||||
MWMechanics::MechanicsManager* mechanics = new MWMechanics::MechanicsManager;
|
||||
|
@ -612,8 +613,12 @@ void OMW::Engine::setStartupScript (const std::string& path)
|
|||
mStartupScript = path;
|
||||
}
|
||||
|
||||
|
||||
void OMW::Engine::setActivationDistanceOverride (int distance)
|
||||
{
|
||||
mActivationDistanceOverride = distance;
|
||||
}
|
||||
|
||||
void OMW::Engine::setWarningsMode (int mode)
|
||||
{
|
||||
mWarningsMode = mode;
|
||||
}
|
|
@ -74,6 +74,7 @@ namespace OMW
|
|||
bool mSkipMenu;
|
||||
bool mUseSound;
|
||||
bool mCompileAll;
|
||||
int mWarningsMode;
|
||||
std::string mFocusName;
|
||||
std::map<std::string,std::string> mFallbackMap;
|
||||
bool mScriptConsoleMode;
|
||||
|
@ -181,6 +182,8 @@ namespace OMW
|
|||
/// Override the game setting specified activation distance.
|
||||
void setActivationDistanceOverride (int distance);
|
||||
|
||||
void setWarningsMode (int mode);
|
||||
|
||||
private:
|
||||
Files::ConfigurationManager& mCfgMgr;
|
||||
};
|
||||
|
|
|
@ -136,6 +136,13 @@ bool parseOptions (int argc, char** argv, OMW::Engine& engine, Files::Configurat
|
|||
("script-run", bpo::value<std::string>()->default_value(""),
|
||||
"select a file containing a list of console commands that is executed on startup")
|
||||
|
||||
("script-warn", bpo::value<int>()->implicit_value (1)
|
||||
->default_value (1),
|
||||
"handling of warnings when compiling scripts\n"
|
||||
"\t0 - ignore warning\n"
|
||||
"\t1 - show warning but consider script as correctly compiled anyway\n"
|
||||
"\t2 - treat warnings as errors")
|
||||
|
||||
("skip-menu", bpo::value<bool>()->implicit_value(true)
|
||||
->default_value(false), "skip main menu on game startup")
|
||||
|
||||
|
@ -241,6 +248,7 @@ bool parseOptions (int argc, char** argv, OMW::Engine& engine, Files::Configurat
|
|||
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>());
|
||||
|
||||
return true;
|
||||
}
|
||||
|
|
|
@ -3,6 +3,8 @@
|
|||
|
||||
#include "../mwworld/esmstore.hpp"
|
||||
|
||||
#include <components/esm/loaddial.hpp>
|
||||
|
||||
#include <components/compiler/locals.hpp>
|
||||
|
||||
#include "../mwbase/environment.hpp"
|
||||
|
@ -28,16 +30,32 @@ namespace MWScript
|
|||
return MWBase::Environment::get().getWorld()->getGlobalVariableType (name);
|
||||
}
|
||||
|
||||
char CompilerContext::getMemberType (const std::string& name, const std::string& id) const
|
||||
std::pair<char, bool> CompilerContext::getMemberType (const std::string& name,
|
||||
const std::string& id) const
|
||||
{
|
||||
MWWorld::Ptr ptr = MWBase::Environment::get().getWorld()->getPtr (id, false);
|
||||
std::string script;
|
||||
bool reference = false;
|
||||
|
||||
std::string script = MWWorld::Class::get (ptr).getScript (ptr);
|
||||
if (const ESM::Script *scriptRecord =
|
||||
MWBase::Environment::get().getWorld()->getStore().get<ESM::Script>().search (id))
|
||||
{
|
||||
script = scriptRecord->mId;
|
||||
}
|
||||
else
|
||||
{
|
||||
MWWorld::Ptr ptr = MWBase::Environment::get().getWorld()->getPtr (id, false);
|
||||
|
||||
if (script.empty())
|
||||
return ' ';
|
||||
script = MWWorld::Class::get (ptr).getScript (ptr);
|
||||
reference = true;
|
||||
}
|
||||
|
||||
return MWBase::Environment::get().getScriptManager()->getLocals (script).getType (name);
|
||||
char type = ' ';
|
||||
|
||||
if (!script.empty())
|
||||
type = MWBase::Environment::get().getScriptManager()->getLocals (script).getType (
|
||||
Misc::StringUtils::lowerCase (name));
|
||||
|
||||
return std::make_pair (type, reference);
|
||||
}
|
||||
|
||||
bool CompilerContext::isId (const std::string& name) const
|
||||
|
@ -67,4 +85,14 @@ namespace MWScript
|
|||
store.get<ESM::Static>().search (name) ||
|
||||
store.get<ESM::Weapon>().search (name);
|
||||
}
|
||||
|
||||
bool CompilerContext::isJournalId (const std::string& name) const
|
||||
{
|
||||
const MWWorld::ESMStore &store =
|
||||
MWBase::Environment::get().getWorld()->getStore();
|
||||
|
||||
const ESM::Dialogue *topic = store.get<ESM::Dialogue>().search (name);
|
||||
|
||||
return topic && topic->mType==ESM::Dialogue::Journal;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -30,11 +30,18 @@ namespace MWScript
|
|||
/// 'l: long, 's': short, 'f': float, ' ': does not exist.
|
||||
virtual char getGlobalType (const std::string& name) const;
|
||||
|
||||
virtual char getMemberType (const std::string& name, const std::string& id) const;
|
||||
///< 'l: long, 's': short, 'f': float, ' ': does not exist.
|
||||
virtual std::pair<char, bool> getMemberType (const std::string& name,
|
||||
const std::string& id) const;
|
||||
///< Return type of member variable \a name in script \a id or in script of reference of
|
||||
/// \a id
|
||||
/// \return first: 'l: long, 's': short, 'f': float, ' ': does not exist.
|
||||
/// second: true: script of reference
|
||||
|
||||
virtual bool isId (const std::string& name) const;
|
||||
///< Does \a name match an ID, that can be referenced?
|
||||
|
||||
virtual bool isJournalId (const std::string& name) const;
|
||||
///< Does \a name match a journal ID?
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
@ -52,7 +52,9 @@ op 0x20023: AiFollow, explicit reference
|
|||
op 0x20024: AiFollowCell
|
||||
op 0x20025: AiFollowCell, explicit reference
|
||||
op 0x20026: ModRegion
|
||||
opcodes 0x20027-0x3ffff unused
|
||||
op 0x20027: RemoveSoulGem
|
||||
op 0x20028: RemoveSoulGem, explicit reference
|
||||
opcodes 0x20029-0x3ffff unused
|
||||
|
||||
Segment 4:
|
||||
(not implemented yet)
|
||||
|
@ -308,8 +310,8 @@ op 0x20001f1: GetDetected
|
|||
op 0x20001f2: GetDetected, explicit reference
|
||||
op 0x20001f3: AddSoulGem
|
||||
op 0x20001f4: AddSoulGem, explicit reference
|
||||
op 0x20001f5: RemoveSoulGem
|
||||
op 0x20001f6: RemoveSoulGem, explicit reference
|
||||
op 0x20001f5: unused
|
||||
op 0x20001f6: unused
|
||||
op 0x20001f7: PlayBink
|
||||
op 0x20001f8: Drop
|
||||
op 0x20001f9: Drop, explicit reference
|
||||
|
@ -381,5 +383,7 @@ op 0x200023a: StartCombat
|
|||
op 0x200023b: StartCombatExplicit
|
||||
op 0x200023c: StopCombat
|
||||
op 0x200023d: StopCombatExplicit
|
||||
op 0x200023e: GetPcInJail
|
||||
op 0x200023f: GetPcTraveling
|
||||
|
||||
opcodes 0x200023e-0x3ffffff unused
|
||||
opcodes 0x2000240-0x3ffffff unused
|
||||
|
|
|
@ -148,4 +148,25 @@ namespace MWScript
|
|||
|
||||
return false;
|
||||
}
|
||||
|
||||
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);
|
||||
|
||||
if (iter==mScripts.end())
|
||||
{
|
||||
if (const ESM::Script *script = mStore.get<ESM::Script>().find (name))
|
||||
{
|
||||
Locals locals;
|
||||
|
||||
locals.configure (*script);
|
||||
|
||||
iter = mScripts.insert (std::make_pair (name, std::make_pair (false, locals))).first;
|
||||
}
|
||||
}
|
||||
|
||||
return iter->second.second;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -52,6 +52,10 @@ namespace MWScript
|
|||
///< Records for variables that do not exist are dropped silently.
|
||||
///
|
||||
/// \return Known type?
|
||||
|
||||
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.
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
@ -54,6 +54,47 @@ namespace MWScript
|
|||
}
|
||||
}
|
||||
|
||||
const Locals& InterpreterContext::getMemberLocals (std::string& id, bool global)
|
||||
const
|
||||
{
|
||||
if (global)
|
||||
{
|
||||
return MWBase::Environment::get().getScriptManager()->getGlobalScripts().
|
||||
getLocals (id);
|
||||
}
|
||||
else
|
||||
{
|
||||
const MWWorld::Ptr ptr = getReference (id, false);
|
||||
|
||||
id = MWWorld::Class::get (ptr).getScript (ptr);
|
||||
|
||||
ptr.getRefData().setLocals (
|
||||
*MWBase::Environment::get().getWorld()->getStore().get<ESM::Script>().find (id));
|
||||
|
||||
return ptr.getRefData().getLocals();
|
||||
}
|
||||
}
|
||||
|
||||
Locals& InterpreterContext::getMemberLocals (std::string& id, bool global)
|
||||
{
|
||||
if (global)
|
||||
{
|
||||
return MWBase::Environment::get().getScriptManager()->getGlobalScripts().
|
||||
getLocals (id);
|
||||
}
|
||||
else
|
||||
{
|
||||
const MWWorld::Ptr ptr = getReference (id, false);
|
||||
|
||||
id = MWWorld::Class::get (ptr).getScript (ptr);
|
||||
|
||||
ptr.getRefData().setLocals (
|
||||
*MWBase::Environment::get().getWorld()->getStore().get<ESM::Script>().find (id));
|
||||
|
||||
return ptr.getRefData().getLocals();
|
||||
}
|
||||
}
|
||||
|
||||
InterpreterContext::InterpreterContext (
|
||||
MWScript::Locals *locals, MWWorld::Ptr reference)
|
||||
: mLocals (locals), mReference (reference),
|
||||
|
@ -407,82 +448,80 @@ namespace MWScript
|
|||
MWBase::Environment::get().getWorld()->disable (ref);
|
||||
}
|
||||
|
||||
int InterpreterContext::getMemberShort (const std::string& id, const std::string& name) const
|
||||
int InterpreterContext::getMemberShort (const std::string& id, const std::string& name,
|
||||
bool global) const
|
||||
{
|
||||
const MWWorld::Ptr ptr = getReference (id, false);
|
||||
std::string scriptId (id);
|
||||
|
||||
std::string scriptId = MWWorld::Class::get (ptr).getScript (ptr);
|
||||
const Locals& locals = getMemberLocals (scriptId, global);
|
||||
|
||||
int index = MWBase::Environment::get().getScriptManager()->getLocalIndex (scriptId, name, 's');
|
||||
int index = MWBase::Environment::get().getScriptManager()->getLocalIndex (
|
||||
scriptId, name, 's');
|
||||
|
||||
ptr.getRefData().setLocals (
|
||||
*MWBase::Environment::get().getWorld()->getStore().get<ESM::Script>().find (scriptId));
|
||||
return ptr.getRefData().getLocals().mShorts[index];
|
||||
return locals.mShorts[index];
|
||||
}
|
||||
|
||||
int InterpreterContext::getMemberLong (const std::string& id, const std::string& name) const
|
||||
int InterpreterContext::getMemberLong (const std::string& id, const std::string& name,
|
||||
bool global) const
|
||||
{
|
||||
const MWWorld::Ptr ptr = getReference (id, false);
|
||||
std::string scriptId (id);
|
||||
|
||||
std::string scriptId = MWWorld::Class::get (ptr).getScript (ptr);
|
||||
const Locals& locals = getMemberLocals (scriptId, global);
|
||||
|
||||
int index = MWBase::Environment::get().getScriptManager()->getLocalIndex (scriptId, name, 'l');
|
||||
int index = MWBase::Environment::get().getScriptManager()->getLocalIndex (
|
||||
scriptId, name, 'l');
|
||||
|
||||
ptr.getRefData().setLocals (
|
||||
*MWBase::Environment::get().getWorld()->getStore().get<ESM::Script>().find (scriptId));
|
||||
return ptr.getRefData().getLocals().mLongs[index];
|
||||
return locals.mLongs[index];
|
||||
}
|
||||
|
||||
float InterpreterContext::getMemberFloat (const std::string& id, const std::string& name) const
|
||||
float InterpreterContext::getMemberFloat (const std::string& id, const std::string& name,
|
||||
bool global) const
|
||||
{
|
||||
const MWWorld::Ptr ptr = getReference (id, false);
|
||||
std::string scriptId (id);
|
||||
|
||||
std::string scriptId = MWWorld::Class::get (ptr).getScript (ptr);
|
||||
const Locals& locals = getMemberLocals (scriptId, global);
|
||||
|
||||
int index = MWBase::Environment::get().getScriptManager()->getLocalIndex (scriptId, name, 'f');
|
||||
int index = MWBase::Environment::get().getScriptManager()->getLocalIndex (
|
||||
scriptId, name, 'f');
|
||||
|
||||
ptr.getRefData().setLocals (
|
||||
*MWBase::Environment::get().getWorld()->getStore().get<ESM::Script>().find (scriptId));
|
||||
return ptr.getRefData().getLocals().mFloats[index];
|
||||
return locals.mFloats[index];
|
||||
}
|
||||
|
||||
void InterpreterContext::setMemberShort (const std::string& id, const std::string& name, int value)
|
||||
void InterpreterContext::setMemberShort (const std::string& id, const std::string& name,
|
||||
int value, bool global)
|
||||
{
|
||||
const MWWorld::Ptr ptr = getReference (id, false);
|
||||
std::string scriptId (id);
|
||||
|
||||
std::string scriptId = MWWorld::Class::get (ptr).getScript (ptr);
|
||||
Locals& locals = getMemberLocals (scriptId, global);
|
||||
|
||||
int index = MWBase::Environment::get().getScriptManager()->getLocalIndex (scriptId, name, 's');
|
||||
int index =
|
||||
MWBase::Environment::get().getScriptManager()->getLocalIndex (scriptId, name, 's');
|
||||
|
||||
ptr.getRefData().setLocals (
|
||||
*MWBase::Environment::get().getWorld()->getStore().get<ESM::Script>().find (scriptId));
|
||||
ptr.getRefData().getLocals().mShorts[index] = value;
|
||||
locals.mShorts[index] = value;
|
||||
}
|
||||
|
||||
void InterpreterContext::setMemberLong (const std::string& id, const std::string& name, int value)
|
||||
void InterpreterContext::setMemberLong (const std::string& id, const std::string& name, int value, bool global)
|
||||
{
|
||||
const MWWorld::Ptr ptr = getReference (id, false);
|
||||
std::string scriptId (id);
|
||||
|
||||
std::string scriptId = MWWorld::Class::get (ptr).getScript (ptr);
|
||||
Locals& locals = getMemberLocals (scriptId, global);
|
||||
|
||||
int index = MWBase::Environment::get().getScriptManager()->getLocalIndex (scriptId, name, 'l');
|
||||
int index =
|
||||
MWBase::Environment::get().getScriptManager()->getLocalIndex (scriptId, name, 'l');
|
||||
|
||||
ptr.getRefData().setLocals (
|
||||
*MWBase::Environment::get().getWorld()->getStore().get<ESM::Script>().find (scriptId));
|
||||
ptr.getRefData().getLocals().mLongs[index] = value;
|
||||
locals.mLongs[index] = value;
|
||||
}
|
||||
|
||||
void InterpreterContext::setMemberFloat (const std::string& id, const std::string& name, float value)
|
||||
void InterpreterContext::setMemberFloat (const std::string& id, const std::string& name, float value, bool global)
|
||||
{
|
||||
const MWWorld::Ptr ptr = getReference (id, false);
|
||||
std::string scriptId (id);
|
||||
|
||||
std::string scriptId = MWWorld::Class::get (ptr).getScript (ptr);
|
||||
Locals& locals = getMemberLocals (scriptId, global);
|
||||
|
||||
int index = MWBase::Environment::get().getScriptManager()->getLocalIndex (scriptId, name, 'f');
|
||||
int index =
|
||||
MWBase::Environment::get().getScriptManager()->getLocalIndex (scriptId, name, 'f');
|
||||
|
||||
ptr.getRefData().setLocals (
|
||||
*MWBase::Environment::get().getWorld()->getStore().get<ESM::Script>().find (scriptId));
|
||||
ptr.getRefData().getLocals().mFloats[index] = value;
|
||||
locals.mFloats[index] = value;
|
||||
}
|
||||
|
||||
MWWorld::Ptr InterpreterContext::getReference(bool required)
|
||||
|
|
|
@ -37,6 +37,12 @@ namespace MWScript
|
|||
|
||||
const MWWorld::Ptr getReference (const std::string& id, bool activeOnly, 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
|
||||
|
||||
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
|
||||
|
||||
public:
|
||||
|
||||
InterpreterContext (MWScript::Locals *locals, MWWorld::Ptr reference);
|
||||
|
@ -75,35 +81,35 @@ namespace MWScript
|
|||
virtual void setGlobalLong (const std::string& name, int value);
|
||||
|
||||
virtual void setGlobalFloat (const std::string& name, float value);
|
||||
|
||||
|
||||
virtual std::vector<std::string> getGlobals () const;
|
||||
|
||||
virtual char getGlobalType (const std::string& name) const;
|
||||
|
||||
|
||||
virtual std::string getActionBinding(const std::string& action) const;
|
||||
|
||||
|
||||
virtual std::string getNPCName() const;
|
||||
|
||||
|
||||
virtual std::string getNPCRace() const;
|
||||
|
||||
|
||||
virtual std::string getNPCClass() const;
|
||||
|
||||
|
||||
virtual std::string getNPCFaction() const;
|
||||
|
||||
virtual std::string getNPCRank() const;
|
||||
|
||||
|
||||
virtual std::string getPCName() const;
|
||||
|
||||
|
||||
virtual std::string getPCRace() const;
|
||||
|
||||
|
||||
virtual std::string getPCClass() const;
|
||||
|
||||
|
||||
virtual std::string getPCRank() const;
|
||||
|
||||
|
||||
virtual std::string getPCNextRank() const;
|
||||
|
||||
|
||||
virtual int getPCBounty() const;
|
||||
|
||||
|
||||
virtual std::string getCurrentCellName() const;
|
||||
|
||||
virtual bool isScriptRunning (const std::string& name) const;
|
||||
|
@ -138,17 +144,17 @@ namespace MWScript
|
|||
|
||||
virtual void disable (const std::string& id = "");
|
||||
|
||||
virtual int getMemberShort (const std::string& id, const std::string& name) const;
|
||||
virtual int getMemberShort (const std::string& id, const std::string& name, bool global) const;
|
||||
|
||||
virtual int getMemberLong (const std::string& id, const std::string& name) const;
|
||||
virtual int getMemberLong (const std::string& id, const std::string& name, bool global) const;
|
||||
|
||||
virtual float getMemberFloat (const std::string& id, const std::string& name) const;
|
||||
virtual float getMemberFloat (const std::string& id, const std::string& name, bool global) const;
|
||||
|
||||
virtual void setMemberShort (const std::string& id, const std::string& name, int value);
|
||||
virtual void setMemberShort (const std::string& id, const std::string& name, int value, bool global);
|
||||
|
||||
virtual void setMemberLong (const std::string& id, const std::string& name, int value);
|
||||
virtual void setMemberLong (const std::string& id, const std::string& name, int value, bool global);
|
||||
|
||||
virtual void setMemberFloat (const std::string& id, const std::string& name, float value);
|
||||
virtual void setMemberFloat (const std::string& id, const std::string& name, float value, bool global);
|
||||
|
||||
MWWorld::Ptr getReference(bool required=true);
|
||||
///< Reference, that the script is running from (can be empty)
|
||||
|
|
|
@ -365,17 +365,21 @@ namespace MWScript
|
|||
};
|
||||
|
||||
template<class R>
|
||||
class OpRemoveSoulGem : public Interpreter::Opcode0
|
||||
class OpRemoveSoulGem : public Interpreter::Opcode1
|
||||
{
|
||||
public:
|
||||
|
||||
virtual void execute (Interpreter::Runtime& runtime)
|
||||
virtual void execute (Interpreter::Runtime& runtime, unsigned int arg0)
|
||||
{
|
||||
MWWorld::Ptr ptr = R()(runtime);
|
||||
|
||||
std::string soul = runtime.getStringLiteral (runtime[0].mInteger);
|
||||
runtime.pop();
|
||||
|
||||
// throw away additional arguments
|
||||
for (unsigned int i=0; i<arg0; ++i)
|
||||
runtime.pop();
|
||||
|
||||
MWWorld::ContainerStore& store = MWWorld::Class::get (ptr).getContainerStore (ptr);
|
||||
for (MWWorld::ContainerStoreIterator it = store.begin(); it != store.end(); ++it)
|
||||
{
|
||||
|
@ -818,6 +822,28 @@ namespace MWScript
|
|||
}
|
||||
};
|
||||
|
||||
class OpGetPcInJail : public Interpreter::Opcode0
|
||||
{
|
||||
public:
|
||||
|
||||
virtual void execute (Interpreter::Runtime &runtime)
|
||||
{
|
||||
/// \todo implement jail check
|
||||
runtime.push (0);
|
||||
}
|
||||
};
|
||||
|
||||
class OpGetPcTraveling : public Interpreter::Opcode0
|
||||
{
|
||||
public:
|
||||
|
||||
virtual void execute (Interpreter::Runtime &runtime)
|
||||
{
|
||||
/// \todo implement traveling check
|
||||
runtime.push (0);
|
||||
}
|
||||
};
|
||||
|
||||
void installOpcodes (Interpreter::Interpreter& interpreter)
|
||||
{
|
||||
interpreter.installSegment5 (Compiler::Misc::opcodeXBox, new OpXBox);
|
||||
|
@ -850,8 +876,8 @@ namespace MWScript
|
|||
interpreter.installSegment5 (Compiler::Misc::opcodeGetEffectExplicit, new OpGetEffect<ExplicitRef>);
|
||||
interpreter.installSegment5 (Compiler::Misc::opcodeAddSoulGem, new OpAddSoulGem<ImplicitRef>);
|
||||
interpreter.installSegment5 (Compiler::Misc::opcodeAddSoulGemExplicit, new OpAddSoulGem<ExplicitRef>);
|
||||
interpreter.installSegment5 (Compiler::Misc::opcodeRemoveSoulGem, new OpRemoveSoulGem<ImplicitRef>);
|
||||
interpreter.installSegment5 (Compiler::Misc::opcodeRemoveSoulGemExplicit, new OpRemoveSoulGem<ExplicitRef>);
|
||||
interpreter.installSegment3 (Compiler::Misc::opcodeRemoveSoulGem, new OpRemoveSoulGem<ImplicitRef>);
|
||||
interpreter.installSegment3 (Compiler::Misc::opcodeRemoveSoulGemExplicit, new OpRemoveSoulGem<ExplicitRef>);
|
||||
interpreter.installSegment5 (Compiler::Misc::opcodeDrop, new OpDrop<ImplicitRef>);
|
||||
interpreter.installSegment5 (Compiler::Misc::opcodeDropExplicit, new OpDrop<ExplicitRef>);
|
||||
interpreter.installSegment5 (Compiler::Misc::opcodeDropSoulGem, new OpDropSoulGem<ImplicitRef>);
|
||||
|
@ -888,6 +914,8 @@ namespace MWScript
|
|||
interpreter.installSegment5 (Compiler::Misc::opcodeCastExplicit, new OpCast<ExplicitRef>);
|
||||
interpreter.installSegment5 (Compiler::Misc::opcodeExplodeSpell, new OpExplodeSpell<ImplicitRef>);
|
||||
interpreter.installSegment5 (Compiler::Misc::opcodeExplodeSpellExplicit, new OpExplodeSpell<ExplicitRef>);
|
||||
interpreter.installSegment5 (Compiler::Misc::opcodeGetPcInJail, new OpGetPcInJail);
|
||||
interpreter.installSegment5 (Compiler::Misc::opcodeGetPcTraveling, new OpGetPcTraveling);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -7,22 +7,28 @@
|
|||
#include <exception>
|
||||
|
||||
#include <components/esm/loadscpt.hpp>
|
||||
#include "../mwworld/esmstore.hpp"
|
||||
|
||||
#include <components/misc/stringops.hpp>
|
||||
|
||||
#include <components/compiler/scanner.hpp>
|
||||
#include <components/compiler/context.hpp>
|
||||
#include <components/compiler/exception.hpp>
|
||||
#include <components/compiler/quickfileparser.hpp>
|
||||
|
||||
#include "../mwworld/esmstore.hpp"
|
||||
|
||||
#include "extensions.hpp"
|
||||
|
||||
namespace MWScript
|
||||
{
|
||||
ScriptManager::ScriptManager (const MWWorld::ESMStore& store, bool verbose,
|
||||
Compiler::Context& compilerContext)
|
||||
Compiler::Context& compilerContext, int warningsMode)
|
||||
: mErrorHandler (std::cerr), mStore (store), mVerbose (verbose),
|
||||
mCompilerContext (compilerContext), mParser (mErrorHandler, mCompilerContext),
|
||||
mOpcodesInstalled (false), mGlobalScripts (store)
|
||||
{}
|
||||
{
|
||||
mErrorHandler.setWarningsMode (warningsMode);
|
||||
}
|
||||
|
||||
bool ScriptManager::compile (const std::string& name)
|
||||
{
|
||||
|
@ -138,37 +144,33 @@ namespace MWScript
|
|||
|
||||
Compiler::Locals& ScriptManager::getLocals (const std::string& name)
|
||||
{
|
||||
std::string name2 = Misc::StringUtils::lowerCase (name);
|
||||
|
||||
{
|
||||
ScriptCollection::iterator iter = mScripts.find (name);
|
||||
ScriptCollection::iterator iter = mScripts.find (name2);
|
||||
|
||||
if (iter!=mScripts.end())
|
||||
return iter->second.second;
|
||||
}
|
||||
|
||||
{
|
||||
std::map<std::string, Compiler::Locals>::iterator iter = mOtherLocals.find (name);
|
||||
std::map<std::string, Compiler::Locals>::iterator iter = mOtherLocals.find (name2);
|
||||
|
||||
if (iter!=mOtherLocals.end())
|
||||
return iter->second;
|
||||
}
|
||||
|
||||
Compiler::Locals locals;
|
||||
|
||||
if (const ESM::Script *script = mStore.get<ESM::Script>().find (name))
|
||||
if (const ESM::Script *script = mStore.get<ESM::Script>().find (name2))
|
||||
{
|
||||
int index = 0;
|
||||
Compiler::Locals locals;
|
||||
|
||||
for (int i=0; i<script->mData.mNumShorts; ++i)
|
||||
locals.declare ('s', script->mVarNames[index++]);
|
||||
|
||||
for (int i=0; i<script->mData.mNumLongs; ++i)
|
||||
locals.declare ('l', script->mVarNames[index++]);
|
||||
|
||||
for (int i=0; i<script->mData.mNumFloats; ++i)
|
||||
locals.declare ('f', script->mVarNames[index++]);
|
||||
std::istringstream stream (script->mScriptText);
|
||||
Compiler::QuickFileParser parser (mErrorHandler, mCompilerContext, locals);
|
||||
Compiler::Scanner scanner (mErrorHandler, stream, mCompilerContext.getExtensions());
|
||||
scanner.scan (parser);
|
||||
|
||||
std::map<std::string, Compiler::Locals>::iterator iter =
|
||||
mOtherLocals.insert (std::make_pair (name, locals)).first;
|
||||
mOtherLocals.insert (std::make_pair (name2, locals)).first;
|
||||
|
||||
return iter->second;
|
||||
}
|
||||
|
@ -214,8 +216,10 @@ namespace MWScript
|
|||
throw std::runtime_error ("invalid variable type");
|
||||
}
|
||||
|
||||
std::string variable2 = Misc::StringUtils::lowerCase (variable);
|
||||
|
||||
for (int i=0; i<size; ++i)
|
||||
if (script->mVarNames.at (i+offset)==variable)
|
||||
if (Misc::StringUtils::lowerCase (script->mVarNames.at (i+offset))==variable2)
|
||||
return i;
|
||||
|
||||
throw std::runtime_error ("unable to access local variable " + variable + " of " + scriptId);
|
||||
|
|
|
@ -52,7 +52,7 @@ namespace MWScript
|
|||
public:
|
||||
|
||||
ScriptManager (const MWWorld::ESMStore& store, bool verbose,
|
||||
Compiler::Context& compilerContext);
|
||||
Compiler::Context& compilerContext, int warningsMode);
|
||||
|
||||
virtual void run (const std::string& name, Interpreter::Context& interpreterContext);
|
||||
///< Run the script with the given name (compile first, if not compiled yet)
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue