1
0
Fork 0
mirror of https://github.com/OpenMW/openmw.git synced 2025-10-18 00:46:38 +00:00
This commit is contained in:
Andrew Lanzone 2025-07-13 14:55:27 -07:00
commit 6a02e6a4bc
27 changed files with 398 additions and 302 deletions

View file

@ -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 "")

View file

@ -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 controllerbuttonsoverlay inventorytabsoverlay
postprocessorhud settings worlditemmodel itemtransfer controllerbuttonsoverlay inventorytabsoverlay
)
add_openmw_dir (mwdialogue

View file

@ -16,7 +16,7 @@
#include "companionitemmodel.hpp"
#include "countdialog.hpp"
#include "draganddrop.hpp"
#include "inventorywindow.hpp"
#include "itemtransfer.hpp"
#include "itemview.hpp"
#include "messagebox.hpp"
#include "sortfilteritemmodel.hpp"
@ -41,13 +41,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");
@ -102,13 +103,13 @@ namespace MWGui
name += MWGui::ToolTips::getSoulString(object.getCellRef());
dialog->openCountDialog(name, "#{sTake}", count);
dialog->eventOkClicked.clear();
if (Settings::gui().mControllerMenus)
dialog->eventOkClicked += MyGUI::newDelegate(this, &CompanionWindow::takeItem);
if (Settings::gui().mControllerMenus || MyGUI::InputManager::getInstance().isAltPressed())
dialog->eventOkClicked += MyGUI::newDelegate(this, &CompanionWindow::transferItem);
else
dialog->eventOkClicked += MyGUI::newDelegate(this, &CompanionWindow::dragItem);
}
else if (Settings::gui().mControllerMenus)
takeItem(nullptr, count);
else if (Settings::gui().mControllerMenus || MyGUI::InputManager::getInstance().isAltPressed())
transferItem(nullptr, count);
else
dragItem(nullptr, count);
}
@ -119,32 +120,14 @@ 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);
}
void CompanionWindow::takeItem(MyGUI::Widget* sender, int count)
void CompanionWindow::transferItem(MyGUI::Widget* /*sender*/, std::size_t count)
{
if (!mModel)
return;
const ItemStack& item = mModel->getItem(mSelectedItem);
if (!mModel->onTakeItem(item.mBase, count))
return;
MWGui::InventoryWindow* inventoryWindow = MWBase::Environment::get().getWindowManager()->getInventoryWindow();
ItemModel* playerModel = inventoryWindow->getModel();
mModel->moveItem(item, count, playerModel);
inventoryWindow->updateItemView();
mItemView->update();
// play the item's sound
MWWorld::Ptr itemBase = item.mBase;
const ESM::RefId& sound = itemBase.getClass().getUpSoundId(itemBase);
MWBase::Environment::get().getWindowManager()->playSound(sound);
mItemTransfer->apply(mModel->getItem(mSelectedItem), count, *mItemView);
}
void CompanionWindow::onBackgroundSelected()
@ -257,6 +240,16 @@ namespace MWGui
mUpdateNextFrame = true;
}
void CompanionWindow::onOpen()
{
mItemTransfer->addTarget(*mItemView);
}
void CompanionWindow::onClose()
{
mItemTransfer->removeTarget(*mItemView);
}
bool CompanionWindow::onControllerButtonEvent(const SDL_ControllerButtonEvent& arg)
{
if (arg.button == SDL_CONTROLLER_BUTTON_A)

View file

@ -8,6 +8,8 @@
#include "../mwworld/containerstore.hpp"
#include <components/misc/notnullptr.hpp>
namespace MWGui
{
namespace Widgets
@ -20,11 +22,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;
@ -52,7 +55,8 @@ namespace MWGui
int mSelectedItem;
bool mUpdateNextFrame;
DragAndDrop* mDragAndDrop;
Misc::NotNullPtr<DragAndDrop> mDragAndDrop;
Misc::NotNullPtr<ItemTransfer> mItemTransfer;
MyGUI::Button* mCloseButton;
MyGUI::EditBox* mFilterEdit;
@ -63,8 +67,8 @@ namespace MWGui
void onItemSelected(int index);
void onNameFilterChanged(MyGUI::EditBox* _sender);
void onBackgroundSelected();
void dragItem(MyGUI::Widget* sender, int count);
void takeItem(MyGUI::Widget* sender, int count);
void dragItem(MyGUI::Widget* sender, std::size_t count);
void transferItem(MyGUI::Widget* sender, std::size_t count);
void onMessageBoxButtonClicked(int button);
@ -73,6 +77,10 @@ namespace MWGui
void onCloseButtonClicked(MyGUI::Widget* _sender);
void onReferenceUnavailable() override;
void onOpen() override;
void onClose() override;
};
}

