From cab535dd6918c08d60ab3350e769865d88a25585 Mon Sep 17 00:00:00 2001 From: scrawl Date: Tue, 19 Nov 2013 06:48:47 +0100 Subject: [PATCH] Implement magic item recharging via soulgem use --- apps/openmw/CMakeLists.txt | 1 + apps/openmw/mwbase/windowmanager.hpp | 1 + apps/openmw/mwgui/mode.hpp | 1 + apps/openmw/mwgui/recharge.cpp | 194 ++++++++++++++++++++++ apps/openmw/mwgui/recharge.hpp | 42 +++++ apps/openmw/mwgui/soulgemdialog.cpp | 3 +- apps/openmw/mwgui/windowmanagerimp.cpp | 13 ++ apps/openmw/mwgui/windowmanagerimp.hpp | 3 + files/mygui/CMakeLists.txt | 1 + files/mygui/openmw_recharge_dialog.layout | 29 ++++ 10 files changed, 287 insertions(+), 1 deletion(-) create mode 100644 apps/openmw/mwgui/recharge.cpp create mode 100644 apps/openmw/mwgui/recharge.hpp create mode 100644 files/mygui/openmw_recharge_dialog.layout diff --git a/apps/openmw/CMakeLists.txt b/apps/openmw/CMakeLists.txt index a36c179968..576b28ea1a 100644 --- a/apps/openmw/CMakeLists.txt +++ b/apps/openmw/CMakeLists.txt @@ -36,6 +36,7 @@ add_openmw_dir (mwgui merchantrepair repair soulgemdialog companionwindow bookpage journalviewmodel journalbooks keywordsearch itemmodel containeritemmodel inventoryitemmodel sortfilteritemmodel itemview tradeitemmodel companionitemmodel pickpocketitemmodel fontloader controllers savegamedialog + recharge ) add_openmw_dir (mwdialogue diff --git a/apps/openmw/mwbase/windowmanager.hpp b/apps/openmw/mwbase/windowmanager.hpp index 1cd8672230..c6864de369 100644 --- a/apps/openmw/mwbase/windowmanager.hpp +++ b/apps/openmw/mwbase/windowmanager.hpp @@ -265,6 +265,7 @@ namespace MWBase virtual void showCompanionWindow(MWWorld::Ptr actor) = 0; virtual void startSpellMaking(MWWorld::Ptr actor) = 0; virtual void startEnchanting(MWWorld::Ptr actor) = 0; + virtual void startRecharge(MWWorld::Ptr soulgem) = 0; virtual void startSelfEnchanting(MWWorld::Ptr soulgem) = 0; virtual void startTraining(MWWorld::Ptr actor) = 0; virtual void startRepair(MWWorld::Ptr actor) = 0; diff --git a/apps/openmw/mwgui/mode.hpp b/apps/openmw/mwgui/mode.hpp index 879fcb483f..50d53abacd 100644 --- a/apps/openmw/mwgui/mode.hpp +++ b/apps/openmw/mwgui/mode.hpp @@ -28,6 +28,7 @@ namespace MWGui GM_Travel, GM_SpellCreation, GM_Enchanting, + GM_Recharge, GM_Training, GM_MerchantRepair, diff --git a/apps/openmw/mwgui/recharge.cpp b/apps/openmw/mwgui/recharge.cpp new file mode 100644 index 0000000000..7af9fbcfb9 --- /dev/null +++ b/apps/openmw/mwgui/recharge.cpp @@ -0,0 +1,194 @@ +#include "recharge.hpp" + +#include +#include + +#include "../mwbase/world.hpp" +#include "../mwbase/environment.hpp" +#include "../mwbase/windowmanager.hpp" + +#include "../mwworld/player.hpp" +#include "../mwworld/containerstore.hpp" +#include "../mwworld/class.hpp" + +#include "../mwmechanics/creaturestats.hpp" +#include "../mwmechanics/npcstats.hpp" + +#include "widgets.hpp" + +namespace MWGui +{ + +Recharge::Recharge() + : WindowBase("openmw_recharge_dialog.layout") +{ + getWidget(mBox, "Box"); + getWidget(mView, "View"); + getWidget(mGemBox, "GemBox"); + getWidget(mGemIcon, "GemIcon"); + getWidget(mChargeLabel, "ChargeLabel"); + getWidget(mCancelButton, "CancelButton"); + + mCancelButton->eventMouseButtonClick += MyGUI::newDelegate(this, &Recharge::onCancel); + + setVisible(false); +} + +void Recharge::open() +{ + center(); +} + +void Recharge::start (const MWWorld::Ptr &item) +{ + std::string path = std::string("icons\\"); + path += MWWorld::Class::get(item).getInventoryIcon(item); + int pos = path.rfind("."); + path.erase(pos); + path.append(".dds"); + mGemIcon->setImageTexture (path); + mGemIcon->setUserString("ToolTipType", "ItemPtr"); + mGemIcon->setUserData(item); + + updateView(); +} + +void Recharge::updateView() +{ + MWWorld::Ptr gem = *mGemIcon->getUserData(); + + std::string soul = gem.getCellRef().mSoul; + const ESM::Creature *creature = MWBase::Environment::get().getWorld()->getStore().get().find(soul); + + mChargeLabel->setCaptionWithReplacing("#{sCharges} " + boost::lexical_cast(creature->mData.mSoul)); + + bool toolBoxVisible = (gem.getRefData().getCount() != 0); + mGemBox->setVisible(toolBoxVisible); + + bool toolBoxWasVisible = (mBox->getPosition().top != mGemBox->getPosition().top); + + if (toolBoxVisible && !toolBoxWasVisible) + { + // shrink + mBox->setPosition(mBox->getPosition() + MyGUI::IntPoint(0, mGemBox->getSize().height)); + mBox->setSize(mBox->getSize() - MyGUI::IntSize(0,mGemBox->getSize().height)); + } + else if (!toolBoxVisible && toolBoxWasVisible) + { + // expand + mBox->setPosition(MyGUI::IntPoint (mBox->getPosition().left, mGemBox->getPosition().top)); + mBox->setSize(mBox->getSize() + MyGUI::IntSize(0,mGemBox->getSize().height)); + } + + while (mView->getChildCount()) + MyGUI::Gui::getInstance().destroyWidget(mView->getChildAt(0)); + + int currentY = 0; + + MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayer().getPlayer(); + MWWorld::ContainerStore& store = MWWorld::Class::get(player).getContainerStore(player); + for (MWWorld::ContainerStoreIterator iter (store.begin()); + iter!=store.end(); ++iter) + { + std::string enchantmentName = iter->getClass().getEnchantment(*iter); + if (enchantmentName.empty()) + continue; + const ESM::Enchantment* enchantment = MWBase::Environment::get().getWorld()->getStore().get().find(enchantmentName); + if (iter->getCellRef().mEnchantmentCharge >= enchantment->mData.mCharge + || iter->getCellRef().mEnchantmentCharge == -1) + continue; + + MyGUI::TextBox* text = mView->createWidget ( + "SandText", MyGUI::IntCoord(8, currentY, mView->getWidth()-8, 18), MyGUI::Align::Default); + text->setCaption(MWWorld::Class::get(*iter).getName(*iter)); + text->setNeedMouseFocus(false); + currentY += 19; + + MyGUI::ImageBox* icon = mView->createWidget ( + "ImageBox", MyGUI::IntCoord(16, currentY, 32, 32), MyGUI::Align::Default); + std::string path = std::string("icons\\"); + path += MWWorld::Class::get(*iter).getInventoryIcon(*iter); + int pos = path.rfind("."); + path.erase(pos); + path.append(".dds"); + icon->setImageTexture (path); + icon->setUserString("ToolTipType", "ItemPtr"); + icon->setUserData(*iter); + icon->eventMouseButtonClick += MyGUI::newDelegate(this, &Recharge::onItemClicked); + icon->eventMouseWheel += MyGUI::newDelegate(this, &Recharge::onMouseWheel); + + Widgets::MWDynamicStatPtr chargeWidget = mView->createWidget + ("MW_ChargeBar", MyGUI::IntCoord(72, currentY+2, 199, 20), MyGUI::Align::Default); + chargeWidget->setValue(iter->getCellRef().mEnchantmentCharge, enchantment->mData.mCharge); + chargeWidget->setNeedMouseFocus(false); + + currentY += 32 + 4; + } + mView->setCanvasSize (MyGUI::IntSize(mView->getWidth(), std::max(mView->getHeight(), currentY))); +} + +void Recharge::onCancel(MyGUI::Widget *sender) +{ + MWBase::Environment::get().getWindowManager()->removeGuiMode(GM_Recharge); +} + +void Recharge::onItemClicked(MyGUI::Widget *sender) +{ + MWWorld::Ptr gem = *mGemIcon->getUserData(); + + if (!gem.getRefData().getCount()) + return; + + MWWorld::Ptr item = *sender->getUserData(); + + MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayer().getPlayer(); + MWMechanics::CreatureStats& stats = player.getClass().getCreatureStats(player); + MWMechanics::NpcStats& npcStats = player.getClass().getNpcStats(player); + + float luckTerm = 0.1 * stats.getAttribute(ESM::Attribute::Luck).getModified(); + if (luckTerm < 1|| luckTerm > 10) + luckTerm = 1; + + float intelligenceTerm = 0.2 * stats.getAttribute(ESM::Attribute::Intelligence).getModified(); + + if (intelligenceTerm > 20) + intelligenceTerm = 20; + if (intelligenceTerm < 1) + intelligenceTerm = 1; + + float x = (npcStats.getSkill(ESM::Skill::Enchant).getModified() + intelligenceTerm + luckTerm) * stats.getFatigueTerm(); + int roll = std::rand()/ (static_cast (RAND_MAX) + 1) * 100; // [0, 99] + if (roll < x) + { + std::string soul = gem.getCellRef().mSoul; + const ESM::Creature *creature = MWBase::Environment::get().getWorld()->getStore().get().find(soul); + + float restored = creature->mData.mSoul * (roll / x); + + const ESM::Enchantment* enchantment = MWBase::Environment::get().getWorld()->getStore().get().find( + item.getClass().getEnchantment(item)); + item.getCellRef().mEnchantmentCharge = + std::min(item.getCellRef().mEnchantmentCharge + restored, static_cast(enchantment->mData.mCharge)); + } + + gem.getContainerStore()->remove(gem, 1, player); + + if (gem.getRefData().getCount() == 0) + { + std::string message = MWBase::Environment::get().getWorld()->getStore().get().find("sNotifyMessage51")->getString(); + message = boost::str(boost::format(message) % gem.getClass().getName(gem)); + MWBase::Environment::get().getWindowManager()->messageBox(message); + } + + updateView(); +} + +void Recharge::onMouseWheel(MyGUI::Widget* _sender, int _rel) +{ + if (mView->getViewOffset().top + _rel*0.3 > 0) + mView->setViewOffset(MyGUI::IntPoint(0, 0)); + else + mView->setViewOffset(MyGUI::IntPoint(0, mView->getViewOffset().top + _rel*0.3)); +} + +} diff --git a/apps/openmw/mwgui/recharge.hpp b/apps/openmw/mwgui/recharge.hpp new file mode 100644 index 0000000000..2ffc5e10f8 --- /dev/null +++ b/apps/openmw/mwgui/recharge.hpp @@ -0,0 +1,42 @@ +#ifndef OPENMW_MWGUI_RECHARGE_H +#define OPENMW_MWGUI_RECHARGE_H + +#include "windowbase.hpp" + +#include "../mwworld/ptr.hpp" + +namespace MWGui +{ + +class Recharge : public WindowBase +{ +public: + Recharge(); + + virtual void open(); + + void start (const MWWorld::Ptr& gem); + +protected: + MyGUI::Widget* mBox; + MyGUI::ScrollView* mView; + + MyGUI::Widget* mGemBox; + + MyGUI::ImageBox* mGemIcon; + + MyGUI::TextBox* mChargeLabel; + + MyGUI::Button* mCancelButton; + + void updateView(); + + void onItemClicked (MyGUI::Widget* sender); + void onCancel (MyGUI::Widget* sender); + void onMouseWheel(MyGUI::Widget* _sender, int _rel); + +}; + +} + +#endif diff --git a/apps/openmw/mwgui/soulgemdialog.cpp b/apps/openmw/mwgui/soulgemdialog.cpp index b95eec0b67..6d70c85d9d 100644 --- a/apps/openmw/mwgui/soulgemdialog.cpp +++ b/apps/openmw/mwgui/soulgemdialog.cpp @@ -21,7 +21,8 @@ namespace MWGui { if (button == 0) { - /// \todo show recharge enchanted item dialog here + MWBase::Environment::get().getWindowManager()->pushGuiMode(GM_Recharge); + MWBase::Environment::get().getWindowManager()->startRecharge(mSoulgem); } else { diff --git a/apps/openmw/mwgui/windowmanagerimp.cpp b/apps/openmw/mwgui/windowmanagerimp.cpp index 83325de23a..b77d1a885b 100644 --- a/apps/openmw/mwgui/windowmanagerimp.cpp +++ b/apps/openmw/mwgui/windowmanagerimp.cpp @@ -43,6 +43,7 @@ #include "waitdialog.hpp" #include "enchantingdialog.hpp" #include "trainingwindow.hpp" +#include "recharge.hpp" #include "exposedwindow.hpp" #include "cursor.hpp" #include "merchantrepair.hpp" @@ -95,6 +96,7 @@ namespace MWGui , mTrainingWindow(NULL) , mMerchantRepair(NULL) , mSoulgemDialog(NULL) + , mRecharge(NULL) , mRepair(NULL) , mCompanionWindow(NULL) , mTranslationDataStorage (translationDataStorage) @@ -197,6 +199,7 @@ namespace MWGui mDragAndDrop->mDraggedWidget = 0; mDragAndDrop->mDragAndDropWidget = dragAndDropWidget; + mRecharge = new Recharge(); mMenu = new MainMenu(w,h); mMap = new MapWindow(""); mStatsWindow = new StatsWindow(); @@ -312,6 +315,7 @@ namespace MWGui delete mSoulgemDialog; delete mSoftwareCursor; delete mCursorManager; + delete mRecharge; cleanupGarbage(); @@ -375,6 +379,7 @@ namespace MWGui mRepair->setVisible(false); mCompanionWindow->setVisible(false); mInventoryWindow->setTrading(false); + mRecharge->setVisible(false); mHud->setVisible(mHudEnabled); @@ -492,6 +497,9 @@ namespace MWGui case GM_SpellCreation: mSpellCreationDialog->setVisible(true); break; + case GM_Recharge: + mRecharge->setVisible(true); + break; case GM_Enchanting: mEnchantingDialog->setVisible(true); break; @@ -1363,4 +1371,9 @@ namespace MWGui return mLoadingScreen; } + void WindowManager::startRecharge(MWWorld::Ptr soulgem) + { + mRecharge->start(soulgem); + } + } diff --git a/apps/openmw/mwgui/windowmanagerimp.hpp b/apps/openmw/mwgui/windowmanagerimp.hpp index badb333a7f..965c7d6382 100644 --- a/apps/openmw/mwgui/windowmanagerimp.hpp +++ b/apps/openmw/mwgui/windowmanagerimp.hpp @@ -77,6 +77,7 @@ namespace MWGui class MerchantRepair; class Repair; class SoulgemDialog; + class Recharge; class CompanionWindow; class WindowManager : public MWBase::WindowManager @@ -263,6 +264,7 @@ namespace MWGui virtual void startTraining(MWWorld::Ptr actor); virtual void startRepair(MWWorld::Ptr actor); virtual void startRepairItem(MWWorld::Ptr item); + virtual void startRecharge(MWWorld::Ptr soulgem); virtual void frameStarted(float dt); @@ -313,6 +315,7 @@ namespace MWGui MerchantRepair* mMerchantRepair; SoulgemDialog* mSoulgemDialog; Repair* mRepair; + Recharge* mRecharge; CompanionWindow* mCompanionWindow; Translation::Storage& mTranslationDataStorage; diff --git a/files/mygui/CMakeLists.txt b/files/mygui/CMakeLists.txt index f79f2c3ed6..70fdf42489 100644 --- a/files/mygui/CMakeLists.txt +++ b/files/mygui/CMakeLists.txt @@ -81,6 +81,7 @@ set(MYGUI_FILES openmw_repair.layout openmw_companion_window.layout openmw_savegame_dialog.layout + openmw_recharge_dialog.layout smallbars.png DejaVuLGCSansMono.ttf markers.png diff --git a/files/mygui/openmw_recharge_dialog.layout b/files/mygui/openmw_recharge_dialog.layout new file mode 100644 index 0000000000..49e7357645 --- /dev/null +++ b/files/mygui/openmw_recharge_dialog.layout @@ -0,0 +1,29 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +