Added birthsign dialog and spell effect widget.

pull/17/head
Jan Borsodi 14 years ago
parent 3e611b5d4c
commit cd3e976b7c

@ -39,6 +39,7 @@ set(GAMEGUI_HEADER
mwgui/widgets.hpp
mwgui/race.hpp
mwgui/class.hpp
mwgui/birth.hpp
mwgui/window_manager.hpp
mwgui/console.hpp
)
@ -49,6 +50,7 @@ set(GAMEGUI
mwgui/text_input.cpp
mwgui/widgets.cpp
mwgui/race.cpp
mwgui/birth.cpp
mwgui/class.cpp
)
source_group(apps\\openmw\\mwgui FILES ${GAMEGUI_HEADER} ${GAMEGUI})

@ -243,6 +243,7 @@ void OMW::Engine::go()
MyGUI::FactoryManager::getInstance().registerFactory<MWGui::Widgets::MWSkill>("Widget");
MyGUI::FactoryManager::getInstance().registerFactory<MWGui::Widgets::MWAttribute>("Widget");
MyGUI::FactoryManager::getInstance().registerFactory<MWGui::Widgets::MWSpell>("Widget");
MyGUI::FactoryManager::getInstance().registerFactory<MWGui::Widgets::MWSpellEffect>("Widget");
// Create window manager - this manages all the MW-specific GUI windows
MWScript::registerExtensions (mExtensions);