View file

@ -20,12 +20,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"
@ -34,9 +34,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)
@ -97,54 +98,46 @@ namespace MWGui
name += MWGui::ToolTips::getSoulString(object.getCellRef());
dialog->openCountDialog(name, "#{sTake}", count);
dialog->eventOkClicked.clear();
if (Settings::gui().mControllerMenus)
dialog->eventOkClicked += MyGUI::newDelegate(this, &ContainerWindow::takeItem);
if (Settings::gui().mControllerMenus || MyGUI::InputManager::getInstance().isAltPressed())
dialog->eventOkClicked += MyGUI::newDelegate(this, &ContainerWindow::transferItem);
else
dialog->eventOkClicked += MyGUI::newDelegate(this, &ContainerWindow::dragItem);
}
else if (Settings::gui().mControllerMenus)
takeItem(nullptr, count);
else if (Settings::gui().mControllerMenus || MyGUI::InputManager::getInstance().isAltPressed())
transferItem(nullptr, count);
else
dragItem(nullptr, count);
}
void ContainerWindow::dragItem(MyGUI::Widget* sender, int count)
void ContainerWindow::dragItem(MyGUI::Widget* /*sender*/, std::size_t count)
{
if (!mModel)
if (mModel == nullptr)
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);
}
void ContainerWindow::takeItem(MyGUI::Widget* sender, int count)
void ContainerWindow::transferItem(MyGUI::Widget* /*sender*/, std::size_t count)
{
if (!mModel)
if (mModel == nullptr)
return;
const ItemStack& item = mModel->getItem(mSelectedItem);
if (!onTakeItem(item, count))
const ItemStack item = mModel->getItem(mSelectedItem);
if (!mModel->onTakeItem(item.mBase, count))
return;
MWGui::InventoryWindow* inventoryWindow = MWBase::Environment::get().getWindowManager()->getInventoryWindow();
ItemModel* playerModel = inventoryWindow->getModel();
mModel->moveItem(item, count, playerModel);
inventoryWindow->updateItemView();
mItemView->update();
// play the item's sound
MWWorld::Ptr itemBase = item.mBase;
const ESM::RefId& sound = itemBase.getClass().getUpSoundId(itemBase);
MWBase::Environment::get().getWindowManager()->playSound(sound);
mItemTransfer->apply(item, count, *mItemView);
}
void ContainerWindow::dropItem()
{
if (!mModel)
if (mModel == nullptr)
return;
bool success = mModel->onDropItem(mDragAndDrop->mItem.mBase, mDragAndDrop->mDraggedCount);
@ -209,10 +202,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;
@ -223,6 +219,8 @@ namespace MWGui
if (!mPtr.isEmpty())
MWBase::Environment::get().getMechanicsManager()->onClose(mPtr);
resetReference();
mItemTransfer->removeTarget(*mItemView);
}
void ContainerWindow::onCloseButtonClicked(MyGUI::Widget* _sender)
@ -270,9 +268,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);
@ -349,11 +347,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))

View file

