From cd343c4fbd5a99d12126fdc99fa61c03e60e0409 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Thu, 27 Sep 2012 11:59:40 +0200 Subject: [PATCH 01/15] Issue #61: Basic alchemy class (doesn't do anything yet) --- apps/openmw/CMakeLists.txt | 2 +- apps/openmw/mwgui/alchemywindow.cpp | 4 +++- apps/openmw/mwgui/alchemywindow.hpp | 6 ++++++ 3 files changed, 10 insertions(+), 2 deletions(-) diff --git a/apps/openmw/CMakeLists.txt b/apps/openmw/CMakeLists.txt index 66844b280..69cfb2fd5 100644 --- a/apps/openmw/CMakeLists.txt +++ b/apps/openmw/CMakeLists.txt @@ -61,7 +61,7 @@ add_openmw_dir (mwclass add_openmw_dir (mwmechanics mechanicsmanagerimp stat creaturestats magiceffects movement actors drawstate spells - activespells npcstats aipackage aisequence + activespells npcstats aipackage aisequence alchemy ) add_openmw_dir (mwbase diff --git a/apps/openmw/mwgui/alchemywindow.cpp b/apps/openmw/mwgui/alchemywindow.cpp index 308029810..6fd88d5ca 100644 --- a/apps/openmw/mwgui/alchemywindow.cpp +++ b/apps/openmw/mwgui/alchemywindow.cpp @@ -253,8 +253,10 @@ namespace MWGui void AlchemyWindow::open() { - openContainer(MWBase::Environment::get().getWorld()->getPlayer().getPlayer()); + openContainer(MWBase::Environment::get().getWorld()->getPlayer().getPlayer()); // this sets mPtr setFilter(ContainerBase::Filter_Ingredients); + + mAlchemy.setAlchemist (mPtr); // pick the best available apparatus MWWorld::ContainerStore& store = MWWorld::Class::get(mPtr).getContainerStore(mPtr); diff --git a/apps/openmw/mwgui/alchemywindow.hpp b/apps/openmw/mwgui/alchemywindow.hpp index 53e7178d5..67378d7de 100644 --- a/apps/openmw/mwgui/alchemywindow.hpp +++ b/apps/openmw/mwgui/alchemywindow.hpp @@ -1,6 +1,8 @@ #ifndef MWGUI_ALCHEMY_H #define MWGUI_ALCHEMY_H +#include "../mwmechanics/alchemy.hpp" + #include "window_base.hpp" #include "container.hpp" #include "widgets.hpp" @@ -46,6 +48,10 @@ namespace MWGui virtual void onReferenceUnavailable() { ; } void update(); + + private: + + MWMechanics::Alchemy mAlchemy; }; } From c6fd864a76e010807a512e85f4a1c4a5078de4db Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Sat, 29 Sep 2012 10:02:46 +0200 Subject: [PATCH 02/15] Issue #61: Forgot to add some files --- apps/openmw/mwmechanics/alchemy.cpp | 7 +++++++ apps/openmw/mwmechanics/alchemy.hpp | 22 ++++++++++++++++++++++ 2 files changed, 29 insertions(+) create mode 100644 apps/openmw/mwmechanics/alchemy.cpp create mode 100644 apps/openmw/mwmechanics/alchemy.hpp diff --git a/apps/openmw/mwmechanics/alchemy.cpp b/apps/openmw/mwmechanics/alchemy.cpp new file mode 100644 index 000000000..ea5cbe965 --- /dev/null +++ b/apps/openmw/mwmechanics/alchemy.cpp @@ -0,0 +1,7 @@ + +#include "alchemy.hpp" + +void MWMechanics::Alchemy::setAlchemist (const MWWorld::Ptr& npc) +{ + mNpc = npc; +} diff --git a/apps/openmw/mwmechanics/alchemy.hpp b/apps/openmw/mwmechanics/alchemy.hpp new file mode 100644 index 000000000..93c50f1ff --- /dev/null +++ b/apps/openmw/mwmechanics/alchemy.hpp @@ -0,0 +1,22 @@ +#ifndef GAME_MWMECHANICS_ALCHEMY_H +#define GAME_MWMECHANICS_ALCHEMY_H + +#include "../mwworld/ptr.hpp" + +namespace MWMechanics +{ + /// \brief Potion creatin via alchemy skill + class Alchemy + { + MWWorld::Ptr mNpc; + + public: + + void setAlchemist (const MWWorld::Ptr& npc); + ///< Set alchemist and configure alchemy setup accordingly. \a npc may be empty to indicate that + /// there is no alchemist (alchemy session has ended). + }; +} + +#endif + From 42f02f3ccd2b11e06868587871174661448865e3 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Sun, 30 Sep 2012 18:54:20 +0200 Subject: [PATCH 03/15] Issue #61: Re-implemented tool selection in Alchemy class --- apps/openmw/mwmechanics/alchemy.cpp | 39 +++++++++++++++++++++++++++++ apps/openmw/mwmechanics/alchemy.hpp | 14 +++++++++++ 2 files changed, 53 insertions(+) diff --git a/apps/openmw/mwmechanics/alchemy.cpp b/apps/openmw/mwmechanics/alchemy.cpp index ea5cbe965..0a0189190 100644 --- a/apps/openmw/mwmechanics/alchemy.cpp +++ b/apps/openmw/mwmechanics/alchemy.cpp @@ -1,7 +1,46 @@ #include "alchemy.hpp" +#include +#include + +#include "../mwworld/containerstore.hpp" +#include "../mwworld/class.hpp" + void MWMechanics::Alchemy::setAlchemist (const MWWorld::Ptr& npc) { mNpc = npc; + + mTools.resize (4); + + std::fill (mTools.begin(), mTools.end(), MWWorld::Ptr()); + + MWWorld::ContainerStore& store = MWWorld::Class::get (npc).getContainerStore (npc); + + for (MWWorld::ContainerStoreIterator iter (store.begin (MWWorld::ContainerStore::Type_Apparatus)); + iter!=store.end(); ++iter) + { + MWWorld::LiveCellRef* ref = iter->get(); + + int type = ref->base->data.type; + + if (type<0 || type>=static_cast (mTools.size())) + throw std::runtime_error ("invalid apparatus type"); + + if (!mTools[type].isEmpty()) + if (ref->base->data.quality<=mTools[type].get()->base->data.quality) + continue; + + mTools[type] = *iter; + } +} + +MWMechanics::Alchemy::TToolsIterator MWMechanics::Alchemy::beginTools() const +{ + return mTools.begin(); +} + +MWMechanics::Alchemy::TToolsIterator MWMechanics::Alchemy::endTools() const +{ + return mTools.end(); } diff --git a/apps/openmw/mwmechanics/alchemy.hpp b/apps/openmw/mwmechanics/alchemy.hpp index 93c50f1ff..fcaba9012 100644 --- a/apps/openmw/mwmechanics/alchemy.hpp +++ b/apps/openmw/mwmechanics/alchemy.hpp @@ -1,6 +1,8 @@ #ifndef GAME_MWMECHANICS_ALCHEMY_H #define GAME_MWMECHANICS_ALCHEMY_H +#include + #include "../mwworld/ptr.hpp" namespace MWMechanics @@ -8,13 +10,25 @@ namespace MWMechanics /// \brief Potion creatin via alchemy skill class Alchemy { + public: + + typedef std::vector TToolsContainer; + typedef TToolsContainer::const_iterator TToolsIterator; + + private: + MWWorld::Ptr mNpc; + TToolsContainer mTools; public: void setAlchemist (const MWWorld::Ptr& npc); ///< Set alchemist and configure alchemy setup accordingly. \a npc may be empty to indicate that /// there is no alchemist (alchemy session has ended). + + TToolsIterator beginTools() const; + + TToolsIterator endTools() const; }; } From 10c8360e07c1a31862f162d234c731829a0aba52 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Sun, 30 Sep 2012 19:05:45 +0200 Subject: [PATCH 04/15] Issue #61: Replaced apparatus handling in alchemy GUI with new implementation in Alchemy class --- apps/openmw/mwgui/alchemywindow.cpp | 72 +++++++---------------------- apps/openmw/mwgui/alchemywindow.hpp | 9 ++-- 2 files changed, 21 insertions(+), 60 deletions(-) diff --git a/apps/openmw/mwgui/alchemywindow.cpp b/apps/openmw/mwgui/alchemywindow.cpp index 6fd88d5ca..26bd9668e 100644 --- a/apps/openmw/mwgui/alchemywindow.cpp +++ b/apps/openmw/mwgui/alchemywindow.cpp @@ -28,7 +28,7 @@ namespace MWGui { AlchemyWindow::AlchemyWindow(MWBase::WindowManager& parWindowManager) : WindowBase("openmw_alchemy_window.layout", parWindowManager) - , ContainerBase(0) + , ContainerBase(0), mApparatus (4) { getWidget(mCreateButton, "CreateButton"); getWidget(mCancelButton, "CancelButton"); @@ -36,10 +36,10 @@ namespace MWGui getWidget(mIngredient2, "Ingredient2"); getWidget(mIngredient3, "Ingredient3"); getWidget(mIngredient4, "Ingredient4"); - getWidget(mApparatus1, "Apparatus1"); - getWidget(mApparatus2, "Apparatus2"); - getWidget(mApparatus3, "Apparatus3"); - getWidget(mApparatus4, "Apparatus4"); + getWidget(mApparatus[0], "Apparatus1"); + getWidget(mApparatus[1], "Apparatus2"); + getWidget(mApparatus[2], "Apparatus3"); + getWidget(mApparatus[3], "Apparatus4"); getWidget(mEffectsBox, "CreatedEffects"); getWidget(mNameEdit, "NameEdit"); @@ -70,7 +70,7 @@ namespace MWGui { // check if mortar & pestle is available (always needed) /// \todo check albemic, calcinator, retort (sometimes needed) - if (!mApparatus1->isUserString("ToolTipType")) + if (!mApparatus[0]->isUserString("ToolTipType")) { mWindowManager.messageBox("#{sNotifyMessage45}", std::vector()); return; @@ -253,60 +253,22 @@ namespace MWGui void AlchemyWindow::open() { - openContainer(MWBase::Environment::get().getWorld()->getPlayer().getPlayer()); // this sets mPtr - setFilter(ContainerBase::Filter_Ingredients); + openContainer (MWBase::Environment::get().getWorld()->getPlayer().getPlayer()); // this sets mPtr + setFilter (ContainerBase::Filter_Ingredients); mAlchemy.setAlchemist (mPtr); - // pick the best available apparatus - MWWorld::ContainerStore& store = MWWorld::Class::get(mPtr).getContainerStore(mPtr); + int index = 0; - MWWorld::Ptr bestAlbemic; - MWWorld::Ptr bestMortarPestle; - MWWorld::Ptr bestCalcinator; - MWWorld::Ptr bestRetort; - - for (MWWorld::ContainerStoreIterator it(store.begin(MWWorld::ContainerStore::Type_Apparatus)); - it != store.end(); ++it) + for (MWMechanics::Alchemy::TToolsIterator iter (mAlchemy.beginTools()); + iter!=mAlchemy.endTools() && index (mApparatus.size()); ++iter, ++index) { - MWWorld::LiveCellRef* ref = it->get(); - if (ref->base->data.type == ESM::Apparatus::Albemic - && (bestAlbemic.isEmpty() || ref->base->data.quality > bestAlbemic.get()->base->data.quality)) - bestAlbemic = *it; - else if (ref->base->data.type == ESM::Apparatus::MortarPestle - && (bestMortarPestle.isEmpty() || ref->base->data.quality > bestMortarPestle.get()->base->data.quality)) - bestMortarPestle = *it; - else if (ref->base->data.type == ESM::Apparatus::Calcinator - && (bestCalcinator.isEmpty() || ref->base->data.quality > bestCalcinator.get()->base->data.quality)) - bestCalcinator = *it; - else if (ref->base->data.type == ESM::Apparatus::Retort - && (bestRetort.isEmpty() || ref->base->data.quality > bestRetort.get()->base->data.quality)) - bestRetort = *it; - } - - if (!bestMortarPestle.isEmpty()) - { - mApparatus1->setUserString("ToolTipType", "ItemPtr"); - mApparatus1->setUserData(bestMortarPestle); - mApparatus1->setImageTexture(getIconPath(bestMortarPestle)); - } - if (!bestAlbemic.isEmpty()) - { - mApparatus2->setUserString("ToolTipType", "ItemPtr"); - mApparatus2->setUserData(bestAlbemic); - mApparatus2->setImageTexture(getIconPath(bestAlbemic)); - } - if (!bestCalcinator.isEmpty()) - { - mApparatus3->setUserString("ToolTipType", "ItemPtr"); - mApparatus3->setUserData(bestCalcinator); - mApparatus3->setImageTexture(getIconPath(bestCalcinator)); - } - if (!bestRetort.isEmpty()) - { - mApparatus4->setUserString("ToolTipType", "ItemPtr"); - mApparatus4->setUserData(bestRetort); - mApparatus4->setImageTexture(getIconPath(bestRetort)); + if (!iter->isEmpty()) + { + mApparatus[index]->setUserString ("ToolTipType", "ItemPtr"); + mApparatus[index]->setUserData (*iter); + mApparatus[index]->setImageTexture (getIconPath (*iter)); + } } } diff --git a/apps/openmw/mwgui/alchemywindow.hpp b/apps/openmw/mwgui/alchemywindow.hpp index 67378d7de..5091fb57a 100644 --- a/apps/openmw/mwgui/alchemywindow.hpp +++ b/apps/openmw/mwgui/alchemywindow.hpp @@ -1,6 +1,8 @@ #ifndef MWGUI_ALCHEMY_H #define MWGUI_ALCHEMY_H +#include + #include "../mwmechanics/alchemy.hpp" #include "window_base.hpp" @@ -25,11 +27,6 @@ namespace MWGui MyGUI::ImageBox* mIngredient3; MyGUI::ImageBox* mIngredient4; - MyGUI::ImageBox* mApparatus1; - MyGUI::ImageBox* mApparatus2; - MyGUI::ImageBox* mApparatus3; - MyGUI::ImageBox* mApparatus4; - MyGUI::Widget* mEffectsBox; MyGUI::EditBox* mNameEdit; @@ -52,6 +49,8 @@ namespace MWGui private: MWMechanics::Alchemy mAlchemy; + + std::vector mApparatus; }; } From 1cc2c2055f41a0d68757972fb27e077290490360 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Tue, 2 Oct 2012 10:20:26 +0200 Subject: [PATCH 05/15] Issue #61: Implemented basic ingredient handling in Alchemy class --- apps/openmw/mwmechanics/alchemy.cpp | 52 +++++++++++++++++++++++++++++ apps/openmw/mwmechanics/alchemy.hpp | 22 +++++++++++- 2 files changed, 73 insertions(+), 1 deletion(-) diff --git a/apps/openmw/mwmechanics/alchemy.cpp b/apps/openmw/mwmechanics/alchemy.cpp index c7e5da70a..6d3deed3c 100644 --- a/apps/openmw/mwmechanics/alchemy.cpp +++ b/apps/openmw/mwmechanics/alchemy.cpp @@ -11,6 +11,10 @@ void MWMechanics::Alchemy::setAlchemist (const MWWorld::Ptr& npc) { mNpc = npc; + mIngredients.resize (4); + + std::fill (mIngredients.begin(), mIngredients.end(), MWWorld::Ptr()); + mTools.resize (4); std::fill (mTools.begin(), mTools.end(), MWWorld::Ptr()); @@ -44,3 +48,51 @@ MWMechanics::Alchemy::TToolsIterator MWMechanics::Alchemy::endTools() const { return mTools.end(); } + +MWMechanics::Alchemy::TIngredientsIterator MWMechanics::Alchemy::beginIngredients() const +{ + return mIngredients.begin(); +} + +MWMechanics::Alchemy::TIngredientsIterator MWMechanics::Alchemy::endIngredients() const +{ + return mIngredients.end(); +} + +void MWMechanics::Alchemy::clear() +{ + mNpc = MWWorld::Ptr(); + mTools.clear(); + mIngredients.clear(); +} + +int MWMechanics::Alchemy::addIngredient (const MWWorld::Ptr& ingredient) +{ + // find a free slot + int slot = -1; + + for (int i=0; i (mIngredients.size()); ++i) + if (mIngredients[i].isEmpty()) + { + slot = i; + break; + } + + if (slot==-1) + return -1; + + for (TIngredientsIterator iter (mIngredients.begin()); iter!=mIngredients.end(); ++iter) + if (!iter->isEmpty() && ingredient.get()==iter->get()) + return -1; + + mIngredients[slot] = ingredient; + + return slot; +} + +void MWMechanics::Alchemy::removeIngredient (int index) +{ + if (index>=0 && index (mIngredients.size())) + mIngredients[index] = MWWorld::Ptr(); +} + diff --git a/apps/openmw/mwmechanics/alchemy.hpp b/apps/openmw/mwmechanics/alchemy.hpp index fcaba9012..7c3cf9e68 100644 --- a/apps/openmw/mwmechanics/alchemy.hpp +++ b/apps/openmw/mwmechanics/alchemy.hpp @@ -7,7 +7,7 @@ namespace MWMechanics { - /// \brief Potion creatin via alchemy skill + /// \brief Potion creation via alchemy skill class Alchemy { public: @@ -15,10 +15,14 @@ namespace MWMechanics typedef std::vector TToolsContainer; typedef TToolsContainer::const_iterator TToolsIterator; + typedef std::vector TIngredientsContainer; + typedef TIngredientsContainer::const_iterator TIngredientsIterator; + private: MWWorld::Ptr mNpc; TToolsContainer mTools; + TIngredientsContainer mIngredients; public: @@ -29,6 +33,22 @@ namespace MWMechanics TToolsIterator beginTools() const; TToolsIterator endTools() const; + + TIngredientsIterator beginIngredients() const; + + TIngredientsIterator endIngredients() const; + + void clear(); + ///< Remove alchemist, tools and ingredients. + + int addIngredient (const MWWorld::Ptr& ingredient); + ///< Add ingredient into the next free slot. + /// + /// \return Slot index or -1, if adding failed because of no free slot or the ingredient type being + /// listed already. + + void removeIngredient (int index); + ///< Remove ingredient from slot (calling this function on an empty slot is a no-op). }; } From 14833a4c3abbae15a5d000e00f80649f8117acb1 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Tue, 2 Oct 2012 10:20:49 +0200 Subject: [PATCH 06/15] Issue #61: More robust tools handling in alchemy window --- apps/openmw/mwgui/alchemywindow.cpp | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/apps/openmw/mwgui/alchemywindow.cpp b/apps/openmw/mwgui/alchemywindow.cpp index 93eee60ee..2aa46fda0 100644 --- a/apps/openmw/mwgui/alchemywindow.cpp +++ b/apps/openmw/mwgui/alchemywindow.cpp @@ -62,6 +62,8 @@ namespace MWGui void AlchemyWindow::onCancelButtonClicked(MyGUI::Widget* _sender) { + mAlchemy.clear(); + mWindowManager.removeGuiMode(GM_Alchemy); mWindowManager.removeGuiMode(GM_Inventory); } @@ -265,9 +267,9 @@ namespace MWGui { if (!iter->isEmpty()) { - mApparatus[index]->setUserString ("ToolTipType", "ItemPtr"); - mApparatus[index]->setUserData (*iter); - mApparatus[index]->setImageTexture (getIconPath (*iter)); + mApparatus.at (index)->setUserString ("ToolTipType", "ItemPtr"); + mApparatus.at (index)->setUserData (*iter); + mApparatus.at (index)->setImageTexture (getIconPath (*iter)); } } } From 332039da10d303b611d85298a690ddf23392fbf5 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Tue, 2 Oct 2012 10:29:47 +0200 Subject: [PATCH 07/15] Issue #61: replaced 4 ingredient member variables with vector in alchemy GUI --- apps/openmw/mwgui/alchemywindow.cpp | 148 ++++++++-------------------- apps/openmw/mwgui/alchemywindow.hpp | 6 +- 2 files changed, 44 insertions(+), 110 deletions(-) diff --git a/apps/openmw/mwgui/alchemywindow.cpp b/apps/openmw/mwgui/alchemywindow.cpp index 2aa46fda0..cef5d6e2e 100644 --- a/apps/openmw/mwgui/alchemywindow.cpp +++ b/apps/openmw/mwgui/alchemywindow.cpp @@ -28,14 +28,14 @@ namespace MWGui { AlchemyWindow::AlchemyWindow(MWBase::WindowManager& parWindowManager) : WindowBase("openmw_alchemy_window.layout", parWindowManager) - , ContainerBase(0), mApparatus (4) + , ContainerBase(0), mApparatus (4), mIngredients (4) { getWidget(mCreateButton, "CreateButton"); getWidget(mCancelButton, "CancelButton"); - getWidget(mIngredient1, "Ingredient1"); - getWidget(mIngredient2, "Ingredient2"); - getWidget(mIngredient3, "Ingredient3"); - getWidget(mIngredient4, "Ingredient4"); + getWidget(mIngredients[0], "Ingredient1"); + getWidget(mIngredients[1], "Ingredient2"); + getWidget(mIngredients[2], "Ingredient3"); + getWidget(mIngredients[3], "Ingredient4"); getWidget(mApparatus[0], "Apparatus1"); getWidget(mApparatus[1], "Apparatus2"); getWidget(mApparatus[2], "Apparatus3"); @@ -43,10 +43,10 @@ namespace MWGui getWidget(mEffectsBox, "CreatedEffects"); getWidget(mNameEdit, "NameEdit"); - mIngredient1->eventMouseButtonClick += MyGUI::newDelegate(this, &AlchemyWindow::onIngredientSelected); - mIngredient2->eventMouseButtonClick += MyGUI::newDelegate(this, &AlchemyWindow::onIngredientSelected); - mIngredient3->eventMouseButtonClick += MyGUI::newDelegate(this, &AlchemyWindow::onIngredientSelected); - mIngredient4->eventMouseButtonClick += MyGUI::newDelegate(this, &AlchemyWindow::onIngredientSelected); + mIngredients[0]->eventMouseButtonClick += MyGUI::newDelegate(this, &AlchemyWindow::onIngredientSelected); + mIngredients[1]->eventMouseButtonClick += MyGUI::newDelegate(this, &AlchemyWindow::onIngredientSelected); + mIngredients[2]->eventMouseButtonClick += MyGUI::newDelegate(this, &AlchemyWindow::onIngredientSelected); + mIngredients[3]->eventMouseButtonClick += MyGUI::newDelegate(this, &AlchemyWindow::onIngredientSelected); mCreateButton->eventMouseButtonClick += MyGUI::newDelegate(this, &AlchemyWindow::onCreateButtonClicked); mCancelButton->eventMouseButtonClick += MyGUI::newDelegate(this, &AlchemyWindow::onCancelButtonClicked); @@ -80,14 +80,10 @@ namespace MWGui // make sure 2 or more ingredients were selected int numIngreds = 0; - if (mIngredient1->isUserString("ToolTipType")) - ++numIngreds; - if (mIngredient2->isUserString("ToolTipType")) - ++numIngreds; - if (mIngredient3->isUserString("ToolTipType")) - ++numIngreds; - if (mIngredient4->isUserString("ToolTipType")) - ++numIngreds; + for (int i=0; i<4; ++i) + if (mIngredients[i]->isUserString("ToolTipType")) + ++numIngreds; + if (numIngreds < 2) { mWindowManager.messageBox("#{sNotifyMessage6a}", std::vector()); @@ -138,14 +134,9 @@ namespace MWGui // note by scrawl: not rounding down here, I can't imagine a created potion to // have 0 weight when using ingredients with 0.1 weight respectively float weight = 0; - if (mIngredient1->isUserString("ToolTipType")) - weight += mIngredient1->getUserData()->get()->base->mData.mWeight; - if (mIngredient2->isUserString("ToolTipType")) - weight += mIngredient2->getUserData()->get()->base->mData.mWeight; - if (mIngredient3->isUserString("ToolTipType")) - weight += mIngredient3->getUserData()->get()->base->mData.mWeight; - if (mIngredient4->isUserString("ToolTipType")) - weight += mIngredient4->getUserData()->get()->base->mData.mWeight; + for (int i=0; i<4; ++i) + if (mIngredients[i]->isUserString("ToolTipType")) + weight += mIngredients[i]->getUserData()->get()->base->mData.mWeight; newPotion.mData.mWeight = weight / float(numIngreds); newPotion.mData.mValue = 100; /// \todo @@ -222,34 +213,15 @@ namespace MWGui } // reduce count of the ingredients - if (mIngredient1->isUserString("ToolTipType")) - { - MWWorld::Ptr ingred = *mIngredient1->getUserData(); - ingred.getRefData().setCount(ingred.getRefData().getCount()-1); - if (ingred.getRefData().getCount() == 0) - removeIngredient(mIngredient1); - } - if (mIngredient2->isUserString("ToolTipType")) - { - MWWorld::Ptr ingred = *mIngredient2->getUserData(); - ingred.getRefData().setCount(ingred.getRefData().getCount()-1); - if (ingred.getRefData().getCount() == 0) - removeIngredient(mIngredient2); - } - if (mIngredient3->isUserString("ToolTipType")) - { - MWWorld::Ptr ingred = *mIngredient3->getUserData(); - ingred.getRefData().setCount(ingred.getRefData().getCount()-1); - if (ingred.getRefData().getCount() == 0) - removeIngredient(mIngredient3); - } - if (mIngredient4->isUserString("ToolTipType")) - { - MWWorld::Ptr ingred = *mIngredient4->getUserData(); - ingred.getRefData().setCount(ingred.getRefData().getCount()-1); - if (ingred.getRefData().getCount() == 0) - removeIngredient(mIngredient4); + for (int i=0; i<4; ++i) + if (mIngredients[i]->isUserString("ToolTipType")) + { + MWWorld::Ptr ingred = *mIngredients[i]->getUserData(); + ingred.getRefData().setCount(ingred.getRefData().getCount()-1); + if (ingred.getRefData().getCount() == 0) + removeIngredient(mIngredients[i]); } + update(); } @@ -289,45 +261,24 @@ namespace MWGui // (which could happen if two similiar ingredients don't stack because of script / owner) bool alreadyAdded = false; std::string name = MWWorld::Class::get(item).getName(item); - if (mIngredient1->isUserString("ToolTipType")) - { - MWWorld::Ptr item2 = *mIngredient1->getUserData(); - std::string name2 = MWWorld::Class::get(item2).getName(item2); - if (name == name2) - alreadyAdded = true; - } - if (mIngredient2->isUserString("ToolTipType")) - { - MWWorld::Ptr item2 = *mIngredient2->getUserData(); - std::string name2 = MWWorld::Class::get(item2).getName(item2); - if (name == name2) - alreadyAdded = true; - } - if (mIngredient3->isUserString("ToolTipType")) - { - MWWorld::Ptr item2 = *mIngredient3->getUserData(); - std::string name2 = MWWorld::Class::get(item2).getName(item2); - if (name == name2) - alreadyAdded = true; - } - if (mIngredient4->isUserString("ToolTipType")) - { - MWWorld::Ptr item2 = *mIngredient4->getUserData(); - std::string name2 = MWWorld::Class::get(item2).getName(item2); - if (name == name2) - alreadyAdded = true; - } + for (int i=0; i<4; ++i) + if (mIngredients[i]->isUserString("ToolTipType")) + { + MWWorld::Ptr item2 = *mIngredients[i]->getUserData(); + std::string name2 = MWWorld::Class::get(item2).getName(item2); + if (name == name2) + alreadyAdded = true; + } + if (alreadyAdded) return; - if (!mIngredient1->isUserString("ToolTipType")) - add = mIngredient1; - if (add == NULL && !mIngredient2->isUserString("ToolTipType")) - add = mIngredient2; - if (add == NULL && !mIngredient3->isUserString("ToolTipType")) - add = mIngredient3; - if (add == NULL && !mIngredient4->isUserString("ToolTipType")) - add = mIngredient4; + for (int i=0; i<4; ++i) + if (!mIngredients[i]->isUserString("ToolTipType")) + { + add = mIngredients[i]; + break; + } if (add != NULL) { @@ -346,14 +297,9 @@ namespace MWGui { std::vector ignore; // don't show ingredients that are currently selected in the "available ingredients" box. - if (mIngredient1->isUserString("ToolTipType")) - ignore.push_back(*mIngredient1->getUserData()); - if (mIngredient2->isUserString("ToolTipType")) - ignore.push_back(*mIngredient2->getUserData()); - if (mIngredient3->isUserString("ToolTipType")) - ignore.push_back(*mIngredient3->getUserData()); - if (mIngredient4->isUserString("ToolTipType")) - ignore.push_back(*mIngredient4->getUserData()); + for (int i=0; i<4; ++i) + if (mIngredients[i]->isUserString("ToolTipType")) + ignore.push_back(*mIngredients[i]->getUserData()); return ignore; } @@ -364,15 +310,7 @@ namespace MWGui for (int i=0; i<4; ++i) { - MyGUI::ImageBox* ingredient; - if (i==0) - ingredient = mIngredient1; - else if (i==1) - ingredient = mIngredient2; - else if (i==2) - ingredient = mIngredient3; - else if (i==3) - ingredient = mIngredient4; + MyGUI::ImageBox* ingredient = mIngredients[i]; if (!ingredient->isUserString("ToolTipType")) continue; diff --git a/apps/openmw/mwgui/alchemywindow.hpp b/apps/openmw/mwgui/alchemywindow.hpp index 5091fb57a..179cdd174 100644 --- a/apps/openmw/mwgui/alchemywindow.hpp +++ b/apps/openmw/mwgui/alchemywindow.hpp @@ -22,11 +22,6 @@ namespace MWGui MyGUI::Button* mCreateButton; MyGUI::Button* mCancelButton; - MyGUI::ImageBox* mIngredient1; - MyGUI::ImageBox* mIngredient2; - MyGUI::ImageBox* mIngredient3; - MyGUI::ImageBox* mIngredient4; - MyGUI::Widget* mEffectsBox; MyGUI::EditBox* mNameEdit; @@ -51,6 +46,7 @@ namespace MWGui MWMechanics::Alchemy mAlchemy; std::vector mApparatus; + std::vector mIngredients; }; } From 5fbca239dd4da63fecd0634674d7e80e43e4e0b6 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Thu, 18 Oct 2012 14:02:06 +0200 Subject: [PATCH 08/15] Issue #61: potion creation (1st part; still missing some implementations) --- apps/openmw/mwmechanics/alchemy.cpp | 308 +++++++++++++++++++++++++++- apps/openmw/mwmechanics/alchemy.hpp | 62 +++++- components/esm/loadmgef.hpp | 2 + 3 files changed, 369 insertions(+), 3 deletions(-) diff --git a/apps/openmw/mwmechanics/alchemy.cpp b/apps/openmw/mwmechanics/alchemy.cpp index 6d3deed3c..c8a3cf162 100644 --- a/apps/openmw/mwmechanics/alchemy.cpp +++ b/apps/openmw/mwmechanics/alchemy.cpp @@ -1,15 +1,259 @@ #include "alchemy.hpp" +#include + #include #include +#include +#include +#include +#include + +#include + +#include "../mwbase/environment.hpp" +#include "../mwbase/world.hpp" + #include "../mwworld/containerstore.hpp" #include "../mwworld/class.hpp" +#include "../mwworld/cellstore.hpp" + +#include "magiceffects.hpp" +#include "creaturestats.hpp" +#include "npcstats.hpp" + +std::set MWMechanics::Alchemy::listEffects() const +{ + std::set effects; + + for (TIngredientsIterator iter (mIngredients.begin()); iter!=mIngredients.end(); ++iter) + { + if (!iter->isEmpty()) + { + const MWWorld::LiveCellRef *ingredient = iter->get(); + + for (int i=0; i<4; ++i) + if (ingredient->base->mData.mEffectID[i]!=-1) + effects.insert (EffectKey ( + ingredient->base->mData.mEffectID[i], ingredient->base->mData.mSkills[i]!=-1 ? + ingredient->base->mData.mSkills[i] : ingredient->base->mData.mAttributes[i])); + } + } + + return effects; +} + +void MWMechanics::Alchemy::filterEffects (std::set& effects) const +{ + std::set::iterator iter = effects.begin(); + + while (iter!=effects.end()) + { + bool remove = false; + + const EffectKey& key = *iter; + + { // dodge pointless g++ warning + for (TIngredientsIterator iter (mIngredients.begin()); iter!=mIngredients.end(); ++iter) + { + bool found = false; + + const MWWorld::LiveCellRef *ingredient = iter->get(); + + for (int i=0; i<4; ++i) + if (key.mId==ingredient->base->mData.mEffectID[i] && + (key.mArg==ingredient->base->mData.mSkills[i] || + key.mArg==ingredient->base->mData.mAttributes[i])) + { + found = true; + break; + } + + if (!found) + { + remove = true; + break; + } + } + } + + if (remove) + effects.erase (iter++); + else + ++iter; + } +} + +void MWMechanics::Alchemy::applyTools (int flags, float& value) const +{ + bool magnitude = !(flags & ESM::MagicEffect::NoMagnitude); + bool duration = !(flags & ESM::MagicEffect::NoDuration); + bool negative = flags & (ESM::MagicEffect::Negative | ESM::MagicEffect::Negative2); + + int tool = negative ? ESM::Apparatus::Retort : ESM::Apparatus::Albemic; + + int setup = 0; + + if (!mTools[tool].isEmpty() && !mTools[ESM::Apparatus::Calcinator].isEmpty()) + setup = 1; + else if (!mTools[tool].isEmpty()) + setup = 2; + else if (!mTools[ESM::Apparatus::Calcinator].isEmpty()) + setup = 3; + else + return; + + float toolQuality = setup==1 || setup==2 ? mTools[tool].get()->base->mData.mQuality : 0; + float calcinatorQuality = setup==1 || setup==3 ? + mTools[ESM::Apparatus::Calcinator].get()->base->mData.mQuality : 0; + + float quality = 1; + + switch (setup) + { + case 1: + + quality = negative ? 2 * toolQuality + 3 * calcinatorQuality : + (magnitude && duration ? + 2 * toolQuality + calcinatorQuality : 2/3.0 * (toolQuality + calcinatorQuality) + 0.5); + break; + + case 2: + + quality = negative ? 1+toolQuality : (magnitude && duration ? toolQuality : toolQuality + 0.5); + break; + + case 3: + + quality = magnitude && duration ? calcinatorQuality : calcinatorQuality + 0.5; + break; + } + + if (setup==3 || !negative) + { + value += quality; + } + else + { + if (quality==0) + throw std::runtime_error ("invalid derived alchemy apparatus quality"); + + value /= quality; + } +} + +void MWMechanics::Alchemy::updateEffects() +{ + mEffects.clear(); + + int ingredients = 0; + + for (TIngredientsIterator iter (beginIngredients()); iter!=endIngredients(); ++iter) + if (!iter->isEmpty()) + ++ingredients; + + if (ingredients<2 || mAlchemist.isEmpty() || mTools[ESM::Apparatus::MortarPestle].isEmpty()) + return; + + // find effects + std::set effects (listEffects()); + filterEffects (effects); + + // general alchemy factor + float x = getChance(); + + x *= mTools[ESM::Apparatus::MortarPestle].get()->base->mData.mQuality; + x *= MWBase::Environment::get().getWorld()->getStore().gameSettings.find ("fPotionStrengthMult")->getFloat(); + + // build quantified effect list + for (std::set::const_iterator iter (effects.begin()); iter!=effects.end(); ++iter) + { + const ESM::MagicEffect *magicEffect = + MWBase::Environment::get().getWorld()->getStore().magicEffects.find (iter->mId); + + if (magicEffect->mData.mBaseCost<=0) + throw std::runtime_error ("invalid base cost for magic effect " + iter->mId); + + float fPotionT1MagMul = + MWBase::Environment::get().getWorld()->getStore().gameSettings.find ("fPotionT1MagMul")->getFloat(); + + if (fPotionT1MagMul<=0) + throw std::runtime_error ("invalid gmst: fPotionT1MagMul"); + + float fPotionT1DurMult = + MWBase::Environment::get().getWorld()->getStore().gameSettings.find ("fPotionT1DurMult")->getFloat(); + + if (fPotionT1DurMult<=0) + throw std::runtime_error ("invalid gmst: fPotionT1DurMult"); + + float magnitude = magicEffect->mData.mFlags && ESM::MagicEffect::NoMagnitude ? + 1 : (x / fPotionT1MagMul) / magicEffect->mData.mBaseCost; + float duration = magicEffect->mData.mFlags && ESM::MagicEffect::NoDuration ? + 1 : (x / fPotionT1DurMult) / magicEffect->mData.mBaseCost; + + if (!(magicEffect->mData.mFlags && ESM::MagicEffect::NoMagnitude)) + applyTools (magicEffect->mData.mFlags, magnitude); + + if (!(magicEffect->mData.mFlags && ESM::MagicEffect::NoDuration)) + applyTools (magicEffect->mData.mFlags, duration); + + duration = static_cast (duration+0.5); + magnitude = static_cast (magnitude+0.5); + + if (magnitude>0 && duration>0) + { + ESM::ENAMstruct effect; + effect.mEffectID = iter->mId; + + effect.mSkill = effect.mAttribute = iter->mArg; // somewhat hack-ish, but should work + + effect.mRange = 0; + effect.mArea = 0; + + effect.mDuration = duration; + effect.mMagnMin = effect.mMagnMax = magnitude; + + mEffects.push_back (effect); + } + } +} + +const ESM::Potion *MWMechanics::Alchemy::getRecord() const +{ + +} + +void MWMechanics::Alchemy::removeIngredients() +{ + +} + +void MWMechanics::Alchemy::addPotion (const std::string& name) +{ + +} + +void MWMechanics::Alchemy::increaseSkill() +{ + +} + +float MWMechanics::Alchemy::getChance() const +{ + const CreatureStats& creatureStats = MWWorld::Class::get (mAlchemist).getCreatureStats (mAlchemist); + const NpcStats& npcStats = MWWorld::Class::get (mAlchemist).getNpcStats (mAlchemist); + + return + (npcStats.getSkill (ESM::Skill::Alchemy).getModified() + + 0.1 * creatureStats.getAttribute (1).getModified() + + 0.1 * creatureStats.getAttribute (7).getModified()); +} void MWMechanics::Alchemy::setAlchemist (const MWWorld::Ptr& npc) { - mNpc = npc; + mAlchemist = npc; mIngredients.resize (4); @@ -19,6 +263,8 @@ void MWMechanics::Alchemy::setAlchemist (const MWWorld::Ptr& npc) std::fill (mTools.begin(), mTools.end(), MWWorld::Ptr()); + mEffects.clear(); + MWWorld::ContainerStore& store = MWWorld::Class::get (npc).getContainerStore (npc); for (MWWorld::ContainerStoreIterator iter (store.begin (MWWorld::ContainerStore::Type_Apparatus)); @@ -61,9 +307,10 @@ MWMechanics::Alchemy::TIngredientsIterator MWMechanics::Alchemy::endIngredients( void MWMechanics::Alchemy::clear() { - mNpc = MWWorld::Ptr(); + mAlchemist = MWWorld::Ptr(); mTools.clear(); mIngredients.clear(); + mEffects.clear(); } int MWMechanics::Alchemy::addIngredient (const MWWorld::Ptr& ingredient) @@ -86,6 +333,8 @@ int MWMechanics::Alchemy::addIngredient (const MWWorld::Ptr& ingredient) return -1; mIngredients[slot] = ingredient; + + updateEffects(); return slot; } @@ -93,6 +342,61 @@ int MWMechanics::Alchemy::addIngredient (const MWWorld::Ptr& ingredient) void MWMechanics::Alchemy::removeIngredient (int index) { if (index>=0 && index (mIngredients.size())) + { mIngredients[index] = MWWorld::Ptr(); + updateEffects(); + } } +MWMechanics::Alchemy::TEffectsIterator MWMechanics::Alchemy::beginEffects() const +{ + return mEffects.begin(); +} + +MWMechanics::Alchemy::TEffectsIterator MWMechanics::Alchemy::endEffects() const +{ + return mEffects.end(); +} + +std::string MWMechanics::Alchemy::getPotionName() const +{ + if (const ESM::Potion *potion = getRecord()) + return potion->mName; + + return ""; +} + +MWMechanics::Alchemy::Result MWMechanics::Alchemy::create (const std::string& name) +{ + if (mTools[ESM::Apparatus::MortarPestle].isEmpty()) + return Result_NoMortarAndPestle; + + int ingredients = 0; + + for (TIngredientsIterator iter (beginIngredients()); iter!=endIngredients(); ++iter) + if (!iter->isEmpty()) + ++ingredients; + + if (ingredients<2) + return Result_LessThanTwoIngredients; + + if (name.empty() && getPotionName().empty()) + return Result_NoName; + + if (beginEffects()==endEffects()) + return Result_NoEffects; + + if (getChance() (RAND_MAX)*100) + { + removeIngredients(); + return Result_RandomFailure; + } + + addPotion (name); + + removeIngredients(); + + increaseSkill(); + + return Result_Success; +} diff --git a/apps/openmw/mwmechanics/alchemy.hpp b/apps/openmw/mwmechanics/alchemy.hpp index 7c3cf9e68..73fa7eb18 100644 --- a/apps/openmw/mwmechanics/alchemy.hpp +++ b/apps/openmw/mwmechanics/alchemy.hpp @@ -2,11 +2,16 @@ #define GAME_MWMECHANICS_ALCHEMY_H #include +#include + +#include #include "../mwworld/ptr.hpp" namespace MWMechanics { + struct EffectKey; + /// \brief Potion creation via alchemy skill class Alchemy { @@ -17,13 +22,54 @@ namespace MWMechanics typedef std::vector TIngredientsContainer; typedef TIngredientsContainer::const_iterator TIngredientsIterator; + + typedef std::vector TEffectsContainer; + typedef TEffectsContainer::const_iterator TEffectsIterator; + + enum Result + { + Result_Success, + + Result_NoMortarAndPestle, + Result_LessThanTwoIngredients, + Result_NoName, + Result_NoEffects, + Result_RandomFailure + }; private: - MWWorld::Ptr mNpc; + MWWorld::Ptr mAlchemist; TToolsContainer mTools; TIngredientsContainer mIngredients; + TEffectsContainer mEffects; + std::set listEffects() const; + ///< List all effects of all used ingredients. + + void filterEffects (std::set& effects) const; + ///< Filter out effects not shared by all ingredients. + + void applyTools (int flags, float& value) const; + + void updateEffects(); + + const ESM::Potion *getRecord() const; + ///< Return existing recrod for created potion (may return 0) + + void removeIngredients(); + ///< Remove selected ingredients from alchemist's inventory, cleanup selected ingredients and + /// update effect list accordingly. + + void addPotion (const std::string& name); + ///< Add a potion to the alchemist's inventory. + + void increaseSkill(); + ///< Increase alchemist's skill. + + float getChance() const; + ///< Return chance of success. + public: void setAlchemist (const MWWorld::Ptr& npc); @@ -49,6 +95,20 @@ namespace MWMechanics void removeIngredient (int index); ///< Remove ingredient from slot (calling this function on an empty slot is a no-op). + + TEffectsIterator beginEffects() const; + + TEffectsIterator endEffects() const; + + std::string getPotionName() const; + ///< Return the name of the potion that would be created when calling create (if a record for such + /// a potion already exists) or return an empty string. + + Result create (const std::string& name); + ///< Try to create a potion from the ingredients, place it in the inventory of the alchemist and + /// adjust the skills of the alchemist accordingly. + /// \param name must not be an empty string, unless there is already a potion record ( + /// getPotionName() does not return an empty string). }; } diff --git a/components/esm/loadmgef.hpp b/components/esm/loadmgef.hpp index 861f66be0..a763576c3 100644 --- a/components/esm/loadmgef.hpp +++ b/components/esm/loadmgef.hpp @@ -14,6 +14,8 @@ struct MagicEffect enum Flags { NoDuration = 0x4, + NoMagnitude = 0x8, + Negative2 = 0x10, SpellMaking = 0x0200, Enchanting = 0x0400, Negative = 0x0800 // A harmful effect. Will determine whether From 3fe0a73cf24349a8a8abff9c27724dda9812e330 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Thu, 18 Oct 2012 14:38:38 +0200 Subject: [PATCH 09/15] Issue #61: increase alchemy skill on successful potion creation --- apps/openmw/mwmechanics/alchemy.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/openmw/mwmechanics/alchemy.cpp b/apps/openmw/mwmechanics/alchemy.cpp index bf39afefb..3a5efbaaf 100644 --- a/apps/openmw/mwmechanics/alchemy.cpp +++ b/apps/openmw/mwmechanics/alchemy.cpp @@ -237,7 +237,7 @@ void MWMechanics::Alchemy::addPotion (const std::string& name) void MWMechanics::Alchemy::increaseSkill() { - + MWWorld::Class::get (mAlchemist).skillUsageSucceeded (mAlchemist, ESM::Skill::Alchemy, 0); } float MWMechanics::Alchemy::getChance() const From 3c71378fade9b52cd011034425aa7c585f818444 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Thu, 18 Oct 2012 14:41:57 +0200 Subject: [PATCH 10/15] Issue 61: improved ingredients handling in alchemy and documenation --- apps/openmw/mwmechanics/alchemy.cpp | 29 ++++++++++++++--------------- apps/openmw/mwmechanics/alchemy.hpp | 4 ++++ 2 files changed, 18 insertions(+), 15 deletions(-) diff --git a/apps/openmw/mwmechanics/alchemy.cpp b/apps/openmw/mwmechanics/alchemy.cpp index 3a5efbaaf..d59d71306 100644 --- a/apps/openmw/mwmechanics/alchemy.cpp +++ b/apps/openmw/mwmechanics/alchemy.cpp @@ -148,13 +148,7 @@ void MWMechanics::Alchemy::updateEffects() { mEffects.clear(); - int ingredients = 0; - - for (TIngredientsIterator iter (beginIngredients()); iter!=endIngredients(); ++iter) - if (!iter->isEmpty()) - ++ingredients; - - if (ingredients<2 || mAlchemist.isEmpty() || mTools[ESM::Apparatus::MortarPestle].isEmpty()) + if (countIngredients()<2 || mAlchemist.isEmpty() || mTools[ESM::Apparatus::MortarPestle].isEmpty()) return; // find effects @@ -251,6 +245,17 @@ float MWMechanics::Alchemy::getChance() const + 0.1 * creatureStats.getAttribute (7).getModified()); } +int MWMechanics::Alchemy::countIngredients() const +{ + int ingredients = 0; + + for (TIngredientsIterator iter (beginIngredients()); iter!=endIngredients(); ++iter) + if (!iter->isEmpty()) + ++ingredients; + + return ingredients; +} + void MWMechanics::Alchemy::setAlchemist (const MWWorld::Ptr& npc) { mAlchemist = npc; @@ -370,14 +375,8 @@ MWMechanics::Alchemy::Result MWMechanics::Alchemy::create (const std::string& na { if (mTools[ESM::Apparatus::MortarPestle].isEmpty()) return Result_NoMortarAndPestle; - - int ingredients = 0; - - for (TIngredientsIterator iter (beginIngredients()); iter!=endIngredients(); ++iter) - if (!iter->isEmpty()) - ++ingredients; - - if (ingredients<2) + + if (countIngredients()<2) return Result_LessThanTwoIngredients; if (name.empty() && getPotionName().empty()) diff --git a/apps/openmw/mwmechanics/alchemy.hpp b/apps/openmw/mwmechanics/alchemy.hpp index 73fa7eb18..52af29912 100644 --- a/apps/openmw/mwmechanics/alchemy.hpp +++ b/apps/openmw/mwmechanics/alchemy.hpp @@ -70,6 +70,8 @@ namespace MWMechanics float getChance() const; ///< Return chance of success. + int countIngredients() const; + public: void setAlchemist (const MWWorld::Ptr& npc); @@ -77,10 +79,12 @@ namespace MWMechanics /// there is no alchemist (alchemy session has ended). TToolsIterator beginTools() const; + ///< \attention Iterates over tool slots, not over tools. Some of the slots may be empty. TToolsIterator endTools() const; TIngredientsIterator beginIngredients() const; + ///< \attention Iterates over ingredient slots, not over ingredients. Some of the slots may be empty. TIngredientsIterator endIngredients() const; From f5caf227b23e602dba92da031648c78eeee84450 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Thu, 18 Oct 2012 14:47:23 +0200 Subject: [PATCH 11/15] Issue #61: remove ingredients on potion creation --- apps/openmw/mwmechanics/alchemy.cpp | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/apps/openmw/mwmechanics/alchemy.cpp b/apps/openmw/mwmechanics/alchemy.cpp index d59d71306..f59d87ae7 100644 --- a/apps/openmw/mwmechanics/alchemy.cpp +++ b/apps/openmw/mwmechanics/alchemy.cpp @@ -221,7 +221,21 @@ const ESM::Potion *MWMechanics::Alchemy::getRecord() const void MWMechanics::Alchemy::removeIngredients() { - + bool needsUpdate = false; + + for (TIngredientsContainer::iterator iter (mIngredients.begin()); iter!=mIngredients.end(); ++iter) + if (!iter->isEmpty()) + { + iter->getRefData().setCount (iter->getRefData().getCount()-1); + if (iter->getRefData().getCount()<1) + { + needsUpdate = true; + *iter = MWWorld::Ptr(); + } + } + + if (needsUpdate) + updateEffects(); } void MWMechanics::Alchemy::addPotion (const std::string& name) From 1864dbe0311da194b720c92da4fb9f4b91f91743 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Thu, 18 Oct 2012 15:33:27 +0200 Subject: [PATCH 12/15] Issue #61: potion creation --- apps/openmw/mwmechanics/alchemy.cpp | 72 +++++++++++++++++++++++++++++ apps/openmw/mwmechanics/alchemy.hpp | 1 + 2 files changed, 73 insertions(+) diff --git a/apps/openmw/mwmechanics/alchemy.cpp b/apps/openmw/mwmechanics/alchemy.cpp index f59d87ae7..e37a30210 100644 --- a/apps/openmw/mwmechanics/alchemy.cpp +++ b/apps/openmw/mwmechanics/alchemy.cpp @@ -1,6 +1,7 @@ #include "alchemy.hpp" +#include #include #include @@ -19,6 +20,7 @@ #include "../mwworld/containerstore.hpp" #include "../mwworld/class.hpp" #include "../mwworld/cellstore.hpp" +#include "../mwworld/manualref.hpp" #include "magiceffects.hpp" #include "creaturestats.hpp" @@ -147,6 +149,7 @@ void MWMechanics::Alchemy::applyTools (int flags, float& value) const void MWMechanics::Alchemy::updateEffects() { mEffects.clear(); + mValue = 0; if (countIngredients()<2 || mAlchemist.isEmpty() || mTools[ESM::Apparatus::MortarPestle].isEmpty()) return; @@ -161,6 +164,10 @@ void MWMechanics::Alchemy::updateEffects() x *= mTools[ESM::Apparatus::MortarPestle].get()->base->mData.mQuality; x *= MWBase::Environment::get().getWorld()->getStore().gameSettings.find ("fPotionStrengthMult")->getFloat(); + // value + mValue = static_cast ( + x * MWBase::Environment::get().getWorld()->getStore().gameSettings.find ("iAlchemyMod")->getFloat()); + // build quantified effect list for (std::set::const_iterator iter (effects.begin()); iter!=effects.end(); ++iter) { @@ -216,7 +223,39 @@ void MWMechanics::Alchemy::updateEffects() const ESM::Potion *MWMechanics::Alchemy::getRecord() const { + for (ESMS::RecListWithIDT::MapType::const_iterator iter ( + MWBase::Environment::get().getWorld()->getStore().potions.list.begin()); + iter!=MWBase::Environment::get().getWorld()->getStore().potions.list.end(); ++iter) + { + if (iter->second.mEffects.mList.size()!=mEffects.size()) + continue; + + bool mismatch = false; + for (int i=0; i (iter->second.mEffects.mList.size()); ++iter) + { + const ESM::ENAMstruct& first = iter->second.mEffects.mList[i]; + const ESM::ENAMstruct& second = mEffects[i]; + + if (first.mEffectID!=second.mEffectID || + first.mArea!=second.mArea || + first.mRange!=second.mRange || + first.mSkill!=second.mSkill || + first.mAttribute!=second.mAttribute || + first.mMagnMin!=second.mMagnMin || + first.mMagnMax!=second.mMagnMax || + first.mDuration!=second.mDuration) + { + mismatch = true; + break; + } + } + + if (!mismatch) + return &iter->second; + } + + return 0; } void MWMechanics::Alchemy::removeIngredients() @@ -240,7 +279,40 @@ void MWMechanics::Alchemy::removeIngredients() void MWMechanics::Alchemy::addPotion (const std::string& name) { + const ESM::Potion *record = getRecord(); + + if (!record) + { + ESM::Potion newRecord; + + newRecord.mData.mWeight = 0; + + for (TIngredientsIterator iter (beginIngredients()); iter!=endIngredients(); ++iter) + if (!iter->isEmpty()) + newRecord.mData.mWeight += iter->get()->base->mData.mWeight; + + newRecord.mData.mWeight /= countIngredients(); + + newRecord.mData.mValue = mValue; + newRecord.mData.mAutoCalc = 0; + + newRecord.mName = name; + int index = static_cast (std::rand()/static_cast (RAND_MAX)*6); + assert (index>=0 && index<6); + + static const char *name[] = { "standard", "bargain", "cheap", "fresh", "exclusive", "quality" }; + + newRecord.mModel = "m\\misc_potion_" + std::string (name[index]) + "_01.nif"; + newRecord.mIcon = "m\\tx_potion_" + std::string (name[index]) + "_01.dds"; + + newRecord.mEffects.mList = mEffects; + + record = MWBase::Environment::get().getWorld()->createRecord (newRecord).second; + } + + MWWorld::ManualRef ref (MWBase::Environment::get().getWorld()->getStore(), record->mId); + MWWorld::Class::get (mAlchemist).getContainerStore (mAlchemist).add (ref.getPtr()); } void MWMechanics::Alchemy::increaseSkill() diff --git a/apps/openmw/mwmechanics/alchemy.hpp b/apps/openmw/mwmechanics/alchemy.hpp index 52af29912..7f3e2c0ea 100644 --- a/apps/openmw/mwmechanics/alchemy.hpp +++ b/apps/openmw/mwmechanics/alchemy.hpp @@ -43,6 +43,7 @@ namespace MWMechanics TToolsContainer mTools; TIngredientsContainer mIngredients; TEffectsContainer mEffects; + int mValue; std::set listEffects() const; ///< List all effects of all used ingredients. From 28cc480ce1d4175d54c1971d2449c0066c27d23a Mon Sep 17 00:00:00 2001 From: scrawl Date: Thu, 18 Oct 2012 22:21:39 +0200 Subject: [PATCH 13/15] fix some alchemy issues and make the gui use the new implementation --- apps/openmw/engine.cpp | 15 +- apps/openmw/mwgui/alchemywindow.cpp | 204 +++++----------------------- apps/openmw/mwgui/alchemywindow.hpp | 12 +- apps/openmw/mwgui/tooltips.cpp | 10 +- apps/openmw/mwmechanics/alchemy.cpp | 15 +- apps/openmw/mwworld/worldimp.cpp | 18 +-- 6 files changed, 58 insertions(+), 216 deletions(-) diff --git a/apps/openmw/engine.cpp b/apps/openmw/engine.cpp index adbfca129..3867cb76a 100644 --- a/apps/openmw/engine.cpp +++ b/apps/openmw/engine.cpp @@ -424,21 +424,10 @@ void OMW::Engine::activate() if (handle.empty()) return; - // the faced handle is not updated immediately, so on a cell change it might - // point to an object that doesn't exist anymore - // therefore, we are catching the "Unknown Ogre handle" exception that occurs in this case - MWWorld::Ptr ptr; - try - { - ptr = MWBase::Environment::get().getWorld()->getPtrViaHandle (handle); + MWWorld::Ptr ptr = MWBase::Environment::get().getWorld()->getPtrViaHandle (handle); - if (ptr.isEmpty()) - return; - } - catch (std::runtime_error&) - { + if (ptr.isEmpty()) return; - } MWScript::InterpreterContext interpreterContext (&ptr.getRefData().getLocals(), ptr); diff --git a/apps/openmw/mwgui/alchemywindow.cpp b/apps/openmw/mwgui/alchemywindow.cpp index cef5d6e2e..192bbd090 100644 --- a/apps/openmw/mwgui/alchemywindow.cpp +++ b/apps/openmw/mwgui/alchemywindow.cpp @@ -70,142 +70,44 @@ namespace MWGui void AlchemyWindow::onCreateButtonClicked(MyGUI::Widget* _sender) { + std::string name = mNameEdit->getCaption(); + boost::algorithm::trim(name); + + MWMechanics::Alchemy::Result result = mAlchemy.create (mNameEdit->getCaption ()); + + if (result == MWMechanics::Alchemy::Result_NoName) + { + mWindowManager.messageBox("#{sNotifyMessage37}", std::vector()); + return; + } + // check if mortar & pestle is available (always needed) - /// \todo check albemic, calcinator, retort (sometimes needed) - if (!mApparatus[0]->isUserString("ToolTipType")) + if (result == MWMechanics::Alchemy::Result_NoMortarAndPestle) { mWindowManager.messageBox("#{sNotifyMessage45}", std::vector()); return; } // make sure 2 or more ingredients were selected - int numIngreds = 0; - for (int i=0; i<4; ++i) - if (mIngredients[i]->isUserString("ToolTipType")) - ++numIngreds; - - if (numIngreds < 2) + if (result == MWMechanics::Alchemy::Result_LessThanTwoIngredients) { mWindowManager.messageBox("#{sNotifyMessage6a}", std::vector()); return; } - // make sure a name was entered - std::string name = mNameEdit->getCaption(); - boost::algorithm::trim(name); - if (name == "") - { - mWindowManager.messageBox("#{sNotifyMessage37}", std::vector()); - return; - } - - // if there are no created effects, the potion will always fail (but the ingredients won't be destroyed) - if (mEffects.empty()) + if (result == MWMechanics::Alchemy::Result_NoEffects) { mWindowManager.messageBox("#{sNotifyMessage8}", std::vector()); MWBase::Environment::get().getSoundManager()->playSound("potion fail", 1.f, 1.f); return; } - if (rand() % 2 == 0) /// \todo + if (result == MWMechanics::Alchemy::Result_Success) { - ESM::Potion newPotion; - newPotion.mName = mNameEdit->getCaption(); - ESM::EffectList effects; - for (unsigned int i=0; i<4; ++i) - { - if (mEffects.size() >= i+1) - { - ESM::ENAMstruct effect; - effect.mEffectID = mEffects[i].mEffectID; - effect.mArea = 0; - effect.mRange = ESM::RT_Self; - effect.mSkill = mEffects[i].mSkill; - effect.mAttribute = mEffects[i].mAttribute; - effect.mMagnMin = 1; /// \todo - effect.mMagnMax = 10; /// \todo - effect.mDuration = 60; /// \todo - effects.mList.push_back(effect); - } - } - - // UESP Wiki / Morrowind:Alchemy - // "The weight of a potion is an average of the weight of the ingredients, rounded down." - // note by scrawl: not rounding down here, I can't imagine a created potion to - // have 0 weight when using ingredients with 0.1 weight respectively - float weight = 0; - for (int i=0; i<4; ++i) - if (mIngredients[i]->isUserString("ToolTipType")) - weight += mIngredients[i]->getUserData()->get()->base->mData.mWeight; - newPotion.mData.mWeight = weight / float(numIngreds); - - newPotion.mData.mValue = 100; /// \todo - newPotion.mEffects = effects; - // pick a random mesh and icon - std::vector names; - /// \todo is the mesh/icon dependent on alchemy skill? - names.push_back("standard"); - names.push_back("bargain"); - names.push_back("cheap"); - names.push_back("fresh"); - names.push_back("exclusive"); - names.push_back("quality"); - int random = rand() % names.size(); - newPotion.mModel = "m\\misc_potion_" + names[random ] + "_01.nif"; - newPotion.mIcon = "m\\tx_potion_" + names[random ] + "_01.dds"; - - // check if a similiar potion record exists already - bool found = false; - std::string objectId; - typedef std::map PotionMap; - PotionMap potions = MWBase::Environment::get().getWorld()->getStore().potions.list; - for (PotionMap::const_iterator it = potions.begin(); it != potions.end(); ++it) - { - if (found) break; - - if (it->second.mData.mValue == newPotion.mData.mValue - && it->second.mData.mWeight == newPotion.mData.mWeight - && it->second.mName == newPotion.mName - && it->second.mEffects.mList.size() == newPotion.mEffects.mList.size()) - { - // check effects - for (unsigned int i=0; i < it->second.mEffects.mList.size(); ++i) - { - const ESM::ENAMstruct& a = it->second.mEffects.mList[i]; - const ESM::ENAMstruct& b = newPotion.mEffects.mList[i]; - if (a.mEffectID == b.mEffectID - && a.mArea == b.mArea - && a.mRange == b.mRange - && a.mSkill == b.mSkill - && a.mAttribute == b.mAttribute - && a.mMagnMin == b.mMagnMin - && a.mMagnMax == b.mMagnMax - && a.mDuration == b.mDuration) - { - found = true; - objectId = it->first; - break; - } - } - } - } - - if (!found) - { - std::pair result = MWBase::Environment::get().getWorld()->createRecord(newPotion); - objectId = result.first; - } - - // create a reference and add it to player inventory - MWWorld::ManualRef ref(MWBase::Environment::get().getWorld()->getStore(), objectId); - MWWorld::ContainerStore& store = MWWorld::Class::get(mPtr).getContainerStore(mPtr); - ref.getPtr().getRefData().setCount(1); - store.add(ref.getPtr()); - mWindowManager.messageBox("#{sPotionSuccess}", std::vector()); MWBase::Environment::get().getSoundManager()->playSound("potion success", 1.f, 1.f); } - else + else if (result == MWMechanics::Alchemy::Result_RandomFailure) { // potion failed mWindowManager.messageBox("#{sNotifyMessage8}", std::vector()); @@ -229,7 +131,7 @@ namespace MWGui { openContainer (MWBase::Environment::get().getWorld()->getPlayer().getPlayer()); // this sets mPtr setFilter (ContainerBase::Filter_Ingredients); - + mAlchemy.setAlchemist (mPtr); int index = 0; @@ -277,6 +179,9 @@ namespace MWGui if (!mIngredients[i]->isUserString("ToolTipType")) { add = mIngredients[i]; + + mAlchemy.addIngredient(item); + break; } @@ -306,8 +211,6 @@ namespace MWGui void AlchemyWindow::update() { - Widgets::SpellEffectList effects; - for (int i=0; i<4; ++i) { MyGUI::ImageBox* ingredient = mIngredients[i]; @@ -315,19 +218,6 @@ namespace MWGui if (!ingredient->isUserString("ToolTipType")) continue; - // add the effects of this ingredient to list of effects - MWWorld::LiveCellRef* ref = ingredient->getUserData()->get(); - for (int i=0; i<4; ++i) - { - if (ref->base->mData.mEffectID[i] < 0) - continue; - MWGui::Widgets::SpellEffectParams params; - params.mEffectID = ref->base->mData.mEffectID[i]; - params.mAttribute = ref->base->mData.mAttributes[i]; - params.mSkill = ref->base->mData.mSkills[i]; - effects.push_back(params); - } - // update ingredient count labels if (ingredient->getChildCount()) MyGUI::Gui::getInstance().destroyWidget(ingredient->getChildAt(0)); @@ -340,50 +230,14 @@ namespace MWGui text->setCaption(getCountString(ingredient->getUserData()->getRefData().getCount())); } - // now remove effects that are only present once - Widgets::SpellEffectList::iterator it = effects.begin(); - while (it != effects.end()) + std::vector effects; + ESM::EffectList list; + list.mList = effects; + for (MWMechanics::Alchemy::TEffectsIterator it = mAlchemy.beginEffects (); it != mAlchemy.endEffects (); ++it) { - Widgets::SpellEffectList::iterator next = it; - ++next; - bool found = false; - for (; next != effects.end(); ++next) - { - if (*next == *it) - found = true; - } - - if (!found) - it = effects.erase(it); - else - ++it; + list.mList.push_back(*it); } - // now remove duplicates, and don't allow more than 4 effects - Widgets::SpellEffectList old = effects; - effects.clear(); - int i=0; - for (Widgets::SpellEffectList::iterator it = old.begin(); - it != old.end(); ++it) - { - bool found = false; - for (Widgets::SpellEffectList::iterator it2 = effects.begin(); - it2 != effects.end(); ++it2) - { - // MW considers all "foritfy attribute" effects as the same effect. See the - // "Can't create multi-state boost potions" discussion on http://www.uesp.net/wiki/Morrowind_talk:Alchemy - // thus, we are only checking effectID here and not attribute or skill - if (it2->mEffectID == it->mEffectID) - found = true; - } - if (!found && i<4) - { - ++i; - effects.push_back(*it); - } - } - mEffects = effects; - while (mEffectsBox->getChildCount()) MyGUI::Gui::getInstance().destroyWidget(mEffectsBox->getChildAt(0)); @@ -391,7 +245,9 @@ namespace MWGui Widgets::MWEffectListPtr effectsWidget = mEffectsBox->createWidget ("MW_StatName", coord, MyGUI::Align::Left | MyGUI::Align::Top); effectsWidget->setWindowManager(&mWindowManager); - effectsWidget->setEffectList(effects); + + Widgets::SpellEffectList _list = Widgets::MWEffectList::effectListFromESM(&list); + effectsWidget->setEffectList(_list); std::vector effectItems; effectsWidget->createEffectWidgets(effectItems, mEffectsBox, coord, false, 0); @@ -404,5 +260,9 @@ namespace MWGui static_cast(ingredient)->setImageTexture(""); if (ingredient->getChildCount()) MyGUI::Gui::getInstance().destroyWidget(ingredient->getChildAt(0)); + + for (int i=0; i<4; ++i) + if (mIngredients[i] == ingredient) + mAlchemy.removeIngredient (i); } } diff --git a/apps/openmw/mwgui/alchemywindow.hpp b/apps/openmw/mwgui/alchemywindow.hpp index 179cdd174..5f84e73e9 100644 --- a/apps/openmw/mwgui/alchemywindow.hpp +++ b/apps/openmw/mwgui/alchemywindow.hpp @@ -26,8 +26,6 @@ namespace MWGui MyGUI::EditBox* mNameEdit; - Widgets::SpellEffectList mEffects; // effects of created potion - void onCancelButtonClicked(MyGUI::Widget* _sender); void onCreateButtonClicked(MyGUI::Widget* _sender); void onIngredientSelected(MyGUI::Widget* _sender); @@ -41,12 +39,12 @@ namespace MWGui void update(); - private: - - MWMechanics::Alchemy mAlchemy; + private: - std::vector mApparatus; - std::vector mIngredients; + MWMechanics::Alchemy mAlchemy; + + std::vector mApparatus; + std::vector mIngredients; }; } diff --git a/apps/openmw/mwgui/tooltips.cpp b/apps/openmw/mwgui/tooltips.cpp index 39afba749..5256028eb 100644 --- a/apps/openmw/mwgui/tooltips.cpp +++ b/apps/openmw/mwgui/tooltips.cpp @@ -79,14 +79,10 @@ void ToolTips::onFrame(float frameDuration) || (mWindowManager->getMode() == GM_Inventory))) { std::string handle = MWBase::Environment::get().getWorld()->getFacedHandle(); - try - { - mFocusObject = MWBase::Environment::get().getWorld()->getPtrViaHandle(handle); - } - catch (std::exception /* & e */) - { + + mFocusObject = MWBase::Environment::get().getWorld()->getPtrViaHandle(handle); + if (mFocusObject.isEmpty ()) return; - } MyGUI::IntSize tooltipSize = getToolTipViaPtr(true); diff --git a/apps/openmw/mwmechanics/alchemy.cpp b/apps/openmw/mwmechanics/alchemy.cpp index e37a30210..583a3c18e 100644 --- a/apps/openmw/mwmechanics/alchemy.cpp +++ b/apps/openmw/mwmechanics/alchemy.cpp @@ -62,6 +62,9 @@ void MWMechanics::Alchemy::filterEffects (std::set& effects) const { bool found = false; + if (iter->isEmpty()) + continue; + const MWWorld::LiveCellRef *ingredient = iter->get(); for (int i=0; i<4; ++i) @@ -178,7 +181,7 @@ void MWMechanics::Alchemy::updateEffects() throw std::runtime_error ("invalid base cost for magic effect " + iter->mId); float fPotionT1MagMul = - MWBase::Environment::get().getWorld()->getStore().gameSettings.find ("fPotionT1MagMul")->getFloat(); + MWBase::Environment::get().getWorld()->getStore().gameSettings.find ("fPotionT1MagMult")->getFloat(); if (fPotionT1MagMul<=0) throw std::runtime_error ("invalid gmst: fPotionT1MagMul"); @@ -189,15 +192,15 @@ void MWMechanics::Alchemy::updateEffects() if (fPotionT1DurMult<=0) throw std::runtime_error ("invalid gmst: fPotionT1DurMult"); - float magnitude = magicEffect->mData.mFlags && ESM::MagicEffect::NoMagnitude ? + float magnitude = magicEffect->mData.mFlags & ESM::MagicEffect::NoMagnitude ? 1 : (x / fPotionT1MagMul) / magicEffect->mData.mBaseCost; - float duration = magicEffect->mData.mFlags && ESM::MagicEffect::NoDuration ? + float duration = magicEffect->mData.mFlags & ESM::MagicEffect::NoDuration ? 1 : (x / fPotionT1DurMult) / magicEffect->mData.mBaseCost; - if (!(magicEffect->mData.mFlags && ESM::MagicEffect::NoMagnitude)) + if (!(magicEffect->mData.mFlags & ESM::MagicEffect::NoMagnitude)) applyTools (magicEffect->mData.mFlags, magnitude); - if (!(magicEffect->mData.mFlags && ESM::MagicEffect::NoDuration)) + if (!(magicEffect->mData.mFlags & ESM::MagicEffect::NoDuration)) applyTools (magicEffect->mData.mFlags, duration); duration = static_cast (duration+0.5); @@ -471,7 +474,7 @@ MWMechanics::Alchemy::Result MWMechanics::Alchemy::create (const std::string& na if (beginEffects()==endEffects()) return Result_NoEffects; - if (getChance() (RAND_MAX)*100) + if (getChance() (RAND_MAX)) { removeIngredients(); return Result_RandomFailure; diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index 6fc228f0b..8d8542bb5 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -339,7 +339,7 @@ namespace MWWorld return ptr; } - throw std::runtime_error ("unknown Ogre handle: " + handle); + return MWWorld::Ptr(); } void World::enable (const Ptr& reference) @@ -850,12 +850,13 @@ namespace MWWorld mWeatherManager->update (duration); // inform the GUI about focused object - try - { - MWWorld::Ptr object = getPtrViaHandle(mFacedHandle); - MWBase::Environment::get().getWindowManager()->setFocusObject(object); + MWWorld::Ptr object = getPtrViaHandle(mFacedHandle); - // retrieve object dimensions so we know where to place the floating label + MWBase::Environment::get().getWindowManager()->setFocusObject(object); + + // retrieve object dimensions so we know where to place the floating label + if (!object.isEmpty ()) + { Ogre::SceneNode* node = object.getRefData().getBaseNode(); Ogre::AxisAlignedBox bounds; int i; @@ -871,11 +872,6 @@ namespace MWWorld screenCoords[0], screenCoords[1], screenCoords[2], screenCoords[3]); } } - catch (std::runtime_error&) - { - MWWorld::Ptr null; - MWBase::Environment::get().getWindowManager()->setFocusObject(null); - } if (!mRendering->occlusionQuerySupported()) { From d76522e7a48ed83c659e782d81bfdbe44ca761a1 Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 19 Oct 2012 19:48:02 +0200 Subject: [PATCH 14/15] searchPtrViaHandle --- apps/openmw/engine.cpp | 2 +- apps/openmw/mwbase/world.hpp | 3 +++ apps/openmw/mwgui/hud.cpp | 10 +--------- apps/openmw/mwgui/tooltips.cpp | 2 +- apps/openmw/mwworld/worldimp.cpp | 10 +++++++++- apps/openmw/mwworld/worldimp.hpp | 3 +++ 6 files changed, 18 insertions(+), 12 deletions(-) diff --git a/apps/openmw/engine.cpp b/apps/openmw/engine.cpp index 3867cb76a..2ce890363 100644 --- a/apps/openmw/engine.cpp +++ b/apps/openmw/engine.cpp @@ -424,7 +424,7 @@ void OMW::Engine::activate() if (handle.empty()) return; - MWWorld::Ptr ptr = MWBase::Environment::get().getWorld()->getPtrViaHandle (handle); + MWWorld::Ptr ptr = MWBase::Environment::get().getWorld()->searchPtrViaHandle (handle); if (ptr.isEmpty()) return; diff --git a/apps/openmw/mwbase/world.hpp b/apps/openmw/mwbase/world.hpp index 521bbb988..9dcdc312f 100644 --- a/apps/openmw/mwbase/world.hpp +++ b/apps/openmw/mwbase/world.hpp @@ -142,6 +142,9 @@ namespace MWBase virtual MWWorld::Ptr getPtrViaHandle (const std::string& handle) = 0; ///< Return a pointer to a liveCellRef with the given Ogre handle. + virtual MWWorld::Ptr searchPtrViaHandle (const std::string& handle) = 0; + ///< Return a pointer to a liveCellRef with the given Ogre handle or Ptr() if not found + /// \todo enable reference in the OGRE scene virtual void enable (const MWWorld::Ptr& ptr) = 0; diff --git a/apps/openmw/mwgui/hud.cpp b/apps/openmw/mwgui/hud.cpp index ed0e59226..66cc6b21a 100644 --- a/apps/openmw/mwgui/hud.cpp +++ b/apps/openmw/mwgui/hud.cpp @@ -245,15 +245,7 @@ void HUD::onWorldClicked(MyGUI::Widget* _sender) return; std::string handle = MWBase::Environment::get().getWorld()->getFacedHandle(); - MWWorld::Ptr object; - try - { - object = MWBase::Environment::get().getWorld()->getPtrViaHandle(handle); - } - catch (std::exception& /* e */) - { - return; - } + MWWorld::Ptr object = MWBase::Environment::get().getWorld()->searchPtrViaHandle(handle); if (mode == GM_Console) MWBase::Environment::get().getWindowManager()->getConsole()->setSelectedObject(object); diff --git a/apps/openmw/mwgui/tooltips.cpp b/apps/openmw/mwgui/tooltips.cpp index 5256028eb..35224613c 100644 --- a/apps/openmw/mwgui/tooltips.cpp +++ b/apps/openmw/mwgui/tooltips.cpp @@ -80,7 +80,7 @@ void ToolTips::onFrame(float frameDuration) { std::string handle = MWBase::Environment::get().getWorld()->getFacedHandle(); - mFocusObject = MWBase::Environment::get().getWorld()->getPtrViaHandle(handle); + mFocusObject = MWBase::Environment::get().getWorld()->searchPtrViaHandle(handle); if (mFocusObject.isEmpty ()) return; diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index 8d8542bb5..2e3d80aa4 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -326,6 +326,14 @@ namespace MWWorld } Ptr World::getPtrViaHandle (const std::string& handle) + { + Ptr res = searchPtrViaHandle (handle); + if (res.isEmpty ()) + throw std::runtime_error ("unknown Ogre handle: " + handle); + return res; + } + + Ptr World::searchPtrViaHandle (const std::string& handle) { if (mPlayer->getPlayer().getRefData().getHandle()==handle) return mPlayer->getPlayer(); @@ -850,7 +858,7 @@ namespace MWWorld mWeatherManager->update (duration); // inform the GUI about focused object - MWWorld::Ptr object = getPtrViaHandle(mFacedHandle); + MWWorld::Ptr object = searchPtrViaHandle(mFacedHandle); MWBase::Environment::get().getWindowManager()->setFocusObject(object); diff --git a/apps/openmw/mwworld/worldimp.hpp b/apps/openmw/mwworld/worldimp.hpp index 90cd2151b..f94882c10 100644 --- a/apps/openmw/mwworld/worldimp.hpp +++ b/apps/openmw/mwworld/worldimp.hpp @@ -163,6 +163,9 @@ namespace MWWorld virtual Ptr getPtrViaHandle (const std::string& handle); ///< Return a pointer to a liveCellRef with the given Ogre handle. + virtual Ptr searchPtrViaHandle (const std::string& handle); + ///< Return a pointer to a liveCellRef with the given Ogre handle or Ptr() if not found + virtual void enable (const Ptr& ptr); virtual void disable (const Ptr& ptr); From 8d7514e341f4cd2c554507ea8c6c64772fec9714 Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 19 Oct 2012 19:48:54 +0200 Subject: [PATCH 15/15] corrected chance --- apps/openmw/mwmechanics/alchemy.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/openmw/mwmechanics/alchemy.cpp b/apps/openmw/mwmechanics/alchemy.cpp index 583a3c18e..df7c786b1 100644 --- a/apps/openmw/mwmechanics/alchemy.cpp +++ b/apps/openmw/mwmechanics/alchemy.cpp @@ -474,7 +474,7 @@ MWMechanics::Alchemy::Result MWMechanics::Alchemy::create (const std::string& na if (beginEffects()==endEffects()) return Result_NoEffects; - if (getChance() (RAND_MAX)) + if (getChance() (RAND_MAX)*100) { removeIngredients(); return Result_RandomFailure;