mirror of
https://gitlab.com/OpenMW/openmw.git
synced 2024-12-29 03:19:44 +00:00
Mass potion creation (feature #4642)
This commit is contained in:
parent
07be9ae8ac
commit
276b7830a9
@ -155,6 +155,7 @@
|
||||
Feature #4626: Weapon priority: account for weapon speed
|
||||
Feature #4632: AI priority: utilize vanilla AI GMSTs for priority rating
|
||||
Feature #4636: Use sTo GMST in spellmaking menu
|
||||
Feature #4642: Batching potion creation
|
||||
Task #2490: Don't open command prompt window on Release-mode builds automatically
|
||||
Task #4545: Enable is_pod string test
|
||||
Task #4605: Optimize skinning
|
||||
|
@ -1,5 +1,7 @@
|
||||
#include "alchemywindow.hpp"
|
||||
|
||||
#include <climits>
|
||||
|
||||
#include <MyGUI_Gui.h>
|
||||
#include <MyGUI_Button.h>
|
||||
#include <MyGUI_EditBox.h>
|
||||
@ -25,6 +27,9 @@
|
||||
|
||||
namespace MWGui
|
||||
{
|
||||
const float AlchemyWindow::sCountChangeInitialPause = 0.5f;
|
||||
const float AlchemyWindow::sCountChangeInterval = 0.1f;
|
||||
|
||||
AlchemyWindow::AlchemyWindow()
|
||||
: WindowBase("openmw_alchemy_window.layout")
|
||||
, mSortModel(NULL)
|
||||
@ -43,9 +48,21 @@ namespace MWGui
|
||||
getWidget(mApparatus[2], "Apparatus3");
|
||||
getWidget(mApparatus[3], "Apparatus4");
|
||||
getWidget(mEffectsBox, "CreatedEffects");
|
||||
getWidget(mBrewCountEdit, "BrewCount");
|
||||
getWidget(mIncreaseButton, "IncreaseButton");
|
||||
getWidget(mDecreaseButton, "DecreaseButton");
|
||||
getWidget(mNameEdit, "NameEdit");
|
||||
getWidget(mItemView, "ItemView");
|
||||
|
||||
mBrewCountEdit->eventValueChanged += MyGUI::newDelegate(this, &AlchemyWindow::onCountValueChanged);
|
||||
mBrewCountEdit->eventEditSelectAccept += MyGUI::newDelegate(this, &AlchemyWindow::onAccept);
|
||||
mBrewCountEdit->setMinValue(1);
|
||||
mBrewCountEdit->setValue(1);
|
||||
|
||||
mIncreaseButton->eventMouseButtonPressed += MyGUI::newDelegate(this, &AlchemyWindow::onIncreaseButtonPressed);
|
||||
mIncreaseButton->eventMouseButtonReleased += MyGUI::newDelegate(this, &AlchemyWindow::onCountButtonReleased);
|
||||
mDecreaseButton->eventMouseButtonPressed += MyGUI::newDelegate(this, &AlchemyWindow::onDecreaseButtonPressed);
|
||||
mDecreaseButton->eventMouseButtonReleased += MyGUI::newDelegate(this, &AlchemyWindow::onCountButtonReleased);
|
||||
|
||||
mItemView->eventItemClicked += MyGUI::newDelegate(this, &AlchemyWindow::onSelectedItem);
|
||||
|
||||
@ -77,7 +94,15 @@ namespace MWGui
|
||||
|
||||
void AlchemyWindow::onCreateButtonClicked(MyGUI::Widget* _sender)
|
||||
{
|
||||
MWMechanics::Alchemy::Result result = mAlchemy->create (mNameEdit->getCaption ());
|
||||
mAlchemy->setPotionName(mNameEdit->getCaption());
|
||||
int count = mAlchemy->countPotionsToBrew();
|
||||
count = std::min(count, mBrewCountEdit->getValue());
|
||||
createPotions(count);
|
||||
}
|
||||
|
||||
void AlchemyWindow::createPotions(int count)
|
||||
{
|
||||
MWMechanics::Alchemy::Result result = mAlchemy->create(mNameEdit->getCaption(), count);
|
||||
MWBase::WindowManager *winMgr = MWBase::Environment::get().getWindowManager();
|
||||
|
||||
switch (result)
|
||||
@ -92,8 +117,11 @@ namespace MWGui
|
||||
winMgr->messageBox("#{sNotifyMessage6a}");
|
||||
break;
|
||||
case MWMechanics::Alchemy::Result_Success:
|
||||
winMgr->messageBox("#{sPotionSuccess}");
|
||||
winMgr->playSound("potion success");
|
||||
if (count == 1)
|
||||
winMgr->messageBox("#{sPotionSuccess}");
|
||||
else
|
||||
winMgr->messageBox("#{sPotionSuccess} "+mNameEdit->getCaption()+" ("+std::to_string(count)+")");
|
||||
break;
|
||||
case MWMechanics::Alchemy::Result_NoEffects:
|
||||
case MWMechanics::Alchemy::Result_RandomFailure:
|
||||
@ -126,6 +154,7 @@ namespace MWGui
|
||||
mItemView->resetScrollBars();
|
||||
|
||||
mNameEdit->setCaption("");
|
||||
mBrewCountEdit->setValue(1);
|
||||
|
||||
int index = 0;
|
||||
for (MWMechanics::Alchemy::TToolsIterator iter (mAlchemy->beginTools());
|
||||
@ -250,4 +279,61 @@ namespace MWGui
|
||||
|
||||
update();
|
||||
}
|
||||
|
||||
void AlchemyWindow::addRepeatController(MyGUI::Widget *widget)
|
||||
{
|
||||
MyGUI::ControllerItem* item = MyGUI::ControllerManager::getInstance().createItem(Controllers::ControllerRepeatEvent::getClassTypeName());
|
||||
Controllers::ControllerRepeatEvent* controller = item->castType<Controllers::ControllerRepeatEvent>();
|
||||
controller->eventRepeatClick += MyGUI::newDelegate(this, &AlchemyWindow::onRepeatClick);
|
||||
controller->setRepeat(sCountChangeInitialPause, sCountChangeInterval);
|
||||
MyGUI::ControllerManager::getInstance().addItem(widget, controller);
|
||||
}
|
||||
|
||||
void AlchemyWindow::onIncreaseButtonPressed(MyGUI::Widget* _sender, int _left, int _top, MyGUI::MouseButton _id)
|
||||
{
|
||||
addRepeatController(_sender);
|
||||
onIncreaseButtonTriggered();
|
||||
}
|
||||
|
||||
void AlchemyWindow::onDecreaseButtonPressed(MyGUI::Widget* _sender, int _left, int _top, MyGUI::MouseButton _id)
|
||||
{
|
||||
addRepeatController(_sender);
|
||||
onDecreaseButtonTriggered();
|
||||
}
|
||||
|
||||
void AlchemyWindow::onRepeatClick(MyGUI::Widget* widget, MyGUI::ControllerItem* controller)
|
||||
{
|
||||
if (widget == mIncreaseButton)
|
||||
onIncreaseButtonTriggered();
|
||||
else if (widget == mDecreaseButton)
|
||||
onDecreaseButtonTriggered();
|
||||
}
|
||||
|
||||
void AlchemyWindow::onCountButtonReleased(MyGUI::Widget *_sender, int _left, int _top, MyGUI::MouseButton _id)
|
||||
{
|
||||
MyGUI::ControllerManager::getInstance().removeItem(_sender);
|
||||
}
|
||||
|
||||
void AlchemyWindow::onCountValueChanged(int value)
|
||||
{
|
||||
mBrewCountEdit->setValue(std::abs(value));
|
||||
}
|
||||
|
||||
void AlchemyWindow::onIncreaseButtonTriggered()
|
||||
{
|
||||
int currentCount = mBrewCountEdit->getValue();
|
||||
|
||||
// prevent overflows, and prevent entering INT_MIN since abs(INT_MIN) is undefined
|
||||
if (currentCount == INT_MAX || currentCount == INT_MIN+1)
|
||||
return;
|
||||
|
||||
mBrewCountEdit->setValue(currentCount+1);
|
||||
}
|
||||
|
||||
void AlchemyWindow::onDecreaseButtonTriggered()
|
||||
{
|
||||
int currentCount = mBrewCountEdit->getValue();
|
||||
if (currentCount > 1)
|
||||
mBrewCountEdit->setValue(currentCount-1);
|
||||
}
|
||||
}
|
||||
|
@ -3,8 +3,13 @@
|
||||
|
||||
#include <vector>
|
||||
|
||||
#include <MyGUI_ControllerManager.h>
|
||||
|
||||
#include "../mwmechanics/alchemy.hpp"
|
||||
|
||||
#include <components/widgets/numericeditbox.hpp>
|
||||
|
||||
#include "controllers.hpp"
|
||||
#include "windowbase.hpp"
|
||||
|
||||
namespace MWMechanics
|
||||
@ -28,6 +33,10 @@ namespace MWGui
|
||||
void onResChange(int, int) { center(); }
|
||||
|
||||
private:
|
||||
|
||||
static const float sCountChangeInitialPause; // in seconds
|
||||
static const float sCountChangeInterval; // in seconds
|
||||
|
||||
std::string mSuggestedPotionName;
|
||||
|
||||
ItemView* mItemView;
|
||||
@ -38,17 +47,32 @@ namespace MWGui
|
||||
|
||||
MyGUI::Widget* mEffectsBox;
|
||||
|
||||
MyGUI::Button* mIncreaseButton;
|
||||
MyGUI::Button* mDecreaseButton;
|
||||
MyGUI::EditBox* mNameEdit;
|
||||
Gui::NumericEditBox* mBrewCountEdit;
|
||||
|
||||
void onCancelButtonClicked(MyGUI::Widget* _sender);
|
||||
void onCreateButtonClicked(MyGUI::Widget* _sender);
|
||||
void onIngredientSelected(MyGUI::Widget* _sender);
|
||||
void onAccept(MyGUI::EditBox*);
|
||||
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 onCountButtonReleased(MyGUI::Widget* _sender, int _left, int _top, MyGUI::MouseButton _id);
|
||||
void onCountValueChanged(int value);
|
||||
void onRepeatClick(MyGUI::Widget* widget, MyGUI::ControllerItem* controller);
|
||||
|
||||
void addRepeatController(MyGUI::Widget* widget);
|
||||
|
||||
void onIncreaseButtonTriggered();
|
||||
void onDecreaseButtonTriggered();
|
||||
|
||||
void onSelectedItem(int index);
|
||||
|
||||
void removeIngredient(MyGUI::Widget* ingredient);
|
||||
|
||||
void createPotions(int count);
|
||||
|
||||
void update();
|
||||
|
||||
std::unique_ptr<MWMechanics::Alchemy> mAlchemy;
|
||||
|
@ -30,6 +30,7 @@
|
||||
|
||||
MWMechanics::Alchemy::Alchemy()
|
||||
: mValue(0)
|
||||
, mPotionName("")
|
||||
{
|
||||
}
|
||||
|
||||
@ -336,6 +337,25 @@ int MWMechanics::Alchemy::countIngredients() const
|
||||
return ingredients;
|
||||
}
|
||||
|
||||
int MWMechanics::Alchemy::countPotionsToBrew() const
|
||||
{
|
||||
Result readyStatus = getReadyStatus();
|
||||
if (readyStatus != Result_Success)
|
||||
return 0;
|
||||
|
||||
int toBrew = -1;
|
||||
|
||||
for (TIngredientsIterator iter (beginIngredients()); iter!=endIngredients(); ++iter)
|
||||
if (!iter->isEmpty())
|
||||
{
|
||||
int count = iter->getRefData().getCount();
|
||||
if ((count > 0 && count < toBrew) || toBrew < 0)
|
||||
toBrew = count;
|
||||
}
|
||||
|
||||
return toBrew;
|
||||
}
|
||||
|
||||
void MWMechanics::Alchemy::setAlchemist (const MWWorld::Ptr& npc)
|
||||
{
|
||||
mAlchemist = npc;
|
||||
@ -396,6 +416,12 @@ void MWMechanics::Alchemy::clear()
|
||||
mTools.clear();
|
||||
mIngredients.clear();
|
||||
mEffects.clear();
|
||||
setPotionName("");
|
||||
}
|
||||
|
||||
void MWMechanics::Alchemy::setPotionName(const std::string& name)
|
||||
{
|
||||
mPotionName = name;
|
||||
}
|
||||
|
||||
int MWMechanics::Alchemy::addIngredient (const MWWorld::Ptr& ingredient)
|
||||
@ -456,7 +482,7 @@ bool MWMechanics::Alchemy::knownEffect(unsigned int potionEffectIndex, const MWW
|
||||
|| (potionEffectIndex <= 7 && alchemySkill >= fWortChanceValue*4);
|
||||
}
|
||||
|
||||
MWMechanics::Alchemy::Result MWMechanics::Alchemy::create (const std::string& name)
|
||||
MWMechanics::Alchemy::Result MWMechanics::Alchemy::getReadyStatus() const
|
||||
{
|
||||
if (mTools[ESM::Apparatus::MortarPestle].isEmpty())
|
||||
return Result_NoMortarAndPestle;
|
||||
@ -464,15 +490,43 @@ MWMechanics::Alchemy::Result MWMechanics::Alchemy::create (const std::string& na
|
||||
if (countIngredients()<2)
|
||||
return Result_LessThanTwoIngredients;
|
||||
|
||||
if (name.empty())
|
||||
if (mPotionName.empty())
|
||||
return Result_NoName;
|
||||
|
||||
if (listEffects().empty())
|
||||
{
|
||||
removeIngredients();
|
||||
return Result_NoEffects;
|
||||
|
||||
return Result_Success;
|
||||
}
|
||||
|
||||
MWMechanics::Alchemy::Result MWMechanics::Alchemy::create (const std::string& name, int& count)
|
||||
{
|
||||
setPotionName(name);
|
||||
Result readyStatus = getReadyStatus();
|
||||
|
||||
if (readyStatus == Result_NoEffects)
|
||||
removeIngredients();
|
||||
|
||||
if (readyStatus != Result_Success)
|
||||
return readyStatus;
|
||||
|
||||
Result result = Result_RandomFailure;
|
||||
int brewedCount = 0;
|
||||
for (int i = 0; i < count; ++i)
|
||||
{
|
||||
if (createSingle() == Result_Success)
|
||||
{
|
||||
result = Result_Success;
|
||||
brewedCount++;
|
||||
}
|
||||
}
|
||||
|
||||
count = brewedCount;
|
||||
return result;
|
||||
}
|
||||
|
||||
MWMechanics::Alchemy::Result MWMechanics::Alchemy::createSingle ()
|
||||
{
|
||||
if (beginEffects() == endEffects())
|
||||
{
|
||||
// all effects were nullified due to insufficient skill
|
||||
@ -486,7 +540,7 @@ MWMechanics::Alchemy::Result MWMechanics::Alchemy::create (const std::string& na
|
||||
return Result_RandomFailure;
|
||||
}
|
||||
|
||||
addPotion (name);
|
||||
addPotion(mPotionName);
|
||||
|
||||
removeIngredients();
|
||||
|
||||
|
@ -51,11 +51,14 @@ namespace MWMechanics
|
||||
TIngredientsContainer mIngredients;
|
||||
TEffectsContainer mEffects;
|
||||
int mValue;
|
||||
std::string mPotionName;
|
||||
|
||||
void applyTools (int flags, float& value) const;
|
||||
|
||||
void updateEffects();
|
||||
|
||||
Result getReadyStatus() const;
|
||||
|
||||
const ESM::Potion *getRecord(const ESM::Potion& toFind) const;
|
||||
///< Try to find a potion record similar to \a toFind in the record store, or return 0 if not found
|
||||
/// \note Does not account for record ID, model or icon
|
||||
@ -70,6 +73,10 @@ namespace MWMechanics
|
||||
void increaseSkill();
|
||||
///< Increase alchemist's skill.
|
||||
|
||||
Result createSingle ();
|
||||
///< Try to create a potion from the ingredients, place it in the inventory of the alchemist and
|
||||
/// adjust the skills of the alchemist accordingly.
|
||||
|
||||
float getAlchemyFactor() const;
|
||||
|
||||
int countIngredients() const;
|
||||
@ -79,6 +86,8 @@ namespace MWMechanics
|
||||
TEffectsIterator endEffects() const;
|
||||
|
||||
public:
|
||||
int countPotionsToBrew() const;
|
||||
///< calculates maximum amount of potions, which you can make from selected ingredients
|
||||
|
||||
static bool knownEffect (unsigned int potionEffectIndex, const MWWorld::Ptr& npc);
|
||||
///< Does npc have sufficient alchemy skill to know about this potion effect?
|
||||
@ -100,6 +109,9 @@ namespace MWMechanics
|
||||
void clear();
|
||||
///< Remove alchemist, tools and ingredients.
|
||||
|
||||
void setPotionName(const std::string& name);
|
||||
///< Set name of potion to create
|
||||
|
||||
std::set<EffectKey> listEffects() const;
|
||||
///< List all effects shared by at least two ingredients.
|
||||
|
||||
@ -115,8 +127,8 @@ namespace MWMechanics
|
||||
std::string suggestPotionName ();
|
||||
///< Suggest a name for the potion, based on the current effects
|
||||
|
||||
Result create (const std::string& name);
|
||||
///< Try to create a potion from the ingredients, place it in the inventory of the alchemist and
|
||||
Result create (const std::string& name, int& count);
|
||||
///< Try to create potions from the ingredients, place them in the inventory of the alchemist and
|
||||
/// adjust the skills of the alchemist accordingly.
|
||||
/// \param name must not be an empty string, or Result_NoName is returned
|
||||
};
|
||||
|
@ -59,6 +59,11 @@ namespace Gui
|
||||
}
|
||||
}
|
||||
|
||||
int NumericEditBox::getValue()
|
||||
{
|
||||
return mValue;
|
||||
}
|
||||
|
||||
void NumericEditBox::setMinValue(int minValue)
|
||||
{
|
||||
mMinValue = minValue;
|
||||
|
@ -30,6 +30,7 @@ namespace Gui
|
||||
|
||||
/// @note Does not trigger eventValueChanged
|
||||
void setValue (int value);
|
||||
int getValue();
|
||||
|
||||
void setMinValue(int minValue);
|
||||
void setMaxValue(int maxValue);
|
||||
|
@ -74,7 +74,20 @@
|
||||
|
||||
<!-- Buttons -->
|
||||
|
||||
<Widget type="HBox" skin="" position="110 374 452 28" align="Bottom Right">
|
||||
<Widget type="HBox" skin="" position="10 374 552 28" align="Bottom HStretch">
|
||||
<Widget type="AutoSizedButton" skin="MW_Button" name="DecreaseButton">
|
||||
<Property key="Caption" value=" - "/>
|
||||
<Property key="NeedKey" value="false"/>
|
||||
</Widget>
|
||||
|
||||
<Widget type="NumericEditBox" skin="MW_TextEdit" position="0 0 96 25" name="BrewCount">
|
||||
<Property key="TextAlign" value="Center"/>
|
||||
</Widget>
|
||||
|
||||
<Widget type="AutoSizedButton" skin="MW_Button" name="IncreaseButton">
|
||||
<Property key="Caption" value=" + "/>
|
||||
<Property key="NeedKey" value="false"/>
|
||||
</Widget>
|
||||
|
||||
<Widget type="Spacer"/>
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user