Merge branch 'script'

Conflicts:
	readme.txt
This commit is contained in:
Marc Zinnschlag 2014-02-16 12:12:56 +01:00
commit 6ac64bbe15
54 changed files with 1129 additions and 286 deletions

View file

@ -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
)

View 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;
}

View 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

View file

@ -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;

View file

@ -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();
}

View file

@ -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.
};
}

View file

@ -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;
}

View file

@ -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;
};

View file

@ -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;
}

View file

@ -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;
}
}

View file

@ -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?
};
}

View file

@ -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

View file

@ -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;
}
}

View file

@ -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.
};
}

View file

@ -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)

View file

@ -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)

View file

@ -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);
}
}
}

View file

@ -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);

View file

@ -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)