@ -0,0 +1,224 @@
#include "birth.hpp"
#include "../mwworld/environment.hpp"
#include "../mwworld/world.hpp"
#include "window_manager.hpp"
#include "widgets.hpp"
#include "components/esm_store/store.hpp"
#include <boost/algorithm/string.hpp>
#include <boost/lexical_cast.hpp>
using namespace MWGui;
using namespace Widgets;
BirthDialog::BirthDialog(MWWorld::Environment& environment, MyGUI::IntSize gameWindowSize)
: Layout("openmw_chargen_birth_layout.xml")
, environment(environment)
{
// Centre dialog
MyGUI::IntCoord coord = mMainWidget->getCoord();
coord.left = (gameWindowSize.width - coord.width)/2;
coord.top = (gameWindowSize.height - coord.height)/2;
mMainWidget->setCoord(coord);
WindowManager *wm = environment.mWindowManager;
getWidget(spellArea, "SpellArea");
getWidget(birthImage, "BirthsignImage");
getWidget(birthList, "BirthsignList");
birthList->setScrollVisible(true);
birthList->eventListSelectAccept = MyGUI::newDelegate(this, &BirthDialog::onSelectBirth);
birthList->eventListMouseItemActivate = MyGUI::newDelegate(this, &BirthDialog::onSelectBirth);
birthList->eventListChangePosition = MyGUI::newDelegate(this, &BirthDialog::onSelectBirth);
// TODO: These buttons should be managed by a Dialog class
MyGUI::ButtonPtr backButton;
getWidget(backButton, "BackButton");
backButton->eventMouseButtonClick = MyGUI::newDelegate(this, &BirthDialog::onBackClicked);
MyGUI::ButtonPtr okButton;
getWidget(okButton, "OKButton");
okButton->eventMouseButtonClick = MyGUI::newDelegate(this, &BirthDialog::onOkClicked);
updateBirths();
updateSpells();
}
void BirthDialog::setNextButtonShow(bool shown)
{
MyGUI::ButtonPtr backButton;
getWidget(backButton, "BackButton");
MyGUI::ButtonPtr okButton;
getWidget(okButton, "OKButton");
// TODO: All hardcoded coords for buttons are temporary, will be replaced with a dynamic system.
if (shown)
{
okButton->setCaption("Next");
// Adjust back button when next is shown
backButton->setCoord(MyGUI::IntCoord(375 - 18, 340, 53, 23));
okButton->setCoord(MyGUI::IntCoord(431 - 18, 340, 42 + 18, 23));
}
else
{
okButton->setCaption("OK");
backButton->setCoord(MyGUI::IntCoord(375, 340, 53, 23));
okButton->setCoord(MyGUI::IntCoord(431, 340, 42, 23));
}
}
void BirthDialog::open()
{
updateBirths();
updateSpells();
setVisible(true);
}
void BirthDialog::setBirthId(const std::string &birthId)
{
currentBirthId = birthId;
birthList->setIndexSelected(MyGUI::ITEM_NONE);
size_t count = birthList->getItemCount();
for (size_t i = 0; i < count; ++i)
{
if (boost::iequals(*birthList->getItemDataAt<std::string>(i), birthId))
{
birthList->setIndexSelected(i);
break;
}
}
updateSpells();
}
// widget controls
void BirthDialog::onOkClicked(MyGUI::Widget* _sender)
{
eventDone();
}
void BirthDialog::onBackClicked(MyGUI::Widget* _sender)
{
eventBack();
}
void BirthDialog::onSelectBirth(MyGUI::List* _sender, size_t _index)
{
if (_index == MyGUI::ITEM_NONE)
return;
const std::string *birthId = birthList->getItemDataAt<std::string>(_index);
if (boost::iequals(currentBirthId, *birthId))
return;
currentBirthId = *birthId;
updateSpells();
}
// update widget content
void BirthDialog::updateBirths()
{
birthList->removeAllItems();
ESMS::ESMStore &store = environment.mWorld->getStore();
ESMS::RecListT<ESM::BirthSign>::MapType::const_iterator it = store.birthSigns.list.begin();
ESMS::RecListT<ESM::BirthSign>::MapType::const_iterator end = store.birthSigns.list.end();
int index = 0;
for (; it != end; ++it)
{
const ESM::BirthSign &birth = it->second;
birthList->addItem(birth.name, it->first);
if (boost::iequals(it->first, currentBirthId))
birthList->setIndexSelected(index);
++index;
}
}
void BirthDialog::updateSpells()
{
for (std::vector<MyGUI::WidgetPtr>::iterator it = spellItems.begin(); it != spellItems.end(); ++it)
{
MyGUI::Gui::getInstance().destroyWidget(*it);
}
spellItems.clear();
if (currentBirthId.empty())
return;
MWSpellPtr spellWidget;
const int lineHeight = 18;
MyGUI::IntCoord coord(0, 0, spellArea->getWidth(), 18);
ESMS::ESMStore &store = environment.mWorld->getStore();
const ESM::BirthSign *birth = store.birthSigns.find(currentBirthId);
std::string texturePath = std::string("textures\\") + birth->texture;
fixTexturePath(texturePath);
birthImage->setImageTexture(texturePath);
std::vector<std::string> abilities, powers, spells;
std::vector<std::string>::const_iterator it = birth->powers.list.begin();
std::vector<std::string>::const_iterator end = birth->powers.list.end();
for (; it != end; ++it)
{
const std::string &spellId = *it;
const ESM::Spell *spell = store.spells.search(spellId);
if (!spell)
continue; // Skip spells which cannot be found
ESM::Spell::SpellType type = static_cast<ESM::Spell::SpellType>(spell->data.type);
if (type != ESM::Spell::ST_Spell && type != ESM::Spell::ST_Ability && type != ESM::Spell::ST_Power)
continue; // We only want spell, ability and powers.
if (type == ESM::Spell::ST_Ability)
abilities.push_back(spellId);
else if (type == ESM::Spell::ST_Power)
powers.push_back(spellId);
else if (type == ESM::Spell::ST_Spell)
spells.push_back(spellId);
}
int i = 0;
static struct{ const std::vector<std::string> &spells; const char *label; } categories[3] = {
{abilities, "sBirthsignmenu1"},
{powers, "sPowers"},
{spells, "sBirthsignmenu2"}
};
for (int category = 0; category < 3; ++category)
{
if (!categories[category].spells.empty())
{
MyGUI::StaticTextPtr label = spellArea->createWidget<MyGUI::StaticText>("SandBrightText", coord, MyGUI::Align::Default, std::string("Label"));
label->setCaption(environment.mWindowManager->getGameSettingString(categories[category].label, ""));
spellItems.push_back(label);
coord.top += lineHeight;
std::vector<std::string>::const_iterator end = categories[category].spells.end();
for (std::vector<std::string>::const_iterator it = categories[category].spells.begin(); it != end; ++it)
{
const std::string &spellId = *it;
spellWidget = spellArea->createWidget<MWSpell>("MW_StatName", coord, MyGUI::Align::Default, std::string("Spell") + boost::lexical_cast<std::string>(i));
spellWidget->setEnvironment(&environment);
spellWidget->setSpellId(spellId);
spellItems.push_back(spellWidget);
coord.top += lineHeight;
MyGUI::IntCoord spellCoord = coord;
spellCoord.height = 24; // TODO: This should be fetched from the skin somehow, or perhaps a widget in the layout as a template?
spellWidget->createEffectWidgets(spellItems, spellArea, spellCoord);
coord.top = spellCoord.top;
++i;
}
}
}
}

