#include "containerextensions.hpp" #include #include #include #include #include #include #include #include "../mwbase/environment.hpp" #include "../mwbase/windowmanager.hpp" #include "../mwworld/manualref.hpp" #include "../mwworld/class.hpp" #include "../mwworld/containerstore.hpp" #include "../mwworld/actionequip.hpp" #include "../mwworld/inventorystore.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); 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 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 (Misc::StringUtils::ciEqual(iter->getCellRef().mRefID, item)) 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); 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); std::string itemName = ""; Interpreter::Type_Integer originalCount = count; for (MWWorld::ContainerStoreIterator iter (store.begin()); iter!=store.end() && count; ++iter) { if (Misc::StringUtils::ciEqual(iter->getCellRef().mRefID, item)) { 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; } } } /* 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()); // 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. } }; template 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 (Misc::StringUtils::ciEqual(it->getCellRef().mRefID, item)) break; } if (it == invStore.end()) throw std::runtime_error("Item to equip not found"); MWWorld::ActionEquip action (*it); action.execute(ptr); } }; template 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); if (it == invStore.end() || it->getTypeName () != typeid(ESM::Armor).name()) { 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); } }; template 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); if (it != invStore.end() && Misc::StringUtils::ciEqual(it->getCellRef().mRefID, item)) { runtime.push(1); return; } } runtime.push(0); } }; template class OpHasSoulGem : public Interpreter::Opcode0 { public: virtual void execute(Interpreter::Runtime &runtime) { MWWorld::Ptr ptr = R()(runtime); const std::string &name = runtime.getStringLiteral (runtime[0].mInteger); 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) { if (Misc::StringUtils::ciEqual(it->getCellRef().mSoul, name)) { runtime.push(1); return; } } runtime.push(0); } }; template 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); if (it == invStore.end() || it->getTypeName () != typeid(ESM::Weapon).name()) { runtime.push(-1); return; } runtime.push(it->get()->mBase->mData.mType); } }; const int opcodeAddItem = 0x2000076; const int opcodeAddItemExplicit = 0x2000077; const int opcodeGetItemCount = 0x2000078; const int opcodeGetItemCountExplicit = 0x2000079; const int opcodeRemoveItem = 0x200007a; const int opcodeRemoveItemExplicit = 0x200007b; const int opcodeEquip = 0x20001b3; const int opcodeEquipExplicit = 0x20001b4; const int opcodeGetArmorType = 0x20001d1; const int opcodeGetArmorTypeExplicit = 0x20001d2; const int opcodeHasItemEquipped = 0x20001d5; const int opcodeHasItemEquippedExplicit = 0x20001d6; const int opcodeHasSoulGem = 0x20001de; const int opcodeHasSoulGemExplicit = 0x20001df; const int opcodeGetWeaponType = 0x20001e0; const int opcodeGetWeaponTypeExplicit = 0x20001e1; void registerExtensions (Compiler::Extensions& extensions) { extensions.registerInstruction ("additem", "cl", opcodeAddItem, opcodeAddItemExplicit); extensions.registerFunction ("getitemcount", 'l', "c", opcodeGetItemCount, opcodeGetItemCountExplicit); extensions.registerInstruction ("removeitem", "cl", opcodeRemoveItem, opcodeRemoveItemExplicit); extensions.registerInstruction ("equip", "c", opcodeEquip, opcodeEquipExplicit); extensions.registerFunction ("getarmortype", 'l', "l", opcodeGetArmorType, opcodeGetArmorTypeExplicit); extensions.registerFunction ("hasitemequipped", 'l', "c", opcodeHasItemEquipped, opcodeHasItemEquippedExplicit); extensions.registerFunction ("hassoulgem", 'l', "c", opcodeHasSoulGem, opcodeHasSoulGemExplicit); extensions.registerFunction ("getweapontype", 'l', "", opcodeGetWeaponType, opcodeGetWeaponTypeExplicit); } 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); interpreter.installSegment5 (opcodeEquip, new OpEquip); interpreter.installSegment5 (opcodeEquipExplicit, new OpEquip); interpreter.installSegment5 (opcodeGetArmorType, new OpGetArmorType); interpreter.installSegment5 (opcodeGetArmorTypeExplicit, new OpGetArmorType); interpreter.installSegment5 (opcodeHasItemEquipped, new OpHasItemEquipped); interpreter.installSegment5 (opcodeHasItemEquippedExplicit, new OpHasItemEquipped); interpreter.installSegment5 (opcodeHasSoulGem, new OpHasSoulGem); interpreter.installSegment5 (opcodeHasSoulGemExplicit, new OpHasSoulGem); interpreter.installSegment5 (opcodeGetWeaponType, new OpGetWeaponType); interpreter.installSegment5 (opcodeGetWeaponTypeExplicit, new OpGetWeaponType); } } }