Magic effect icons for spells

actorid
scrawl 12 years ago
parent e1957e4ee9
commit cf87708c1f

@ -30,7 +30,7 @@ add_openmw_dir (mwgui
formatting inventorywindow container hud countdialog tradewindow settingswindow
confirmationdialog alchemywindow referenceinterface spellwindow mainmenu quickkeysmenu
itemselection spellbuyingwindow loadingscreen levelupdialog waitdialog spellcreationdialog
enchantingdialog trainingwindow travelwindow imagebutton exposedwindow cursor
enchantingdialog trainingwindow travelwindow imagebutton exposedwindow cursor spellicons
)
add_openmw_dir (mwdialogue

@ -19,6 +19,7 @@
#include "inventorywindow.hpp"
#include "container.hpp"
#include "console.hpp"
#include "spellicons.hpp"
using namespace MWGui;
@ -32,7 +33,6 @@ HUD::HUD(int width, int height, int fpsLevel, DragAndDrop* dragAndDrop)
, mWeapStatus(NULL)
, mSpellStatus(NULL)
, mEffectBox(NULL)
, mEffect1(NULL)
, mMinimap(NULL)
, mCompass(NULL)
, mCrosshair(NULL)
@ -86,9 +86,7 @@ HUD::HUD(int width, int height, int fpsLevel, DragAndDrop* dragAndDrop)
mSpellBox->eventMouseButtonClick += MyGUI::newDelegate(this, &HUD::onMagicClicked);
getWidget(mEffectBox, "EffectBox");
getWidget(mEffect1, "Effect1");
mEffectBoxBaseRight = viewSize.width - mEffectBox->getRight();
mEffectBox->eventMouseButtonClick += MyGUI::newDelegate(this, &HUD::onMagicClicked);
getWidget(mMinimapBox, "MiniMapBox");
mMinimapBoxBaseRight = viewSize.width - mMinimapBox->getRight();
@ -107,13 +105,18 @@ HUD::HUD(int width, int height, int fpsLevel, DragAndDrop* dragAndDrop)
getWidget(mTriangleCounter, "TriangleCounter");
getWidget(mBatchCounter, "BatchCounter");
setEffect("icons\\s\\tx_s_chameleon.dds");
LocalMapBase::init(mMinimap, mCompass, this);
mMainWidget->eventMouseButtonClick += MyGUI::newDelegate(this, &HUD::onWorldClicked);
mMainWidget->eventMouseMove += MyGUI::newDelegate(this, &HUD::onWorldMouseOver);
mMainWidget->eventMouseLostFocus += MyGUI::newDelegate(this, &HUD::onWorldMouseLostFocus);
mSpellIcons = new SpellIcons();
}
HUD::~HUD()
{
delete mSpellIcons;
}
void HUD::setFpsLevel(int level)
@ -156,11 +159,6 @@ void HUD::setBatchCount(unsigned int count)
mBatchCounter->setCaption(boost::lexical_cast<std::string>(count));
}
void HUD::setEffect(const char *img)
{
mEffect1->setImageTexture(img);
}
void HUD::setValue(const std::string& id, const MWMechanics::DynamicStat<float>& value)
{
static const char *ids[] =
@ -542,3 +540,8 @@ void HUD::updatePositions()
mMapVisible = mMinimapBox->getVisible ();
mEffectBox->setPosition((viewSize.width - mEffectBoxBaseRight) - mEffectBox->getWidth() + effectsDx, mEffectBox->getTop());
}
void HUD::update()
{
mSpellIcons->updateWidgets(mEffectBox, true);
}