@ -0,0 +1,70 @@
#ifndef MWGUI_BIRTH_H
#define MWGUI_BIRTH_H
#include <openengine/gui/layout.hpp>
namespace MWWorld
{
class Environment;
}
/*
This file contains the dialog for choosing a birth sign.
Layout is defined by resources/mygui/openmw_chargen_race_layout.xml.
*/
namespace MWGui
{
using namespace MyGUI;
class BirthDialog : public OEngine::GUI::Layout
{
public:
BirthDialog(MWWorld::Environment& environment, MyGUI::IntSize gameWindowSize);
enum Gender
{
GM_Male,
GM_Female
};
const std::string &getBirthId() const { return currentBirthId; }
void setBirthId(const std::string &raceId);
void setNextButtonShow(bool shown);
void open();
// Events
typedef delegates::CDelegate0 EventHandle_Void;
/** Event : Back button clicked.\n
signature : void method()\n
*/
EventHandle_Void eventBack;
/** Event : Dialog finished, OK button clicked.\n
signature : void method()\n
*/
EventHandle_Void eventDone;
protected:
void onSelectBirth(MyGUI::List* _sender, size_t _index);
void onOkClicked(MyGUI::Widget* _sender);
void onBackClicked(MyGUI::Widget* _sender);
private:
void updateBirths();
void updateSpells();
MWWorld::Environment& environment;
MyGUI::ListPtr birthList;
MyGUI::WidgetPtr spellArea;
MyGUI::StaticImagePtr birthImage;
std::vector<MyGUI::WidgetPtr> spellItems;
std::string currentBirthId;
};
}
#endif