@ -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 <components/misc/notnullptr.hpp>
#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;
@ -53,7 +56,8 @@ namespace MWGui
ItemModel* getModel() { return mModel; }
private:
DragAndDrop* mDragAndDrop;
Misc::NotNullPtr<DragAndDrop> mDragAndDrop;
Misc::NotNullPtr<ItemTransfer> mItemTransfer;
MWGui::ItemView* mItemView;
SortFilterItemModel* mSortModel;
@ -67,16 +71,13 @@ namespace MWGui
void onItemSelected(int index);
void onBackgroundSelected();
void dragItem(MyGUI::Widget* sender, int count);
void takeItem(MyGUI::Widget* sender, int 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);
void onDisposeCorpseButtonClicked(MyGUI::Widget* sender);
/// @return is taking the item allowed?
bool onTakeItem(const ItemStack& item, int count);
void onReferenceUnavailable() override;
};
}

View file

@ -19,12 +19,10 @@ namespace MWGui
void openCountDialog(const std::string& item, const std::string& message, const int maxCount);
void setCount(int count);
typedef MyGUI::delegates::MultiDelegate<MyGUI::Widget*, int> 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<MyGUI::Widget*, std::size_t> eventOkClicked;
private:
Gui::ScrollBar* mSlider;

View file

@ -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;
@ -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()

View file

@ -4,6 +4,8 @@
#include "itemmodel.hpp"
#include "itemwidget.hpp"
#include <cstddef>
namespace MyGUI
{
class Widget;
@ -24,12 +26,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();

View file

@ -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)
@ -262,13 +207,14 @@ namespace MWGui
MWBase::WindowManager* winMgr = MWBase::Environment::get().getWindowManager();
if (mDragAndDrop->mIsOnDragAndDrop)
{
// drop item into the gameworld
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);
const MyGUI::IntSize viewSize = MyGUI::RenderManager::getInstance().getViewSize();
const MyGUI::IntPoint cursorPosition = MyGUI::InputManager::getInstance().getMousePosition();
const float cursorX = cursorPosition.left / static_cast<float>(viewSize.width);
const float cursorY = cursorPosition.top / static_cast<float>(viewSize.height);
dropDraggedItem(mouseX, mouseY);
// drop item into the gameworld
WorldItemModel worldItemModel(cursorX, cursorY);
mDragAndDrop->drop(&worldItemModel, nullptr);
winMgr->changePointer("arrow");
}

View file