@ -8,12 +8,13 @@
namespace MWGui
{
class DragAndDrop;
class SpellIcons;
class HUD : public OEngine::GUI::Layout, public LocalMapBase
{
public:
HUD(int width, int height, int fpsLevel, DragAndDrop* dragAndDrop);
void setEffect(const char *img);
virtual ~HUD();
void setValue (const std::string& id, const MWMechanics::DynamicStat<float>& value);
void setFPS(float fps);
void setTriangleCount(unsigned int count);
@ -43,6 +44,10 @@ namespace MWGui
bool getWorldMouseOver() { return mWorldMouseOver; }
MyGUI::Widget* getEffectBox() { return mEffectBox; }
void update();
private:
MyGUI::ProgressPtr mHealth, mMagicka, mStamina;
MyGUI::Widget* mHealthFrame;
@ -51,7 +56,6 @@ namespace MWGui
MyGUI::ProgressPtr mWeapStatus, mSpellStatus;
MyGUI::Widget *mEffectBox, *mMinimapBox;
MyGUI::Button* mMinimapButton;
MyGUI::ImageBox* mEffect1;
MyGUI::ScrollView* mMinimap;
MyGUI::ImageBox* mCompass;
MyGUI::ImageBox* mCrosshair;
@ -85,6 +89,8 @@ namespace MWGui
bool mWorldMouseOver;
SpellIcons* mSpellIcons;
void onWorldClicked(MyGUI::Widget* _sender);
void onWorldMouseOver(MyGUI::Widget* _sender, int x, int y);
void onWorldMouseLostFocus(MyGUI::Widget* _sender, MyGUI::Widget* _new);

@ -0,0 +1,246 @@
#include "spellicons.hpp"
#include <MyGUI_Widget.h>
#include <MyGUI_Gui.h>
#include <MyGUI_ImageBox.h>
#include <boost/lexical_cast.hpp>
#include "../mwbase/world.hpp"
#include "../mwbase/environment.hpp"
#include "../mwbase/windowmanager.hpp"
#include "../mwworld/player.hpp"
#include "../mwworld/class.hpp"
#include "../mwmechanics/activespells.hpp"
#include "../mwmechanics/creaturestats.hpp"
#include "tooltips.hpp"
namespace MWGui
{
void SpellIcons::updateWidgets(MyGUI::Widget *parent, bool adjustSize)
{
MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayer().getPlayer();
const MWMechanics::CreatureStats& stats = MWWorld::Class::get(player).getCreatureStats(player);
std::map <int, std::vector<MagicEffectInfo> > effects;
// add permanent spells
const MWMechanics::Spells& spells = stats.getSpells();
for (MWMechanics::Spells::TIterator it = spells.begin(); it != spells.end(); ++it)
{
const ESM::Spell* spell = MWBase::Environment::get().getWorld()->getStore().get<ESM::Spell>().find(it->first);
// these are the spell types that are permanently in effect
if (!(spell->mData.mType == ESM::Spell::ST_Ability)
&& !(spell->mData.mType == ESM::Spell::ST_Disease)
&& !(spell->mData.mType == ESM::Spell::ST_Curse)
&& !(spell->mData.mType == ESM::Spell::ST_Blight))
continue;
ESM::EffectList list = spell->mEffects;
for (std::vector<ESM::ENAMstruct>::const_iterator effectIt = list.mList.begin();
effectIt != list.mList.end(); ++effectIt)
{
const ESM::MagicEffect* magicEffect =
MWBase::Environment::get().getWorld ()->getStore ().get<ESM::MagicEffect>().find(effectIt->mEffectID);
MagicEffectInfo effectInfo;
effectInfo.mSource = getSpellDisplayName (it->first);
effectInfo.mKey = MWMechanics::EffectKey (effectIt->mEffectID);
if (magicEffect->mData.mFlags & ESM::MagicEffect::TargetSkill)
effectInfo.mKey.mArg = effectIt->mSkill;
else if (magicEffect->mData.mFlags & ESM::MagicEffect::TargetAttribute)
effectInfo.mKey.mArg = effectIt->mAttribute;
// just using the min magnitude here, permanent spells with a random magnitude just wouldn't make any sense
effectInfo.mMagnitude = effectIt->mMagnMin;
effectInfo.mPermanent = true;
effects[effectIt->mEffectID].push_back (effectInfo);
}
}
// add lasting effect spells/potions etc
const MWMechanics::ActiveSpells::TContainer& activeSpells = stats.getActiveSpells().getActiveSpells();
for (MWMechanics::ActiveSpells::TContainer::const_iterator it = activeSpells.begin();
it != activeSpells.end(); ++it)
{
ESM::EffectList list = getSpellEffectList(it->first);
float timeScale = MWBase::Environment::get().getWorld()->getTimeScaleFactor();
for (std::vector<ESM::ENAMstruct>::const_iterator effectIt = list.mList.begin();
effectIt != list.mList.end(); ++effectIt)
{
const ESM::MagicEffect* magicEffect =
MWBase::Environment::get().getWorld ()->getStore ().get<ESM::MagicEffect>().find(effectIt->mEffectID);
MagicEffectInfo effectInfo;
effectInfo.mSource = getSpellDisplayName (it->first);
effectInfo.mKey = MWMechanics::EffectKey (effectIt->mEffectID);
if (magicEffect->mData.mFlags & ESM::MagicEffect::TargetSkill)
effectInfo.mKey.mArg = effectIt->mSkill;
else if (magicEffect->mData.mFlags & ESM::MagicEffect::TargetAttribute)
effectInfo.mKey.mArg = effectIt->mAttribute;
effectInfo.mMagnitude = effectIt->mMagnMin + (effectIt->mMagnMax-effectIt->mMagnMin) * it->second.second;
effectInfo.mRemainingTime = effectIt->mDuration +
(it->second.first - MWBase::Environment::get().getWorld()->getTimeStamp())*3600/timeScale;
effects[effectIt->mEffectID].push_back (effectInfo);
}
}
parent->setVisible(effects.size() != 0);
int w=2;
if (adjustSize)
{
int s = effects.size() * 16+4;
int diff = parent->getWidth() - s;
parent->setSize(s, parent->getHeight());
parent->setPosition(parent->getLeft()+diff, parent->getTop());
}
for (std::map <int, std::vector<MagicEffectInfo> >::const_iterator it = effects.begin(); it != effects.end(); ++it)
{
MyGUI::ImageBox* image;
if (mWidgetMap.find(it->first) == mWidgetMap.end())
image = parent->createWidget<MyGUI::ImageBox>
("ImageBox", MyGUI::IntCoord(w,2,16,16), MyGUI::Align::Default);
else
image = mWidgetMap[it->first];
mWidgetMap[it->first] = image;
image->setPosition(w,2);
image->setVisible(true);
const ESM::MagicEffect* effect =
MWBase::Environment::get().getWorld ()->getStore ().get<ESM::MagicEffect>().find(it->first);
std::string icon = effect->mIcon;
icon[icon.size()-3] = 'd';
icon[icon.size()-2] = 'd';
icon[icon.size()-1] = 's';
icon = "icons\\" + icon;
image->setImageTexture(icon);
w += 16;
float remainingDuration = 0;
std::string sourcesDescription;
const float fadeTime = 5.f;
for (std::vector<MagicEffectInfo>::const_iterator effectIt = it->second.begin();
effectIt != it->second.end(); ++effectIt)
{
if (effectIt != it->second.begin())
sourcesDescription += "\n";
// if at least one of the effect sources is permanent, the effect will never wear off
if (effectIt->mPermanent)
remainingDuration = fadeTime;
else
remainingDuration = std::max(remainingDuration, effectIt->mRemainingTime);
sourcesDescription += effectIt->mSource;
if (effect->mData.mFlags & ESM::MagicEffect::TargetSkill)
sourcesDescription += " (" +
MWBase::Environment::get().getWindowManager()->getGameSettingString(
ESM::Skill::sSkillNameIds[effectIt->mKey.mArg], "") + ")";
if (effect->mData.mFlags & ESM::MagicEffect::TargetAttribute)
sourcesDescription += " (" +
MWBase::Environment::get().getWindowManager()->getGameSettingString(
ESM::Attribute::sGmstAttributeIds[effectIt->mKey.mArg], "") + ")";
if (!(effect->mData.mFlags & ESM::MagicEffect::NoMagnitude))
{
std::string pt = MWBase::Environment::get().getWindowManager()->getGameSettingString("spoint", "");
std::string pts = MWBase::Environment::get().getWindowManager()->getGameSettingString("spoints", "");
sourcesDescription += ": " + boost::lexical_cast<std::string>(effectIt->mMagnitude);
sourcesDescription += " " + ((effectIt->mMagnitude > 1) ? pts : pt);
}
}
std::string name = ESM::MagicEffect::effectIdToString (it->first);
ToolTipInfo tooltipInfo;
tooltipInfo.caption = "#{" + name + "}";
tooltipInfo.icon = effect->mIcon;
tooltipInfo.text = sourcesDescription;
tooltipInfo.imageSize = 16;
tooltipInfo.wordWrap = false;
image->setUserData(tooltipInfo);
image->setUserString("ToolTipType", "ToolTipInfo");
// Fade out during the last 5 seconds
image->setAlpha(std::min(remainingDuration/fadeTime, 1.f));
}
// hide inactive effects
for (std::map<int, MyGUI::ImageBox*>::iterator it = mWidgetMap.begin(); it != mWidgetMap.end(); ++it)
{
if (effects.find(it->first) == effects.end())
it->second->setVisible(false);
}
}
std::string SpellIcons::getSpellDisplayName (const std::string& id)
{
if (const ESM::Spell *spell =
MWBase::Environment::get().getWorld()->getStore().get<ESM::Spell>().search (id))
return spell->mName;
if (const ESM::Potion *potion =
MWBase::Environment::get().getWorld()->getStore().get<ESM::Potion>().search (id))
return potion->mName;
if (const ESM::Ingredient *ingredient =
MWBase::Environment::get().getWorld()->getStore().get<ESM::Ingredient>().search (id))
return ingredient->mName;
throw std::runtime_error ("ID " + id + " has no display name");
}
ESM::EffectList SpellIcons::getSpellEffectList (const std::string& id)
{
if (const ESM::Spell *spell =
MWBase::Environment::get().getWorld()->getStore().get<ESM::Spell>().search (id))
return spell->mEffects;
if (const ESM::Potion *potion =
MWBase::Environment::get().getWorld()->getStore().get<ESM::Potion>().search (id))
return potion->mEffects;
if (const ESM::Ingredient *ingredient =
MWBase::Environment::get().getWorld()->getStore().get<ESM::Ingredient>().search (id))
{
const ESM::MagicEffect *magicEffect =
MWBase::Environment::get().getWorld()->getStore().get<ESM::MagicEffect>().find (
ingredient->mData.mEffectID[0]);
ESM::ENAMstruct effect;
effect.mEffectID = ingredient->mData.mEffectID[0];
effect.mSkill = ingredient->mData.mSkills[0];
effect.mAttribute = ingredient->mData.mAttributes[0];
effect.mRange = 0;
effect.mArea = 0;
effect.mDuration = magicEffect->mData.mFlags & ESM::MagicEffect::NoDuration ? 0 : 1;
effect.mMagnMin = 1;
effect.mMagnMax = 1;
ESM::EffectList result;
result.mList.push_back (effect);
return result;
}
throw std::runtime_error("ID " + id + " does not have effects");
}
}

@ -0,0 +1,47 @@
#ifndef MWGUI_SPELLICONS_H
#define MWGUI_SPELLICONS_H
#include <string>
#include "../mwmechanics/magiceffects.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() : mPermanent(false) {}
std::string mSource; // display name for effect source (e.g. potion name)
MWMechanics::EffectKey mKey;
int mMagnitude;
float mRemainingTime;
bool mPermanent; // the effect is permanent
};
class SpellIcons
{
public:
void updateWidgets(MyGUI::Widget* parent, bool adjustSize);
private:
std::string getSpellDisplayName (const std::string& id);
ESM::EffectList getSpellEffectList (const std::string& id);
std::map<int, MyGUI::ImageBox*> mWidgetMap;
};
}
#endif

@ -19,6 +19,7 @@
#include "../mwmechanics/creaturestats.hpp"
#include "../mwmechanics/spellsuccess.hpp"
#include "spellicons.hpp"
#include "inventorywindow.hpp"
#include "confirmationdialog.hpp"
@ -51,6 +52,8 @@ namespace MWGui
, mHeight(0)
, mWidth(0)
{
mSpellIcons = new SpellIcons();
getWidget(mSpellView, "SpellView");
getWidget(mEffectBox, "EffectsBox");
@ -61,6 +64,11 @@ namespace MWGui
mMainWidget->castType<MyGUI::Window>()->eventWindowChangeCoord += MyGUI::newDelegate(this, &SpellWindow::onWindowResize);
}
SpellWindow::~SpellWindow()
{
delete mSpellIcons;
}
void SpellWindow::onPinToggled()
{
mWindowManager.setSpellVisibility(!mPinned);
@ -73,6 +81,8 @@ namespace MWGui
void SpellWindow::updateSpells()
{
mSpellIcons->updateWidgets(mEffectBox, false);
const int spellHeight = 18;
mHeight = 0;

@ -5,10 +5,13 @@
namespace MWGui
{
class SpellIcons;
class SpellWindow : public WindowPinnableBase
{
public:
SpellWindow(MWBase::WindowManager& parWindowManager);
virtual ~SpellWindow();
void updateSpells();
@ -33,6 +36,8 @@ namespace MWGui
virtual void onPinToggled();
virtual void open();
SpellIcons* mSpellIcons;
};
}

@ -127,9 +127,7 @@ void ToolTips::onFrame(float frameDuration)
Widget* focus = InputManager::getInstance().getMouseFocusWidget();
if (focus == 0)
{
return;
}
IntSize tooltipSize;
@ -168,6 +166,10 @@ void ToolTips::onFrame(float frameDuration)
mFocusObject = *focus->getUserData<MWWorld::Ptr>();
tooltipSize = getToolTipViaPtr(false);
}
else if (type == "ToolTipInfo")
{
tooltipSize = createToolTip(*focus->getUserData<MWGui::ToolTipInfo>());
}
else if (type == "AvatarItemSelection")
{
MyGUI::IntCoord avatarPos = mWindowManager->getInventoryWindow ()->getAvatarScreenCoord ();
@ -363,7 +365,7 @@ IntSize ToolTips::createToolTip(const MWGui::ToolTipInfo& info)
std::string caption = info.caption;
std::string image = info.icon;
int imageSize = (image != "") ? 32 : 0;
int imageSize = (image != "") ? info.imageSize : 0;
std::string text = info.text;
// remove the first newline (easier this way)
@ -403,7 +405,7 @@ IntSize ToolTips::createToolTip(const MWGui::ToolTipInfo& info)
EditBox* captionWidget = mDynamicToolTipBox->createWidget<EditBox>("NormalText", IntCoord(0, 0, 300, 300), Align::Left | Align::Top, "ToolTipCaption");
captionWidget->setProperty("Static", "true");
captionWidget->setCaption(caption);
captionWidget->setCaptionWithReplacing(caption);
IntSize captionSize = captionWidget->getTextSize();
int captionHeight = std::max(caption != "" ? captionSize.height : 0, imageSize);
@ -411,7 +413,7 @@ IntSize ToolTips::createToolTip(const MWGui::ToolTipInfo& info)
EditBox* textWidget = mDynamicToolTipBox->createWidget<EditBox>("SandText", IntCoord(0, captionHeight+imageCaptionVPadding, 300, 300-captionHeight-imageCaptionVPadding), Align::Stretch, "ToolTipText");
textWidget->setProperty("Static", "true");
textWidget->setProperty("MultiLine", "true");
textWidget->setProperty("WordWrap", "true");
textWidget->setProperty("WordWrap", info.wordWrap ? "true" : "false");
textWidget->setCaptionWithReplacing(text);
textWidget->setTextAlign(Align::HCenter | Align::Top);
IntSize textSize = textWidget->getTextSize();

@ -15,11 +15,14 @@ namespace MWGui
public:
ToolTipInfo()
: isPotion(false)
, imageSize(32)
, wordWrap(true)
{}
std::string caption;
std::string text;
std::string icon;
int imageSize;
// enchantment (for cloth, armor, weapons)
std::string enchant;
@ -28,6 +31,7 @@ namespace MWGui
Widgets::SpellEffectList effects;
bool isPotion; // potions do not show target in the tooltip
bool wordWrap;
};
class ToolTips : public OEngine::GUI::Layout

@ -421,17 +421,7 @@ void MWSpellEffect::updateWidgets()
}
if (magicEffect->mData.mFlags & ESM::MagicEffect::TargetAttribute)
{
static const char *attributes[8] = {
"sAttributeStrength",
"sAttributeIntelligence",
"sAttributeWillpower",
"sAttributeAgility",
"sAttributeSpeed",
"sAttributeEndurance",
"sAttributePersonality",
"sAttributeLuck"
};
spellLine += " " + mWindowManager->getGameSettingString(attributes[mEffectParams.mAttribute], "");
spellLine += " " + mWindowManager->getGameSettingString(ESM::Attribute::sGmstAttributeIds[mEffectParams.mAttribute], "");
}
if ((mEffectParams.mMagnMin >= 0 || mEffectParams.mMagnMax >= 0) && !(magicEffect->mData.mFlags & ESM::MagicEffect::NoMagnitude))