@ -4,12 +4,25 @@
#include "../mwworld/world.hpp"
#include "components/esm_store/store.hpp"
//#include <boost/algorithm/string.hpp>
#include <boost/lexical_cast.hpp>
using namespace MWGui;
using namespace MWGui::Widgets;
/* Helper functions */
/*
* Fixes the filename of a texture path to use the correct .dds extension.
* This is needed on some ESM entries which point to a .tga file instead.
*/
void MWGui::Widgets::fixTexturePath(std::string &path)
{
int offset = path.rfind(".");
if (offset < 0)
return;
path.replace(offset, path.length() - offset, ".dds");
}
/* MWSkill */
MWSkill::MWSkill()
@ -224,6 +237,24 @@ void MWSpell::setSpellId(const std::string &spellId)
updateWidgets();
}
void MWSpell::createEffectWidgets(std::vector<MyGUI::WidgetPtr> &effects, MyGUI::WidgetPtr creator, MyGUI::IntCoord &coord)
{
ESMS::ESMStore &store = env->mWorld->getStore();
const ESM::Spell *spell = store.spells.search(id);
MYGUI_ASSERT(spell, "spell with id '" << id << "' not found");
MWSpellEffectPtr effect = nullptr;
std::vector<ESM::ENAMstruct>::const_iterator end = spell->effects.list.end();
for (std::vector<ESM::ENAMstruct>::const_iterator it = spell->effects.list.begin(); it != end; ++it)
{
effect = creator->createWidget<MWSpellEffect>("MW_EffectImage", coord, MyGUI::Align::Default);
effect->setEnvironment(env);
effect->setSpellEffect(*it);
effects.push_back(effect);
coord.top += effect->getHeight();
}
}
void MWSpell::updateWidgets()
{
if (spellNameWidget && env)
@ -272,3 +303,124 @@ void MWSpell::initialiseWidgetSkin(ResourceSkin* _info)
void MWSpell::shutdownWidgetSkin()
{
}
/* MWSpellEffect */
MWSpellEffect::MWSpellEffect()
: env(nullptr)
, imageWidget(nullptr)
, textWidget(nullptr)
{
}
void MWSpellEffect::setSpellEffect(SpellEffectValue value)
{
effect = value;
updateWidgets();
}
void MWSpellEffect::updateWidgets()
{
if (!env)
return;
ESMS::ESMStore &store = env->mWorld->getStore();
WindowManager *wm = env->mWindowManager;
const ESM::MagicEffect *magicEffect = store.magicEffects.search(effect.effectID);
if (textWidget)
{
if (magicEffect)
{
// TODO: Get name of effect from GMST
std::string spellLine = "";
if (effect.skill >= 0 && effect.skill < ESM::Skill::Length)
{
spellLine += " " + wm->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 += " " + wm->getGameSettingString(attributes[effect.attribute], "");
}
if (effect.magnMin >= 0 || effect.magnMax >= 0)
{
if (effect.magnMin == effect.magnMax)
spellLine += " " + boost::lexical_cast<std::string>(effect.magnMin) + " pts";
else
{
spellLine += " " + boost::lexical_cast<std::string>(effect.magnMin) + " to " + boost::lexical_cast<std::string>(effect.magnMin) + " pts";
}
}
if (effect.duration >= 0)
{
spellLine += " for " + boost::lexical_cast<std::string>(effect.duration) + " secs";
}
if (effect.range == ESM::RT_Self)
spellLine += " on Self";
else if (effect.range == ESM::RT_Touch)
spellLine += " on Touch";
else if (effect.range == ESM::RT_Target)
spellLine += " on Target";
textWidget->setCaption(spellLine);
}
else
textWidget->setCaption("");
}
if (imageWidget)
{
std::string path = std::string("icons\\") + magicEffect->icon;
fixTexturePath(path);
imageWidget->setImageTexture(path);
}
}
void MWSpellEffect::_initialise(WidgetStyle _style, const IntCoord& _coord, Align _align, ResourceSkin* _info, Widget* _parent, ICroppedRectangle * _croppedParent, IWidgetCreator * _creator, const std::string& _name)
{
Base::_initialise(_style, _coord, _align, _info, _parent, _croppedParent, _creator, _name);
initialiseWidgetSkin(_info);
}
MWSpellEffect::~MWSpellEffect()
{
shutdownWidgetSkin();
}
void MWSpellEffect::baseChangeWidgetSkin(ResourceSkin* _info)
{
shutdownWidgetSkin();
Base::baseChangeWidgetSkin(_info);
initialiseWidgetSkin(_info);
}
void MWSpellEffect::initialiseWidgetSkin(ResourceSkin* _info)
{
for (VectorWidgetPtr::iterator iter=mWidgetChildSkin.begin(); iter!=mWidgetChildSkin.end(); ++iter)
{
const std::string &name = *(*iter)->_getInternalData<std::string>();
if (name == "Text")
{
MYGUI_DEBUG_ASSERT( ! textWidget, "widget already assigned");
textWidget = (*iter)->castType<StaticText>();
}
else if (name == "Image")
{
MYGUI_DEBUG_ASSERT( ! imageWidget, "widget already assigned");
imageWidget = (*iter)->castType<StaticImage>();
}
}
}
void MWSpellEffect::shutdownWidgetSkin()
{
}

@ -23,6 +23,8 @@ namespace MWGui
namespace Widgets
{
void fixTexturePath(std::string &path);
class MYGUI_EXPORT MWSkill : public Widget
{
MYGUI_RTTI_DERIVED( MWSkill );
@ -98,6 +100,7 @@ namespace MWGui
};
typedef MWAttribute* MWAttributePtr;
class MWSpellEffect;
class MYGUI_EXPORT MWSpell : public Widget
{
MYGUI_RTTI_DERIVED( MWSpell );
@ -108,6 +111,7 @@ namespace MWGui
void setEnvironment(MWWorld::Environment *env_) { env = env_; }
void setSpellId(const std::string &id);
void createEffectWidgets(std::vector<MyGUI::WidgetPtr> &effects, MyGUI::WidgetPtr creator, MyGUI::IntCoord &coord);
MWWorld::Environment *getEnvironment() const { return env; }
const std::string &getSpellId() const { return id; }
@ -131,6 +135,41 @@ namespace MWGui
MyGUI::StaticTextPtr spellNameWidget;
};
typedef MWSpell* MWSpellPtr;
class MYGUI_EXPORT MWSpellEffect : public Widget
{
MYGUI_RTTI_DERIVED( MWSpellEffect );
public:
MWSpellEffect();
typedef ESM::ENAMstruct SpellEffectValue;
void setEnvironment(MWWorld::Environment *env_) { env = env_; }
void setSpellEffect(SpellEffectValue value);
MWWorld::Environment *getEnvironment() const { return env; }
const SpellEffectValue &getSpellEffect() const { return effect; }
/*internal:*/
virtual void _initialise(WidgetStyle _style, const IntCoord& _coord, Align _align, ResourceSkin* _info, Widget* _parent, ICroppedRectangle * _croppedParent, IWidgetCreator * _creator, const std::string& _name);
protected:
virtual ~MWSpellEffect();
void baseChangeWidgetSkin(ResourceSkin* _info);
private:
void initialiseWidgetSkin(ResourceSkin* _info);
void shutdownWidgetSkin();
void updateWidgets();
MWWorld::Environment *env;
SpellEffectValue effect;
MyGUI::StaticImagePtr imageWidget;
MyGUI::StaticTextPtr textWidget;
};
typedef MWSpellEffect* MWSpellEffectPtr;
}
}