@ -38,6 +38,7 @@
#include "draganddrop.hpp"
#include "hud.hpp"
#include "inventoryitemmodel.hpp"
#include "itemtransfer.hpp"
#include "itemview.hpp"
#include "settings.hpp"
#include "sortfilteritemmodel.hpp"
@ -78,10 +79,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)
@ -346,14 +348,16 @@ namespace MWGui
name += MWGui::ToolTips::getSoulString(object.getCellRef());
dialog->openCountDialog(name, message, count);
dialog->eventOkClicked.clear();
if (mPendingControllerAction == ControllerAction::Give)
dialog->eventOkClicked += MyGUI::newDelegate(this, &InventoryWindow::giveItem);
else if (mPendingControllerAction == ControllerAction::Drop)
if (mPendingControllerAction == ControllerAction::Drop)
dialog->eventOkClicked += MyGUI::newDelegate(this, &InventoryWindow::dropItem);
else if (mTrading || mPendingControllerAction == ControllerAction::Sell)
dialog->eventOkClicked += MyGUI::newDelegate(this, &InventoryWindow::sellItem);
else if (MyGUI::InputManager::getInstance().isAltPressed()
|| mPendingControllerAction == ControllerAction::Transfer)
dialog->eventOkClicked += MyGUI::newDelegate(this, &InventoryWindow::transferItem);
else
dialog->eventOkClicked += MyGUI::newDelegate(this, &InventoryWindow::dragItem);
mSelectedItem = index;
}
else
@ -369,12 +373,13 @@ namespace MWGui
// stack of items; we only want to use the first item.
onBackgroundSelected();
}
else if (mPendingControllerAction == ControllerAction::Give)
giveItem(nullptr, count);
else if (mPendingControllerAction == ControllerAction::Drop)
dropItem(nullptr, count);
else if (mTrading || mPendingControllerAction == ControllerAction::Sell)
sellItem(nullptr, count);
else if (MyGUI::InputManager::getInstance().isAltPressed()
|| mPendingControllerAction == ControllerAction::Transfer)
transferItem(nullptr, count);
else
dragItem(nullptr, count);
}
@ -415,14 +420,21 @@ 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::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);
const ItemStack& item = mTradeModel->getItem(mSelectedItem);
@ -446,32 +458,7 @@ namespace MWGui
notifyContentChanged();
}
void InventoryWindow::giveItem(MyGUI::Widget* sender, int count)
{
if (!mDragAndDrop->mIsOnDragAndDrop)
dragItem(sender, count);
if (mGuiMode == MWGui::GM_Companion && mDragAndDrop->mIsOnDragAndDrop)
{
// Drag and drop the item on the companion's window.
MWGui::CompanionWindow* companionWindow = (MWGui::CompanionWindow*)MWBase::Environment::get()
.getWindowManager()
->getGuiModeWindows(mGuiMode)
.at(1);
mDragAndDrop->drop(companionWindow->getModel(), companionWindow->getItemView());
}
else if (mGuiMode == MWGui::GM_Container && mDragAndDrop->mIsOnDragAndDrop)
{
// Drag and drop the item on the container window.
MWGui::ContainerWindow* containerWindow = (MWGui::ContainerWindow*)MWBase::Environment::get()
.getWindowManager()
->getGuiModeWindows(mGuiMode)
.at(0);
mDragAndDrop->drop(containerWindow->getModel(), containerWindow->getItemView());
}
}
void InventoryWindow::dropItem(MyGUI::Widget* sender, int count)
void InventoryWindow::dropItem(MyGUI::Widget* sender, size_t count)
{
if (mGuiMode != MWGui::GM_Inventory)
return;
@ -507,6 +494,13 @@ namespace MWGui
notifyContentChanged();
}
adjustPanes();
mItemTransfer->addTarget(*mItemView);
}
void InventoryWindow::onClose()
{
mItemTransfer->removeTarget(*mItemView);
}
void InventoryWindow::onWindowResize(MyGUI::Window* _sender)
@ -868,7 +862,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();
}
@ -1017,7 +1020,7 @@ namespace MWGui
if (mGuiMode == MWGui::GM_Inventory)
mPendingControllerAction = ControllerAction::Use;
else if (mGuiMode == MWGui::GM_Companion || mGuiMode == MWGui::GM_Container)
mPendingControllerAction = ControllerAction::Give;
mPendingControllerAction = ControllerAction::Transfer;
else if (mGuiMode == MWGui::GM_Barter)
mPendingControllerAction = ControllerAction::Sell;

View file

@ -8,6 +8,8 @@
#include "../mwworld/containerstore.hpp"
#include "../mwworld/ptr.hpp"
#include <components/misc/notnullptr.hpp>
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);
@ -79,7 +85,8 @@ namespace MWGui
void setActiveControllerWindow(bool active) override;
private:
DragAndDrop* mDragAndDrop;
Misc::NotNullPtr<DragAndDrop> mDragAndDrop;
Misc::NotNullPtr<ItemTransfer> mItemTransfer;
int mSelectedItem;
std::optional<int> mEquippedStackableCount;
@ -128,16 +135,16 @@ namespace MWGui
{
None = 0,
Use,
Give,
Transfer,
Sell,
Drop,
};
ControllerAction mPendingControllerAction;
void sellItem(MyGUI::Widget* sender, int count);
void dragItem(MyGUI::Widget* sender, int count);
void giveItem(MyGUI::Widget* sender, int count);
void dropItem(MyGUI::Widget* sender, int count);
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 dropItem(MyGUI::Widget* sender, std::size_t count);
void onWindowResize(MyGUI::Window* _sender);
void onFilterChanged(MyGUI::Widget* _sender);

View file

@ -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 <apps/openmw/mwbase/windowmanager.hpp>
#include <apps/openmw/mwworld/class.hpp>
#include <components/misc/notnullptr.hpp>
#include <unordered_set>
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<WindowManager> mWindowManager;
std::unordered_set<ItemView*> mTargets;
};
}
#endif

View file

@ -18,6 +18,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<ItemModel> model);

View file