@ -54,6 +54,7 @@
#include "imagebutton.hpp"
#include "exposedwindow.hpp"
#include "cursor.hpp"
#include "spellicons.hpp"
using namespace MWGui;
@ -270,6 +271,8 @@ void WindowManager::update()
mHud->setTriangleCount(mTriangleCount);
mHud->setBatchCount(mBatchCount);
mHud->update();
mCursor->update();
}

@ -73,6 +73,7 @@ namespace MWGui
class EnchantingDialog;
class TrainingWindow;
class Cursor;
class SpellIcons;
class WindowManager : public MWBase::WindowManager
{

@ -274,4 +274,9 @@ namespace MWMechanics
}
return false;
}
const ActiveSpells::TContainer& ActiveSpells::getActiveSpells() const
{
return mSpells;
}
}

@ -63,6 +63,8 @@ namespace MWMechanics
const MagicEffects& getMagicEffects() const;
const TContainer& getActiveSpells() const;
TIterator begin() const;
TIterator end() const;

@ -61,10 +61,7 @@
</Widget>
<!-- Spell effects box -->
<Widget type="Button" skin="HUD_Box" position="199 168 20 20"
align="Right Bottom" name="EffectBox">
<Widget type="ImageBox" skin="ImageBox" position="2 2 16 16" align="Left Bottom"
name="Effect1"/>
<Widget type="Widget" skin="HUD_Box_Transparent" position="199 168 20 20" align="Right Bottom" name="EffectBox">
</Widget>
<!-- Cell name display when cell changes -->

@ -16,6 +16,10 @@
</Skin>
<Skin name="HUD_Box_Transparent" size="40 40">
<Child type="Widget" skin="MW_Box" offset="0 0 40 40" align="ALIGN_LEFT Stretch" name="Client"/>
</Skin>
<Skin name="HUD_Box_NoTransp" size="40 40">
<!-- Borders -->

@ -4,8 +4,8 @@
<Widget type="ExposedWindow" skin="MW_Window_Pinnable" layer="Windows" position="0 0 300 600" name="_Main">
<!-- Effect box-->
<Widget type="Widget" skin="MW_Box" position="8 8 268 24" align="Left Top HStretch">
<Widget type="Widget" skin="" position="4 4 260 16" align="Left Top Stretch" name="EffectsBox">
<Widget type="Widget" skin="MW_Box" position="8 8 268 23" align="Left Top HStretch">
<Widget type="Widget" skin="" position="2 1 264 20" align="Left Top Stretch" name="EffectsBox">
</Widget>
</Widget>

Loading…
Cancel
Save