From 6902569d035bf87afd8b0336f9c2486b3e9ff9d4 Mon Sep 17 00:00:00 2001 From: scrawl Date: Mon, 18 Nov 2013 04:57:54 +0100 Subject: [PATCH 1/6] Implement Absorb effects (AbsorbHealth, etc) --- apps/openmw/mwmechanics/actors.cpp | 9 ++++++--- apps/openmw/mwmechanics/spellcasting.cpp | 16 +++++++++++++++- 2 files changed, 21 insertions(+), 4 deletions(-) diff --git a/apps/openmw/mwmechanics/actors.cpp b/apps/openmw/mwmechanics/actors.cpp index 6d31a810aa..6c559f0946 100644 --- a/apps/openmw/mwmechanics/actors.cpp +++ b/apps/openmw/mwmechanics/actors.cpp @@ -155,7 +155,8 @@ namespace MWMechanics { Stat stat = creatureStats.getAttribute(i); stat.setModifier(effects.get(EffectKey(ESM::MagicEffect::FortifyAttribute, i)).mMagnitude - - effects.get(EffectKey(ESM::MagicEffect::DrainAttribute, i)).mMagnitude); + effects.get(EffectKey(ESM::MagicEffect::DrainAttribute, i)).mMagnitude - + effects.get(EffectKey(ESM::MagicEffect::AbsorbAttribute, i)).mMagnitude); creatureStats.setAttribute(i, stat); } @@ -168,7 +169,8 @@ namespace MWMechanics effects.get(EffectKey(ESM::MagicEffect::DrainHealth+i)).mMagnitude); float currentDiff = creatureStats.getMagicEffects().get(EffectKey(ESM::MagicEffect::RestoreHealth+i)).mMagnitude - - creatureStats.getMagicEffects().get(EffectKey(ESM::MagicEffect::DamageHealth+i)).mMagnitude; + - creatureStats.getMagicEffects().get(EffectKey(ESM::MagicEffect::DamageHealth+i)).mMagnitude + - creatureStats.getMagicEffects().get(EffectKey(ESM::MagicEffect::AbsorbHealth)).mMagnitude; stat.setCurrent(stat.getCurrent() + currentDiff * duration); creatureStats.setDynamic(i, stat); @@ -198,7 +200,8 @@ namespace MWMechanics { Stat& skill = npcStats.getSkill(i); skill.setModifier(effects.get(EffectKey(ESM::MagicEffect::FortifySkill, i)).mMagnitude - - effects.get(EffectKey(ESM::MagicEffect::DrainSkill, i)).mMagnitude); + effects.get(EffectKey(ESM::MagicEffect::DrainSkill, i)).mMagnitude - + effects.get(EffectKey(ESM::MagicEffect::AbsorbSkill, i)).mMagnitude); } } diff --git a/apps/openmw/mwmechanics/spellcasting.cpp b/apps/openmw/mwmechanics/spellcasting.cpp index 1498a34aac..5763549cf5 100644 --- a/apps/openmw/mwmechanics/spellcasting.cpp +++ b/apps/openmw/mwmechanics/spellcasting.cpp @@ -116,7 +116,7 @@ namespace MWMechanics { float random = std::rand() / static_cast(RAND_MAX); float magnitude = effectIt->mMagnMin + (effectIt->mMagnMax - effectIt->mMagnMin) * random; - magnitude *= magnitudeMult; + magnitude *= magnitudeMult; if (target.getClass().isActor() && !(magicEffect->mData.mFlags & ESM::MagicEffect::NoDuration)) { @@ -126,6 +126,20 @@ namespace MWMechanics effect.mMagnitude = magnitude; appliedLastingEffects.push_back(effect); + + // For absorb effects, also apply the effect to the caster - but with a negative + // magnitude, since we're transfering stats from the target to the caster + for (int i=0; i<5; ++i) + { + if (effectIt->mEffectID == ESM::MagicEffect::AbsorbAttribute+i) + { + std::vector effects; + ActiveSpells::Effect effect_ = effect; + effect_.mMagnitude *= -1; + effects.push_back(effect_); + caster.getClass().getCreatureStats(caster).getActiveSpells().addSpell("", true, effects, mSourceName); + } + } } else applyInstantEffect(mTarget, effectIt->mEffectID, magnitude); From 16e5477c60b9e724fc758432eea915136caf511a Mon Sep 17 00:00:00 2001 From: scrawl Date: Tue, 19 Nov 2013 02:17:44 +0100 Subject: [PATCH 2/6] Fix an uninitalized member --- apps/openmw/mwgui/mapwindow.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/apps/openmw/mwgui/mapwindow.cpp b/apps/openmw/mwgui/mapwindow.cpp index 5ed002d7b3..93e1d11a3d 100644 --- a/apps/openmw/mwgui/mapwindow.cpp +++ b/apps/openmw/mwgui/mapwindow.cpp @@ -261,6 +261,7 @@ namespace MWGui : MWGui::WindowPinnableBase("openmw_map_window.layout") , mGlobal(false) , mGlobalMap(0) + , mGlobalMapRender(0) { setCoord(500,0,320,300); From cab535dd6918c08d60ab3350e769865d88a25585 Mon Sep 17 00:00:00 2001 From: scrawl Date: Tue, 19 Nov 2013 06:48:47 +0100 Subject: [PATCH 3/6] 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 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + From 74e42a2d02d1a1e37df1a2aeccacae7c77ac70de Mon Sep 17 00:00:00 2001 From: scrawl Date: Tue, 19 Nov 2013 06:55:53 +0100 Subject: [PATCH 4/6] Add missing skill increases for Enchant skill --- apps/openmw/mwclass/npc.cpp | 3 +++ apps/openmw/mwgui/recharge.cpp | 2 ++ apps/openmw/mwmechanics/enchanting.cpp | 2 +- apps/openmw/mwmechanics/spellcasting.cpp | 3 +++ 4 files changed, 9 insertions(+), 1 deletion(-) diff --git a/apps/openmw/mwclass/npc.cpp b/apps/openmw/mwclass/npc.cpp index 5c67f17afb..e9182d0941 100644 --- a/apps/openmw/mwclass/npc.cpp +++ b/apps/openmw/mwclass/npc.cpp @@ -471,6 +471,9 @@ namespace MWClass MWMechanics::CastSpell cast(ptr, victim); cast.cast(weapon); + + if (ptr.getRefData().getHandle() == "player") + skillUsageSucceeded (ptr, ESM::Skill::Enchant, 3); } } } diff --git a/apps/openmw/mwgui/recharge.cpp b/apps/openmw/mwgui/recharge.cpp index 7af9fbcfb9..b700360bac 100644 --- a/apps/openmw/mwgui/recharge.cpp +++ b/apps/openmw/mwgui/recharge.cpp @@ -169,6 +169,8 @@ void Recharge::onItemClicked(MyGUI::Widget *sender) item.getClass().getEnchantment(item)); item.getCellRef().mEnchantmentCharge = std::min(item.getCellRef().mEnchantmentCharge + restored, static_cast(enchantment->mData.mCharge)); + + player.getClass().skillUsageSucceeded (player, ESM::Skill::Enchant, 0); } gem.getContainerStore()->remove(gem, 1, player); diff --git a/apps/openmw/mwmechanics/enchanting.cpp b/apps/openmw/mwmechanics/enchanting.cpp index 5d148d1106..ba53a1a725 100644 --- a/apps/openmw/mwmechanics/enchanting.cpp +++ b/apps/openmw/mwmechanics/enchanting.cpp @@ -72,7 +72,7 @@ namespace MWMechanics if(getEnchantChance() (RAND_MAX)*100) return false; - MWWorld::Class::get (mEnchanter).skillUsageSucceeded (mEnchanter, ESM::Skill::Enchant, 1); + MWWorld::Class::get (mEnchanter).skillUsageSucceeded (mEnchanter, ESM::Skill::Enchant, 2); } if(mCastStyle==ESM::Enchantment::ConstantEffect) diff --git a/apps/openmw/mwmechanics/spellcasting.cpp b/apps/openmw/mwmechanics/spellcasting.cpp index 5763549cf5..f733472063 100644 --- a/apps/openmw/mwmechanics/spellcasting.cpp +++ b/apps/openmw/mwmechanics/spellcasting.cpp @@ -303,6 +303,9 @@ namespace MWMechanics MWBase::Environment::get().getWindowManager()->setSelectedEnchantItem(item); // Set again to show the modified charge } + if (mCaster.getRefData().getHandle() == "player") + mCaster.getClass().skillUsageSucceeded (mCaster, ESM::Skill::Enchant, 1); + inflict(mCaster, mCaster, enchantment->mEffects, ESM::RT_Self); if (!mTarget.isEmpty()) From e8dcd747416eacd5e098609b2bf6f9c598ec9584 Mon Sep 17 00:00:00 2001 From: scrawl Date: Tue, 19 Nov 2013 16:42:24 +0100 Subject: [PATCH 5/6] Recharge enchanted items in player's inventory over time --- apps/openmw/mwbase/mechanicsmanager.hpp | 2 ++ .../mwmechanics/mechanicsmanagerimp.cpp | 8 +++++ .../mwmechanics/mechanicsmanagerimp.hpp | 2 ++ apps/openmw/mwworld/inventorystore.cpp | 36 +++++++++++++++++++ apps/openmw/mwworld/inventorystore.hpp | 8 +++++ apps/openmw/mwworld/worldimp.cpp | 2 ++ 6 files changed, 58 insertions(+) diff --git a/apps/openmw/mwbase/mechanicsmanager.hpp b/apps/openmw/mwbase/mechanicsmanager.hpp index 24dc569d8c..c8db203252 100644 --- a/apps/openmw/mwbase/mechanicsmanager.hpp +++ b/apps/openmw/mwbase/mechanicsmanager.hpp @@ -59,6 +59,8 @@ namespace MWBase /// \param paused In game type does not currently advance (this usually means some GUI /// component is up). + virtual void advanceTime (float duration) = 0; + virtual void setPlayerName (const std::string& name) = 0; ///< Set player name. diff --git a/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp b/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp index e1a7ac1231..8ae413b0a5 100644 --- a/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp +++ b/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp @@ -213,6 +213,14 @@ namespace MWMechanics mWatched = ptr; } + void MechanicsManager::advanceTime (float duration) + { + // Uses ingame time, but scaled to real time + duration /= MWBase::Environment::get().getWorld()->getTimeScaleFactor(); + MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayer().getPlayer(); + player.getClass().getInventoryStore(player).rechargeItems(duration); + } + void MechanicsManager::update(float duration, bool paused) { if(!mWatched.isEmpty()) diff --git a/apps/openmw/mwmechanics/mechanicsmanagerimp.hpp b/apps/openmw/mwmechanics/mechanicsmanagerimp.hpp index 42656d5abc..57309a6f09 100644 --- a/apps/openmw/mwmechanics/mechanicsmanagerimp.hpp +++ b/apps/openmw/mwmechanics/mechanicsmanagerimp.hpp @@ -63,6 +63,8 @@ namespace MWMechanics /// \param paused In game type does not currently advance (this usually means some GUI /// component is up). + virtual void advanceTime (float duration); + virtual void setPlayerName (const std::string& name); ///< Set player name. diff --git a/apps/openmw/mwworld/inventorystore.cpp b/apps/openmw/mwworld/inventorystore.cpp index 6483b32b2e..349c664c3f 100644 --- a/apps/openmw/mwworld/inventorystore.cpp +++ b/apps/openmw/mwworld/inventorystore.cpp @@ -88,6 +88,8 @@ MWWorld::ContainerStoreIterator MWWorld::InventoryStore::add(const Ptr& itemPtr, autoEquip(actorPtr); } + updateRechargingItems(); + return retVal; } @@ -459,6 +461,8 @@ int MWWorld::InventoryStore::remove(const Ptr& item, int count, const Ptr& actor MWBase::Environment::get().getWindowManager()->unsetSelectedSpell(); } + updateRechargingItems(); + return retCount; } @@ -577,3 +581,35 @@ void MWWorld::InventoryStore::visitEffectSources(MWMechanics::EffectSourceVisito } } } + +void MWWorld::InventoryStore::updateRechargingItems() +{ + mRechargingItems.clear(); + for (ContainerStoreIterator it = begin(); it != end(); ++it) + { + if (it->getClass().getEnchantment(*it) != "") + { + const ESM::Enchantment* enchantment = MWBase::Environment::get().getWorld()->getStore().get().find( + it->getClass().getEnchantment(*it)); + if (enchantment->mData.mType == ESM::Enchantment::WhenUsed + || enchantment->mData.mType == ESM::Enchantment::WhenStrikes) + mRechargingItems.push_back(std::make_pair(it, enchantment->mData.mCharge)); + } + } +} + +void MWWorld::InventoryStore::rechargeItems(float duration) +{ + for (TRechargingItems::iterator it = mRechargingItems.begin(); it != mRechargingItems.end(); ++it) + { + if (it->first->getCellRef().mEnchantmentCharge == -1 + || it->first->getCellRef().mEnchantmentCharge == it->second) + continue; + + static float fMagicItemRechargePerSecond = MWBase::Environment::get().getWorld()->getStore().get().find( + "fMagicItemRechargePerSecond")->getFloat(); + + it->first->getCellRef().mEnchantmentCharge = std::min (it->first->getCellRef().mEnchantmentCharge + fMagicItemRechargePerSecond * duration, + it->second); + } +} diff --git a/apps/openmw/mwworld/inventorystore.hpp b/apps/openmw/mwworld/inventorystore.hpp index f53ce8efb9..58ff50ead0 100644 --- a/apps/openmw/mwworld/inventorystore.hpp +++ b/apps/openmw/mwworld/inventorystore.hpp @@ -92,11 +92,16 @@ namespace MWWorld // selected magic item (for using enchantments of type "Cast once" or "Cast when used") ContainerStoreIterator mSelectedEnchantItem; + // (item, max charge) + typedef std::vector > TRechargingItems; + TRechargingItems mRechargingItems; + void copySlots (const InventoryStore& store); void initSlots (TSlots& slots_); void updateMagicEffects(const Ptr& actor); + void updateRechargingItems(); void fireEquipmentChangedEvent(); @@ -172,6 +177,9 @@ namespace MWWorld ///< Set a listener for various events, see \a InventoryStoreListener void visitEffectSources (MWMechanics::EffectSourceVisitor& visitor); + + void rechargeItems (float duration); + /// Restore charge on enchanted items. Note this should only be done for the player. }; } diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index 7dec848ad3..7702ea2502 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -607,6 +607,8 @@ namespace MWWorld void World::advanceTime (double hours) { + MWBase::Environment::get().getMechanicsManager()->advanceTime(hours*3600); + mWeatherManager->advanceTime (hours); hours += mGlobalVariables->getFloat ("gamehour"); From 654b7d9ba5e61bd5522383d75d8f373bb42a89a7 Mon Sep 17 00:00:00 2001 From: scrawl Date: Tue, 19 Nov 2013 16:52:26 +0100 Subject: [PATCH 6/6] Apply disease resistance manually as according to wiki --- apps/openmw/mwmechanics/spellcasting.cpp | 35 ++++++++++++++++++------ 1 file changed, 27 insertions(+), 8 deletions(-) diff --git a/apps/openmw/mwmechanics/spellcasting.cpp b/apps/openmw/mwmechanics/spellcasting.cpp index f733472063..ac5be48918 100644 --- a/apps/openmw/mwmechanics/spellcasting.cpp +++ b/apps/openmw/mwmechanics/spellcasting.cpp @@ -95,18 +95,37 @@ namespace MWMechanics } // Try resisting - if (magnitudeMult > 0 && caster.getClass().isActor()) + if (magnitudeMult > 0 && target.getClass().isActor()) { const ESM::Spell *spell = MWBase::Environment::get().getWorld()->getStore().get().search (mId); - magnitudeMult = MWMechanics::getEffectMultiplier(effectIt->mEffectID, target, caster, spell); - if (magnitudeMult == 0) + + if (spell->mData.mType == ESM::Spell::ST_Disease || spell->mData.mType == ESM::Spell::ST_Blight) { - // Fully resisted, show message - if (target.getRefData().getHandle() == "player") - MWBase::Environment::get().getWindowManager()->messageBox("#{sMagicPCResisted}"); - else - MWBase::Environment::get().getWindowManager()->messageBox("#{sMagicTargetResisted}"); + float x = (spell->mData.mType == ESM::Spell::ST_Disease) ? + target.getClass().getCreatureStats(target).getMagicEffects().get(ESM::MagicEffect::ResistCommonDisease).mMagnitude + : target.getClass().getCreatureStats(target).getMagicEffects().get(ESM::MagicEffect::ResistBlightDisease).mMagnitude; + + int roll = std::rand()/ (static_cast (RAND_MAX) + 1) * 100; // [0, 99] + if (roll <= x) + { + // Fully resisted, show message + if (target.getRefData().getHandle() == "player") + MWBase::Environment::get().getWindowManager()->messageBox("#{sMagicPCResisted}"); + magnitudeMult = 0; + } + } + else + { + magnitudeMult = MWMechanics::getEffectMultiplier(effectIt->mEffectID, target, caster, spell); + if (magnitudeMult == 0) + { + // Fully resisted, show message + if (target.getRefData().getHandle() == "player") + MWBase::Environment::get().getWindowManager()->messageBox("#{sMagicPCResisted}"); + else + MWBase::Environment::get().getWindowManager()->messageBox("#{sMagicTargetResisted}"); + } } } }