@ -3,6 +3,7 @@
#include "text_input.hpp"
#include "race.hpp"
#include "class.hpp"
#include "birth.hpp"
#include "../mwmechanics/mechanicsmanager.hpp"
#include "../mwinput/inputmanager.hpp"
@ -21,10 +22,11 @@ WindowManager::WindowManager(MyGUI::Gui *_gui, MWWorld::Environment& environment
, nameDialog(nullptr)
, raceDialog(nullptr)
, pickClassDialog(nullptr)
, birthSignDialog(nullptr)
, nameChosen(false)
, raceChosen(false)
, classChosen(false)
, birthChosen(false)
, birthSignChosen(false)
, reviewNext(false)
, gui(_gui)
, mode(GM_Game)
@ -66,6 +68,7 @@ WindowManager::~WindowManager()
delete nameDialog;
delete raceDialog;
delete pickClassDialog;
delete birthSignDialog;
}
void WindowManager::updateVisible()
@ -136,6 +139,17 @@ void WindowManager::updateVisible()
return;
}
if (mode == GM_Birth)
{
if (!birthSignDialog)
birthSignDialog = new BirthDialog(environment, gui->getViewSize());
birthSignDialog->setNextButtonShow(birthSignChosen);
birthSignDialog->eventDone = MyGUI::newDelegate(this, &WindowManager::onBirthSignDialogDone);
birthSignDialog->eventBack = MyGUI::newDelegate(this, &WindowManager::onBirthSignDialogBack);
birthSignDialog->open();
return;
}
if(mode == GM_Inventory)
{
// Ah, inventory mode. First, compute the effective set of
@ -337,3 +351,36 @@ void WindowManager::onPickClassDialogBack()
environment.mInputManager->setGuiMode(GM_Race);
}
void WindowManager::onBirthSignDialogDone()
{
birthSignDialog->eventDone = MWGui::BirthDialog::EventHandle_Void();
bool goNext = birthSignChosen; // Go to next dialog if birth sign was previously chosen
birthSignChosen = true;
if (birthSignDialog)
{
birthSignDialog->setVisible(false);
environment.mMechanicsManager->setPlayerBirthsign(birthSignDialog->getBirthId());
}
updateCharacterGeneration();
if (reviewNext || goNext)
environment.mInputManager->setGuiMode(GM_Review);
else
environment.mInputManager->setGuiMode(GM_Game);
}
void WindowManager::onBirthSignDialogBack()
{
if (birthSignDialog)
{
birthSignDialog->setVisible(false);
environment.mMechanicsManager->setPlayerBirthsign(birthSignDialog->getBirthId());
}
updateCharacterGeneration();
environment.mInputManager->setGuiMode(GM_Class);
}

@ -44,6 +44,7 @@ namespace MWGui
class TextInputDialog;
class RaceDialog;
class PickClassDialog;
class BirthDialog;
class WindowManager
{
@ -61,12 +62,13 @@ namespace MWGui
TextInputDialog *nameDialog;
RaceDialog *raceDialog;
PickClassDialog *pickClassDialog;
BirthDialog *birthSignDialog;
// Which dialogs have been shown, controls back/next/ok buttons
bool nameChosen;
bool raceChosen;
bool classChosen;
bool birthChosen;
bool birthSignChosen;
bool reviewNext;
///< If true then any click on Next will cause the summary to be shown
@ -190,6 +192,10 @@ namespace MWGui
// Character generation: Pick Class dialog
void onPickClassDialogDone();
void onPickClassDialogBack();
// Character generation: Birth sign dialog
void onBirthSignDialogDone();
void onBirthSignDialogBack();
};
}
#endif