@ -321,7 +321,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);
@ -382,9 +382,9 @@ namespace MWGui
}
}
void TradeWindow::onOfferSubmitted(MyGUI::Widget* _sender, int offerAmount)
void TradeWindow::onOfferSubmitted(MyGUI::Widget* _sender, size_t offerAmount)
{
mCurrentBalance = mCurrentBalance < 0 ? -offerAmount : offerAmount;
mCurrentBalance = offerAmount * (mCurrentBalance < 0 ? -1 : 1);
updateLabels();
onOfferButtonClicked(mOfferButton);
}

View file

@ -98,7 +98,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);
@ -116,7 +116,7 @@ namespace MWGui
void onBalanceButtonReleased(MyGUI::Widget* _sender, int _left, int _top, MyGUI::MouseButton _id);
void onBalanceValueChanged(int value);
void onRepeatClick(MyGUI::Widget* widget, MyGUI::ControllerItem* controller);
void onOfferSubmitted(MyGUI::Widget* _sender, int offerAmount);
void onOfferSubmitted(MyGUI::Widget* _sender, size_t offerAmount);
void addRepeatController(MyGUI::Widget* widget);

View file

@ -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"
@ -314,6 +315,7 @@ namespace MWGui
mTextColours.loadColours();
mDragAndDrop = std::make_unique<DragAndDrop>();
mItemTransfer = std::make_unique<ItemTransfer>(*this);
auto recharge = std::make_unique<Recharge>();
mGuiModeStates[GM_Recharge] = GuiModeState(recharge.get());
@ -336,7 +338,7 @@ namespace MWGui
trackWindow(mStatsWindow, makeStatsWindowSettingValues());
auto inventoryWindow = std::make_unique<InventoryWindow>(
mDragAndDrop.get(), mViewer->getSceneData()->asGroup(), mResourceSystem);
*mDragAndDrop, *mItemTransfer, mViewer->getSceneData()->asGroup(), mResourceSystem);
mInventoryWindow = inventoryWindow.get();
mWindows.push_back(std::move(inventoryWindow));
@ -383,7 +385,7 @@ namespace MWGui
mGuiModeStates[GM_Dialogue] = GuiModeState(mDialogueWindow);
mTradeWindow->eventTradeDone += MyGUI::newDelegate(mDialogueWindow, &DialogueWindow::onTradeComplete);
auto containerWindow = std::make_unique<ContainerWindow>(mDragAndDrop.get());
auto containerWindow = std::make_unique<ContainerWindow>(*mDragAndDrop, *mItemTransfer);
mContainerWindow = containerWindow.get();
mWindows.push_back(std::move(containerWindow));
trackWindow(mContainerWindow, makeContainerWindowSettingValues());
@ -459,7 +461,8 @@ namespace MWGui
mSoulgemDialog = std::make_unique<SoulgemDialog>(mMessageBoxManager.get());
auto companionWindow = std::make_unique<CompanionWindow>(mDragAndDrop.get(), mMessageBoxManager.get());
auto companionWindow
= std::make_unique<CompanionWindow>(*mDragAndDrop, *mItemTransfer, mMessageBoxManager.get());
trackWindow(companionWindow.get(), makeCompanionWindowSettingValues());
mGuiModeStates[GM_Companion] = GuiModeState({ mInventoryWindow, companionWindow.get() });
mWindows.push_back(std::move(companionWindow));

View file

@ -8,7 +8,6 @@
**/
#include <memory>
#include <stack>
#include <vector>
#include <osg/ref_ptr>
@ -120,6 +119,7 @@ namespace MWGui
class PostProcessorHud;
class JailScreen;
class KeyboardNavigation;
class ItemTransfer;
class ControllerButtonsOverlay;
class InventoryTabsOverlay;
@ -446,6 +446,7 @@ namespace MWGui
Console* mConsole;
DialogueWindow* mDialogueWindow;
std::unique_ptr<DragAndDrop> mDragAndDrop;
std::unique_ptr<ItemTransfer> mItemTransfer;
InventoryWindow* mInventoryWindow;
ScrollWindow* mScrollWindow;
BookWindow* mBookWindow;

