mirror of
https://github.com/OpenMW/openmw.git
synced 2025-06-06 10:11:32 +00:00
Merge branch 'makealchemygreatagain' into 'master'
Allow choosing different apparatus in alchemy window Closes #7665 See merge request OpenMW/openmw!3580
This commit is contained in:
commit
abd2c5326f
8 changed files with 150 additions and 17 deletions
|
@ -95,6 +95,7 @@
|
||||||
Bug #7647: NPC walk cycle bugs after greeting player
|
Bug #7647: NPC walk cycle bugs after greeting player
|
||||||
Bug #7654: Tooltips for enchantments with invalid effects cause crashes
|
Bug #7654: Tooltips for enchantments with invalid effects cause crashes
|
||||||
Bug #7660: Some inconsistencies regarding Invisibility breaking
|
Bug #7660: Some inconsistencies regarding Invisibility breaking
|
||||||
|
Bug #7665: Alchemy menu is missing the ability to deselect and choose different qualities of an apparatus
|
||||||
Bug #7675: Successful lock spell doesn't produce a sound
|
Bug #7675: Successful lock spell doesn't produce a sound
|
||||||
Bug #7679: Scene luminance value flashes when toggling shaders
|
Bug #7679: Scene luminance value flashes when toggling shaders
|
||||||
Feature #3537: Shader-based water ripples
|
Feature #3537: Shader-based water ripples
|
||||||
|
|
|
@ -7,6 +7,7 @@
|
||||||
#include <MyGUI_EditBox.h>
|
#include <MyGUI_EditBox.h>
|
||||||
#include <MyGUI_Gui.h>
|
#include <MyGUI_Gui.h>
|
||||||
|
|
||||||
|
#include <components/esm3/loadappa.hpp>
|
||||||
#include <components/esm3/loadingr.hpp>
|
#include <components/esm3/loadingr.hpp>
|
||||||
#include <components/esm3/loadmgef.hpp>
|
#include <components/esm3/loadmgef.hpp>
|
||||||
|
|
||||||
|
@ -77,6 +78,11 @@ namespace MWGui
|
||||||
mIngredients[2]->eventMouseButtonClick += MyGUI::newDelegate(this, &AlchemyWindow::onIngredientSelected);
|
mIngredients[2]->eventMouseButtonClick += MyGUI::newDelegate(this, &AlchemyWindow::onIngredientSelected);
|
||||||
mIngredients[3]->eventMouseButtonClick += MyGUI::newDelegate(this, &AlchemyWindow::onIngredientSelected);
|
mIngredients[3]->eventMouseButtonClick += MyGUI::newDelegate(this, &AlchemyWindow::onIngredientSelected);
|
||||||
|
|
||||||
|
mApparatus[0]->eventMouseButtonClick += MyGUI::newDelegate(this, &AlchemyWindow::onApparatusSelected);
|
||||||
|
mApparatus[1]->eventMouseButtonClick += MyGUI::newDelegate(this, &AlchemyWindow::onApparatusSelected);
|
||||||
|
mApparatus[2]->eventMouseButtonClick += MyGUI::newDelegate(this, &AlchemyWindow::onApparatusSelected);
|
||||||
|
mApparatus[3]->eventMouseButtonClick += MyGUI::newDelegate(this, &AlchemyWindow::onApparatusSelected);
|
||||||
|
|
||||||
mCreateButton->eventMouseButtonClick += MyGUI::newDelegate(this, &AlchemyWindow::onCreateButtonClicked);
|
mCreateButton->eventMouseButtonClick += MyGUI::newDelegate(this, &AlchemyWindow::onCreateButtonClicked);
|
||||||
mCancelButton->eventMouseButtonClick += MyGUI::newDelegate(this, &AlchemyWindow::onCancelButtonClicked);
|
mCancelButton->eventMouseButtonClick += MyGUI::newDelegate(this, &AlchemyWindow::onCancelButtonClicked);
|
||||||
|
|
||||||
|
@ -141,12 +147,12 @@ namespace MWGui
|
||||||
}
|
}
|
||||||
|
|
||||||
// remove ingredient slots that have been fully used up
|
// remove ingredient slots that have been fully used up
|
||||||
for (int i = 0; i < 4; ++i)
|
for (size_t i = 0; i < mIngredients.size(); ++i)
|
||||||
if (mIngredients[i]->isUserString("ToolTipType"))
|
if (mIngredients[i]->isUserString("ToolTipType"))
|
||||||
{
|
{
|
||||||
MWWorld::Ptr ingred = *mIngredients[i]->getUserData<MWWorld::Ptr>();
|
MWWorld::Ptr ingred = *mIngredients[i]->getUserData<MWWorld::Ptr>();
|
||||||
if (ingred.getRefData().getCount() == 0)
|
if (ingred.getRefData().getCount() == 0)
|
||||||
removeIngredient(mIngredients[i]);
|
mAlchemy->removeIngredient(i);
|
||||||
}
|
}
|
||||||
|
|
||||||
updateFilters();
|
updateFilters();
|
||||||
|
@ -289,7 +295,85 @@ namespace MWGui
|
||||||
|
|
||||||
void AlchemyWindow::onIngredientSelected(MyGUI::Widget* _sender)
|
void AlchemyWindow::onIngredientSelected(MyGUI::Widget* _sender)
|
||||||
{
|
{
|
||||||
removeIngredient(_sender);
|
size_t i = std::distance(mIngredients.begin(), std::find(mIngredients.begin(), mIngredients.end(), _sender));
|
||||||
|
mAlchemy->removeIngredient(i);
|
||||||
|
update();
|
||||||
|
}
|
||||||
|
|
||||||
|
void AlchemyWindow::onItemSelected(MWWorld::Ptr item)
|
||||||
|
{
|
||||||
|
mItemSelectionDialog->setVisible(false);
|
||||||
|
|
||||||
|
int32_t index = item.get<ESM::Apparatus>()->mBase->mData.mType;
|
||||||
|
const auto& widget = mApparatus[index];
|
||||||
|
|
||||||
|
widget->setItem(item);
|
||||||
|
|
||||||
|
if (item.isEmpty())
|
||||||
|
{
|
||||||
|
widget->clearUserStrings();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
mAlchemy->addApparatus(item);
|
||||||
|
|
||||||
|
widget->setUserString("ToolTipType", "ItemPtr");
|
||||||
|
widget->setUserData(MWWorld::Ptr(item));
|
||||||
|
|
||||||
|
MWBase::Environment::get().getWindowManager()->playSound(item.getClass().getDownSoundId(item));
|
||||||
|
update();
|
||||||
|
}
|
||||||
|
|
||||||
|
void AlchemyWindow::onItemCancel()
|
||||||
|
{
|
||||||
|
mItemSelectionDialog->setVisible(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
void AlchemyWindow::onApparatusSelected(MyGUI::Widget* _sender)
|
||||||
|
{
|
||||||
|
size_t i = std::distance(mApparatus.begin(), std::find(mApparatus.begin(), mApparatus.end(), _sender));
|
||||||
|
if (_sender->getUserData<MWWorld::Ptr>()->isEmpty()) // if this apparatus slot is empty
|
||||||
|
{
|
||||||
|
std::string title;
|
||||||
|
switch (i)
|
||||||
|
{
|
||||||
|
case ESM::Apparatus::AppaType::MortarPestle:
|
||||||
|
title = "#{sMortar}";
|
||||||
|
break;
|
||||||
|
case ESM::Apparatus::AppaType::Alembic:
|
||||||
|
title = "#{sAlembic}";
|
||||||
|
break;
|
||||||
|
case ESM::Apparatus::AppaType::Calcinator:
|
||||||
|
title = "#{sCalcinator}";
|
||||||
|
break;
|
||||||
|
case ESM::Apparatus::AppaType::Retort:
|
||||||
|
title = "#{sRetort}";
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
title = "#{sApparatus}";
|
||||||
|
}
|
||||||
|
|
||||||
|
mItemSelectionDialog = std::make_unique<ItemSelectionDialog>(title);
|
||||||
|
mItemSelectionDialog->eventItemSelected += MyGUI::newDelegate(this, &AlchemyWindow::onItemSelected);
|
||||||
|
mItemSelectionDialog->eventDialogCanceled += MyGUI::newDelegate(this, &AlchemyWindow::onItemCancel);
|
||||||
|
mItemSelectionDialog->setVisible(true);
|
||||||
|
mItemSelectionDialog->openContainer(MWMechanics::getPlayer());
|
||||||
|
mItemSelectionDialog->getSortModel()->setApparatusTypeFilter(i);
|
||||||
|
mItemSelectionDialog->setFilter(SortFilterItemModel::Filter_OnlyAlchemyTools);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
const auto& widget = mApparatus[i];
|
||||||
|
mAlchemy->removeApparatus(i);
|
||||||
|
|
||||||
|
if (widget->getChildCount())
|
||||||
|
MyGUI::Gui::getInstance().destroyWidget(widget->getChildAt(0));
|
||||||
|
|
||||||
|
widget->clearUserStrings();
|
||||||
|
widget->setItem(MWWorld::Ptr());
|
||||||
|
widget->setUserData(MWWorld::Ptr());
|
||||||
|
}
|
||||||
|
|
||||||
update();
|
update();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -386,15 +470,6 @@ namespace MWGui
|
||||||
effectsWidget->setCoord(coord);
|
effectsWidget->setCoord(coord);
|
||||||
}
|
}
|
||||||
|
|
||||||
void AlchemyWindow::removeIngredient(MyGUI::Widget* ingredient)
|
|
||||||
{
|
|
||||||
for (int i = 0; i < 4; ++i)
|
|
||||||
if (mIngredients[i] == ingredient)
|
|
||||||
mAlchemy->removeIngredient(i);
|
|
||||||
|
|
||||||
update();
|
|
||||||
}
|
|
||||||
|
|
||||||
void AlchemyWindow::addRepeatController(MyGUI::Widget* widget)
|
void AlchemyWindow::addRepeatController(MyGUI::Widget* widget)
|
||||||
{
|
{
|
||||||
MyGUI::ControllerItem* item
|
MyGUI::ControllerItem* item
|
||||||
|
|
|
@ -10,6 +10,7 @@
|
||||||
#include <components/widgets/box.hpp>
|
#include <components/widgets/box.hpp>
|
||||||
#include <components/widgets/numericeditbox.hpp>
|
#include <components/widgets/numericeditbox.hpp>
|
||||||
|
|
||||||
|
#include "itemselection.hpp"
|
||||||
#include "windowbase.hpp"
|
#include "windowbase.hpp"
|
||||||
|
|
||||||
#include "../mwmechanics/alchemy.hpp"
|
#include "../mwmechanics/alchemy.hpp"
|
||||||
|
@ -44,6 +45,8 @@ namespace MWGui
|
||||||
};
|
};
|
||||||
FilterType mCurrentFilter;
|
FilterType mCurrentFilter;
|
||||||
|
|
||||||
|
std::unique_ptr<ItemSelectionDialog> mItemSelectionDialog;
|
||||||
|
|
||||||
ItemView* mItemView;
|
ItemView* mItemView;
|
||||||
InventoryItemModel* mModel;
|
InventoryItemModel* mModel;
|
||||||
SortFilterItemModel* mSortModel;
|
SortFilterItemModel* mSortModel;
|
||||||
|
@ -63,6 +66,7 @@ namespace MWGui
|
||||||
void onCancelButtonClicked(MyGUI::Widget* _sender);
|
void onCancelButtonClicked(MyGUI::Widget* _sender);
|
||||||
void onCreateButtonClicked(MyGUI::Widget* _sender);
|
void onCreateButtonClicked(MyGUI::Widget* _sender);
|
||||||
void onIngredientSelected(MyGUI::Widget* _sender);
|
void onIngredientSelected(MyGUI::Widget* _sender);
|
||||||
|
void onApparatusSelected(MyGUI::Widget* _sender);
|
||||||
void onAccept(MyGUI::EditBox*);
|
void onAccept(MyGUI::EditBox*);
|
||||||
void onIncreaseButtonPressed(MyGUI::Widget* _sender, int _left, int _top, MyGUI::MouseButton _id);
|
void onIncreaseButtonPressed(MyGUI::Widget* _sender, int _left, int _top, MyGUI::MouseButton _id);
|
||||||
void onDecreaseButtonPressed(MyGUI::Widget* _sender, int _left, int _top, MyGUI::MouseButton _id);
|
void onDecreaseButtonPressed(MyGUI::Widget* _sender, int _left, int _top, MyGUI::MouseButton _id);
|
||||||
|
@ -84,7 +88,8 @@ namespace MWGui
|
||||||
|
|
||||||
void onSelectedItem(int index);
|
void onSelectedItem(int index);
|
||||||
|
|
||||||
void removeIngredient(MyGUI::Widget* ingredient);
|
void onItemSelected(MWWorld::Ptr item);
|
||||||
|
void onItemCancel();
|
||||||
|
|
||||||
void createPotions(int count);
|
void createPotions(int count);
|
||||||
|
|
||||||
|
|
|
@ -32,6 +32,8 @@ namespace MWGui
|
||||||
void setCategory(int category);
|
void setCategory(int category);
|
||||||
void setFilter(int filter);
|
void setFilter(int filter);
|
||||||
|
|
||||||
|
SortFilterItemModel* getSortModel() { return mSortModel; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
ItemView* mItemView;
|
ItemView* mItemView;
|
||||||
SortFilterItemModel* mSortModel;
|
SortFilterItemModel* mSortModel;
|
||||||
|
|
|
@ -174,6 +174,7 @@ namespace MWGui
|
||||||
: mCategory(Category_All)
|
: mCategory(Category_All)
|
||||||
, mFilter(0)
|
, mFilter(0)
|
||||||
, mSortByType(true)
|
, mSortByType(true)
|
||||||
|
, mApparatusTypeFilter(-1)
|
||||||
{
|
{
|
||||||
mSourceModel = std::move(sourceModel);
|
mSourceModel = std::move(sourceModel);
|
||||||
}
|
}
|
||||||
|
@ -311,6 +312,16 @@ namespace MWGui
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if ((mFilter & Filter_OnlyAlchemyTools))
|
||||||
|
{
|
||||||
|
if (base.getType() != ESM::Apparatus::sRecordId)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
int32_t apparatusType = base.get<ESM::Apparatus>()->mBase->mData.mType;
|
||||||
|
if (mApparatusTypeFilter >= 0 && apparatusType != mApparatusTypeFilter)
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
std::string compare = Utf8Stream::lowerCaseUtf8(item.mBase.getClass().getName(item.mBase));
|
std::string compare = Utf8Stream::lowerCaseUtf8(item.mBase.getClass().getName(item.mBase));
|
||||||
if (compare.find(mNameFilter) == std::string::npos)
|
if (compare.find(mNameFilter) == std::string::npos)
|
||||||
return false;
|
return false;
|
||||||
|
@ -352,6 +363,11 @@ namespace MWGui
|
||||||
mEffectFilter = Utf8Stream::lowerCaseUtf8(filter);
|
mEffectFilter = Utf8Stream::lowerCaseUtf8(filter);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void SortFilterItemModel::setApparatusTypeFilter(const int32_t type)
|
||||||
|
{
|
||||||
|
mApparatusTypeFilter = type;
|
||||||
|
}
|
||||||
|
|
||||||
void SortFilterItemModel::update()
|
void SortFilterItemModel::update()
|
||||||
{
|
{
|
||||||
mSourceModel->update();
|
mSourceModel->update();
|
||||||
|
|
|
@ -27,6 +27,7 @@ namespace MWGui
|
||||||
void setFilter(int filter);
|
void setFilter(int filter);
|
||||||
void setNameFilter(const std::string& filter);
|
void setNameFilter(const std::string& filter);
|
||||||
void setEffectFilter(const std::string& filter);
|
void setEffectFilter(const std::string& filter);
|
||||||
|
void setApparatusTypeFilter(const int32_t type);
|
||||||
|
|
||||||
/// Use ItemStack::Type for sorting?
|
/// Use ItemStack::Type for sorting?
|
||||||
void setSortByType(bool sort) { mSortByType = sort; }
|
void setSortByType(bool sort) { mSortByType = sort; }
|
||||||
|
@ -49,6 +50,7 @@ namespace MWGui
|
||||||
static constexpr int Filter_OnlyRepairable = (1 << 5);
|
static constexpr int Filter_OnlyRepairable = (1 << 5);
|
||||||
static constexpr int Filter_OnlyRechargable = (1 << 6);
|
static constexpr int Filter_OnlyRechargable = (1 << 6);
|
||||||
static constexpr int Filter_OnlyRepairTools = (1 << 7);
|
static constexpr int Filter_OnlyRepairTools = (1 << 7);
|
||||||
|
static constexpr int Filter_OnlyAlchemyTools = (1 << 8);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
std::vector<ItemStack> mItems;
|
std::vector<ItemStack> mItems;
|
||||||
|
@ -59,6 +61,7 @@ namespace MWGui
|
||||||
int mFilter;
|
int mFilter;
|
||||||
bool mSortByType;
|
bool mSortByType;
|
||||||
|
|
||||||
|
int32_t mApparatusTypeFilter; // filter by apparatus type
|
||||||
std::string mNameFilter; // filter by item name
|
std::string mNameFilter; // filter by item name
|
||||||
std::string mEffectFilter; // filter by magic effect
|
std::string mEffectFilter; // filter by magic effect
|
||||||
};
|
};
|
||||||
|
|
|
@ -368,6 +368,8 @@ void MWMechanics::Alchemy::setAlchemist(const MWWorld::Ptr& npc)
|
||||||
|
|
||||||
mTools.resize(4);
|
mTools.resize(4);
|
||||||
|
|
||||||
|
std::vector<MWWorld::Ptr> prevTools(mTools);
|
||||||
|
|
||||||
std::fill(mTools.begin(), mTools.end(), MWWorld::Ptr());
|
std::fill(mTools.begin(), mTools.end(), MWWorld::Ptr());
|
||||||
|
|
||||||
mEffects.clear();
|
mEffects.clear();
|
||||||
|
@ -384,6 +386,12 @@ void MWMechanics::Alchemy::setAlchemist(const MWWorld::Ptr& npc)
|
||||||
if (type < 0 || type >= static_cast<int>(mTools.size()))
|
if (type < 0 || type >= static_cast<int>(mTools.size()))
|
||||||
throw std::runtime_error("invalid apparatus type");
|
throw std::runtime_error("invalid apparatus type");
|
||||||
|
|
||||||
|
if (prevTools[type] == *iter)
|
||||||
|
mTools[type] = *iter; // prefer the previous tool if still in the container
|
||||||
|
|
||||||
|
if (!mTools[type].isEmpty() && !prevTools[type].isEmpty() && mTools[type] == prevTools[type])
|
||||||
|
continue;
|
||||||
|
|
||||||
if (!mTools[type].isEmpty())
|
if (!mTools[type].isEmpty())
|
||||||
if (ref->mBase->mData.mQuality <= mTools[type].get<ESM::Apparatus>()->mBase->mData.mQuality)
|
if (ref->mBase->mData.mQuality <= mTools[type].get<ESM::Apparatus>()->mBase->mData.mQuality)
|
||||||
continue;
|
continue;
|
||||||
|
@ -415,7 +423,6 @@ MWMechanics::Alchemy::TIngredientsIterator MWMechanics::Alchemy::endIngredients(
|
||||||
void MWMechanics::Alchemy::clear()
|
void MWMechanics::Alchemy::clear()
|
||||||
{
|
{
|
||||||
mAlchemist = MWWorld::Ptr();
|
mAlchemist = MWWorld::Ptr();
|
||||||
mTools.clear();
|
|
||||||
mIngredients.clear();
|
mIngredients.clear();
|
||||||
mEffects.clear();
|
mEffects.clear();
|
||||||
setPotionName("");
|
setPotionName("");
|
||||||
|
@ -452,15 +459,33 @@ int MWMechanics::Alchemy::addIngredient(const MWWorld::Ptr& ingredient)
|
||||||
return slot;
|
return slot;
|
||||||
}
|
}
|
||||||
|
|
||||||
void MWMechanics::Alchemy::removeIngredient(int index)
|
void MWMechanics::Alchemy::removeIngredient(size_t index)
|
||||||
{
|
{
|
||||||
if (index >= 0 && index < static_cast<int>(mIngredients.size()))
|
if (index < mIngredients.size())
|
||||||
{
|
{
|
||||||
mIngredients[index] = MWWorld::Ptr();
|
mIngredients[index] = MWWorld::Ptr();
|
||||||
updateEffects();
|
updateEffects();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void MWMechanics::Alchemy::addApparatus(const MWWorld::Ptr& apparatus)
|
||||||
|
{
|
||||||
|
int32_t slot = apparatus.get<ESM::Apparatus>()->mBase->mData.mType;
|
||||||
|
|
||||||
|
mTools[slot] = apparatus;
|
||||||
|
|
||||||
|
updateEffects();
|
||||||
|
}
|
||||||
|
|
||||||
|
void MWMechanics::Alchemy::removeApparatus(size_t index)
|
||||||
|
{
|
||||||
|
if (index < mTools.size())
|
||||||
|
{
|
||||||
|
mTools[index] = MWWorld::Ptr();
|
||||||
|
updateEffects();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
MWMechanics::Alchemy::TEffectsIterator MWMechanics::Alchemy::beginEffects() const
|
MWMechanics::Alchemy::TEffectsIterator MWMechanics::Alchemy::beginEffects() const
|
||||||
{
|
{
|
||||||
return mEffects.begin();
|
return mEffects.begin();
|
||||||
|
|
|
@ -119,9 +119,15 @@ namespace MWMechanics
|
||||||
/// \return Slot index or -1, if adding failed because of no free slot or the ingredient type being
|
/// \return Slot index or -1, if adding failed because of no free slot or the ingredient type being
|
||||||
/// listed already.
|
/// listed already.
|
||||||
|
|
||||||
void removeIngredient(int index);
|
void addApparatus(const MWWorld::Ptr& apparatus);
|
||||||
|
///< Add apparatus into the appropriate slot.
|
||||||
|
|
||||||
|
void removeIngredient(size_t index);
|
||||||
///< Remove ingredient from slot (calling this function on an empty slot is a no-op).
|
///< Remove ingredient from slot (calling this function on an empty slot is a no-op).
|
||||||
|
|
||||||
|
void removeApparatus(size_t index);
|
||||||
|
///< Remove apparatus from slot.
|
||||||
|
|
||||||
std::string suggestPotionName();
|
std::string suggestPotionName();
|
||||||
///< Suggest a name for the potion, based on the current effects
|
///< Suggest a name for the potion, based on the current effects
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue