1
0
Fork 1
mirror of https://github.com/TES3MP/openmw-tes3mp.git synced 2025-01-30 22:45:34 +00:00

Merged pull request #1891

This commit is contained in:
Marc Zinnschlag 2018-09-21 11:38:19 +02:00
commit 7be9f2ca45
12 changed files with 211 additions and 24 deletions

View file

@ -155,6 +155,7 @@
Feature #4626: Weapon priority: account for weapon speed Feature #4626: Weapon priority: account for weapon speed
Feature #4632: AI priority: utilize vanilla AI GMSTs for priority rating Feature #4632: AI priority: utilize vanilla AI GMSTs for priority rating
Feature #4636: Use sTo GMST in spellmaking menu 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 #2490: Don't open command prompt window on Release-mode builds automatically
Task #4545: Enable is_pod string test Task #4545: Enable is_pod string test
Task #4605: Optimize skinning Task #4605: Optimize skinning

View file

@ -1,8 +1,6 @@
#include "util.hpp" #include "util.hpp"
#include <stdexcept> #include <stdexcept>
#include <climits>
#include <cfloat>
#include <QUndoStack> #include <QUndoStack>
#include <QMetaProperty> #include <QMetaProperty>
@ -209,7 +207,7 @@ QWidget *CSVWorld::CommandDelegate::createEditor (QWidget *parent, const QStyleO
case CSMWorld::ColumnBase::Display_Integer: case CSMWorld::ColumnBase::Display_Integer:
{ {
DialogueSpinBox *sb = new DialogueSpinBox(parent); DialogueSpinBox *sb = new DialogueSpinBox(parent);
sb->setRange(INT_MIN, INT_MAX); sb->setRange(std::numeric_limits<int>::min(), std::numeric_limits<int>::max());
return sb; return sb;
} }

View file

@ -25,6 +25,9 @@
namespace MWGui namespace MWGui
{ {
const float AlchemyWindow::sCountChangeInitialPause = 0.5f;
const float AlchemyWindow::sCountChangeInterval = 0.1f;
AlchemyWindow::AlchemyWindow() AlchemyWindow::AlchemyWindow()
: WindowBase("openmw_alchemy_window.layout") : WindowBase("openmw_alchemy_window.layout")
, mSortModel(NULL) , mSortModel(NULL)
@ -43,9 +46,21 @@ namespace MWGui
getWidget(mApparatus[2], "Apparatus3"); getWidget(mApparatus[2], "Apparatus3");
getWidget(mApparatus[3], "Apparatus4"); getWidget(mApparatus[3], "Apparatus4");
getWidget(mEffectsBox, "CreatedEffects"); getWidget(mEffectsBox, "CreatedEffects");
getWidget(mBrewCountEdit, "BrewCount");
getWidget(mIncreaseButton, "IncreaseButton");
getWidget(mDecreaseButton, "DecreaseButton");
getWidget(mNameEdit, "NameEdit"); getWidget(mNameEdit, "NameEdit");
getWidget(mItemView, "ItemView"); 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); mItemView->eventItemClicked += MyGUI::newDelegate(this, &AlchemyWindow::onSelectedItem);
@ -77,7 +92,15 @@ namespace MWGui
void AlchemyWindow::onCreateButtonClicked(MyGUI::Widget* _sender) 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(); MWBase::WindowManager *winMgr = MWBase::Environment::get().getWindowManager();
switch (result) switch (result)
@ -92,8 +115,11 @@ namespace MWGui
winMgr->messageBox("#{sNotifyMessage6a}"); winMgr->messageBox("#{sNotifyMessage6a}");
break; break;
case MWMechanics::Alchemy::Result_Success: case MWMechanics::Alchemy::Result_Success:
winMgr->messageBox("#{sPotionSuccess}");
winMgr->playSound("potion success"); winMgr->playSound("potion success");
if (count == 1)
winMgr->messageBox("#{sPotionSuccess}");
else
winMgr->messageBox("#{sPotionSuccess} "+mNameEdit->getCaption()+" ("+std::to_string(count)+")");
break; break;
case MWMechanics::Alchemy::Result_NoEffects: case MWMechanics::Alchemy::Result_NoEffects:
case MWMechanics::Alchemy::Result_RandomFailure: case MWMechanics::Alchemy::Result_RandomFailure:
@ -126,6 +152,7 @@ namespace MWGui
mItemView->resetScrollBars(); mItemView->resetScrollBars();
mNameEdit->setCaption(""); mNameEdit->setCaption("");
mBrewCountEdit->setValue(1);
int index = 0; int index = 0;
for (MWMechanics::Alchemy::TToolsIterator iter (mAlchemy->beginTools()); for (MWMechanics::Alchemy::TToolsIterator iter (mAlchemy->beginTools());
@ -250,4 +277,61 @@ namespace MWGui
update(); 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
if (currentCount == std::numeric_limits<int>::max())
return;
mBrewCountEdit->setValue(currentCount+1);
}
void AlchemyWindow::onDecreaseButtonTriggered()
{
int currentCount = mBrewCountEdit->getValue();
if (currentCount > 1)
mBrewCountEdit->setValue(currentCount-1);
}
} }

View file

@ -3,8 +3,13 @@
#include <vector> #include <vector>
#include <MyGUI_ControllerManager.h>
#include "../mwmechanics/alchemy.hpp" #include "../mwmechanics/alchemy.hpp"
#include <components/widgets/numericeditbox.hpp>
#include "controllers.hpp"
#include "windowbase.hpp" #include "windowbase.hpp"
namespace MWMechanics namespace MWMechanics
@ -28,6 +33,10 @@ namespace MWGui
void onResChange(int, int) { center(); } void onResChange(int, int) { center(); }
private: private:
static const float sCountChangeInitialPause; // in seconds
static const float sCountChangeInterval; // in seconds
std::string mSuggestedPotionName; std::string mSuggestedPotionName;
ItemView* mItemView; ItemView* mItemView;
@ -38,17 +47,32 @@ namespace MWGui
MyGUI::Widget* mEffectsBox; MyGUI::Widget* mEffectsBox;
MyGUI::Button* mIncreaseButton;
MyGUI::Button* mDecreaseButton;
MyGUI::EditBox* mNameEdit; MyGUI::EditBox* mNameEdit;
Gui::NumericEditBox* mBrewCountEdit;
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 onAccept(MyGUI::EditBox*); 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 onSelectedItem(int index);
void removeIngredient(MyGUI::Widget* ingredient); void removeIngredient(MyGUI::Widget* ingredient);
void createPotions(int count);
void update(); void update();
std::unique_ptr<MWMechanics::Alchemy> mAlchemy; std::unique_ptr<MWMechanics::Alchemy> mAlchemy;

View file

@ -1,7 +1,5 @@
#include "tradewindow.hpp" #include "tradewindow.hpp"
#include <climits>
#include <MyGUI_Button.h> #include <MyGUI_Button.h>
#include <MyGUI_InputManager.h> #include <MyGUI_InputManager.h>
#include <MyGUI_ControllerManager.h> #include <MyGUI_ControllerManager.h>
@ -96,7 +94,7 @@ namespace MWGui
mTotalBalance->eventValueChanged += MyGUI::newDelegate(this, &TradeWindow::onBalanceValueChanged); mTotalBalance->eventValueChanged += MyGUI::newDelegate(this, &TradeWindow::onBalanceValueChanged);
mTotalBalance->eventEditSelectAccept += MyGUI::newDelegate(this, &TradeWindow::onAccept); mTotalBalance->eventEditSelectAccept += MyGUI::newDelegate(this, &TradeWindow::onAccept);
mTotalBalance->setMinValue(INT_MIN+1); // disallow INT_MIN since abs(INT_MIN) is undefined mTotalBalance->setMinValue(std::numeric_limits<int>::min()+1); // disallow INT_MIN since abs(INT_MIN) is undefined
setCoord(400, 0, 400, 300); setCoord(400, 0, 400, 300);
} }
@ -431,7 +429,7 @@ namespace MWGui
void TradeWindow::onIncreaseButtonTriggered() void TradeWindow::onIncreaseButtonTriggered()
{ {
// prevent overflows, and prevent entering INT_MIN since abs(INT_MIN) is undefined // prevent overflows, and prevent entering INT_MIN since abs(INT_MIN) is undefined
if (mCurrentBalance == INT_MAX || mCurrentBalance == INT_MIN+1) if (mCurrentBalance == std::numeric_limits<int>::max() || mCurrentBalance == std::numeric_limits<int>::min()+1)
return; return;
if (mCurrentBalance < 0) mCurrentBalance -= 1; if (mCurrentBalance < 0) mCurrentBalance -= 1;
else mCurrentBalance += 1; else mCurrentBalance += 1;

View file

@ -30,6 +30,7 @@
MWMechanics::Alchemy::Alchemy() MWMechanics::Alchemy::Alchemy()
: mValue(0) : mValue(0)
, mPotionName("")
{ {
} }
@ -336,6 +337,25 @@ int MWMechanics::Alchemy::countIngredients() const
return ingredients; 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) void MWMechanics::Alchemy::setAlchemist (const MWWorld::Ptr& npc)
{ {
mAlchemist = npc; mAlchemist = npc;
@ -396,6 +416,12 @@ void MWMechanics::Alchemy::clear()
mTools.clear(); mTools.clear();
mIngredients.clear(); mIngredients.clear();
mEffects.clear(); mEffects.clear();
setPotionName("");
}
void MWMechanics::Alchemy::setPotionName(const std::string& name)
{
mPotionName = name;
} }
int MWMechanics::Alchemy::addIngredient (const MWWorld::Ptr& ingredient) 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); || (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()) if (mTools[ESM::Apparatus::MortarPestle].isEmpty())
return Result_NoMortarAndPestle; return Result_NoMortarAndPestle;
@ -464,15 +490,43 @@ MWMechanics::Alchemy::Result MWMechanics::Alchemy::create (const std::string& na
if (countIngredients()<2) if (countIngredients()<2)
return Result_LessThanTwoIngredients; return Result_LessThanTwoIngredients;
if (name.empty()) if (mPotionName.empty())
return Result_NoName; return Result_NoName;
if (listEffects().empty()) if (listEffects().empty())
{
removeIngredients();
return Result_NoEffects; 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()) if (beginEffects() == endEffects())
{ {
// all effects were nullified due to insufficient skill // 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; return Result_RandomFailure;
} }
addPotion (name); addPotion(mPotionName);
removeIngredients(); removeIngredients();

View file

@ -51,11 +51,14 @@ namespace MWMechanics
TIngredientsContainer mIngredients; TIngredientsContainer mIngredients;
TEffectsContainer mEffects; TEffectsContainer mEffects;
int mValue; int mValue;
std::string mPotionName;
void applyTools (int flags, float& value) const; void applyTools (int flags, float& value) const;
void updateEffects(); void updateEffects();
Result getReadyStatus() const;
const ESM::Potion *getRecord(const ESM::Potion& toFind) 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 ///< 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 /// \note Does not account for record ID, model or icon
@ -70,6 +73,10 @@ namespace MWMechanics
void increaseSkill(); void increaseSkill();
///< Increase alchemist's skill. ///< 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; float getAlchemyFactor() const;
int countIngredients() const; int countIngredients() const;
@ -79,6 +86,8 @@ namespace MWMechanics
TEffectsIterator endEffects() const; TEffectsIterator endEffects() const;
public: 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); static bool knownEffect (unsigned int potionEffectIndex, const MWWorld::Ptr& npc);
///< Does npc have sufficient alchemy skill to know about this potion effect? ///< Does npc have sufficient alchemy skill to know about this potion effect?
@ -100,6 +109,9 @@ namespace MWMechanics
void clear(); void clear();
///< Remove alchemist, tools and ingredients. ///< Remove alchemist, tools and ingredients.
void setPotionName(const std::string& name);
///< Set name of potion to create
std::set<EffectKey> listEffects() const; std::set<EffectKey> listEffects() const;
///< List all effects shared by at least two ingredients. ///< List all effects shared by at least two ingredients.
@ -115,8 +127,8 @@ namespace MWMechanics
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
Result create (const std::string& name); Result create (const std::string& name, int& count);
///< Try to create a potion from the ingredients, place it in the inventory of the alchemist and ///< Try to create potions from the ingredients, place them in the inventory of the alchemist and
/// adjust the skills of the alchemist accordingly. /// adjust the skills of the alchemist accordingly.
/// \param name must not be an empty string, or Result_NoName is returned /// \param name must not be an empty string, or Result_NoName is returned
}; };

View file

@ -1,7 +1,6 @@
#include "autocalcspell.hpp" #include "autocalcspell.hpp"
#include "spellcasting.hpp" #include "spellcasting.hpp"
#include <climits>
#include <limits> #include <limits>
#include "../mwworld/esmstore.hpp" #include "../mwworld/esmstore.hpp"
@ -50,7 +49,7 @@ namespace MWMechanics
caps.mCount = 0; caps.mCount = 0;
caps.mLimit = iAutoSpellSchoolMax[i]; caps.mLimit = iAutoSpellSchoolMax[i];
caps.mReachedLimit = iAutoSpellSchoolMax[i] <= 0; caps.mReachedLimit = iAutoSpellSchoolMax[i] <= 0;
caps.mMinCost = INT_MAX; caps.mMinCost = std::numeric_limits<int>::max();
caps.mWeakestSpell.clear(); caps.mWeakestSpell.clear();
schoolCaps[i] = caps; schoolCaps[i] = caps;
} }
@ -101,7 +100,7 @@ namespace MWMechanics
if (found != selectedSpells.end()) if (found != selectedSpells.end())
selectedSpells.erase(found); selectedSpells.erase(found);
cap.mMinCost = INT_MAX; cap.mMinCost = std::numeric_limits<int>::max();
for (std::vector<std::string>::iterator weakIt = selectedSpells.begin(); weakIt != selectedSpells.end(); ++weakIt) for (std::vector<std::string>::iterator weakIt = selectedSpells.begin(); weakIt != selectedSpells.end(); ++weakIt)
{ {
const ESM::Spell* testSpell = spells.find(*weakIt); const ESM::Spell* testSpell = spells.find(*weakIt);
@ -151,7 +150,7 @@ namespace MWMechanics
float baseMagicka = fPCbaseMagickaMult * actorAttributes[ESM::Attribute::Intelligence]; float baseMagicka = fPCbaseMagickaMult * actorAttributes[ESM::Attribute::Intelligence];
bool reachedLimit = false; bool reachedLimit = false;
const ESM::Spell* weakestSpell = NULL; const ESM::Spell* weakestSpell = NULL;
int minCost = INT_MAX; int minCost = std::numeric_limits<int>::max();
std::vector<std::string> selectedSpells; std::vector<std::string> selectedSpells;
@ -188,7 +187,7 @@ namespace MWMechanics
if (it != selectedSpells.end()) if (it != selectedSpells.end())
selectedSpells.erase(it); selectedSpells.erase(it);
minCost = INT_MAX; minCost = std::numeric_limits<int>::max();
for (std::vector<std::string>::iterator weakIt = selectedSpells.begin(); weakIt != selectedSpells.end(); ++weakIt) for (std::vector<std::string>::iterator weakIt = selectedSpells.begin(); weakIt != selectedSpells.end(); ++weakIt)
{ {
const ESM::Spell* testSpell = esmStore.get<ESM::Spell>().find(*weakIt); const ESM::Spell* testSpell = esmStore.get<ESM::Spell>().find(*weakIt);

View file

@ -1,7 +1,5 @@
#include "globalmap.hpp" #include "globalmap.hpp"
#include <climits>
#include <osg/Image> #include <osg/Image>
#include <osg/Texture2D> #include <osg/Texture2D>
#include <osg/Group> #include <osg/Group>

View file

@ -59,6 +59,11 @@ namespace Gui
} }
} }
int NumericEditBox::getValue()
{
return mValue;
}
void NumericEditBox::setMinValue(int minValue) void NumericEditBox::setMinValue(int minValue)
{ {
mMinValue = minValue; mMinValue = minValue;

View file

@ -30,6 +30,7 @@ namespace Gui
/// @note Does not trigger eventValueChanged /// @note Does not trigger eventValueChanged
void setValue (int value); void setValue (int value);
int getValue();
void setMinValue(int minValue); void setMinValue(int minValue);
void setMaxValue(int maxValue); void setMaxValue(int maxValue);

View file

@ -74,7 +74,20 @@
<!-- Buttons --> <!-- 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"/> <Widget type="Spacer"/>