mirror of
https://github.com/OpenMW/openmw.git
synced 2026-02-11 13:08:30 +00:00
Rework spell icon update (#8946)
This commit is contained in:
parent
3ac4a744a8
commit
1241bf270c
2 changed files with 113 additions and 183 deletions
|
|
@ -1,6 +1,5 @@
|
|||
#include "spellicons.hpp"
|
||||
|
||||
#include <format>
|
||||
#include <iomanip>
|
||||
#include <sstream>
|
||||
|
||||
|
|
@ -24,184 +23,139 @@
|
|||
|
||||
namespace MWGui
|
||||
{
|
||||
void SpellIcons::updateWidgets(MyGUI::Widget* parent, bool adjustSize)
|
||||
namespace
|
||||
{
|
||||
MWWorld::Ptr player = MWMechanics::getPlayer();
|
||||
const MWMechanics::CreatureStats& stats = player.getClass().getCreatureStats(player);
|
||||
|
||||
std::map<ESM::RefId, std::vector<MagicEffectInfo>> effects;
|
||||
for (const auto& params : stats.getActiveSpells())
|
||||
MyGUI::ImageBox* createIcon(MyGUI::Widget& parent, std::string_view name, std::string_view icon, int size)
|
||||
{
|
||||
for (const auto& effect : params.getEffects())
|
||||
{
|
||||
if (!(effect.mFlags & ESM::ActiveEffect::Flag_Applied))
|
||||
continue;
|
||||
MagicEffectInfo newEffectSource;
|
||||
newEffectSource.mKey = MWMechanics::EffectKey(effect.mEffectId, effect.getSkillOrAttribute());
|
||||
newEffectSource.mMagnitude = static_cast<int>(effect.mMagnitude);
|
||||
newEffectSource.mPermanent = effect.mDuration == -1.f;
|
||||
newEffectSource.mRemainingTime = effect.mTimeLeft;
|
||||
newEffectSource.mSource = params.getDisplayName();
|
||||
newEffectSource.mTotalTime = effect.mDuration;
|
||||
effects[effect.mEffectId].push_back(std::move(newEffectSource));
|
||||
}
|
||||
const VFS::Manager& vfs = *MWBase::Environment::get().getResourceSystem()->getVFS();
|
||||
|
||||
const MyGUI::IntCoord coord(0, 0, size, size);
|
||||
MyGUI::ImageBox* widget = parent.createWidget<MyGUI::ImageBox>("ImageBox", coord, MyGUI::Align::Default);
|
||||
widget->setImageTexture(Misc::ResourceHelpers::correctIconPath(VFS::Path::toNormalized(icon), vfs));
|
||||
|
||||
ToolTipInfo tooltipInfo;
|
||||
tooltipInfo.caption = name;
|
||||
tooltipInfo.icon = icon;
|
||||
tooltipInfo.imageSize = size;
|
||||
tooltipInfo.wordWrap = false;
|
||||
|
||||
widget->setUserData(tooltipInfo);
|
||||
widget->setUserString("ToolTipType", "ToolTipInfo");
|
||||
widget->setVisible(false);
|
||||
|
||||
return widget;
|
||||
}
|
||||
|
||||
int w = 2;
|
||||
const auto& store = MWBase::Environment::get().getESMStore();
|
||||
for (const auto& [effectId, effectInfos] : effects)
|
||||
std::string printEffectMagnitude(float srcMagnitude, ESM::MagicEffect::MagnitudeDisplayType displayType)
|
||||
{
|
||||
const ESM::MagicEffect* effect = store->get<ESM::MagicEffect>().find(effectId);
|
||||
std::string result;
|
||||
if (displayType == ESM::MagicEffect::MDT_None)
|
||||
return result;
|
||||
|
||||
float remainingDuration = 0;
|
||||
float totalDuration = 0;
|
||||
|
||||
std::string sourcesDescription;
|
||||
|
||||
static const float fadeTime
|
||||
= store->get<ESM::GameSetting>().find("fMagicStartIconBlink")->mValue.getFloat();
|
||||
|
||||
bool addNewLine = false;
|
||||
for (const MagicEffectInfo& effectInfo : effectInfos)
|
||||
const int magnitude = static_cast<int>(srcMagnitude);
|
||||
if (displayType == ESM::MagicEffect::MDT_TimesInt)
|
||||
{
|
||||
if (addNewLine)
|
||||
sourcesDescription += '\n';
|
||||
|
||||
// if at least one of the effect sources is permanent, the effect will never wear off
|
||||
if (effectInfo.mPermanent)
|
||||
{
|
||||
remainingDuration = fadeTime;
|
||||
totalDuration = fadeTime;
|
||||
}
|
||||
else
|
||||
{
|
||||
remainingDuration = std::max(remainingDuration, effectInfo.mRemainingTime);
|
||||
totalDuration = std::max(totalDuration, effectInfo.mTotalTime);
|
||||
}
|
||||
|
||||
sourcesDescription += effectInfo.mSource;
|
||||
|
||||
if (effect->mData.mFlags & ESM::MagicEffect::TargetSkill)
|
||||
{
|
||||
const ESM::Skill* skill = store->get<ESM::Skill>().find(effectInfo.mKey.mArg);
|
||||
sourcesDescription += " (" + skill->mName + ')';
|
||||
}
|
||||
if (effect->mData.mFlags & ESM::MagicEffect::TargetAttribute)
|
||||
{
|
||||
const ESM::Attribute* attribute = store->get<ESM::Attribute>().find(effectInfo.mKey.mArg);
|
||||
sourcesDescription += " (" + attribute->mName + ')';
|
||||
}
|
||||
ESM::MagicEffect::MagnitudeDisplayType displayType = effect->getMagnitudeDisplayType();
|
||||
if (displayType == ESM::MagicEffect::MDT_TimesInt)
|
||||
{
|
||||
std::string_view timesInt
|
||||
= MWBase::Environment::get().getWindowManager()->getGameSettingString("sXTimesINT", {});
|
||||
std::stringstream formatter;
|
||||
formatter << std::fixed << std::setprecision(1) << " " << (effectInfo.mMagnitude / 10.0f)
|
||||
<< timesInt;
|
||||
sourcesDescription += formatter.str();
|
||||
}
|
||||
else if (displayType != ESM::MagicEffect::MDT_None)
|
||||
{
|
||||
sourcesDescription += ": " + MyGUI::utility::toString(effectInfo.mMagnitude);
|
||||
|
||||
if (displayType == ESM::MagicEffect::MDT_Percentage)
|
||||
sourcesDescription
|
||||
+= MWBase::Environment::get().getWindowManager()->getGameSettingString("spercent", {});
|
||||
else if (displayType == ESM::MagicEffect::MDT_Feet)
|
||||
{
|
||||
sourcesDescription += ' ';
|
||||
sourcesDescription
|
||||
+= MWBase::Environment::get().getWindowManager()->getGameSettingString("sfeet", {});
|
||||
}
|
||||
else if (displayType == ESM::MagicEffect::MDT_Level)
|
||||
{
|
||||
sourcesDescription += ' ';
|
||||
if (effectInfo.mMagnitude > 1)
|
||||
sourcesDescription
|
||||
+= MWBase::Environment::get().getWindowManager()->getGameSettingString("sLevels", {});
|
||||
else
|
||||
sourcesDescription
|
||||
+= MWBase::Environment::get().getWindowManager()->getGameSettingString("sLevel", {});
|
||||
}
|
||||
else // ESM::MagicEffect::MDT_Points
|
||||
{
|
||||
sourcesDescription += ' ';
|
||||
if (effectInfo.mMagnitude > 1)
|
||||
sourcesDescription
|
||||
+= MWBase::Environment::get().getWindowManager()->getGameSettingString("spoints", {});
|
||||
else
|
||||
sourcesDescription
|
||||
+= MWBase::Environment::get().getWindowManager()->getGameSettingString("spoint", {});
|
||||
}
|
||||
}
|
||||
if (effectInfo.mRemainingTime > -1 && Settings::game().mShowEffectDuration)
|
||||
sourcesDescription
|
||||
+= MWGui::ToolTips::getDurationString(effectInfo.mRemainingTime, " #{sDuration}");
|
||||
|
||||
addNewLine = true;
|
||||
std::stringstream formatter;
|
||||
formatter << std::fixed << std::setprecision(1) << " " << (magnitude / 10.0f);
|
||||
result += formatter.str();
|
||||
}
|
||||
else
|
||||
{
|
||||
result += ": " + MyGUI::utility::toString(magnitude);
|
||||
if (displayType != ESM::MagicEffect::MDT_Percentage)
|
||||
result += ' ';
|
||||
}
|
||||
|
||||
if (remainingDuration > 0.f)
|
||||
std::string_view unit;
|
||||
if (displayType == ESM::MagicEffect::MDT_TimesInt)
|
||||
unit = "sXTimesINT";
|
||||
else if (displayType == ESM::MagicEffect::MDT_Percentage)
|
||||
unit = "sPercent";
|
||||
else if (displayType == ESM::MagicEffect::MDT_Feet)
|
||||
unit = "sFeet";
|
||||
else if (displayType == ESM::MagicEffect::MDT_Level)
|
||||
unit = magnitude > 1 ? "sLevels" : "sLevel";
|
||||
else if (displayType == ESM::MagicEffect::MDT_Points)
|
||||
unit = magnitude > 1 ? "sPoints" : "sPoint";
|
||||
|
||||
result += MWBase::Environment::get().getWindowManager()->getGameSettingString(unit, {});
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
void SpellIcons::updateWidgets(MyGUI::Widget* parent, bool adjustSize)
|
||||
{
|
||||
for (auto& [effectId, widget] : mWidgetMap)
|
||||
{
|
||||
widget->setVisible(false);
|
||||
widget->setAlpha(1.f);
|
||||
widget->getUserData<ToolTipInfo>()->text.clear();
|
||||
}
|
||||
|
||||
int horizontalOffset = 2;
|
||||
constexpr int verticalOffset = 2;
|
||||
constexpr int size = 16;
|
||||
|
||||
const MWWorld::ESMStore& store = *MWBase::Environment::get().getESMStore();
|
||||
static const float fadeTime = store.get<ESM::GameSetting>().find("fMagicStartIconBlink")->mValue.getFloat();
|
||||
|
||||
const MWWorld::Ptr player = MWMechanics::getPlayer();
|
||||
const MWMechanics::CreatureStats& stats = player.getClass().getCreatureStats(player);
|
||||
for (const auto& params : stats.getActiveSpells())
|
||||
{
|
||||
for (const auto& source : params.getEffects())
|
||||
{
|
||||
MyGUI::ImageBox* image;
|
||||
if (!(source.mFlags & ESM::ActiveEffect::Flag_Applied))
|
||||
continue;
|
||||
if (source.mDuration != -1.f && source.mTimeLeft <= 0.f)
|
||||
continue;
|
||||
|
||||
const ESM::RefId effectId = source.mEffectId;
|
||||
const ESM::MagicEffect& effect = *store.get<ESM::MagicEffect>().find(effectId);
|
||||
const ESM::RefId arg = source.getSkillOrAttribute();
|
||||
|
||||
if (mWidgetMap.find(effectId) == mWidgetMap.end())
|
||||
mWidgetMap[effectId] = createIcon(*parent, effect.mName, effect.mIcon, size);
|
||||
|
||||
MyGUI::ImageBox& widget = *mWidgetMap[effectId];
|
||||
if (!widget.getVisible())
|
||||
{
|
||||
image = parent->createWidget<MyGUI::ImageBox>(
|
||||
"ImageBox", MyGUI::IntCoord(w, 2, 16, 16), MyGUI::Align::Default);
|
||||
mWidgetMap[effectId] = image;
|
||||
|
||||
image->setImageTexture(
|
||||
Misc::ResourceHelpers::correctIconPath(VFS::Path::toNormalized(effect->mIcon),
|
||||
*MWBase::Environment::get().getResourceSystem()->getVFS()));
|
||||
|
||||
ToolTipInfo tooltipInfo;
|
||||
tooltipInfo.caption = effect->mName;
|
||||
tooltipInfo.icon = effect->mIcon;
|
||||
tooltipInfo.imageSize = 16;
|
||||
tooltipInfo.wordWrap = false;
|
||||
|
||||
image->setUserData(tooltipInfo);
|
||||
image->setUserString("ToolTipType", "ToolTipInfo");
|
||||
widget.setPosition(horizontalOffset, verticalOffset);
|
||||
widget.setVisible(true);
|
||||
if (source.mDuration >= fadeTime && fadeTime > 0.f)
|
||||
widget.setAlpha(std::min(source.mTimeLeft / fadeTime, 1.f));
|
||||
horizontalOffset += size;
|
||||
}
|
||||
else
|
||||
image = mWidgetMap[effectId];
|
||||
|
||||
image->setPosition(w, 2);
|
||||
image->setVisible(true);
|
||||
w += 16;
|
||||
std::string& desc = widget.getUserData<ToolTipInfo>()->text;
|
||||
if (!desc.empty())
|
||||
desc += '\n';
|
||||
|
||||
ToolTipInfo* tooltipInfo = image->getUserData<ToolTipInfo>();
|
||||
tooltipInfo->text = std::move(sourcesDescription);
|
||||
desc += params.getDisplayName();
|
||||
|
||||
// Fade out
|
||||
if (totalDuration >= fadeTime && fadeTime > 0.f)
|
||||
image->setAlpha(std::min(remainingDuration / fadeTime, 1.f));
|
||||
}
|
||||
else if (mWidgetMap.find(effectId) != mWidgetMap.end())
|
||||
{
|
||||
MyGUI::ImageBox* image = mWidgetMap[effectId];
|
||||
image->setVisible(false);
|
||||
image->setAlpha(1.f);
|
||||
if (effect.mData.mFlags & ESM::MagicEffect::TargetSkill)
|
||||
{
|
||||
const ESM::Skill& skill = *store.get<ESM::Skill>().find(arg);
|
||||
desc += " (" + skill.mName + ')';
|
||||
}
|
||||
if (effect.mData.mFlags & ESM::MagicEffect::TargetAttribute)
|
||||
{
|
||||
const ESM::Attribute& attribute = *store.get<ESM::Attribute>().find(arg);
|
||||
desc += " (" + attribute.mName + ')';
|
||||
}
|
||||
desc += printEffectMagnitude(source.mMagnitude, effect.getMagnitudeDisplayType());
|
||||
if (source.mTimeLeft > -1 && Settings::game().mShowEffectDuration)
|
||||
desc += MWGui::ToolTips::getDurationString(source.mTimeLeft, " #{sDuration}");
|
||||
}
|
||||
}
|
||||
|
||||
if (adjustSize)
|
||||
{
|
||||
int s = w + 2;
|
||||
if (effects.empty())
|
||||
s = 0;
|
||||
int diff = parent->getWidth() - s;
|
||||
parent->setSize(s, parent->getHeight());
|
||||
const int newWidth = horizontalOffset > 2 ? horizontalOffset + 2 : 0;
|
||||
const int diff = parent->getWidth() - newWidth;
|
||||
parent->setSize(newWidth, parent->getHeight());
|
||||
parent->setPosition(parent->getLeft() + diff, parent->getTop());
|
||||
}
|
||||
|
||||
// hide inactive effects
|
||||
for (auto& widgetPair : mWidgetMap)
|
||||
{
|
||||
if (effects.find(widgetPair.first) == effects.end())
|
||||
widgetPair.second->setVisible(false);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,43 +1,19 @@
|
|||
#ifndef MWGUI_SPELLICONS_H
|
||||
#define MWGUI_SPELLICONS_H
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <map>
|
||||
|
||||
#include "../mwmechanics/magiceffects.hpp"
|
||||
#include <components/esm/refid.hpp>
|
||||
|
||||
namespace MyGUI
|
||||
{
|
||||
class Widget;
|
||||
class ImageBox;
|
||||
}
|
||||
namespace ESM
|
||||
{
|
||||
struct ENAMstruct;
|
||||
struct EffectList;
|
||||
}
|
||||
|
||||
namespace MWGui
|
||||
{
|
||||
|
||||
// information about a single magic effect source as required for display in the tooltip
|
||||
struct MagicEffectInfo
|
||||
{
|
||||
MagicEffectInfo()
|
||||
: mMagnitude(0)
|
||||
, mRemainingTime(0.f)
|
||||
, mTotalTime(0.f)
|
||||
, mPermanent(false)
|
||||
{
|
||||
}
|
||||
std::string mSource; // display name for effect source (e.g. potion name)
|
||||
MWMechanics::EffectKey mKey;
|
||||
int mMagnitude;
|
||||
float mRemainingTime;
|
||||
float mTotalTime;
|
||||
bool mPermanent; // the effect is permanent
|
||||
};
|
||||
|
||||
class SpellIcons
|
||||
{
|
||||
public:
|
||||
|
|
|
|||
Loading…
Reference in a new issue