View file

@ -0,0 +1,82 @@
#ifndef OPENMW_APPS_OPENMW_MWGUI_WORLDITEMMODEL_H
#define OPENMW_APPS_OPENMW_MWGUI_WORLDITEMMODEL_H
#include "itemmodel.hpp"
#include <apps/openmw/mwbase/environment.hpp>
#include <apps/openmw/mwbase/world.hpp>
#include <components/esm/refid.hpp>
#include <MyGUI_InputManager.h>
#include <MyGUI_RenderManager.h>
#include <stdexcept>
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

View file

@ -6,6 +6,7 @@
#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"
@ -195,6 +196,22 @@ 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_view topicId) {
verifyPlayer(player);
ESM::RefId topic = ESM::RefId::deserializeText(topicId);
const ESM::Dialogue* dialogueRecord
= MWBase::Environment::get().getESMStore()->get<ESM::Dialogue>().search(topic);
if (!dialogueRecord)
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);
};
player["sendMenuEvent"] = [context](const Object& player, std::string eventName, const sol::object& eventData) {
verifyPlayer(player);
context.mLuaEvents->addMenuEvent({ std::move(eventName), LuaUtil::serialize(eventData) });

View file

@ -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<unsigned>(std::abs(std::visit(Visitor(), mCellRef.mVariant)));
}
void setCount(int value);
// Write the content of this CellRef into the given ObjectState

View file

@ -3,9 +3,7 @@
#ifndef OPENMW_COMPONENTS_NIF_NIFKEY_HPP
#define OPENMW_COMPONENTS_NIF_NIFKEY_HPP
#include <algorithm>
#include <map>
#include <vector>
#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 <typename T>
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<float>;
using Vector3Key = KeyT<osg::Vec3f>;
using Vector4Key = KeyT<osg::Vec4f>;
using QuaternionKey = KeyT<osg::Quat>;
template <typename T, T (NIFStream::*getValue)()>
struct KeyMapT
@ -104,20 +101,15 @@ namespace Nif
mKeys[time] = key;
}
}
else if (mInterpolationType == InterpolationType_TCB)
else if (mInterpolationType == InterpolationType_TBC)
{
std::vector<TCBKey<T>> tcbKeys(count);
for (TCBKey<T>& 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<T>& 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<osg::Quat>& key) { readValue(nif, key); }
template <typename U>
static void generateTCBTangents(std::vector<TCBKey<U>>& keys)
static void readTBC(NIFStream& nif, KeyT<T>& 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<U>& curr = keys[i];
const TCBKey<U>& prev = (i == 0) ? curr : keys[i - 1];
const TCBKey<U>& 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<TCBKey<bool>>& keys)
{
// TODO: is this even legal?
}
static void generateTCBTangents(std::vector<TCBKey<osg::Quat>>& keys)
{
// TODO: implement TCB interpolation for quaternions
readValue(nif, key);
/*key.mTension = */ nif.get<float>();
/*key.mBias = */ nif.get<float>();
/*key.mContinuity = */ nif.get<float>();
}
};
using FloatKeyMap = KeyMapT<float, &NIFStream::get<float>>;

View file

@ -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);
}

View file

@ -10,8 +10,6 @@
#include <MyGUI_Colour.h>
#include <cstdint>
#include <string>
#include <string_view>
namespace Settings

View file

@ -98,7 +98,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.
@ -108,7 +108,7 @@ GUI Settings
:type: boolean
:range: true, false
:default: true
Enable or disable the werewolf visual effect in first-person mode.
@ -117,7 +117,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).
@ -128,7 +128,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).

View file

@ -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.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</source>
<translation>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Om den här funktionen är aktiverad kommer spekularitetskartor (specular maps) att hittas och användas
<translation>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Om den här funktionen är aktiverad kommer spekularitetskartor (specular maps) att hittas och användas
(see &apos;specular map pattern&apos;, 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.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</translation>
</message>
<message>

View file

@ -378,8 +378,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
@ -1142,7 +1142,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
@ -1275,7 +1275,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.