You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
openmw-tes3mp/apps/openmw/mwscript/containerextensions.cpp

192 lines
7.0 KiB
C++

#include "containerextensions.hpp"
#include <stdexcept>
#include <components/compiler/extensions.hpp>
#include <components/interpreter/interpreter.hpp>
#include <components/interpreter/runtime.hpp>
#include <components/interpreter/opcodes.hpp>
#include "../mwbase/environment.hpp"
#include "../mwworld/manualref.hpp"
#include "../mwworld/class.hpp"
#include "../mwworld/containerstore.hpp"
12 years ago
#include "../mwworld/actionequip.hpp"
#include "../mwworld/inventorystore.hpp"
#include "interpretercontext.hpp"
#include "ref.hpp"
namespace
{
std::string toLower (const std::string& name)
{
std::string lowerCase;
std::transform (name.begin(), name.end(), std::back_inserter (lowerCase),
(int(*)(int)) std::tolower);
return lowerCase;
}
}
namespace MWScript
{
namespace Container
{
template<class R>
class OpAddItem : public Interpreter::Opcode0
{
public:
virtual void execute (Interpreter::Runtime& runtime)
{
MWWorld::Ptr ptr = R()(runtime);
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 (MWBase::Environment::get().getWorld()->getStore(), item);
ref.getPtr().getRefData().setCount (count);
MWWorld::Class::get (ptr).getContainerStore (ptr).add (ref.getPtr());
}
};
template<class R>
class OpGetItemCount : public Interpreter::Opcode0
{
public:
virtual void execute (Interpreter::Runtime& runtime)
{
MWWorld::Ptr ptr = R()(runtime);
std::string item = runtime.getStringLiteral (runtime[0].mInteger);
runtime.pop();
MWWorld::ContainerStore& store = MWWorld::Class::get (ptr).getContainerStore (ptr);
Interpreter::Type_Integer sum = 0;
for (MWWorld::ContainerStoreIterator iter (store.begin()); iter!=store.end(); ++iter)
if (toLower(iter->getCellRef().mRefID) == toLower(item))
sum += iter->getRefData().getCount();
runtime.push (sum);
}
};
template<class R>
15 years ago
class OpRemoveItem : public Interpreter::Opcode0
{
public:
virtual void execute (Interpreter::Runtime& runtime)
{
MWWorld::Ptr ptr = R()(runtime);
15 years ago
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");
MWWorld::ContainerStore& store = MWWorld::Class::get (ptr).getContainerStore (ptr);
15 years ago
for (MWWorld::ContainerStoreIterator iter (store.begin()); iter!=store.end() && count;
15 years ago
++iter)
{
if (toLower(iter->getCellRef().mRefID) == toLower(item))
15 years ago
{
if (iter->getRefData().getCount()<=count)
{
count -= iter->getRefData().getCount();
iter->getRefData().setCount (0);
}
else
{
iter->getRefData().setCount (iter->getRefData().getCount()-count);
count = 0;
}
15 years ago
}
}
// 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.
}
};
12 years ago
template <class R>
class OpEquip : public Interpreter::Opcode0
{
public:
virtual void execute(Interpreter::Runtime &runtime)
{
MWWorld::Ptr ptr = R()(runtime);
std::string item = runtime.getStringLiteral (runtime[0].mInteger);
runtime.pop();
MWWorld::InventoryStore& invStore = MWWorld::Class::get(ptr).getInventoryStore (ptr);
MWWorld::ContainerStoreIterator it = invStore.begin();
for (; it != invStore.end(); ++it)
{
if (toLower(it->getCellRef().mRefID) == toLower(item))
break;
}
if (it == invStore.end())
throw std::runtime_error("Item to equip not found");
MWWorld::ActionEquip action (*it);
action.execute(ptr);
}
};
const int opcodeAddItem = 0x2000076;
const int opcodeAddItemExplicit = 0x2000077;
const int opcodeGetItemCount = 0x2000078;
const int opcodeGetItemCountExplicit = 0x2000079;
15 years ago
const int opcodeRemoveItem = 0x200007a;
const int opcodeRemoveItemExplicit = 0x200007b;
12 years ago
const int opcodeEquip = 0x20001b3;
const int opcodeEquipExplicit = 0x20001b4;
void registerExtensions (Compiler::Extensions& extensions)
{
extensions.registerInstruction ("additem", "cl", opcodeAddItem, opcodeAddItemExplicit);
extensions.registerFunction ("getitemcount", 'l', "c", opcodeGetItemCount,
opcodeGetItemCountExplicit);
15 years ago
extensions.registerInstruction ("removeitem", "cl", opcodeRemoveItem,
opcodeRemoveItemExplicit);
12 years ago
extensions.registerInstruction ("equip", "c", opcodeEquip, opcodeEquipExplicit);
}
void installOpcodes (Interpreter::Interpreter& interpreter)
{
interpreter.installSegment5 (opcodeAddItem, new OpAddItem<ImplicitRef>);
interpreter.installSegment5 (opcodeAddItemExplicit, new OpAddItem<ExplicitRef>);
interpreter.installSegment5 (opcodeGetItemCount, new OpGetItemCount<ImplicitRef>);
interpreter.installSegment5 (opcodeGetItemCountExplicit, new OpGetItemCount<ExplicitRef>);
interpreter.installSegment5 (opcodeRemoveItem, new OpRemoveItem<ImplicitRef>);
interpreter.installSegment5 (opcodeRemoveItemExplicit, new OpRemoveItem<ExplicitRef>);
12 years ago
interpreter.installSegment5 (opcodeEquip, new OpEquip<ImplicitRef>);
interpreter.installSegment5 (opcodeEquipExplicit, new OpEquip<ExplicitRef>);
}
}
}