#include "containerextensions.hpp" #include #include #include #include #include #include "../mwworld/manualref.hpp" #include "../mwworld/class.hpp" #include "../mwworld/containerutil.hpp" #include "interpretercontext.hpp" #include "ref.hpp" namespace MWScript { namespace Container { template class OpAddItem : public Interpreter::Opcode0 { public: virtual void execute (Interpreter::Runtime& runtime) { MWWorld::Ptr ptr = R()(runtime); MWScript::InterpreterContext& context = static_cast (runtime.getContext()); std::string item = runtime.getStringLiteral (runtime[0].mInteger); runtime.pop(); Interpreter::Type_Integer count = runtime[0].mInteger; runtime.pop(); if (count<0) throw std::runtime_error ("second argument for AddItem must be non-negative"); MWWorld::ManualRef ref (context.getWorld().getStore(), item); ref.getPtr().getRefData().setCount (count); MWWorld::Class::get (ref.getPtr()).insertIntoContainer (ref.getPtr(), MWWorld::Class::get (ptr).getContainerStore (ptr)); } }; template class OpGetItemCount : public Interpreter::Opcode0 { public: virtual void execute (Interpreter::Runtime& runtime) { MWWorld::Ptr ptr = R()(runtime); MWScript::InterpreterContext& context = static_cast (runtime.getContext()); std::string item = runtime.getStringLiteral (runtime[0].mInteger); runtime.pop(); std::vector list; MWWorld::listItemsInContainer (item, MWWorld::Class::get (ptr).getContainerStore (ptr), context.getWorld().getStore(), list); Interpreter::Type_Integer sum = 0; for (std::vector::iterator iter (list.begin()); iter!=list.end(); ++iter) { sum += iter->getRefData().getCount(); } runtime.push (sum); } }; template class OpRemoveItem : public Interpreter::Opcode0 { public: virtual void execute (Interpreter::Runtime& runtime) { MWWorld::Ptr ptr = R()(runtime); MWScript::InterpreterContext& context = static_cast (runtime.getContext()); std::string item = runtime.getStringLiteral (runtime[0].mInteger); runtime.pop(); Interpreter::Type_Integer count = runtime[0].mInteger; runtime.pop(); if (count<0) throw std::runtime_error ("second argument for RemoveItem must be non-negative"); std::vector list; MWWorld::listItemsInContainer (item, MWWorld::Class::get (ptr).getContainerStore (ptr), context.getWorld().getStore(), list); for (std::vector::iterator iter (list.begin()); iter!=list.end() && count; ++iter) { if (iter->getRefData().getCount()<=count) { count -= iter->getRefData().getCount(); iter->getRefData().setCount (0); } else { iter->getRefData().setCount (iter->getRefData().getCount()-count); count = 0; } } // To be fully compatible with original Morrowind, we would need to check if // count is >= 0 here and throw an exception. But let's be tollerant instead. } }; const int opcodeAddItem = 0x2000076; const int opcodeAddItemExplicit = 0x2000077; const int opcodeGetItemCount = 0x2000078; const int opcodeGetItemCountExplicit = 0x2000079; const int opcodeRemoveItem = 0x200007a; const int opcodeRemoveItemExplicit = 0x200007b; void registerExtensions (Compiler::Extensions& extensions) { extensions.registerInstruction ("additem", "cl", opcodeAddItem, opcodeAddItemExplicit); extensions.registerFunction ("getitemcount", 'l', "c", opcodeGetItemCount, opcodeGetItemCountExplicit); extensions.registerInstruction ("removeitem", "cl", opcodeRemoveItem, opcodeRemoveItemExplicit); } void installOpcodes (Interpreter::Interpreter& interpreter) { interpreter.installSegment5 (opcodeAddItem, new OpAddItem); interpreter.installSegment5 (opcodeAddItemExplicit, new OpAddItem); interpreter.installSegment5 (opcodeGetItemCount, new OpGetItemCount); interpreter.installSegment5 (opcodeGetItemCountExplicit, new OpGetItemCount); interpreter.installSegment5 (opcodeRemoveItem, new OpRemoveItem); interpreter.installSegment5 (opcodeRemoveItemExplicit, new OpRemoveItem); } } }