@ -27,6 +27,13 @@ enum Specialization
SPC_Stealth = 2
};
enum RangeType
{
RT_Self = 0,
RT_Touch = 1,
RT_Target = 2
};
/** A list of references to spells and spell effects. This is shared
between the records BSGN, NPC and RACE.
*/
@ -64,7 +71,7 @@ struct ENAMstruct
char skill, attribute; // -1 if N/A
// Other spell parameters
int range; // 0 - self, 1 - touch, 2 - target
int range; // 0 - self, 1 - touch, 2 - target (RangeType enum)
int area, duration, magnMin, magnMax;
// Struct size should be 24 bytes

@ -44,6 +44,7 @@ configure_file("${SDIR}/openmw_hud_layout.xml" "${DDIR}/openmw_hud_layout.xml" C
configure_file("${SDIR}/openmw_text_input_layout.xml" "${DDIR}/openmw_text_input_layout.xml" COPYONLY)
configure_file("${SDIR}/openmw_chargen_race_layout.xml" "${DDIR}/openmw_chargen_race_layout.xml" COPYONLY)
configure_file("${SDIR}/openmw_chargen_class_layout.xml" "${DDIR}/openmw_chargen_class_layout.xml" COPYONLY)
configure_file("${SDIR}/openmw_chargen_birth_layout.xml" "${DDIR}/openmw_chargen_birth_layout.xml" COPYONLY)
configure_file("${SDIR}/openmw_inventory_window_layout.xml" "${DDIR}/openmw_inventory_window_layout.xml" COPYONLY)
configure_file("${SDIR}/openmw_layers.xml" "${DDIR}/openmw_layers.xml" COPYONLY)
configure_file("${SDIR}/openmw_mainmenu_layout.xml" "${DDIR}/openmw_mainmenu_layout.xml" COPYONLY)

@ -0,0 +1,25 @@
<?xml version="1.0" encoding="UTF-8"?>
<MyGUI type="Layout">
<!-- correct size is 485 375, adjust when skin is changed to a dialog -->
<Widget type="Window" skin="MW_Window" layer="Windows" position="0 0 493 403" name="_Main">
<!-- Birthsign list -->
<Widget type="List" skin="MW_List" position="8 13 196 137" name="BirthsignList" />
<!-- Birthsign image -->
<Widget type="Widget" skin="MW_Box" position="206 13 263 137" align="ALIGN_LEFT ALIGN_TOP">
<Widget type="StaticImage" skin="StaticImage" position="2 2 259 133" name="BirthsignImage" align="ALIGN_LEFT ALIGN_TOP" />
</Widget>
<!-- Spell list -->
<Widget type="Widget" skin="" position="8 160 465 178" align="ALIGN_LEFT ALIGN_TOP" name="SpellArea">
</Widget>
<!-- Dialog buttons -->
<Widget type="Button" skin="MW_Button" position="375 340 53 23" name="BackButton">
<Property key="Widget_Caption" value="Back"/>
</Widget>
<Widget type="Button" skin="MW_Button" position="431 340 42 23" name="OKButton">
<Property key="Widget_Caption" value="OK"/>
</Widget>
</Widget>
</MyGUI>

@ -61,4 +61,9 @@
<Child type="StaticText" skin="SandText" offset = "0 0 160 18" align = "ALIGN_LEFT ALIGN_HSTRETCH" name = "StatName" />
<Child type="StaticText" skin="SandTextRight" offset = "160 0 40 18" align = "ALIGN_RIGHT ALIGN_TOP" name = "StatValue" />
</Skin>
<Skin name = "MW_EffectImage" size = "200 24">
<Child type="StaticImage" skin="StaticImage" offset = "4 4 16 16" align = "ALIGN_LEFT ALIGN_TOP" name = "Image" />
<Child type="StaticText" skin="SandText" offset = "24 0 176 20" align = "ALIGN_VCENTRE ALIGN_HSTRETCH" name = "Text" />
</Skin>
</MyGUI>

Loading…
Cancel
Save