diff --git a/apps/openmw/CMakeLists.txt b/apps/openmw/CMakeLists.txt index 3464a2c33e..260ebcd70f 100644 --- a/apps/openmw/CMakeLists.txt +++ b/apps/openmw/CMakeLists.txt @@ -50,6 +50,7 @@ set(GAMESCRIPT mwscript/guiextensions.cpp mwscript/soundextensions.cpp mwscript/skyextensions.cpp + mwscript/statsextensions.cpp mwscript/extensions.cpp mwscript/globalscripts.cpp ) @@ -63,6 +64,7 @@ set(GAMESCRIPT_HEADER mwscript/guiextensions.hpp mwscript/soundextensions.hpp mwscript/skyextensions.hpp + mwscript/statsextensions.hpp mwscript/extensions.hpp mwscript/globalscripts.hpp ) diff --git a/apps/openmw/mwmechanics/stat.hpp b/apps/openmw/mwmechanics/stat.hpp index eb0e35bd96..e13c0aff29 100644 --- a/apps/openmw/mwmechanics/stat.hpp +++ b/apps/openmw/mwmechanics/stat.hpp @@ -1,6 +1,8 @@ #ifndef GAME_MWMECHANICS_STAT_H #define GAME_MWMECHANICS_STAT_H +#include + namespace MWMechanics { template @@ -37,6 +39,26 @@ namespace MWMechanics mModified += diff; } + /// Set modified value an adjust base accordingly. + void setModified (T value, const T& min, const T& max = std::numeric_limits::max()) + { + T diff = value - mModified; + + if (mBase+diffmax-diff) + { + value = max + (mModified - mBase); + diff = value - mModified; + } + + mModified = value; + mBase += diff; + } + /// Change modified relatively. void modify (const T& diff) { diff --git a/apps/openmw/mwscript/docs/vmformat.txt b/apps/openmw/mwscript/docs/vmformat.txt index 6d78065b32..55b34f32da 100644 --- a/apps/openmw/mwscript/docs/vmformat.txt +++ b/apps/openmw/mwscript/docs/vmformat.txt @@ -60,5 +60,11 @@ op 0x2000023: TurnMoonRed op 0x2000024: GetMasserPhase op 0x2000025: GetSecundaPhase op 0x2000026: COC -opcodes 0x2000027-0x3ffffff unused +op 0x2000027-0x200002e: GetAttribute +op 0x200002f-0x2000036: GetAttribute, explicit reference +op 0x2000037-0x200003e: SetAttribute +op 0x200003f-0x2000046: SetAttribute, explicit reference +op 0x2000047-0x200004e: ModAttribute +op 0x200004f-0x2000056: ModAttribute, explicit reference +opcodes 0x2000057-0x3ffffff unused diff --git a/apps/openmw/mwscript/extensions.cpp b/apps/openmw/mwscript/extensions.cpp index 94f553b58e..3abaac58cb 100644 --- a/apps/openmw/mwscript/extensions.cpp +++ b/apps/openmw/mwscript/extensions.cpp @@ -9,6 +9,7 @@ #include "miscextensions.hpp" #include "guiextensions.hpp" #include "skyextensions.hpp" +#include "statsextensions.hpp" namespace MWScript { @@ -19,6 +20,7 @@ namespace MWScript Gui::registerExtensions (extensions); Sound::registerExtensions (extensions); Sky::registerExtensions (extensions); + Stats::registerExtensions (extensions); } void installOpcodes (Interpreter::Interpreter& interpreter) @@ -29,6 +31,7 @@ namespace MWScript Gui::installOpcodes (interpreter); Sound::installOpcodes (interpreter); Sky::installOpcodes (interpreter); + Stats::installOpcodes (interpreter); } } diff --git a/apps/openmw/mwscript/interpretercontext.cpp b/apps/openmw/mwscript/interpretercontext.cpp index cc9d5f33bd..f2dc57dd0e 100644 --- a/apps/openmw/mwscript/interpretercontext.cpp +++ b/apps/openmw/mwscript/interpretercontext.cpp @@ -242,7 +242,7 @@ namespace MWScript MWWorld::Ptr InterpreterContext::getReference() { - return mReference; + return getReference ("", true); } } diff --git a/apps/openmw/mwscript/statsextensions.cpp b/apps/openmw/mwscript/statsextensions.cpp new file mode 100644 index 0000000000..fd1f5eda69 --- /dev/null +++ b/apps/openmw/mwscript/statsextensions.cpp @@ -0,0 +1,211 @@ + +#include "statsextensions.hpp" + +#include + +#include +#include +#include + +#include "interpretercontext.hpp" + +namespace MWScript +{ + namespace Stats + { + class OpGetAttribute : public Interpreter::Opcode0 + { + int mIndex; + + public: + + OpGetAttribute (int index) : mIndex (index) {} + + virtual void execute (Interpreter::Runtime& runtime) + { + MWScript::InterpreterContext& context + = static_cast (runtime.getContext()); + + Interpreter::Type_Integer value = + context.getReference().getCreatureStats().mAttributes[mIndex]. + getModified(); + + runtime.push (value); + } + }; + + class OpGetAttributeExplicit : public Interpreter::Opcode0 + { + int mIndex; + + public: + + OpGetAttributeExplicit (int index) : mIndex (index) {} + + virtual void execute (Interpreter::Runtime& runtime) + { + MWScript::InterpreterContext& context + = static_cast (runtime.getContext()); + + std::string id = runtime.getStringLiteral (runtime[0].mInteger); + runtime.pop(); + + Interpreter::Type_Integer value = + context.getWorld().getPtr (id, false).getCreatureStats().mAttributes[mIndex]. + getModified(); + + runtime.push (value); + } + }; + + class OpSetAttribute : public Interpreter::Opcode0 + { + int mIndex; + + public: + + OpSetAttribute (int index) : mIndex (index) {} + + virtual void execute (Interpreter::Runtime& runtime) + { + MWScript::InterpreterContext& context + = static_cast (runtime.getContext()); + + Interpreter::Type_Integer value = runtime[0].mInteger; + runtime.pop(); + + context.getReference().getCreatureStats().mAttributes[mIndex]. + setModified (value, 0); + } + }; + + class OpSetAttributeExplicit : public Interpreter::Opcode0 + { + int mIndex; + + public: + + OpSetAttributeExplicit (int index) : mIndex (index) {} + + virtual void execute (Interpreter::Runtime& runtime) + { + MWScript::InterpreterContext& context + = static_cast (runtime.getContext()); + + std::string id = runtime.getStringLiteral (runtime[0].mInteger); + runtime.pop(); + + Interpreter::Type_Integer value = runtime[0].mInteger; + runtime.pop(); + + context.getWorld().getPtr (id, false).getCreatureStats().mAttributes[mIndex]. + setModified (value, 0); + } + }; + + class OpModAttribute : public Interpreter::Opcode0 + { + int mIndex; + + public: + + OpModAttribute (int index) : mIndex (index) {} + + virtual void execute (Interpreter::Runtime& runtime) + { + MWScript::InterpreterContext& context + = static_cast (runtime.getContext()); + + Interpreter::Type_Integer value = runtime[0].mInteger; + runtime.pop(); + + value += context.getReference().getCreatureStats().mAttributes[mIndex]. + getModified(); + + context.getReference().getCreatureStats().mAttributes[mIndex]. + setModified (value, 0, 100); + } + }; + + class OpModAttributeExplicit : public Interpreter::Opcode0 + { + int mIndex; + + public: + + OpModAttributeExplicit (int index) : mIndex (index) {} + + virtual void execute (Interpreter::Runtime& runtime) + { + MWScript::InterpreterContext& context + = static_cast (runtime.getContext()); + + std::string id = runtime.getStringLiteral (runtime[0].mInteger); + runtime.pop(); + + Interpreter::Type_Integer value = runtime[0].mInteger; + runtime.pop(); + + value += + context.getWorld().getPtr (id, false).getCreatureStats().mAttributes[mIndex]. + getModified(); + + context.getWorld().getPtr (id, false).getCreatureStats().mAttributes[mIndex]. + setModified (value, 0, 100); + } + }; + + const int numberOfAttributes = 8; + + const int opcodeGetAttribute = 0x2000027; + const int opcodeGetAttributeExplicit = 0x200002f; + const int opcodeSetAttribute = 0x2000037; + const int opcodeSetAttributeExplicit = 0x200003f; + const int opcodeModAttribute = 0x2000047; + const int opcodeModAttributeExplicit = 0x200004f; + + void registerExtensions (Compiler::Extensions& extensions) + { + static const char *attributes[numberOfAttributes] = + { + "strength", "intelligence", "willpower", "agility", "speed", "endurance", + "personality", "luck" + }; + + std::string get ("get"); + std::string set ("set"); + std::string mod ("mod"); + + for (int i=0; i *)) { - boost::shared_ptr stats; - data.getCreatureStats() = stats; + boost::shared_ptr stats ( + new MWMechanics::CreatureStats); ESMS::LiveCellRef *ref = get(); @@ -92,11 +92,13 @@ namespace MWWorld stats->mAttributes[5].set (ref->base->data.endurance); stats->mAttributes[6].set (ref->base->data.personality); stats->mAttributes[7].set (ref->base->data.luck); + + data.getCreatureStats() = stats; } else if (mPtr.type()==typeid (ESMS::LiveCellRef *)) { - boost::shared_ptr stats; - data.getCreatureStats() = stats; + boost::shared_ptr stats ( + new MWMechanics::CreatureStats); ESMS::LiveCellRef *ref = get(); @@ -108,6 +110,8 @@ namespace MWWorld stats->mAttributes[5].set (ref->base->npdt52.endurance); stats->mAttributes[6].set (ref->base->npdt52.personality); stats->mAttributes[7].set (ref->base->npdt52.luck); + + data.getCreatureStats() = stats; } else throw std::runtime_error (