diff --git a/apps/openmw/mwclass/ingredient.cpp b/apps/openmw/mwclass/ingredient.cpp index c0186da37a..0c7fa7e698 100644 --- a/apps/openmw/mwclass/ingredient.cpp +++ b/apps/openmw/mwclass/ingredient.cpp @@ -135,6 +135,19 @@ namespace MWClass text += MWGui::ToolTips::getMiscString(ref->base->script, "Script"); } + MWGui::Widgets::SpellEffectList list; + for (int i=0; i<4; ++i) + { + if (ref->base->data.effectID[i] < 0) + continue; + MWGui::Widgets::SpellEffectParams params; + params.mEffectID = ref->base->data.effectID[i]; + params.mAttribute = ref->base->data.attributes[i]; + params.mSkill = ref->base->data.skills[i]; + list.push_back(params); + } + info.effects = list; + info.text = text; return info; diff --git a/apps/openmw/mwclass/potion.cpp b/apps/openmw/mwclass/potion.cpp index ffc8386396..157af01f55 100644 --- a/apps/openmw/mwclass/potion.cpp +++ b/apps/openmw/mwclass/potion.cpp @@ -132,7 +132,7 @@ namespace MWClass text += "\n" + store.gameSettings.search("sWeight")->str + ": " + MWGui::ToolTips::toString(ref->base->data.weight); text += MWGui::ToolTips::getValueString(ref->base->data.value, store.gameSettings.search("sValue")->str); - info.effects = &ref->base->effects; + info.effects = MWGui::Widgets::MWEffectList::effectListFromESM(&ref->base->effects); if (MWBase::Environment::get().getWindowManager()->getFullHelp()) { text += MWGui::ToolTips::getMiscString(ref->ref.owner, "Owner"); diff --git a/apps/openmw/mwgui/tooltips.cpp b/apps/openmw/mwgui/tooltips.cpp index 49e68bd86d..e21c886468 100644 --- a/apps/openmw/mwgui/tooltips.cpp +++ b/apps/openmw/mwgui/tooltips.cpp @@ -285,7 +285,7 @@ IntSize ToolTips::createToolTip(const MWGui::ToolTipInfo& info) IntSize totalSize = IntSize( std::max(textSize.width, captionSize.width + ((image != "") ? imageCaptionHPadding : 0)), ((text != "") ? textSize.height + imageCaptionVPadding : 0) + captionHeight ); - if (info.effects != 0) + if (!info.effects.empty()) { Widget* effectArea = mDynamicToolTipBox->createWidget("", IntCoord(0, totalSize.height, 300, 300-totalSize.height), @@ -305,7 +305,7 @@ IntSize ToolTips::createToolTip(const MWGui::ToolTipInfo& info) effectsWidget->setEffectList(info.effects); std::vector effectItems; - effectsWidget->createEffectWidgets(effectItems, effectArea, coord, true, Widgets::MWEffectList::EF_Potion); + effectsWidget->createEffectWidgets(effectItems, effectArea, coord, true, Widgets::MWEffectList::EF_NoTarget); totalSize.height += coord.top-6; totalSize.width = std::max(totalSize.width, coord.width); } @@ -321,7 +321,7 @@ IntSize ToolTips::createToolTip(const MWGui::ToolTipInfo& info) Widgets::MWEffectListPtr enchantWidget = enchantArea->createWidget ("MW_StatName", coord, Align::Default, "ToolTipEnchantWidget"); enchantWidget->setWindowManager(mWindowManager); - enchantWidget->setEffectList(&enchant->effects); + enchantWidget->setEffectList(Widgets::MWEffectList::effectListFromESM(&enchant->effects)); std::vector enchantEffectItems; int flag = (enchant->data.type == ESM::Enchantment::ConstantEffect) ? Widgets::MWEffectList::EF_Constant : 0; diff --git a/apps/openmw/mwgui/tooltips.hpp b/apps/openmw/mwgui/tooltips.hpp index 4be0baff9d..6d4a205d1a 100644 --- a/apps/openmw/mwgui/tooltips.hpp +++ b/apps/openmw/mwgui/tooltips.hpp @@ -5,6 +5,8 @@ #include #include "../mwworld/ptr.hpp" +#include "widgets.hpp" + namespace MWGui { class WindowManager; @@ -13,11 +15,6 @@ namespace MWGui struct ToolTipInfo { public: - ToolTipInfo() : - effects(0) - { - }; - std::string caption; std::string text; std::string icon; @@ -26,7 +23,7 @@ namespace MWGui std::string enchant; // effects (for potions, ingredients) - const ESM::EffectList* effects; + Widgets::SpellEffectList effects; }; class ToolTips : public OEngine::GUI::Layout diff --git a/apps/openmw/mwgui/widgets.cpp b/apps/openmw/mwgui/widgets.cpp index 0422bb0e23..2fd40b7c22 100644 --- a/apps/openmw/mwgui/widgets.cpp +++ b/apps/openmw/mwgui/widgets.cpp @@ -234,8 +234,17 @@ void MWSpell::createEffectWidgets(std::vector &effects, MyGUI: { effect = creator->createWidget("MW_EffectImage", coord, MyGUI::Align::Default); effect->setWindowManager(mWindowManager); - effect->setFlags(flags); - effect->setSpellEffect(*it); + SpellEffectParams params; + params.mEffectID = it->effectID; + params.mSkill = it->skill; + params.mAttribute = it->attribute; + params.mDuration = it->duration; + params.mMagnMin = it->magnMin; + params.mMagnMax = it->magnMax; + params.mRange = it->range; + params.mIsConstant = (flags & MWEffectList::EF_Constant); + params.mNoTarget = (flags & MWEffectList::EF_NoTarget); + effect->setSpellEffect(params); effects.push_back(effect); coord.top += effect->getHeight(); coord.width = std::max(coord.width, effect->getRequestedWidth()); @@ -274,7 +283,7 @@ MWEffectList::MWEffectList() { } -void MWEffectList::setEffectList(const ESM::EffectList* list) +void MWEffectList::setEffectList(const SpellEffectList& list) { mEffectList = list; updateWidgets(); @@ -283,25 +292,26 @@ void MWEffectList::setEffectList(const ESM::EffectList* list) void MWEffectList::createEffectWidgets(std::vector &effects, MyGUI::WidgetPtr creator, MyGUI::IntCoord &coord, bool center, int flags) { // We don't know the width of all the elements beforehand, so we do it in - // 2 steps: first, create all widgets and check their width + // 2 steps: first, create all widgets and check their width.... MWSpellEffectPtr effect = nullptr; - std::vector::const_iterator end = mEffectList->list.end(); int maxwidth = coord.width; - for (std::vector::const_iterator it = mEffectList->list.begin(); it != end; ++it) + + for (SpellEffectList::iterator it=mEffectList.begin(); + it != mEffectList.end(); ++it) { effect = creator->createWidget("MW_EffectImage", coord, MyGUI::Align::Default); effect->setWindowManager(mWindowManager); - effect->setFlags(flags); + it->mIsConstant = (flags & EF_Constant); + it->mNoTarget = (flags & EF_NoTarget); effect->setSpellEffect(*it); effects.push_back(effect); - if (effect->getRequestedWidth() > maxwidth) maxwidth = effect->getRequestedWidth(); coord.top += effect->getHeight(); } - // then adjust the size for all widgets + // ... then adjust the size for all widgets for (std::vector::iterator it = effects.begin(); it != effects.end(); ++it) { effect = static_cast(*it); @@ -334,6 +344,25 @@ MWEffectList::~MWEffectList() { } +SpellEffectList MWEffectList::effectListFromESM(const ESM::EffectList* effects) +{ + SpellEffectList result; + std::vector::const_iterator end = effects->list.end(); + for (std::vector::const_iterator it = effects->list.begin(); it != end; ++it) + { + SpellEffectParams params; + params.mEffectID = it->effectID; + params.mSkill = it->skill; + params.mAttribute = it->attribute; + params.mDuration = it->duration; + params.mMagnMin = it->magnMin; + params.mMagnMax = it->magnMax; + params.mRange = it->range; + result.push_back(params); + } + return result; +} + /* MWSpellEffect */ MWSpellEffect::MWSpellEffect() @@ -341,13 +370,12 @@ MWSpellEffect::MWSpellEffect() , imageWidget(nullptr) , textWidget(nullptr) , mRequestedWidth(0) - , mFlags(0) { } -void MWSpellEffect::setSpellEffect(SpellEffectValue value) +void MWSpellEffect::setSpellEffect(const SpellEffectParams& params) { - effect = value; + mEffectParams = params; updateWidgets(); } @@ -357,74 +385,71 @@ void MWSpellEffect::updateWidgets() return; const ESMS::ESMStore &store = mWindowManager->getStore(); - const ESM::MagicEffect *magicEffect = store.magicEffects.search(effect.effectID); + const ESM::MagicEffect *magicEffect = store.magicEffects.search(mEffectParams.mEffectID); + if (!magicEffect) + return; if (textWidget) { - if (magicEffect) + std::string pt = mWindowManager->getGameSettingString("spoint", ""); + std::string pts = mWindowManager->getGameSettingString("spoints", ""); + std::string to = " " + mWindowManager->getGameSettingString("sTo", "") + " "; + std::string sec = " " + mWindowManager->getGameSettingString("ssecond", ""); + std::string secs = " " + mWindowManager->getGameSettingString("sseconds", ""); + + std::string effectIDStr = effectIDToString(mEffectParams.mEffectID); + std::string spellLine = mWindowManager->getGameSettingString(effectIDStr, ""); + if (effectInvolvesSkill(effectIDStr) && mEffectParams.mSkill >= 0 && mEffectParams.mSkill < ESM::Skill::Length) { - std::string pt = mWindowManager->getGameSettingString("spoint", ""); - std::string pts = mWindowManager->getGameSettingString("spoints", ""); - std::string to = " " + mWindowManager->getGameSettingString("sTo", "") + " "; - std::string sec = " " + mWindowManager->getGameSettingString("ssecond", ""); - std::string secs = " " + mWindowManager->getGameSettingString("sseconds", ""); - - std::string effectIDStr = effectIDToString(effect.effectID); - std::string spellLine = mWindowManager->getGameSettingString(effectIDStr, ""); - if (effect.skill >= 0 && effect.skill < ESM::Skill::Length) - { - spellLine += " " + mWindowManager->getGameSettingString(ESM::Skill::sSkillNameIds[effect.skill], ""); - } - if (effect.attribute >= 0 && effect.attribute < 8) - { - static const char *attributes[8] = { - "sAttributeStrength", - "sAttributeIntelligence", - "sAttributeWillpower", - "sAttributeAgility", - "sAttributeSpeed", - "sAttributeEndurance", - "sAttributePersonality", - "sAttributeLuck" - }; - spellLine += " " + mWindowManager->getGameSettingString(attributes[effect.attribute], ""); - } - - if ((effect.magnMin >= 0 || effect.magnMax >= 0) && effectHasMagnitude(effectIDStr)) - { - if (effect.magnMin == effect.magnMax) - spellLine += " " + boost::lexical_cast(effect.magnMin) + " " + ((effect.magnMin == 1) ? pt : pts); - else - { - spellLine += " " + boost::lexical_cast(effect.magnMin) + to + boost::lexical_cast(effect.magnMax) + " " + pts; - } - } - - // constant effects have no duration and no target - if (!(mFlags & MWEffectList::EF_Constant)) - { - if (effect.duration >= 0 && effectHasDuration(effectIDStr)) - { - spellLine += " " + mWindowManager->getGameSettingString("sfor", "") + " " + boost::lexical_cast(effect.duration) + ((effect.duration == 1) ? sec : secs); - } - - // potions have no target - if (!(mFlags & MWEffectList::EF_Potion)) - { - std::string on = mWindowManager->getGameSettingString("sonword", ""); - if (effect.range == ESM::RT_Self) - spellLine += " " + on + " " + mWindowManager->getGameSettingString("sRangeSelf", ""); - else if (effect.range == ESM::RT_Touch) - spellLine += " " + on + " " + mWindowManager->getGameSettingString("sRangeTouch", ""); - else if (effect.range == ESM::RT_Target) - spellLine += " " + on + " " + mWindowManager->getGameSettingString("sRangeTarget", ""); - } - } - - static_cast(textWidget)->setCaption(spellLine); - mRequestedWidth = textWidget->getTextSize().width + 24; + spellLine += " " + mWindowManager->getGameSettingString(ESM::Skill::sSkillNameIds[mEffectParams.mSkill], ""); } - else - static_cast(textWidget)->setCaption(""); + if (effectInvolvesAttribute(effectIDStr) && mEffectParams.mAttribute >= 0 && mEffectParams.mAttribute < 8) + { + static const char *attributes[8] = { + "sAttributeStrength", + "sAttributeIntelligence", + "sAttributeWillpower", + "sAttributeAgility", + "sAttributeSpeed", + "sAttributeEndurance", + "sAttributePersonality", + "sAttributeLuck" + }; + spellLine += " " + mWindowManager->getGameSettingString(attributes[mEffectParams.mAttribute], ""); + } + + if ((mEffectParams.mMagnMin >= 0 || mEffectParams.mMagnMax >= 0) && effectHasMagnitude(effectIDStr)) + { + if (mEffectParams.mMagnMin == mEffectParams.mMagnMax) + spellLine += " " + boost::lexical_cast(mEffectParams.mMagnMin) + " " + ((mEffectParams.mMagnMin == 1) ? pt : pts); + else + { + spellLine += " " + boost::lexical_cast(mEffectParams.mMagnMin) + to + boost::lexical_cast(mEffectParams.mMagnMax) + " " + pts; + } + } + + // constant effects have no duration and no target + if (!mEffectParams.mIsConstant) + { + if (mEffectParams.mDuration >= 0 && effectHasDuration(effectIDStr)) + { + spellLine += " " + mWindowManager->getGameSettingString("sfor", "") + " " + boost::lexical_cast(mEffectParams.mDuration) + ((mEffectParams.mDuration == 1) ? sec : secs); + } + + // potions have no target + if (!mEffectParams.mNoTarget) + { + std::string on = mWindowManager->getGameSettingString("sonword", ""); + if (mEffectParams.mRange == ESM::RT_Self) + spellLine += " " + on + " " + mWindowManager->getGameSettingString("sRangeSelf", ""); + else if (mEffectParams.mRange == ESM::RT_Touch) + spellLine += " " + on + " " + mWindowManager->getGameSettingString("sRangeTouch", ""); + else if (mEffectParams.mRange == ESM::RT_Target) + spellLine += " " + on + " " + mWindowManager->getGameSettingString("sRangeTarget", ""); + } + } + + static_cast(textWidget)->setCaption(spellLine); + mRequestedWidth = textWidget->getTextSize().width + 24; } if (imageWidget) { @@ -677,6 +702,24 @@ bool MWSpellEffect::effectHasMagnitude(const std::string& effect) return (std::find(effectsWithoutMagnitude.begin(), effectsWithoutMagnitude.end(), effect) == effectsWithoutMagnitude.end()); } +bool MWSpellEffect::effectInvolvesAttribute (const std::string& effect) +{ + return (effect == "sEffectRestoreAttribute" + || effect == "sEffectAbsorbAttribute" + || effect == "sEffectDrainAttribute" + || effect == "sEffectFortifyAttribute" + || effect == "sEffectDamageAttribute"); +} + +bool MWSpellEffect::effectInvolvesSkill (const std::string& effect) +{ + return (effect == "sEffectRestoreSkill" + || effect == "sEffectAbsorbSkill" + || effect == "sEffectDrainSkill" + || effect == "sEffectFortifySkill" + || effect == "sEffectDamageSkill"); +} + MWSpellEffect::~MWSpellEffect() { } diff --git a/apps/openmw/mwgui/widgets.hpp b/apps/openmw/mwgui/widgets.hpp index 74da7fc933..54a278f1c2 100644 --- a/apps/openmw/mwgui/widgets.hpp +++ b/apps/openmw/mwgui/widgets.hpp @@ -21,8 +21,40 @@ namespace MWGui namespace Widgets { + class MWEffectList; + void fixTexturePath(std::string &path); + struct SpellEffectParams + { + SpellEffectParams() + : mMagnMin(-1) + , mMagnMax(-1) + , mRange(-1) + , mDuration(-1) + , mSkill(-1) + , mAttribute(-1) + , mEffectID(-1) + , mNoTarget(false) + , mIsConstant(false) + { + } + + bool mNoTarget; // potion effects for example have no target (target is always the player) + bool mIsConstant; // constant effect means that duration will not be displayed + + // value of -1 here means the effect is unknown to the player + short mEffectID; + + // value of -1 here means there is no skill/attribute + signed char mSkill, mAttribute; + + // value of -1 here means the value is unavailable + int mMagnMin, mMagnMax, mRange, mDuration; + }; + + typedef std::vector SpellEffectList; + class MYGUI_EXPORT MWSkill : public Widget { MYGUI_RTTI_DERIVED( MWSkill ); @@ -108,6 +140,9 @@ namespace MWGui }; typedef MWAttribute* MWAttributePtr; + /** + * @todo remove this class and use MWEffectList instead + */ class MWSpellEffect; class MYGUI_EXPORT MWSpell : public Widget { @@ -155,12 +190,14 @@ namespace MWGui enum EffectFlags { - EF_Potion = 0x01, // potions have no target (target is always the player) + EF_NoTarget = 0x01, // potions have no target (target is always the player) EF_Constant = 0x02 // constant effect means that duration will not be displayed }; void setWindowManager(WindowManager* parWindowManager) { mWindowManager = parWindowManager; } - void setEffectList(const ESM::EffectList* list); + void setEffectList(const SpellEffectList& list); + + static SpellEffectList effectListFromESM(const ESM::EffectList* effects); /** * @param vector to store the created effect widgets @@ -180,7 +217,7 @@ namespace MWGui void updateWidgets(); WindowManager* mWindowManager; - const ESM::EffectList* mEffectList; + SpellEffectList mEffectList; }; typedef MWEffectList* MWEffectListPtr; @@ -193,14 +230,13 @@ namespace MWGui typedef ESM::ENAMstruct SpellEffectValue; void setWindowManager(WindowManager* parWindowManager) { mWindowManager = parWindowManager; } - void setSpellEffect(SpellEffectValue value); - void setFlags(int flags) { mFlags = flags; } + void setSpellEffect(const SpellEffectParams& params); std::string effectIDToString(const short effectID); bool effectHasMagnitude (const std::string& effect); bool effectHasDuration (const std::string& effect); - - const SpellEffectValue &getSpellEffect() const { return effect; } + bool effectInvolvesAttribute (const std::string& effect); + bool effectInvolvesSkill (const std::string& effect); int getRequestedWidth() const { return mRequestedWidth; } @@ -214,8 +250,7 @@ namespace MWGui void updateWidgets(); WindowManager* mWindowManager; - SpellEffectValue effect; - int mFlags; + SpellEffectParams mEffectParams; MyGUI::ImageBox* imageWidget; MyGUI::TextBox* textWidget; int mRequestedWidth; @@ -247,7 +282,6 @@ namespace MWGui MyGUI::TextBox* barTextWidget; }; typedef MWDynamicStat* MWDynamicStatPtr; - } }