From bcfe06d85aa9db5338bc98b8c96d884b9efc0ec6 Mon Sep 17 00:00:00 2001 From: elsid Date: Sat, 3 May 2025 02:49:19 +0200 Subject: [PATCH 01/12] Use std::size_t for items count --- apps/openmw/mwgui/companionwindow.cpp | 2 +- apps/openmw/mwgui/companionwindow.hpp | 2 +- apps/openmw/mwgui/container.cpp | 2 +- apps/openmw/mwgui/container.hpp | 2 +- apps/openmw/mwgui/countdialog.hpp | 6 ++---- apps/openmw/mwgui/draganddrop.cpp | 2 +- apps/openmw/mwgui/draganddrop.hpp | 4 ++-- apps/openmw/mwgui/inventorywindow.cpp | 4 ++-- apps/openmw/mwgui/inventorywindow.hpp | 4 ++-- apps/openmw/mwgui/tradewindow.cpp | 2 +- apps/openmw/mwgui/tradewindow.hpp | 2 +- 11 files changed, 15 insertions(+), 17 deletions(-) diff --git a/apps/openmw/mwgui/companionwindow.cpp b/apps/openmw/mwgui/companionwindow.cpp index bdcb8abc9b..95dbc8ae22 100644 --- a/apps/openmw/mwgui/companionwindow.cpp +++ b/apps/openmw/mwgui/companionwindow.cpp @@ -106,7 +106,7 @@ namespace MWGui mItemView->update(); } - void CompanionWindow::dragItem(MyGUI::Widget* sender, int count) + void CompanionWindow::dragItem(MyGUI::Widget* /*sender*/, std::size_t count) { mDragAndDrop->startDrag(mSelectedItem, mSortModel, mModel, mItemView, count); } diff --git a/apps/openmw/mwgui/companionwindow.hpp b/apps/openmw/mwgui/companionwindow.hpp index 5a4b5880ff..8ecefa6931 100644 --- a/apps/openmw/mwgui/companionwindow.hpp +++ b/apps/openmw/mwgui/companionwindow.hpp @@ -55,7 +55,7 @@ namespace MWGui void onItemSelected(int index); void onNameFilterChanged(MyGUI::EditBox* _sender); void onBackgroundSelected(); - void dragItem(MyGUI::Widget* sender, int count); + void dragItem(MyGUI::Widget* sender, std::size_t count); void onMessageBoxButtonClicked(int button); diff --git a/apps/openmw/mwgui/container.cpp b/apps/openmw/mwgui/container.cpp index 6e768f6e1e..6f07a2db2e 100644 --- a/apps/openmw/mwgui/container.cpp +++ b/apps/openmw/mwgui/container.cpp @@ -95,7 +95,7 @@ namespace MWGui dragItem(nullptr, count); } - void ContainerWindow::dragItem(MyGUI::Widget* sender, int count) + void ContainerWindow::dragItem(MyGUI::Widget* /*sender*/, std::size_t count) { if (!mModel) return; diff --git a/apps/openmw/mwgui/container.hpp b/apps/openmw/mwgui/container.hpp index a7702ebbfe..660493745b 100644 --- a/apps/openmw/mwgui/container.hpp +++ b/apps/openmw/mwgui/container.hpp @@ -60,7 +60,7 @@ namespace MWGui void onItemSelected(int index); void onBackgroundSelected(); - void dragItem(MyGUI::Widget* sender, int count); + void dragItem(MyGUI::Widget*, std::size_t count); void dropItem(); void onCloseButtonClicked(MyGUI::Widget* _sender); void onTakeAllButtonClicked(MyGUI::Widget* _sender); diff --git a/apps/openmw/mwgui/countdialog.hpp b/apps/openmw/mwgui/countdialog.hpp index 9cdf231549..70fc820899 100644 --- a/apps/openmw/mwgui/countdialog.hpp +++ b/apps/openmw/mwgui/countdialog.hpp @@ -16,12 +16,10 @@ namespace MWGui CountDialog(); void openCountDialog(const std::string& item, const std::string& message, const int maxCount); - typedef MyGUI::delegates::MultiDelegate EventHandle_WidgetInt; - /** Event : Ok button was clicked.\n - signature : void method(MyGUI::Widget* _sender, int _count)\n + signature : void method(MyGUI::Widget* sender, std::size_t count)\n */ - EventHandle_WidgetInt eventOkClicked; + MyGUI::delegates::MultiDelegate eventOkClicked; private: MyGUI::ScrollBar* mSlider; diff --git a/apps/openmw/mwgui/draganddrop.cpp b/apps/openmw/mwgui/draganddrop.cpp index 52b0939238..ee4dc92a7e 100644 --- a/apps/openmw/mwgui/draganddrop.cpp +++ b/apps/openmw/mwgui/draganddrop.cpp @@ -27,7 +27,7 @@ namespace MWGui } void DragAndDrop::startDrag( - int index, SortFilterItemModel* sortModel, ItemModel* sourceModel, ItemView* sourceView, int count) + int index, SortFilterItemModel* sortModel, ItemModel* sourceModel, ItemView* sourceView, std::size_t count) { mItem = sourceModel->getItem(index); mDraggedCount = count; diff --git a/apps/openmw/mwgui/draganddrop.hpp b/apps/openmw/mwgui/draganddrop.hpp index 94da6cce5f..afe4fd0df2 100644 --- a/apps/openmw/mwgui/draganddrop.hpp +++ b/apps/openmw/mwgui/draganddrop.hpp @@ -24,12 +24,12 @@ namespace MWGui ItemView* mSourceView; SortFilterItemModel* mSourceSortModel; ItemStack mItem; - int mDraggedCount; + std::size_t mDraggedCount; DragAndDrop(); void startDrag( - int index, SortFilterItemModel* sortModel, ItemModel* sourceModel, ItemView* sourceView, int count); + int index, SortFilterItemModel* sortModel, ItemModel* sourceModel, ItemView* sourceView, std::size_t count); void drop(ItemModel* targetModel, ItemView* targetView); void update(); void onFrame(); diff --git a/apps/openmw/mwgui/inventorywindow.cpp b/apps/openmw/mwgui/inventorywindow.cpp index acc1dd6068..234df1040e 100644 --- a/apps/openmw/mwgui/inventorywindow.cpp +++ b/apps/openmw/mwgui/inventorywindow.cpp @@ -361,14 +361,14 @@ namespace MWGui } } - void InventoryWindow::dragItem(MyGUI::Widget* sender, int count) + void InventoryWindow::dragItem(MyGUI::Widget* /*sender*/, std::size_t count) { ensureSelectedItemUnequipped(count); mDragAndDrop->startDrag(mSelectedItem, mSortModel, mTradeModel, mItemView, count); notifyContentChanged(); } - void InventoryWindow::sellItem(MyGUI::Widget* sender, int count) + void InventoryWindow::sellItem(MyGUI::Widget* /*sender*/, std::size_t count) { ensureSelectedItemUnequipped(count); const ItemStack& item = mTradeModel->getItem(mSelectedItem); diff --git a/apps/openmw/mwgui/inventorywindow.hpp b/apps/openmw/mwgui/inventorywindow.hpp index 7f0d64dce0..15c93d14eb 100644 --- a/apps/openmw/mwgui/inventorywindow.hpp +++ b/apps/openmw/mwgui/inventorywindow.hpp @@ -120,8 +120,8 @@ namespace MWGui void onBackgroundSelected(); - void sellItem(MyGUI::Widget* sender, int count); - void dragItem(MyGUI::Widget* sender, int count); + void sellItem(MyGUI::Widget* sender, std::size_t count); + void dragItem(MyGUI::Widget* sender, std::size_t count); void onWindowResize(MyGUI::Window* _sender); void onFilterChanged(MyGUI::Widget* _sender); diff --git a/apps/openmw/mwgui/tradewindow.cpp b/apps/openmw/mwgui/tradewindow.cpp index ea124f0a97..bf5d4d4279 100644 --- a/apps/openmw/mwgui/tradewindow.cpp +++ b/apps/openmw/mwgui/tradewindow.cpp @@ -292,7 +292,7 @@ namespace MWGui } } - void TradeWindow::sellItem(MyGUI::Widget* sender, int count) + void TradeWindow::sellItem(MyGUI::Widget* /*sender*/, std::size_t count) { const ItemStack& item = mTradeModel->getItem(mItemToSell); const ESM::RefId& sound = item.mBase.getClass().getUpSoundId(item.mBase); diff --git a/apps/openmw/mwgui/tradewindow.hpp b/apps/openmw/mwgui/tradewindow.hpp index b0581d0d38..5a3889d2d8 100644 --- a/apps/openmw/mwgui/tradewindow.hpp +++ b/apps/openmw/mwgui/tradewindow.hpp @@ -95,7 +95,7 @@ namespace MWGui void updateOffer(); void onItemSelected(int index); - void sellItem(MyGUI::Widget* sender, int count); + void sellItem(MyGUI::Widget* sender, std::size_t count); void borrowItem(int index, size_t count); void returnItem(int index, size_t count); From a4af0372931ddf4cb150e3aae5fd14997ff29463 Mon Sep 17 00:00:00 2001 From: elsid Date: Sun, 4 May 2025 10:26:21 +0200 Subject: [PATCH 02/12] Remove ContainerWindow::onTakeItem --- apps/openmw/mwgui/container.cpp | 13 +++++-------- apps/openmw/mwgui/container.hpp | 3 --- 2 files changed, 5 insertions(+), 11 deletions(-) diff --git a/apps/openmw/mwgui/container.cpp b/apps/openmw/mwgui/container.cpp index 6f07a2db2e..28ec1b5060 100644 --- a/apps/openmw/mwgui/container.cpp +++ b/apps/openmw/mwgui/container.cpp @@ -100,7 +100,9 @@ namespace MWGui if (!mModel) return; - if (!onTakeItem(mModel->getItem(mSelectedItem), count)) + const ItemStack item = mModel->getItem(mSelectedItem); + + if (!mModel->onTakeItem(item.mBase, count)) return; mDragAndDrop->startDrag(mSelectedItem, mSortModel, mModel, mItemView, count); @@ -234,9 +236,9 @@ namespace MWGui MWBase::Environment::get().getWindowManager()->playSound(sound); } - const ItemStack& item = mModel->getItem(i); + const ItemStack item = mModel->getItem(i); - if (!onTakeItem(item, item.mCount)) + if (!mModel->onTakeItem(item.mBase, item.mCount)) break; mModel->moveItem(item, item.mCount, playerModel); @@ -313,11 +315,6 @@ namespace MWGui MWBase::Environment::get().getWindowManager()->removeGuiMode(GM_Container); } - bool ContainerWindow::onTakeItem(const ItemStack& item, int count) - { - return mModel->onTakeItem(item.mBase, count); - } - void ContainerWindow::onDeleteCustomData(const MWWorld::Ptr& ptr) { if (mModel && mModel->usesContainer(ptr)) diff --git a/apps/openmw/mwgui/container.hpp b/apps/openmw/mwgui/container.hpp index 660493745b..697e47ee1b 100644 --- a/apps/openmw/mwgui/container.hpp +++ b/apps/openmw/mwgui/container.hpp @@ -66,9 +66,6 @@ namespace MWGui void onTakeAllButtonClicked(MyGUI::Widget* _sender); void onDisposeCorpseButtonClicked(MyGUI::Widget* sender); - /// @return is taking the item allowed? - bool onTakeItem(const ItemStack& item, int count); - void onReferenceUnavailable() override; }; } From eb7af832e4d705f0257e7ec19801fcbde16bbea0 Mon Sep 17 00:00:00 2001 From: elsid Date: Sun, 6 Jul 2025 11:10:10 +0200 Subject: [PATCH 03/12] Remove trailing spaces --- docs/source/reference/modding/settings/GUI.rst | 8 ++++---- files/lang/launcher_sv.ts | 4 ++-- files/settings-default.cfg | 8 ++++---- 3 files changed, 10 insertions(+), 10 deletions(-) diff --git a/docs/source/reference/modding/settings/GUI.rst b/docs/source/reference/modding/settings/GUI.rst index b9065c8daf..63bbae5f8b 100644 --- a/docs/source/reference/modding/settings/GUI.rst +++ b/docs/source/reference/modding/settings/GUI.rst @@ -77,7 +77,7 @@ GUI Settings :type: boolean :range: true, false :default: true - + Enables or disables the red flash overlay when the character takes damage. Disabling causes the player to "bleed" like NPCs. @@ -87,7 +87,7 @@ GUI Settings :type: boolean :range: true, false :default: true - + Enable or disable the werewolf visual effect in first-person mode. @@ -96,7 +96,7 @@ GUI Settings :type: color :range: [0, 1] :default: 0.15 0.0 0.0 1.0 - + Background color of tooltip and crosshair when hovering over an NPC-owned item. Four floating point values: red, green, blue, alpha (alpha ignored). @@ -107,7 +107,7 @@ GUI Settings :type: color :range: [0, 1] :default: 1.0 0.15 0.15 1.0 - + Crosshair color when hovering over an NPC-owned item. Four floating point values: red, green, blue, alpha (alpha ignored). diff --git a/files/lang/launcher_sv.ts b/files/lang/launcher_sv.ts index 97de9603d7..3e6c5607eb 100644 --- a/files/lang/launcher_sv.ts +++ b/files/lang/launcher_sv.ts @@ -767,10 +767,10 @@ de ordinarie fonterna i Morrowind. Bocka denna ruta om du ändå föredrar ordin the specular map texture would have to be named foo_spec.dds). If this option is disabled, normal maps are only used if they are explicitly listed within the mesh file (.osg file, not supported in .nif files). Affects objects.</p></body></html> - <html><head/><body><p>Om den här funktionen är aktiverad kommer spekularitetskartor (specular maps) att hittas och användas + <html><head/><body><p>Om den här funktionen är aktiverad kommer spekularitetskartor (specular maps) att hittas och användas (see 'specular map pattern', t.ex. för en bastextur foo.dds, ska spekularitetskartan heta foo_spec.dds). - Om funktionen är inaktiverad kommer normalkartor bara användas om texturerna är explicit listade i 3D-modell-filen + Om funktionen är inaktiverad kommer normalkartor bara användas om texturerna är explicit listade i 3D-modell-filen (.nif eller .osg fil). Påverkar objekt.</p></body></html> diff --git a/files/settings-default.cfg b/files/settings-default.cfg index e5654794cc..b9bf113dee 100644 --- a/files/settings-default.cfg +++ b/files/settings-default.cfg @@ -372,8 +372,8 @@ unarmed creature attacks damage armor = false # 2 = Cylinder actor collision shape type = 0 -# When false the player character will base movement on animations. This will sway the camera -# while moving in third person like in vanilla, and reproduce movement bugs caused by glitchy +# When false the player character will base movement on animations. This will sway the camera +# while moving in third person like in vanilla, and reproduce movement bugs caused by glitchy # vanilla animations. player movement ignores animation = false @@ -1136,7 +1136,7 @@ xargonianswimknakf = meshes/xargonian_swimkna.kf # Sky atmosphere mesh skyatmosphere = meshes/sky_atmosphere.nif -# Sky clouds mesh +# Sky clouds mesh skyclouds = meshes/sky_clouds_01.nif # Sky stars mesh 01 @@ -1269,7 +1269,7 @@ right eye fov down = -0.8 [Post Processing] -# Enables post-processing +# Enables post-processing enabled = false # List of active shaders. This is more easily with the in-game shader HUD, by default accessible with the F2 key. From f5e66f3e244c7b8761058f459debc21294ac78a6 Mon Sep 17 00:00:00 2001 From: elsid Date: Sun, 6 Jul 2025 11:13:00 +0200 Subject: [PATCH 04/12] Remove unused includes --- components/settings/categories/gui.hpp | 2 -- 1 file changed, 2 deletions(-) diff --git a/components/settings/categories/gui.hpp b/components/settings/categories/gui.hpp index a26364c5dd..ffef047094 100644 --- a/components/settings/categories/gui.hpp +++ b/components/settings/categories/gui.hpp @@ -10,8 +10,6 @@ #include -#include -#include #include namespace Settings From 463de2d7910ecc5b5b686799df26f9fc58e3d6da Mon Sep 17 00:00:00 2001 From: elsid Date: Sat, 3 May 2025 00:02:06 +0200 Subject: [PATCH 05/12] Instantly transfer items if alt key is pressed Support player's inventory, container and companion windows with dropping and picking up items from the world. Add ItemTransfer class to handle transfers similar to DragAndDrop. When a container window is opened the view is added to the set of targets and removed when closed. If ALT is pressed instead of starting dragging an item perform a transfer. If there is 1 target which is not a source move item there. If there is no target drop item into the world using WorldItemModel. Special case is picking up an item. Don't start dragging, just update the player's inventory view because the item is already there. --- apps/openmw/CMakeLists.txt | 2 +- apps/openmw/mwgui/companionwindow.cpp | 29 ++++++++- apps/openmw/mwgui/companionwindow.hpp | 13 +++- apps/openmw/mwgui/container.cpp | 45 ++++++++++---- apps/openmw/mwgui/container.hpp | 19 +++--- apps/openmw/mwgui/draganddrop.cpp | 24 ++++---- apps/openmw/mwgui/draganddrop.hpp | 4 +- apps/openmw/mwgui/hud.cpp | 75 +++-------------------- apps/openmw/mwgui/inventorywindow.cpp | 40 +++++++++++-- apps/openmw/mwgui/inventorywindow.hpp | 12 +++- apps/openmw/mwgui/itemtransfer.hpp | 78 ++++++++++++++++++++++++ apps/openmw/mwgui/itemview.hpp | 2 + apps/openmw/mwgui/windowmanagerimp.cpp | 9 ++- apps/openmw/mwgui/windowmanagerimp.hpp | 3 +- apps/openmw/mwgui/worlditemmodel.hpp | 82 ++++++++++++++++++++++++++ apps/openmw/mwworld/cellref.hpp | 12 ++++ 16 files changed, 337 insertions(+), 112 deletions(-) create mode 100644 apps/openmw/mwgui/itemtransfer.hpp create mode 100644 apps/openmw/mwgui/worlditemmodel.hpp diff --git a/apps/openmw/CMakeLists.txt b/apps/openmw/CMakeLists.txt index e3629d6f27..4dc2fd1fd1 100644 --- a/apps/openmw/CMakeLists.txt +++ b/apps/openmw/CMakeLists.txt @@ -44,7 +44,7 @@ add_openmw_dir (mwgui tradeitemmodel companionitemmodel pickpocketitemmodel controllers savegamedialog recharge mode videowidget backgroundimage itemwidget screenfader debugwindow spellmodel spellview draganddrop timeadvancer jailscreen itemchargeview keyboardnavigation textcolours statswatcher - postprocessorhud settings + postprocessorhud settings worlditemmodel itemtransfer ) add_openmw_dir (mwdialogue diff --git a/apps/openmw/mwgui/companionwindow.cpp b/apps/openmw/mwgui/companionwindow.cpp index 95dbc8ae22..52fc4cc4ce 100644 --- a/apps/openmw/mwgui/companionwindow.cpp +++ b/apps/openmw/mwgui/companionwindow.cpp @@ -14,6 +14,7 @@ #include "companionitemmodel.hpp" #include "countdialog.hpp" #include "draganddrop.hpp" +#include "itemtransfer.hpp" #include "itemview.hpp" #include "messagebox.hpp" #include "sortfilteritemmodel.hpp" @@ -38,13 +39,14 @@ namespace namespace MWGui { - CompanionWindow::CompanionWindow(DragAndDrop* dragAndDrop, MessageBoxManager* manager) + CompanionWindow::CompanionWindow(DragAndDrop& dragAndDrop, ItemTransfer& itemTransfer, MessageBoxManager* manager) : WindowBase("openmw_companion_window.layout") , mSortModel(nullptr) , mModel(nullptr) , mSelectedItem(-1) , mUpdateNextFrame(false) - , mDragAndDrop(dragAndDrop) + , mDragAndDrop(&dragAndDrop) + , mItemTransfer(&itemTransfer) , mMessageBoxManager(manager) { getWidget(mCloseButton, "CloseButton"); @@ -94,8 +96,14 @@ namespace MWGui name += MWGui::ToolTips::getSoulString(object.getCellRef()); dialog->openCountDialog(name, "#{sTake}", count); dialog->eventOkClicked.clear(); - dialog->eventOkClicked += MyGUI::newDelegate(this, &CompanionWindow::dragItem); + + if (MyGUI::InputManager::getInstance().isAltPressed()) + dialog->eventOkClicked += MyGUI::newDelegate(this, &CompanionWindow::transferItem); + else + dialog->eventOkClicked += MyGUI::newDelegate(this, &CompanionWindow::dragItem); } + else if (MyGUI::InputManager::getInstance().isAltPressed()) + transferItem(nullptr, count); else dragItem(nullptr, count); } @@ -111,6 +119,11 @@ namespace MWGui mDragAndDrop->startDrag(mSelectedItem, mSortModel, mModel, mItemView, count); } + void CompanionWindow::transferItem(MyGUI::Widget* /*sender*/, std::size_t count) + { + mItemTransfer->apply(mModel->getItem(mSelectedItem), count, *mItemView); + } + void CompanionWindow::onBackgroundSelected() { if (mDragAndDrop->mIsOnDragAndDrop) @@ -220,4 +233,14 @@ namespace MWGui { mUpdateNextFrame = true; } + + void CompanionWindow::onOpen() + { + mItemTransfer->addTarget(*mItemView); + } + + void CompanionWindow::onClose() + { + mItemTransfer->removeTarget(*mItemView); + } } diff --git a/apps/openmw/mwgui/companionwindow.hpp b/apps/openmw/mwgui/companionwindow.hpp index 8ecefa6931..5e78d17334 100644 --- a/apps/openmw/mwgui/companionwindow.hpp +++ b/apps/openmw/mwgui/companionwindow.hpp @@ -6,6 +6,8 @@ #include "../mwworld/containerstore.hpp" +#include + namespace MWGui { namespace Widgets @@ -18,11 +20,12 @@ namespace MWGui class DragAndDrop; class SortFilterItemModel; class CompanionItemModel; + class ItemTransfer; class CompanionWindow : public WindowBase, public ReferenceInterface, public MWWorld::ContainerStoreListener { public: - CompanionWindow(DragAndDrop* dragAndDrop, MessageBoxManager* manager); + explicit CompanionWindow(DragAndDrop& dragAndDrop, ItemTransfer& itemTransfer, MessageBoxManager* manager); bool exit() override; @@ -44,7 +47,8 @@ namespace MWGui int mSelectedItem; bool mUpdateNextFrame; - DragAndDrop* mDragAndDrop; + Misc::NotNullPtr mDragAndDrop; + Misc::NotNullPtr mItemTransfer; MyGUI::Button* mCloseButton; MyGUI::EditBox* mFilterEdit; @@ -56,6 +60,7 @@ namespace MWGui void onNameFilterChanged(MyGUI::EditBox* _sender); void onBackgroundSelected(); void dragItem(MyGUI::Widget* sender, std::size_t count); + void transferItem(MyGUI::Widget* sender, std::size_t count); void onMessageBoxButtonClicked(int button); @@ -64,6 +69,10 @@ namespace MWGui void onCloseButtonClicked(MyGUI::Widget* _sender); void onReferenceUnavailable() override; + + void onOpen() override; + + void onClose() override; }; } diff --git a/apps/openmw/mwgui/container.cpp b/apps/openmw/mwgui/container.cpp index 28ec1b5060..937bab0851 100644 --- a/apps/openmw/mwgui/container.cpp +++ b/apps/openmw/mwgui/container.cpp @@ -18,12 +18,12 @@ #include "../mwscript/interpretercontext.hpp" -#include "countdialog.hpp" -#include "inventorywindow.hpp" - #include "containeritemmodel.hpp" +#include "countdialog.hpp" #include "draganddrop.hpp" #include "inventoryitemmodel.hpp" +#include "inventorywindow.hpp" +#include "itemtransfer.hpp" #include "itemview.hpp" #include "pickpocketitemmodel.hpp" #include "sortfilteritemmodel.hpp" @@ -32,9 +32,10 @@ namespace MWGui { - ContainerWindow::ContainerWindow(DragAndDrop* dragAndDrop) + ContainerWindow::ContainerWindow(DragAndDrop& dragAndDrop, ItemTransfer& itemTransfer) : WindowBase("openmw_container_window.layout") - , mDragAndDrop(dragAndDrop) + , mDragAndDrop(&dragAndDrop) + , mItemTransfer(&itemTransfer) , mSortModel(nullptr) , mModel(nullptr) , mSelectedItem(-1) @@ -89,15 +90,21 @@ namespace MWGui name += MWGui::ToolTips::getSoulString(object.getCellRef()); dialog->openCountDialog(name, "#{sTake}", count); dialog->eventOkClicked.clear(); - dialog->eventOkClicked += MyGUI::newDelegate(this, &ContainerWindow::dragItem); + + if (MyGUI::InputManager::getInstance().isAltPressed()) + dialog->eventOkClicked += MyGUI::newDelegate(this, &ContainerWindow::transferItem); + else + dialog->eventOkClicked += MyGUI::newDelegate(this, &ContainerWindow::dragItem); } + else if (MyGUI::InputManager::getInstance().isAltPressed()) + transferItem(nullptr, count); else dragItem(nullptr, count); } void ContainerWindow::dragItem(MyGUI::Widget* /*sender*/, std::size_t count) { - if (!mModel) + if (mModel == nullptr) return; const ItemStack item = mModel->getItem(mSelectedItem); @@ -108,9 +115,22 @@ namespace MWGui mDragAndDrop->startDrag(mSelectedItem, mSortModel, mModel, mItemView, count); } + void ContainerWindow::transferItem(MyGUI::Widget* /*sender*/, std::size_t count) + { + if (mModel == nullptr) + return; + + const ItemStack item = mModel->getItem(mSelectedItem); + + if (!mModel->onTakeItem(item.mBase, count)) + return; + + mItemTransfer->apply(item, count, *mItemView); + } + void ContainerWindow::dropItem() { - if (!mModel) + if (mModel == nullptr) return; bool success = mModel->onDropItem(mDragAndDrop->mItem.mBase, mDragAndDrop->mDraggedCount); @@ -175,10 +195,13 @@ namespace MWGui mSortModel = nullptr; } + void ContainerWindow::onOpen() + { + mItemTransfer->addTarget(*mItemView); + } + void ContainerWindow::onClose() { - WindowBase::onClose(); - // Make sure the window was actually closed and not temporarily hidden. if (MWBase::Environment::get().getWindowManager()->containsMode(GM_Container)) return; @@ -189,6 +212,8 @@ namespace MWGui if (!mPtr.isEmpty()) MWBase::Environment::get().getMechanicsManager()->onClose(mPtr); resetReference(); + + mItemTransfer->removeTarget(*mItemView); } void ContainerWindow::onCloseButtonClicked(MyGUI::Widget* _sender) diff --git a/apps/openmw/mwgui/container.hpp b/apps/openmw/mwgui/container.hpp index 697e47ee1b..86ded2ff75 100644 --- a/apps/openmw/mwgui/container.hpp +++ b/apps/openmw/mwgui/container.hpp @@ -1,10 +1,11 @@ #ifndef MGUI_CONTAINER_H #define MGUI_CONTAINER_H +#include "itemmodel.hpp" #include "referenceinterface.hpp" #include "windowbase.hpp" -#include "itemmodel.hpp" +#include #include "../mwworld/containerstore.hpp" @@ -19,17 +20,19 @@ namespace MWGui class ContainerWindow; class ItemView; class SortFilterItemModel; -} + class ItemTransfer; -namespace MWGui -{ class ContainerWindow : public WindowBase, public ReferenceInterface, public MWWorld::ContainerStoreListener { public: - ContainerWindow(DragAndDrop* dragAndDrop); + explicit ContainerWindow(DragAndDrop& dragAndDrop, ItemTransfer& itemTransfer); void setPtr(const MWWorld::Ptr& container) override; + + void onOpen() override; + void onClose() override; + void clear() override { resetReference(); } void onFrame(float dt) override; @@ -46,7 +49,8 @@ namespace MWGui std::string_view getWindowIdForLua() const override { return "Container"; } private: - DragAndDrop* mDragAndDrop; + Misc::NotNullPtr mDragAndDrop; + Misc::NotNullPtr mItemTransfer; MWGui::ItemView* mItemView; SortFilterItemModel* mSortModel; @@ -60,7 +64,8 @@ namespace MWGui void onItemSelected(int index); void onBackgroundSelected(); - void dragItem(MyGUI::Widget*, std::size_t count); + void dragItem(MyGUI::Widget* sender, std::size_t count); + void transferItem(MyGUI::Widget* sender, std::size_t count); void dropItem(); void onCloseButtonClicked(MyGUI::Widget* _sender); void onTakeAllButtonClicked(MyGUI::Widget* _sender); diff --git a/apps/openmw/mwgui/draganddrop.cpp b/apps/openmw/mwgui/draganddrop.cpp index ee4dc92a7e..85229d0a13 100644 --- a/apps/openmw/mwgui/draganddrop.cpp +++ b/apps/openmw/mwgui/draganddrop.cpp @@ -125,18 +125,18 @@ namespace MWGui void DragAndDrop::update() { - if (mIsOnDragAndDrop) - { - int count = mItem.mBase.getCellRef().getCount(); - if (count < mDraggedCount) - { - mItem.mCount = count; - mDraggedCount = count; - mDraggedWidget->setCount(mDraggedCount); - mSourceSortModel->clearDragItems(); - mSourceSortModel->addDragItem(mItem.mBase, mDraggedCount); - } - } + if (!mIsOnDragAndDrop) + return; + + const unsigned count = mItem.mBase.getCellRef().getAbsCount(); + if (count >= mDraggedCount) + return; + + mItem.mCount = count; + mDraggedCount = count; + mDraggedWidget->setCount(mDraggedCount); + mSourceSortModel->clearDragItems(); + mSourceSortModel->addDragItem(mItem.mBase, mDraggedCount); } void DragAndDrop::onFrame() diff --git a/apps/openmw/mwgui/draganddrop.hpp b/apps/openmw/mwgui/draganddrop.hpp index afe4fd0df2..511e2b7765 100644 --- a/apps/openmw/mwgui/draganddrop.hpp +++ b/apps/openmw/mwgui/draganddrop.hpp @@ -4,6 +4,8 @@ #include "itemmodel.hpp" #include "itemwidget.hpp" +#include + namespace MyGUI { class Widget; @@ -29,7 +31,7 @@ namespace MWGui DragAndDrop(); void startDrag( - int index, SortFilterItemModel* sortModel, ItemModel* sourceModel, ItemView* sourceView, std::size_t count); + int index, SortFilterItemModel* sortModel, ItemModel* sourceModel, ItemView* sourceView, std::size_t count); void drop(ItemModel* targetModel, ItemView* targetView); void update(); void onFrame(); diff --git a/apps/openmw/mwgui/hud.cpp b/apps/openmw/mwgui/hud.cpp index 0a37c93b4f..e5adce7624 100644 --- a/apps/openmw/mwgui/hud.cpp +++ b/apps/openmw/mwgui/hud.cpp @@ -25,67 +25,12 @@ #include "draganddrop.hpp" #include "inventorywindow.hpp" -#include "itemmodel.hpp" -#include "spellicons.hpp" - #include "itemwidget.hpp" +#include "spellicons.hpp" +#include "worlditemmodel.hpp" namespace MWGui { - - /** - * Makes it possible to use ItemModel::moveItem to move an item from an inventory to the world. - */ - class WorldItemModel : public ItemModel - { - public: - WorldItemModel(float left, float top) - : mLeft(left) - , mTop(top) - { - } - virtual ~WorldItemModel() override {} - - MWWorld::Ptr dropItemImpl(const ItemStack& item, size_t count, bool copy) - { - MWBase::World* world = MWBase::Environment::get().getWorld(); - - MWWorld::Ptr dropped; - if (world->canPlaceObject(mLeft, mTop)) - dropped = world->placeObject(item.mBase, mLeft, mTop, count, copy); - else - dropped = world->dropObjectOnGround(world->getPlayerPtr(), item.mBase, count, copy); - dropped.getCellRef().setOwner(ESM::RefId()); - - return dropped; - } - - MWWorld::Ptr addItem(const ItemStack& item, size_t count, bool /*allowAutoEquip*/) override - { - return dropItemImpl(item, count, false); - } - - MWWorld::Ptr copyItem(const ItemStack& item, size_t count, bool /*allowAutoEquip*/) override - { - return dropItemImpl(item, count, true); - } - - void removeItem(const ItemStack& item, size_t count) override - { - throw std::runtime_error("removeItem not implemented"); - } - ModelIndex getIndex(const ItemStack& item) override { throw std::runtime_error("getIndex not implemented"); } - void update() override {} - size_t getItemCount() override { return 0; } - ItemStack getItem(ModelIndex index) override { throw std::runtime_error("getItem not implemented"); } - bool usesContainer(const MWWorld::Ptr&) override { return false; } - - private: - // Where to drop the item - float mLeft; - float mTop; - }; - HUD::HUD(CustomMarkerCollection& customMarkers, DragAndDrop* dragAndDrop, MWRender::LocalMap* localMapRender) : WindowBase("openmw_hud.layout") , LocalMapBase(customMarkers, localMapRender, Settings::map().mLocalMapHudFogOfWar) @@ -251,16 +196,14 @@ namespace MWGui MWBase::WindowManager* winMgr = MWBase::Environment::get().getWindowManager(); if (mDragAndDrop->mIsOnDragAndDrop) { + const MyGUI::IntSize viewSize = MyGUI::RenderManager::getInstance().getViewSize(); + const MyGUI::IntPoint cursorPosition = MyGUI::InputManager::getInstance().getMousePosition(); + const float cursorX = cursorPosition.left / static_cast(viewSize.width); + const float cursorY = cursorPosition.top / static_cast(viewSize.height); + // drop item into the gameworld - MWBase::Environment::get().getWorld()->breakInvisibility(MWMechanics::getPlayer()); - - MyGUI::IntSize viewSize = MyGUI::RenderManager::getInstance().getViewSize(); - MyGUI::IntPoint cursorPosition = MyGUI::InputManager::getInstance().getMousePosition(); - float mouseX = cursorPosition.left / float(viewSize.width); - float mouseY = cursorPosition.top / float(viewSize.height); - - WorldItemModel drop(mouseX, mouseY); - mDragAndDrop->drop(&drop, nullptr); + WorldItemModel worldItemModel(cursorX, cursorY); + mDragAndDrop->drop(&worldItemModel, nullptr); winMgr->changePointer("arrow"); } diff --git a/apps/openmw/mwgui/inventorywindow.cpp b/apps/openmw/mwgui/inventorywindow.cpp index 234df1040e..c558f1bad9 100644 --- a/apps/openmw/mwgui/inventorywindow.cpp +++ b/apps/openmw/mwgui/inventorywindow.cpp @@ -34,6 +34,7 @@ #include "countdialog.hpp" #include "draganddrop.hpp" #include "inventoryitemmodel.hpp" +#include "itemtransfer.hpp" #include "itemview.hpp" #include "settings.hpp" #include "sortfilteritemmodel.hpp" @@ -74,10 +75,11 @@ namespace MWGui } } - InventoryWindow::InventoryWindow( - DragAndDrop* dragAndDrop, osg::Group* parent, Resource::ResourceSystem* resourceSystem) + InventoryWindow::InventoryWindow(DragAndDrop& dragAndDrop, ItemTransfer& itemTransfer, osg::Group* parent, + Resource::ResourceSystem* resourceSystem) : WindowPinnableBase("openmw_inventory_window.layout") - , mDragAndDrop(dragAndDrop) + , mDragAndDrop(&dragAndDrop) + , mItemTransfer(&itemTransfer) , mSelectedItem(-1) , mSortModel(nullptr) , mTradeModel(nullptr) @@ -312,17 +314,24 @@ namespace MWGui name += MWGui::ToolTips::getSoulString(object.getCellRef()); dialog->openCountDialog(name, message, count); dialog->eventOkClicked.clear(); + if (mTrading) dialog->eventOkClicked += MyGUI::newDelegate(this, &InventoryWindow::sellItem); + else if (MyGUI::InputManager::getInstance().isAltPressed()) + dialog->eventOkClicked += MyGUI::newDelegate(this, &InventoryWindow::transferItem); else dialog->eventOkClicked += MyGUI::newDelegate(this, &InventoryWindow::dragItem); + mSelectedItem = index; } else { mSelectedItem = index; + if (mTrading) sellItem(nullptr, count); + else if (MyGUI::InputManager::getInstance().isAltPressed()) + transferItem(nullptr, count); else dragItem(nullptr, count); } @@ -368,6 +377,13 @@ namespace MWGui notifyContentChanged(); } + void InventoryWindow::transferItem(MyGUI::Widget* /*sender*/, std::size_t count) + { + ensureSelectedItemUnequipped(count); + mItemTransfer->apply(mTradeModel->getItem(mSelectedItem), count, *mItemView); + notifyContentChanged(); + } + void InventoryWindow::sellItem(MyGUI::Widget* /*sender*/, std::size_t count) { ensureSelectedItemUnequipped(count); @@ -415,6 +431,13 @@ namespace MWGui notifyContentChanged(); } adjustPanes(); + + mItemTransfer->addTarget(*mItemView); + } + + void InventoryWindow::onClose() + { + mItemTransfer->removeTarget(*mItemView); } void InventoryWindow::onWindowResize(MyGUI::Window* _sender) @@ -776,7 +799,16 @@ namespace MWGui if (mDragAndDrop->mIsOnDragAndDrop) mDragAndDrop->finish(); - mDragAndDrop->startDrag(i, mSortModel, mTradeModel, mItemView, count); + if (MyGUI::InputManager::getInstance().isAltPressed()) + { + const MWWorld::Ptr item = mTradeModel->getItem(i).mBase; + MWBase::Environment::get().getWindowManager()->playSound(item.getClass().getDownSoundId(item)); + mItemView->update(); + } + else + { + mDragAndDrop->startDrag(i, mSortModel, mTradeModel, mItemView, count); + } MWBase::Environment::get().getWindowManager()->updateSpellWindow(); } diff --git a/apps/openmw/mwgui/inventorywindow.hpp b/apps/openmw/mwgui/inventorywindow.hpp index 15c93d14eb..2dc25144d5 100644 --- a/apps/openmw/mwgui/inventorywindow.hpp +++ b/apps/openmw/mwgui/inventorywindow.hpp @@ -8,6 +8,8 @@ #include "../mwworld/containerstore.hpp" #include "../mwworld/ptr.hpp" +#include + namespace osg { class Group; @@ -30,14 +32,18 @@ namespace MWGui class TradeItemModel; class DragAndDrop; class ItemModel; + class ItemTransfer; class InventoryWindow : public WindowPinnableBase, public MWWorld::ContainerStoreListener { public: - InventoryWindow(DragAndDrop* dragAndDrop, osg::Group* parent, Resource::ResourceSystem* resourceSystem); + explicit InventoryWindow(DragAndDrop& dragAndDrop, ItemTransfer& itemTransfer, osg::Group* parent, + Resource::ResourceSystem* resourceSystem); void onOpen() override; + void onClose() override; + /// start trading, disables item drag&drop void setTrading(bool trading); @@ -75,7 +81,8 @@ namespace MWGui void onTitleDoubleClicked() override; private: - DragAndDrop* mDragAndDrop; + Misc::NotNullPtr mDragAndDrop; + Misc::NotNullPtr mItemTransfer; int mSelectedItem; std::optional mEquippedStackableCount; @@ -122,6 +129,7 @@ namespace MWGui void sellItem(MyGUI::Widget* sender, std::size_t count); void dragItem(MyGUI::Widget* sender, std::size_t count); + void transferItem(MyGUI::Widget* sender, std::size_t count); void onWindowResize(MyGUI::Window* _sender); void onFilterChanged(MyGUI::Widget* _sender); diff --git a/apps/openmw/mwgui/itemtransfer.hpp b/apps/openmw/mwgui/itemtransfer.hpp new file mode 100644 index 0000000000..fbd37bf136 --- /dev/null +++ b/apps/openmw/mwgui/itemtransfer.hpp @@ -0,0 +1,78 @@ +#ifndef OPENMW_APPS_OPENMW_MWGUI_ITEMTRANSFER_H +#define OPENMW_APPS_OPENMW_MWGUI_ITEMTRANSFER_H + +#include "inventorywindow.hpp" +#include "itemmodel.hpp" +#include "itemview.hpp" +#include "windowmanagerimp.hpp" +#include "worlditemmodel.hpp" + +#include +#include + +#include + +#include + +namespace MWGui +{ + class ItemTransfer + { + public: + explicit ItemTransfer(WindowManager& windowManager) + : mWindowManager(&windowManager) + { + } + + void addTarget(ItemView& view) { mTargets.insert(&view); } + + void removeTarget(ItemView& view) { mTargets.erase(&view); } + + void apply(const ItemStack& item, std::size_t count, ItemView& sourceView) + { + if (item.mFlags & ItemStack::Flag_Bound) + { + mWindowManager->messageBox("#{sBarterDialog12}"); + return; + } + + ItemView* targetView = nullptr; + + for (ItemView* const view : mTargets) + { + if (view == &sourceView) + continue; + + if (targetView != nullptr) + { + mWindowManager->messageBox("#{sContentsMessage2}"); + return; + } + + targetView = view; + } + + WorldItemModel worldItemModel(0.5f, 0.5f); + ItemModel* const targetModel = targetView == nullptr ? &worldItemModel : targetView->getModel(); + + if (!targetModel->onDropItem(item.mBase, count)) + return; + + sourceView.getModel()->moveItem(item, count, targetModel); + + if (targetView != nullptr) + targetView->update(); + + sourceView.update(); + + mWindowManager->getInventoryWindow()->updateItemView(); + mWindowManager->playSound(item.mBase.getClass().getDownSoundId(item.mBase)); + } + + private: + Misc::NotNullPtr mWindowManager; + std::unordered_set mTargets; + }; +} + +#endif diff --git a/apps/openmw/mwgui/itemview.hpp b/apps/openmw/mwgui/itemview.hpp index cfbc8a37ac..aeed0a9113 100644 --- a/apps/openmw/mwgui/itemview.hpp +++ b/apps/openmw/mwgui/itemview.hpp @@ -17,6 +17,8 @@ namespace MWGui /// Register needed components with MyGUI's factory manager static void registerComponents(); + ItemModel* getModel() { return mModel.get(); } + /// Takes ownership of \a model void setModel(std::unique_ptr model); diff --git a/apps/openmw/mwgui/windowmanagerimp.cpp b/apps/openmw/mwgui/windowmanagerimp.cpp index 4ff297dd94..c7c4b575a5 100644 --- a/apps/openmw/mwgui/windowmanagerimp.cpp +++ b/apps/openmw/mwgui/windowmanagerimp.cpp @@ -93,6 +93,7 @@ #include "hud.hpp" #include "inventorywindow.hpp" #include "itemchargeview.hpp" +#include "itemtransfer.hpp" #include "itemview.hpp" #include "itemwidget.hpp" #include "jailscreen.hpp" @@ -312,6 +313,7 @@ namespace MWGui mTextColours.loadColours(); mDragAndDrop = std::make_unique(); + mItemTransfer = std::make_unique(*this); auto recharge = std::make_unique(); mGuiModeStates[GM_Recharge] = GuiModeState(recharge.get()); @@ -334,7 +336,7 @@ namespace MWGui trackWindow(mStatsWindow, makeStatsWindowSettingValues()); auto inventoryWindow = std::make_unique( - mDragAndDrop.get(), mViewer->getSceneData()->asGroup(), mResourceSystem); + *mDragAndDrop, *mItemTransfer, mViewer->getSceneData()->asGroup(), mResourceSystem); mInventoryWindow = inventoryWindow.get(); mWindows.push_back(std::move(inventoryWindow)); @@ -381,7 +383,7 @@ namespace MWGui mGuiModeStates[GM_Dialogue] = GuiModeState(mDialogueWindow); mTradeWindow->eventTradeDone += MyGUI::newDelegate(mDialogueWindow, &DialogueWindow::onTradeComplete); - auto containerWindow = std::make_unique(mDragAndDrop.get()); + auto containerWindow = std::make_unique(*mDragAndDrop, *mItemTransfer); mContainerWindow = containerWindow.get(); mWindows.push_back(std::move(containerWindow)); trackWindow(mContainerWindow, makeContainerWindowSettingValues()); @@ -457,7 +459,8 @@ namespace MWGui mSoulgemDialog = std::make_unique(mMessageBoxManager.get()); - auto companionWindow = std::make_unique(mDragAndDrop.get(), mMessageBoxManager.get()); + auto companionWindow + = std::make_unique(*mDragAndDrop, *mItemTransfer, mMessageBoxManager.get()); trackWindow(companionWindow.get(), makeCompanionWindowSettingValues()); mGuiModeStates[GM_Companion] = GuiModeState({ mInventoryWindow, companionWindow.get() }); mWindows.push_back(std::move(companionWindow)); diff --git a/apps/openmw/mwgui/windowmanagerimp.hpp b/apps/openmw/mwgui/windowmanagerimp.hpp index 1a96092b60..b04c648986 100644 --- a/apps/openmw/mwgui/windowmanagerimp.hpp +++ b/apps/openmw/mwgui/windowmanagerimp.hpp @@ -8,7 +8,6 @@ **/ #include -#include #include #include @@ -118,6 +117,7 @@ namespace MWGui class PostProcessorHud; class JailScreen; class KeyboardNavigation; + class ItemTransfer; class WindowManager : public MWBase::WindowManager { @@ -433,6 +433,7 @@ namespace MWGui Console* mConsole; DialogueWindow* mDialogueWindow; std::unique_ptr mDragAndDrop; + std::unique_ptr mItemTransfer; InventoryWindow* mInventoryWindow; ScrollWindow* mScrollWindow; BookWindow* mBookWindow; diff --git a/apps/openmw/mwgui/worlditemmodel.hpp b/apps/openmw/mwgui/worlditemmodel.hpp new file mode 100644 index 0000000000..137062eeb4 --- /dev/null +++ b/apps/openmw/mwgui/worlditemmodel.hpp @@ -0,0 +1,82 @@ +#ifndef OPENMW_APPS_OPENMW_MWGUI_WORLDITEMMODEL_H +#define OPENMW_APPS_OPENMW_MWGUI_WORLDITEMMODEL_H + +#include "itemmodel.hpp" + +#include +#include + +#include + +#include +#include + +#include + +namespace MWGui +{ + // Makes it possible to use ItemModel::moveItem to move an item from an inventory to the world. + class WorldItemModel : public ItemModel + { + public: + explicit WorldItemModel(float cursorX, float cursorY) + : mCursorX(cursorX) + , mCursorY(cursorY) + { + } + + MWWorld::Ptr dropItemImpl(const ItemStack& item, size_t count, bool copy) + { + MWBase::World& world = *MWBase::Environment::get().getWorld(); + + const MWWorld::Ptr player = world.getPlayerPtr(); + + world.breakInvisibility(player); + + const MWWorld::Ptr dropped = world.canPlaceObject(mCursorX, mCursorY) + ? world.placeObject(item.mBase, mCursorX, mCursorY, count, copy) + : world.dropObjectOnGround(player, item.mBase, count, copy); + + dropped.getCellRef().setOwner(ESM::RefId()); + + return dropped; + } + + MWWorld::Ptr addItem(const ItemStack& item, size_t count, bool /*allowAutoEquip*/) override + { + return dropItemImpl(item, count, false); + } + + MWWorld::Ptr copyItem(const ItemStack& item, size_t count, bool /*allowAutoEquip*/) override + { + return dropItemImpl(item, count, true); + } + + void removeItem(const ItemStack& /*item*/, size_t /*count*/) override + { + throw std::runtime_error("WorldItemModel::removeItem is not implemented"); + } + + ModelIndex getIndex(const ItemStack& /*item*/) override + { + throw std::runtime_error("WorldItemModel::getIndex is not implemented"); + } + + void update() override {} + + size_t getItemCount() override { return 0; } + + ItemStack getItem(ModelIndex /*index*/) override + { + throw std::runtime_error("WorldItemModel::getItem is not implemented"); + } + + bool usesContainer(const MWWorld::Ptr&) override { return false; } + + private: + float mCursorX; + float mCursorY; + }; +} + +#endif diff --git a/apps/openmw/mwworld/cellref.hpp b/apps/openmw/mwworld/cellref.hpp index 4dcac4def5..c290e2733c 100644 --- a/apps/openmw/mwworld/cellref.hpp +++ b/apps/openmw/mwworld/cellref.hpp @@ -244,6 +244,18 @@ namespace MWWorld return std::abs(count); return count; } + + unsigned getAbsCount() const + { + struct Visitor + { + int operator()(const ESM::CellRef& ref) { return ref.mCount; } + int operator()(const ESM4::Reference& ref) { return ref.mCount; } + int operator()(const ESM4::ActorCharacter& ref) { return ref.mCount; } + }; + return static_cast(std::abs(std::visit(Visitor(), mCellRef.mVariant))); + } + void setCount(int value); // Write the content of this CellRef into the given ObjectState From 4150f5fad6ae722cdcea43444efb50d4eb7e0ad2 Mon Sep 17 00:00:00 2001 From: Dave Corley Date: Sat, 1 Feb 2025 03:21:40 -0700 Subject: [PATCH 06/12] FEAT: AddTopic in Lua, close #8334 --- apps/openmw/mwlua/types/player.cpp | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/apps/openmw/mwlua/types/player.cpp b/apps/openmw/mwlua/types/player.cpp index 15dc719f2e..2235cfc49c 100644 --- a/apps/openmw/mwlua/types/player.cpp +++ b/apps/openmw/mwlua/types/player.cpp @@ -1,5 +1,6 @@ #include "types.hpp" +#include #include #include @@ -195,6 +196,18 @@ namespace MWLua throw std::runtime_error("Only player and global scripts can toggle teleportation."); MWBase::Environment::get().getWorld()->enableTeleporting(state); }; + player["addTopic"] = [](const Object& player, std::string topicId) { + if (dynamic_cast(&player) && !dynamic_cast(&player)) + throw std::runtime_error("Only player and global scripts may add topics."); + + ESM::RefId topic = ESM::RefId::stringRefId(topicId); + if (!MWBase::Environment::get().getESMStore()->get().search(topic)) + { + throw std::runtime_error("Failed to add topic " + topicId + ": topic record not found"); + } + + MWBase::Environment::get().getDialogueManager()->addTopic(topic); + }; player["sendMenuEvent"] = [context](const Object& player, std::string eventName, const sol::object& eventData) { verifyPlayer(player); context.mLuaEvents->addMenuEvent({ std::move(eventName), LuaUtil::serialize(eventData) }); From 05b12ac8799ed18369a8932dad44c0c89a348761 Mon Sep 17 00:00:00 2001 From: Dave Corley Date: Sat, 1 Feb 2025 04:32:20 -0700 Subject: [PATCH 07/12] CLEANUP: Use more appropriate object types & functions in addTopic binding --- apps/openmw/mwlua/types/player.cpp | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/apps/openmw/mwlua/types/player.cpp b/apps/openmw/mwlua/types/player.cpp index 2235cfc49c..25056caa41 100644 --- a/apps/openmw/mwlua/types/player.cpp +++ b/apps/openmw/mwlua/types/player.cpp @@ -3,6 +3,7 @@ #include #include #include +#include #include "../birthsignbindings.hpp" #include "../luamanagerimp.hpp" @@ -196,14 +197,14 @@ namespace MWLua throw std::runtime_error("Only player and global scripts can toggle teleportation."); MWBase::Environment::get().getWorld()->enableTeleporting(state); }; - player["addTopic"] = [](const Object& player, std::string topicId) { - if (dynamic_cast(&player) && !dynamic_cast(&player)) - throw std::runtime_error("Only player and global scripts may add topics."); + player["addTopic"] = [](const Object& player, std::string_view topicId) { + verifyPlayer(player); - ESM::RefId topic = ESM::RefId::stringRefId(topicId); + ESM::RefId topic = ESM::RefId::deserializeText(topicId); if (!MWBase::Environment::get().getESMStore()->get().search(topic)) { - throw std::runtime_error("Failed to add topic " + topicId + ": topic record not found"); + throw std::runtime_error( + Misc::StringUtils::format("Failed to add topic ", topicId, ": topic record not found")); } MWBase::Environment::get().getDialogueManager()->addTopic(topic); From 8ec4fcbf301d81fc21a3a5b60795400a8ad96a5d Mon Sep 17 00:00:00 2001 From: Dave Corley Date: Sat, 1 Feb 2025 12:01:16 -0700 Subject: [PATCH 08/12] CLEANUP: Actually check the record in question is a topic when using addTopic --- apps/openmw/mwlua/types/player.cpp | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/apps/openmw/mwlua/types/player.cpp b/apps/openmw/mwlua/types/player.cpp index 25056caa41..a763575748 100644 --- a/apps/openmw/mwlua/types/player.cpp +++ b/apps/openmw/mwlua/types/player.cpp @@ -201,11 +201,15 @@ namespace MWLua verifyPlayer(player); ESM::RefId topic = ESM::RefId::deserializeText(topicId); - if (!MWBase::Environment::get().getESMStore()->get().search(topic)) - { + const ESM::Dialogue* dialogueRecord + = MWBase::Environment::get().getESMStore()->get().search(topic); + + if (!dialogueRecord) throw std::runtime_error( Misc::StringUtils::format("Failed to add topic ", topicId, ": topic record not found")); - } + else if (dialogueRecord->mType != ESM::Dialogue::Topic) + throw std::runtime_error( + Misc::StringUtils::format("Failed to add topic ", topicId, ": record is not a topic")); MWBase::Environment::get().getDialogueManager()->addTopic(topic); }; From 943cd765e77e370c19353b957aee01dd1202a7f9 Mon Sep 17 00:00:00 2001 From: Dave Corley Date: Thu, 10 Jul 2025 17:25:30 -0700 Subject: [PATCH 09/12] CLEANUP: Update for MR Comments --- apps/openmw/mwlua/types/player.cpp | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/apps/openmw/mwlua/types/player.cpp b/apps/openmw/mwlua/types/player.cpp index a763575748..b0912f5bbd 100644 --- a/apps/openmw/mwlua/types/player.cpp +++ b/apps/openmw/mwlua/types/player.cpp @@ -1,13 +1,12 @@ #include "types.hpp" -#include #include #include -#include #include "../birthsignbindings.hpp" #include "../luamanagerimp.hpp" +#include "apps/openmw/mwbase/dialoguemanager.hpp" #include "apps/openmw/mwbase/inputmanager.hpp" #include "apps/openmw/mwbase/journal.hpp" #include "apps/openmw/mwbase/mechanicsmanager.hpp" @@ -205,11 +204,10 @@ namespace MWLua = MWBase::Environment::get().getESMStore()->get().search(topic); if (!dialogueRecord) - throw std::runtime_error( - Misc::StringUtils::format("Failed to add topic ", topicId, ": topic record not found")); - else if (dialogueRecord->mType != ESM::Dialogue::Topic) - throw std::runtime_error( - Misc::StringUtils::format("Failed to add topic ", topicId, ": record is not a topic")); + throw std::runtime_error("Failed to add topic " + std::string(topicId) + ": topic record not found"); + + if (dialogueRecord->mType != ESM::Dialogue::Topic) + throw std::runtime_error("Failed to add topic " + std::string(topicId) + ": record is not a topic"); MWBase::Environment::get().getDialogueManager()->addTopic(topic); }; From ced135bc87f832c611c21c6ed2c2eff006c681c3 Mon Sep 17 00:00:00 2001 From: Dave Corley Date: Fri, 11 Jul 2025 01:47:22 -0700 Subject: [PATCH 10/12] CLEANUP: No, record ids should totally be quoted --- apps/openmw/mwlua/types/player.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/apps/openmw/mwlua/types/player.cpp b/apps/openmw/mwlua/types/player.cpp index b0912f5bbd..e8e0eaebb5 100644 --- a/apps/openmw/mwlua/types/player.cpp +++ b/apps/openmw/mwlua/types/player.cpp @@ -204,10 +204,11 @@ namespace MWLua = MWBase::Environment::get().getESMStore()->get().search(topic); if (!dialogueRecord) - throw std::runtime_error("Failed to add topic " + std::string(topicId) + ": topic record not found"); + throw std::runtime_error( + "Failed to add topic \"" + std::string(topicId) + "\": topic record not found"); if (dialogueRecord->mType != ESM::Dialogue::Topic) - throw std::runtime_error("Failed to add topic " + std::string(topicId) + ": record is not a topic"); + throw std::runtime_error("Failed to add topic \"" + std::string(topicId) + "\": record is not a topic"); MWBase::Environment::get().getDialogueManager()->addTopic(topic); }; From 1abaf706c81879d6cae95a2f0fe5f0717925b3ed Mon Sep 17 00:00:00 2001 From: Dave Corley Date: Sat, 12 Jul 2025 19:37:36 -0700 Subject: [PATCH 11/12] CLEANUP: Bump api revision --- CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index a1d25f9350..a00dafc7ef 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -82,7 +82,7 @@ message(STATUS "Configuring OpenMW...") set(OPENMW_VERSION_MAJOR 0) set(OPENMW_VERSION_MINOR 50) set(OPENMW_VERSION_RELEASE 0) -set(OPENMW_LUA_API_REVISION 80) +set(OPENMW_LUA_API_REVISION 81) set(OPENMW_POSTPROCESSING_API_REVISION 3) set(OPENMW_VERSION_COMMITHASH "") From 119a87b7f4189252ef61a9bdfaca4c8e8b500bab Mon Sep 17 00:00:00 2001 From: Alexei Kotov Date: Sun, 13 Jul 2025 18:02:15 +0300 Subject: [PATCH 12/12] Revert "Merge branch 'tbcornottbcwaititstcbactually' into 'master'" This reverts merge request !4539 --- components/nif/nifkey.hpp | 92 ++++++++------------------------ components/nifosg/controller.hpp | 2 +- 2 files changed, 23 insertions(+), 71 deletions(-) diff --git a/components/nif/nifkey.hpp b/components/nif/nifkey.hpp index bd362101c6..604cf92c33 100644 --- a/components/nif/nifkey.hpp +++ b/components/nif/nifkey.hpp @@ -3,9 +3,7 @@ #ifndef OPENMW_COMPONENTS_NIF_NIFKEY_HPP #define OPENMW_COMPONENTS_NIF_NIFKEY_HPP -#include #include -#include #include "exception.hpp" #include "niffile.hpp" @@ -19,7 +17,7 @@ namespace Nif InterpolationType_Unknown = 0, InterpolationType_Linear = 1, InterpolationType_Quadratic = 2, - InterpolationType_TCB = 3, + InterpolationType_TBC = 3, InterpolationType_XYZ = 4, InterpolationType_Constant = 5 }; @@ -30,19 +28,18 @@ namespace Nif T mValue; T mInTan; // Only for Quadratic interpolation, and never for QuaternionKeyList T mOutTan; // Only for Quadratic interpolation, and never for QuaternionKeyList - }; - template - struct TCBKey - { - float mTime; - T mValue{}; - T mInTan{}; - T mOutTan{}; - float mTension; - float mContinuity; - float mBias; + // FIXME: Implement TBC interpolation + /* + float mTension; // Only for TBC interpolation + float mBias; // Only for TBC interpolation + float mContinuity; // Only for TBC interpolation + */ }; + using FloatKey = KeyT; + using Vector3Key = KeyT; + using Vector4Key = KeyT; + using QuaternionKey = KeyT; template struct KeyMapT @@ -104,20 +101,15 @@ namespace Nif mKeys[time] = key; } } - else if (mInterpolationType == InterpolationType_TCB) + else if (mInterpolationType == InterpolationType_TBC) { - std::vector> tcbKeys(count); - for (TCBKey& key : tcbKeys) + for (size_t i = 0; i < count; i++) { - nif->read(key.mTime); - key.mValue = ((*nif).*getValue)(); - nif->read(key.mTension); - nif->read(key.mContinuity); - nif->read(key.mBias); + float time; + nif->read(time); + readTBC(*nif, key); + mKeys[time] = key; } - generateTCBTangents(tcbKeys); - for (TCBKey& key : tcbKeys) - mKeys[key.mTime] = KeyType{ std::move(key.mValue), std::move(key.mInTan), std::move(key.mOutTan) }; } else if (mInterpolationType == InterpolationType_XYZ) { @@ -148,52 +140,12 @@ namespace Nif static void readQuadratic(NIFStream& nif, KeyT& key) { readValue(nif, key); } - template - static void generateTCBTangents(std::vector>& keys) + static void readTBC(NIFStream& nif, KeyT& key) { - if (keys.size() <= 1) - return; - - std::sort(keys.begin(), keys.end(), [](const auto& a, const auto& b) { return a.mTime < b.mTime; }); - for (size_t i = 0; i < keys.size(); ++i) - { - TCBKey& curr = keys[i]; - const TCBKey& prev = (i == 0) ? curr : keys[i - 1]; - const TCBKey& next = (i == keys.size() - 1) ? curr : keys[i + 1]; - const float prevLen = curr.mTime - prev.mTime; - const float nextLen = next.mTime - curr.mTime; - if (prevLen + nextLen <= 0.f) - continue; - - const U prevDelta = curr.mValue - prev.mValue; - const U nextDelta = next.mValue - curr.mValue; - const float t = curr.mTension; - const float c = curr.mContinuity; - const float b = curr.mBias; - - U x{}, y{}, z{}, w{}; - if (prevLen > 0.f) - x = prevDelta / prevLen * (1 - t) * (1 - c) * (1 + b); - if (nextLen > 0.f) - y = nextDelta / nextLen * (1 - t) * (1 + c) * (1 - b); - if (prevLen > 0.f) - z = prevDelta / prevLen * (1 - t) * (1 + c) * (1 + b); - if (nextLen > 0.f) - w = nextDelta / nextLen * (1 - t) * (1 - c) * (1 - b); - - curr.mInTan = (x + y) * prevLen / (prevLen + nextLen); - curr.mOutTan = (z + w) * nextLen / (prevLen + nextLen); - } - } - - static void generateTCBTangents(std::vector>& keys) - { - // TODO: is this even legal? - } - - static void generateTCBTangents(std::vector>& keys) - { - // TODO: implement TCB interpolation for quaternions + readValue(nif, key); + /*key.mTension = */ nif.get(); + /*key.mBias = */ nif.get(); + /*key.mContinuity = */ nif.get(); } }; using FloatKeyMap = KeyMapT>; diff --git a/components/nifosg/controller.hpp b/components/nifosg/controller.hpp index 468668ce76..99d3df9545 100644 --- a/components/nifosg/controller.hpp +++ b/components/nifosg/controller.hpp @@ -131,7 +131,6 @@ namespace NifOsg case Nif::InterpolationType_Constant: return fraction > 0.5f ? b.mValue : a.mValue; case Nif::InterpolationType_Quadratic: - case Nif::InterpolationType_TCB: { // Using a cubic Hermite spline. // b1(t) = 2t^3 - 3t^2 + 1 @@ -148,6 +147,7 @@ namespace NifOsg const float b4 = t3 - t2; return a.mValue * b1 + b.mValue * b2 + a.mOutTan * b3 + b.mInTan * b4; } + // TODO: Implement TBC interpolation default: return a.mValue + ((b.mValue - a.mValue) * fraction); }