From 8817f802cb643e288f69302154bc3f51285562ce Mon Sep 17 00:00:00 2001 From: myrix Date: Sun, 24 Jul 2022 23:02:26 +0300 Subject: [PATCH] message when using empty soul gems, using preferentially filled ones with equip command --- apps/openmw/mwclass/misc.cpp | 19 +++++++++++ apps/openmw/mwclass/misc.hpp | 4 +++ apps/openmw/mwgui/inventorywindow.cpp | 13 ++++++++ apps/openmw/mwscript/containerextensions.cpp | 33 ++++++++++++++++++-- components/misc/stringops.hpp | 28 +++++++++++++++++ 5 files changed, 94 insertions(+), 3 deletions(-) diff --git a/apps/openmw/mwclass/misc.cpp b/apps/openmw/mwclass/misc.cpp index be5cf9c143..53c3bc4bcb 100644 --- a/apps/openmw/mwclass/misc.cpp +++ b/apps/openmw/mwclass/misc.cpp @@ -201,6 +201,25 @@ namespace MWClass return newPtr; } + std::pair Miscellaneous::canBeEquipped(const MWWorld::ConstPtr &ptr, const MWWorld::Ptr &npc) const + { + // Special checks for soul gems. + + if (::Misc::StringUtils::ciEqualPrefix("misc_soulgem", ptr.getCellRef().getRefId())) + { + if (npc != MWBase::Environment::get().getWorld()->getPlayerPtr()) + return std::make_pair(0, "Only the player can use soul gems."); + + if (ptr.getCellRef().getSoul().empty()) + return std::make_pair(0, "#{sNotifyMessage32}"); + + if (!MWBase::Environment::get().getWorld()->getStore().get().search(ptr.getCellRef().getSoul())) + return std::make_pair(0, "Unknown soul creature id."); + } + + return std::make_pair(1, ""); + } + std::unique_ptr Miscellaneous::use (const MWWorld::Ptr& ptr, bool force) const { if (ptr.getCellRef().getSoul().empty() || !MWBase::Environment::get().getWorld()->getStore().get().search(ptr.getCellRef().getSoul())) diff --git a/apps/openmw/mwclass/misc.hpp b/apps/openmw/mwclass/misc.hpp index ebf38b10be..95d861955d 100644 --- a/apps/openmw/mwclass/misc.hpp +++ b/apps/openmw/mwclass/misc.hpp @@ -45,6 +45,10 @@ namespace MWClass std::string getModel(const MWWorld::ConstPtr &ptr) const override; + std::pair canBeEquipped(const MWWorld::ConstPtr &ptr, const MWWorld::Ptr &npc) const override; + ///< Return 0 if player cannot equip item. 1 if can equip. 2 if it's twohanded weapon. 3 if twohanded weapon conflicts with that. \n + /// Second item in the pair specifies the error message + std::unique_ptr use (const MWWorld::Ptr& ptr, bool force=false) const override; ///< Generate action for using via inventory menu diff --git a/apps/openmw/mwgui/inventorywindow.cpp b/apps/openmw/mwgui/inventorywindow.cpp index f7cbc30ae1..f464eed88f 100644 --- a/apps/openmw/mwgui/inventorywindow.cpp +++ b/apps/openmw/mwgui/inventorywindow.cpp @@ -549,6 +549,19 @@ namespace MWGui } } + // Separate check for the soul gems. + else if (::Misc::StringUtils::ciEqualPrefix("misc_soulgem", ptr.getCellRef().getRefId())) + { + std::pair canEquip = ptr.getClass().canBeEquipped(ptr, player); + + if (canEquip.first == 0) + { + MWBase::Environment::get().getWindowManager()->messageBox(canEquip.second); + updateItemView(); + return; + } + } + // If the item has a script, set OnPCEquip or PCSkipEquip to 1 if (!script.empty()) { diff --git a/apps/openmw/mwscript/containerextensions.cpp b/apps/openmw/mwscript/containerextensions.cpp index 742cfb1828..1fafbbd5e8 100644 --- a/apps/openmw/mwscript/containerextensions.cpp +++ b/apps/openmw/mwscript/containerextensions.cpp @@ -304,11 +304,38 @@ namespace MWScript MWWorld::InventoryStore& invStore = ptr.getClass().getInventoryStore (ptr); MWWorld::ContainerStoreIterator it = invStore.begin(); - for (; it != invStore.end(); ++it) + + // With soul gems we prefer filled ones. + + if (::Misc::StringUtils::ciEqualPrefix("misc_soulgem", item)) { - if (::Misc::StringUtils::ciEqual(it->getCellRef().getRefId(), item)) - break; + it = invStore.end(); + + for (auto it_any = invStore.begin(); it_any != invStore.end(); ++it_any) + { + if (::Misc::StringUtils::ciEqual(it_any->getCellRef().getRefId(), item)) + { + if (!it_any->getCellRef().getSoul().empty() && + MWBase::Environment::get().getWorld()->getStore().get().search(it_any->getCellRef().getSoul())) + { + it = it_any; + break; + } + else if (it == invStore.end()) + it = it_any; + } + } } + + else + { + for (; it != invStore.end(); ++it) + { + if (::Misc::StringUtils::ciEqual(it->getCellRef().getRefId(), item)) + break; + } + } + if (it == invStore.end()) { MWWorld::ManualRef ref(MWBase::Environment::get().getWorld()->getStore(), item, 1); diff --git a/components/misc/stringops.hpp b/components/misc/stringops.hpp index 3fa82a27fe..db1ed65719 100644 --- a/components/misc/stringops.hpp +++ b/components/misc/stringops.hpp @@ -97,6 +97,34 @@ public: return ciEqual(x, std::string_view(y, n - 1)); } + template + static bool ciEqualPrefix(const X& x, const Y& y) + { + return std::equal(std::begin(x), std::end(x), std::begin(y), + [] (char l, char r) { return toLower(l) == toLower(r); }); + } + + template + static auto ciEqualPrefix(const char(& x)[n], const char(& y)[n]) + { + static_assert(n > 0); + return ciEqualPrefix(std::string_view(x, n - 1), std::string_view(y, n - 1)); + } + + template + static auto ciEqualPrefix(const char(& x)[n], const T& y) + { + static_assert(n > 0); + return ciEqualPrefix(std::string_view(x, n - 1), y); + } + + template + static auto ciEqualPrefix(const T& x, const char(& y)[n]) + { + static_assert(n > 0); + return ciEqualPrefix(x, std::string_view(y, n - 1)); + } + static int ciCompareLen(std::string_view x, std::string_view y, std::size_t len) { std::string_view::const_iterator xit = x.begin();