1
0
Fork 1
mirror of https://github.com/TES3MP/openmw-tes3mp.git synced 2025-01-16 05:49:56 +00:00
openmw-tes3mp/apps/openmw/mwscript/containerextensions.cpp

376 lines
16 KiB
C++
Raw Normal View History

2010-08-07 13:11:31 +00:00
#include "containerextensions.hpp"
#include <stdexcept>
#include <boost/format.hpp>
#include <MyGUI_LanguageManager.h>
2010-08-07 13:11:31 +00:00
#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 "../mwbase/windowmanager.hpp"
2010-08-07 13:11:31 +00:00
#include "../mwworld/manualref.hpp"
#include "../mwworld/class.hpp"
#include "../mwworld/containerstore.hpp"
2012-11-23 19:48:59 +00:00
#include "../mwworld/actionequip.hpp"
#include "../mwworld/inventorystore.hpp"
2010-08-07 13:11:31 +00:00
#include "interpretercontext.hpp"
#include "ref.hpp"
2010-08-07 13:11:31 +00:00
namespace MWScript
{
namespace Container
{
template<class R>
2010-08-07 13:11:31 +00:00
class OpAddItem : public Interpreter::Opcode0
{
public:
virtual void execute (Interpreter::Runtime& runtime)
{
MWWorld::Ptr ptr = R()(runtime);
2010-08-07 13:11:31 +00:00
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);
2010-08-07 13:11:31 +00:00
ref.getPtr().getRefData().setCount (count);
MWWorld::Class::get (ptr).getContainerStore (ptr).add (ref.getPtr());
2010-08-07 13:11:31 +00:00
}
};
template<class R>
2010-08-07 14:21:07 +00:00
class OpGetItemCount : public Interpreter::Opcode0
{
public:
virtual void execute (Interpreter::Runtime& runtime)
{
MWWorld::Ptr ptr = R()(runtime);
2010-08-07 14:21:07 +00:00
std::string item = runtime.getStringLiteral (runtime[0].mInteger);
runtime.pop();
MWWorld::ContainerStore& store = MWWorld::Class::get (ptr).getContainerStore (ptr);
2010-08-07 14:21:07 +00:00
Interpreter::Type_Integer sum = 0;
for (MWWorld::ContainerStoreIterator iter (store.begin()); iter!=store.end(); ++iter)
2012-12-31 07:22:40 +00:00
if (Misc::StringUtils::ciEqual(iter->getCellRef().mRefID, item))
sum += iter->getRefData().getCount();
2010-08-07 14:21:07 +00:00
runtime.push (sum);
}
};
template<class R>
2010-08-07 15:00:04 +00:00
class OpRemoveItem : public Interpreter::Opcode0
{
public:
virtual void execute (Interpreter::Runtime& runtime)
{
MWWorld::Ptr ptr = R()(runtime);
2010-08-07 15:00:04 +00:00
std::string item = runtime.getStringLiteral (runtime[0].mInteger);
runtime.pop();
Interpreter::Type_Integer count = runtime[0].mInteger;
runtime.pop();
2010-08-07 15:00:04 +00:00
if (count<0)
throw std::runtime_error ("second argument for RemoveItem must be non-negative");
MWWorld::ContainerStore& store = MWWorld::Class::get (ptr).getContainerStore (ptr);
std::string itemName = "";
Interpreter::Type_Integer originalCount = count;
2010-08-07 15:00:04 +00:00
for (MWWorld::ContainerStoreIterator iter (store.begin()); iter!=store.end() && count;
2010-08-07 15:00:04 +00:00
++iter)
{
2012-12-31 07:22:40 +00:00
if (Misc::StringUtils::ciEqual(iter->getCellRef().mRefID, item))
2010-08-07 15:00:04 +00:00
{
itemName = MWWorld::Class::get(*iter).getName(*iter);
if (iter->getRefData().getCount()<=count)
{
count -= iter->getRefData().getCount();
iter->getRefData().setCount (0);
}
else
{
iter->getRefData().setCount (iter->getRefData().getCount()-count);
count = 0;
}
2010-08-07 15:00:04 +00:00
}
}
/* The two GMST entries below expand to strings informing the player of what, and how many of it has been removed from their inventory */
std::string msgBox;
if(originalCount - count > 1)
{
msgBox = MyGUI::LanguageManager::getInstance().replaceTags("#{sNotifyMessage63}");
std::stringstream temp;
temp << boost::format(msgBox) % (originalCount - count) % itemName;
msgBox = temp.str();
}
else
{
msgBox = MyGUI::LanguageManager::getInstance().replaceTags("#{sNotifyMessage62}");
std::stringstream temp;
temp << boost::format(msgBox) % itemName;
msgBox = temp.str();
}
if(originalCount - count > 0)
MWBase::Environment::get().getWindowManager()->messageBox(msgBox, std::vector<std::string>());
2010-08-07 15:00:04 +00:00
// 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.
}
};
2012-11-23 19:48:59 +00:00
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)
{
2012-12-31 07:22:40 +00:00
if (Misc::StringUtils::ciEqual(it->getCellRef().mRefID, item))
2012-11-23 19:48:59 +00:00
break;
}
if (it == invStore.end())
throw std::runtime_error("Item to equip not found");
MWWorld::ActionEquip action (*it);
action.execute(ptr);
}
};
2012-11-24 01:38:10 +00:00
template <class R>
class OpGetArmorType : public Interpreter::Opcode0
{
public:
virtual void execute(Interpreter::Runtime &runtime)
{
MWWorld::Ptr ptr = R()(runtime);
Interpreter::Type_Integer location = runtime[0].mInteger;
runtime.pop();
int slot;
switch (location)
{
case 0:
slot = MWWorld::InventoryStore::Slot_Helmet;
break;
case 1:
slot = MWWorld::InventoryStore::Slot_Cuirass;
break;
case 2:
slot = MWWorld::InventoryStore::Slot_LeftPauldron;
break;
case 3:
slot = MWWorld::InventoryStore::Slot_RightPauldron;
break;
case 4:
slot = MWWorld::InventoryStore::Slot_Greaves;
break;
case 5:
slot = MWWorld::InventoryStore::Slot_Boots;
break;
case 6:
slot = MWWorld::InventoryStore::Slot_LeftGauntlet;
break;
case 7:
slot = MWWorld::InventoryStore::Slot_RightGauntlet;
break;
case 8:
slot = MWWorld::InventoryStore::Slot_CarriedLeft; // shield
break;
case 9:
slot = MWWorld::InventoryStore::Slot_LeftGauntlet;
break;
case 10:
slot = MWWorld::InventoryStore::Slot_RightGauntlet;
break;
default:
throw std::runtime_error ("armor index out of range");
}
MWWorld::InventoryStore& invStore = MWWorld::Class::get(ptr).getInventoryStore (ptr);
MWWorld::ContainerStoreIterator it = invStore.getSlot (slot);
2012-11-28 01:48:21 +00:00
if (it == invStore.end() || it->getTypeName () != typeid(ESM::Armor).name())
2012-11-24 01:38:10 +00:00
{
runtime.push(-1);
return;
}
int skill = MWWorld::Class::get(*it).getEquipmentSkill (*it) ;
if (skill == ESM::Skill::HeavyArmor)
runtime.push(2);
else if (skill == ESM::Skill::MediumArmor)
runtime.push(1);
else if (skill == ESM::Skill::LightArmor)
runtime.push(0);
else
runtime.push(-1);
}
};
2012-11-24 01:59:44 +00:00
template <class R>
class OpHasItemEquipped : 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);
for (int slot = 0; slot < MWWorld::InventoryStore::Slots; ++slot)
{
MWWorld::ContainerStoreIterator it = invStore.getSlot (slot);
2012-12-31 07:22:40 +00:00
if (it != invStore.end() && Misc::StringUtils::ciEqual(it->getCellRef().mRefID, item))
2012-11-24 01:59:44 +00:00
{
runtime.push(1);
return;
}
}
runtime.push(0);
}
};
2012-11-25 00:54:37 +00:00
template <class R>
class OpHasSoulGem : public Interpreter::Opcode0
{
public:
virtual void execute(Interpreter::Runtime &runtime)
{
MWWorld::Ptr ptr = R()(runtime);
2012-12-30 18:56:38 +00:00
2012-12-31 07:22:40 +00:00
const std::string &name = runtime.getStringLiteral (runtime[0].mInteger);
2012-11-25 00:54:37 +00:00
runtime.pop();
MWWorld::InventoryStore& invStore = MWWorld::Class::get(ptr).getInventoryStore (ptr);
for (MWWorld::ContainerStoreIterator it = invStore.begin(MWWorld::ContainerStore::Type_Miscellaneous);
it != invStore.end(); ++it)
{
2012-12-31 07:22:40 +00:00
if (Misc::StringUtils::ciEqual(it->getCellRef().mSoul, name))
2012-11-25 00:54:37 +00:00
{
runtime.push(1);
return;
}
}
runtime.push(0);
}
};
2012-11-25 01:06:43 +00:00
template <class R>
class OpGetWeaponType : public Interpreter::Opcode0
{
public:
virtual void execute(Interpreter::Runtime &runtime)
{
MWWorld::Ptr ptr = R()(runtime);
MWWorld::InventoryStore& invStore = MWWorld::Class::get(ptr).getInventoryStore (ptr);
MWWorld::ContainerStoreIterator it = invStore.getSlot (MWWorld::InventoryStore::Slot_CarriedRight);
2012-11-28 01:51:46 +00:00
if (it == invStore.end() || it->getTypeName () != typeid(ESM::Weapon).name())
2012-11-25 01:06:43 +00:00
{
runtime.push(-1);
return;
}
runtime.push(it->get<ESM::Weapon>()->mBase->mData.mType);
}
};
2010-08-07 13:11:31 +00:00
const int opcodeAddItem = 0x2000076;
const int opcodeAddItemExplicit = 0x2000077;
2010-08-07 14:21:07 +00:00
const int opcodeGetItemCount = 0x2000078;
const int opcodeGetItemCountExplicit = 0x2000079;
2010-08-07 15:00:04 +00:00
const int opcodeRemoveItem = 0x200007a;
const int opcodeRemoveItemExplicit = 0x200007b;
2012-11-23 19:48:59 +00:00
const int opcodeEquip = 0x20001b3;
const int opcodeEquipExplicit = 0x20001b4;
2012-11-24 01:38:10 +00:00
const int opcodeGetArmorType = 0x20001d1;
const int opcodeGetArmorTypeExplicit = 0x20001d2;
2012-11-24 01:59:44 +00:00
const int opcodeHasItemEquipped = 0x20001d5;
const int opcodeHasItemEquippedExplicit = 0x20001d6;
2012-11-25 00:54:37 +00:00
const int opcodeHasSoulGem = 0x20001de;
const int opcodeHasSoulGemExplicit = 0x20001df;
2012-11-25 01:06:43 +00:00
const int opcodeGetWeaponType = 0x20001e0;
const int opcodeGetWeaponTypeExplicit = 0x20001e1;
2010-08-07 13:11:31 +00:00
void registerExtensions (Compiler::Extensions& extensions)
{
extensions.registerInstruction ("additem", "cl", opcodeAddItem, opcodeAddItemExplicit);
2010-08-07 14:21:07 +00:00
extensions.registerFunction ("getitemcount", 'l', "c", opcodeGetItemCount,
opcodeGetItemCountExplicit);
2010-08-07 15:00:04 +00:00
extensions.registerInstruction ("removeitem", "cl", opcodeRemoveItem,
opcodeRemoveItemExplicit);
2012-11-23 19:48:59 +00:00
extensions.registerInstruction ("equip", "c", opcodeEquip, opcodeEquipExplicit);
2012-11-24 01:38:10 +00:00
extensions.registerFunction ("getarmortype", 'l', "l", opcodeGetArmorType, opcodeGetArmorTypeExplicit);
2012-11-24 01:59:44 +00:00
extensions.registerFunction ("hasitemequipped", 'l', "c", opcodeHasItemEquipped, opcodeHasItemEquippedExplicit);
2012-11-25 00:54:37 +00:00
extensions.registerFunction ("hassoulgem", 'l', "c", opcodeHasSoulGem, opcodeHasSoulGemExplicit);
2012-11-25 01:06:43 +00:00
extensions.registerFunction ("getweapontype", 'l', "", opcodeGetWeaponType, opcodeGetWeaponTypeExplicit);
2010-08-07 13:11:31 +00:00
}
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>);
2012-11-23 19:48:59 +00:00
interpreter.installSegment5 (opcodeEquip, new OpEquip<ImplicitRef>);
interpreter.installSegment5 (opcodeEquipExplicit, new OpEquip<ExplicitRef>);
2012-11-24 01:38:10 +00:00
interpreter.installSegment5 (opcodeGetArmorType, new OpGetArmorType<ImplicitRef>);
interpreter.installSegment5 (opcodeGetArmorTypeExplicit, new OpGetArmorType<ExplicitRef>);
2012-11-25 00:54:37 +00:00
interpreter.installSegment5 (opcodeHasItemEquipped, new OpHasItemEquipped<ImplicitRef>);
2012-11-24 01:59:44 +00:00
interpreter.installSegment5 (opcodeHasItemEquippedExplicit, new OpHasItemEquipped<ExplicitRef>);
2012-11-25 00:54:37 +00:00
interpreter.installSegment5 (opcodeHasSoulGem, new OpHasSoulGem<ImplicitRef>);
interpreter.installSegment5 (opcodeHasSoulGemExplicit, new OpHasSoulGem<ExplicitRef>);
2012-11-25 01:06:43 +00:00
interpreter.installSegment5 (opcodeGetWeaponType, new OpGetWeaponType<ImplicitRef>);
interpreter.installSegment5 (opcodeGetWeaponTypeExplicit, new OpGetWeaponType<ExplicitRef>);
2010-08-07 13:11:31 +00:00
}
}
}