Merge branch 'newchar'

Conflicts:
	components/esm_store/store.hpp
actorid
Marc Zinnschlag 14 years ago
commit 38ab9f7a3d

@ -9,6 +9,10 @@ option(USE_MPG123 "use mpg123 + libsndfile for sound" ON)
set(MORROWIND_DATA_FILES "data"
CACHE PATH "location of Morrowind data files")
if (WIN32)
option(USE_DEBUG_CONSOLE "whether a debug console should be enabled for debug builds, if false debug output is redirected to Visual Studio output" ON)
endif()
# We probably support older versions than this.
cmake_minimum_required(VERSION 2.6)
@ -102,6 +106,9 @@ source_group(components\\esm_store FILES ${ESM_STORE} ${ESM_STORE_HEADER})
file(GLOB ESM_HEADER ${COMP_DIR}/esm/*.hpp)
set(ESM
${COMP_DIR}/esm/load_impl.cpp
${COMP_DIR}/esm/skill.cpp
${COMP_DIR}/esm/attr.cpp
${COMP_DIR}/esm/class.cpp
)
source_group(components\\esm FILES ${ESM_HEADER} ${ESM})
@ -225,6 +232,16 @@ link_directories(${Boost_LIBRARY_DIRS} ${OGRE_LIB_DIR})
add_subdirectory( extern/caelum )
add_subdirectory( extern/mygui_3.0.1 )
# Make sure that certain libraries are used as static libraries
# This is in effect turns off __declspec (dllexport) for windows
# Each library will also need to be configured to build as a static lib
# MyGUI: extern/mygui_3.0.0/
add_definitions(-DMYGUI_STATIC)
# Caelum: extern/caelum/
add_definitions(-DCAELUM_STATIC)
# Specify build paths
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY "${OpenMW_BINARY_DIR}")
@ -289,3 +306,24 @@ option(BUILD_ESMTOOL "build ESM inspector" ON)
if (BUILD_ESMTOOL)
add_subdirectory( apps/esmtool )
endif()
if (WIN32)
if (USE_DEBUG_CONSOLE)
set_target_properties(openmw PROPERTIES LINK_FLAGS_DEBUG "/SUBSYSTEM:CONSOLE")
set_target_properties(openmw PROPERTIES LINK_FLAGS_RELWITHDEBINFO "/SUBSYSTEM:CONSOLE")
set_target_properties(openmw PROPERTIES COMPILE_DEFINITIONS_DEBUG "_CONSOLE")
else()
# Turn off debug console, debug output will be written to visual studio output instead
set_target_properties(openmw PROPERTIES LINK_FLAGS_DEBUG "/SUBSYSTEM:WINDOWS")
set_target_properties(openmw PROPERTIES LINK_FLAGS_RELWITHDEBINFO "/SUBSYSTEM:WINDOWS")
endif()
# Release builds use the debug console
set_target_properties(openmw PROPERTIES LINK_FLAGS_RELEASE "/SUBSYSTEM:CONSOLE")
set_target_properties(openmw PROPERTIES COMPILE_DEFINITIONS_RELEASE "_CONSOLE")
set_target_properties(openmw PROPERTIES LINK_FLAGS_MINSIZEREL "/SUBSYSTEM:CONSOLE")
# TODO: At some point release builds should not use the console but rather write to a log file
#set_target_properties(openmw PROPERTIES LINK_FLAGS_RELEASE "/SUBSYSTEM:WINDOWS")
#set_target_properties(openmw PROPERTIES LINK_FLAGS_MINSIZEREL "/SUBSYSTEM:WINDOWS")
endif()

@ -34,13 +34,24 @@ set(GAMEINPUT_HEADER
source_group(apps\\openmw\\mwinput FILES ${GAMEINPUT} ${GAMEINPUT_HEADER})
set(GAMEGUI_HEADER
mwgui/mw_layouts.hpp
mwgui/layouts.hpp
mwgui/text_input.hpp
mwgui/widgets.hpp
mwgui/race.hpp
mwgui/class.hpp
mwgui/birth.hpp
mwgui/window_manager.hpp
mwgui/console.hpp
)
set(GAMEGUI
mwgui/window_manager.cpp
mwgui/layouts.cpp
mwgui/console.cpp
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})
@ -171,11 +182,14 @@ set(GAMECLASS_HEADER
source_group(apps\\openmw\\mwclass FILES ${GAMECLASS} ${GAMECLASS_HEADER})
set(GAMEMECHANICS
mwmechanics/mechanicsmanager.cpp)
mwmechanics/mechanicsmanager.cpp
mwmechanics/magiceffects.cpp
)
set(GAMEMECHANICS_HEADER
mwmechanics/mechanicsmanager.hpp
mwmechanics/stat.hpp
mwmechanics/creaturestats.hpp
mwmechanics/magiceffects.hpp
)
source_group(apps\\openmw\\mwmechanics FILES ${GAMEMECHANICS} ${GAMEMECHANICS_HEADER})

@ -34,6 +34,9 @@
#include <OgreRoot.h>
#include <MyGUI_WidgetManager.h>
#include "mwgui/class.hpp"
void OMW::Engine::executeLocalScripts()
{
for (MWWorld::World::ScriptList::const_iterator iter (
@ -56,47 +59,54 @@ void OMW::Engine::executeLocalScripts()
bool OMW::Engine::frameStarted(const Ogre::FrameEvent& evt)
{
mEnvironment.mFrameDuration = evt.timeSinceLastFrame;
try
{
mEnvironment.mFrameDuration = evt.timeSinceLastFrame;
// global scripts
mEnvironment.mGlobalScripts->run (mEnvironment);
// global scripts
mEnvironment.mGlobalScripts->run (mEnvironment);
bool changed = mEnvironment.mWorld->hasCellChanged();
bool changed = mEnvironment.mWorld->hasCellChanged();
// local scripts
executeLocalScripts(); // This does not handle the case where a global script causes a cell
// change, followed by a cell change in a local script during the same
// frame.
// local scripts
executeLocalScripts(); // This does not handle the case where a global script causes a cell
// change, followed by a cell change in a local script during the same
// frame.
// passing of time
if (mEnvironment.mWindowManager->getMode()==MWGui::GM_Game)
mEnvironment.mWorld->advanceTime (
mEnvironment.mFrameDuration*mEnvironment.mWorld->getTimeScaleFactor()/3600);
// passing of time
if (mEnvironment.mWindowManager->getMode()==MWGui::GM_Game)
mEnvironment.mWorld->advanceTime (
mEnvironment.mFrameDuration*mEnvironment.mWorld->getTimeScaleFactor()/3600);
if (changed) // keep change flag for another frame, if cell changed happend in local script
mEnvironment.mWorld->markCellAsUnchanged();
if (changed) // keep change flag for another frame, if cell changed happend in local script
mEnvironment.mWorld->markCellAsUnchanged();
// update actors
mEnvironment.mMechanicsManager->update();
// update actors
mEnvironment.mMechanicsManager->update();
if (focusFrameCounter++ == focusUpdateFrame)
{
std::string handle = mEnvironment.mWorld->getFacedHandle();
if (focusFrameCounter++ == focusUpdateFrame)
{
std::string handle = mEnvironment.mWorld->getFacedHandle();
std::string name;
std::string name;
if (!handle.empty())
{
MWWorld::Ptr ptr = mEnvironment.mWorld->getPtrViaHandle (handle);
if (!handle.empty())
{
MWWorld::Ptr ptr = mEnvironment.mWorld->getPtrViaHandle (handle);
if (!ptr.isEmpty())
name = MWWorld::Class::get (ptr).getName (ptr);
}
if (!ptr.isEmpty())
name = MWWorld::Class::get (ptr).getName (ptr);
}
if (!name.empty())
std::cout << "Object: " << name << std::endl;
if (!name.empty())
std::cout << "Object: " << name << std::endl;
focusFrameCounter = 0;
focusFrameCounter = 0;
}
}
catch (const std::exception& e)
{
std::cerr << "Error in framelistener: " << e.what() << std::endl;
}
return true;
@ -231,6 +241,10 @@ void OMW::Engine::go()
// Set up the GUI system
mGuiManager = new OEngine::GUI::MyGUIManager(mOgre.getWindow(),
mOgre.getScene());
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);
@ -257,8 +271,7 @@ void OMW::Engine::go()
*mScriptManager);
// Create game mechanics system
mEnvironment.mMechanicsManager = new MWMechanics::MechanicsManager (
mEnvironment.mWorld->getStore(), *mEnvironment.mWindowManager);
mEnvironment.mMechanicsManager = new MWMechanics::MechanicsManager (mEnvironment);
// Create dialog system
mEnvironment.mDialogueManager = new MWDialogue::DialogueManager (mEnvironment);
@ -283,6 +296,7 @@ void OMW::Engine::go()
// Sets up the input system
MWInput::MWInputManager input(mOgre, mEnvironment.mWorld->getPlayerPos(),
*mEnvironment.mWindowManager, mDebug, *this);
mEnvironment.mInputManager = &input;
focusFrameCounter = 0;

@ -8,6 +8,22 @@
#include <components/misc/fileops.hpp>
#include "engine.hpp"
#if defined(_WIN32) && !defined(_CONSOLE)
#include <boost/iostreams/concepts.hpp>
#include <boost/iostreams/stream_buffer.hpp>
# if !defined(_DEBUG)
# include <iostream>
# include <fstream>
# endif
// For OutputDebugString
#include <Windows.h>
// makes __argc and __argv available on windows
#include <stdlib.h>
#endif
using namespace std;
/// Parse command line options and openmw.cfg file (if one exists). Results are directly
@ -84,6 +100,7 @@ bool parseOptions (int argc, char**argv, OMW::Engine& engine)
int main(int argc, char**argv)
{
try
{
OMW::Engine engine;
@ -101,3 +118,71 @@ int main(int argc, char**argv)
return 0;
}
// Platform specific for Windows when there is no console built into the executable.
// Windows will call the WinMain function instead of main in this case, the normal
// main function is then called with the __argc and __argv parameters.
// In addition if it is a debug build it will redirect cout to the debug console in Visual Studio
#if defined(_WIN32) && !defined(_CONSOLE)
#if defined(_DEBUG)
class DebugOutput : public boost::iostreams::sink
{
public:
std::streamsize write(const char *str, std::streamsize size)
{
// Make a copy for null termination
std::string tmp (str, size);
// Write string to Visual Studio Debug output
OutputDebugString (tmp.c_str ());
return size;
}
};
#else
class Logger : public boost::iostreams::sink
{
public:
Logger(std::ofstream &stream)
: out(stream)
{
}
std::streamsize write(const char *str, std::streamsize size)
{
out.write (str, size);
out.flush();
return size;
}
private:
std::ofstream &out;
};
#endif
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nShowCmd)
{
std::streambuf* old_rdbuf = std::cout.rdbuf ();
int ret = 0;
#if defined(_DEBUG)
// Redirect cout to VS debug output when running in debug mode
{
boost::iostreams::stream_buffer<DebugOutput> sb;
sb.open(DebugOutput());
#else
// Redirect cout to openmw.log
std::ofstream logfile ("openmw.log");
{
boost::iostreams::stream_buffer<Logger> sb;
sb.open (Logger (logfile));
#endif
std::cout.rdbuf (&sb);
ret = main (__argc, __argv);
std::cout.rdbuf(old_rdbuf);
}
return ret;
}
#endif

@ -78,6 +78,8 @@ namespace MWClass
stats->mDynamic[1].set (ref->base->data.mana);
stats->mDynamic[2].set (ref->base->data.fatigue);
stats->mLevel = ref->base->data.level;
ptr.getRefData().getCreatureStats() = stats;
}

@ -94,6 +94,8 @@ namespace MWClass
stats->mDynamic[1].set (ref->base->npdt52.mana);
stats->mDynamic[2].set (ref->base->npdt52.fatigue);
stats->mLevel = ref->base->npdt52.level;
ptr.getRefData().getCreatureStats() = stats;
}
@ -117,6 +119,9 @@ namespace MWClass
stats->mFactionRank[ref->base->faction] = 0;
}
for (int i=0; i<27; ++i)
stats->mSkill[i].setBase (ref->base->npdt52.skills[i]);
ptr.getRefData().getNpcStats() = stats;
}

@ -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;
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

@ -0,0 +1,989 @@
#include "class.hpp"
#include "../mwworld/environment.hpp"
#include "../mwworld/world.hpp"
#include "window_manager.hpp"
#include "components/esm_store/store.hpp"
#include <assert.h>
#include <iterator>
#include <boost/algorithm/string.hpp>
#include <boost/lexical_cast.hpp>
using namespace MWGui;
/* GenerateClassResultDialog */
GenerateClassResultDialog::GenerateClassResultDialog(MWWorld::Environment& environment)
: Layout("openmw_chargen_generate_class_result_layout.xml")
, environment(environment)
{
// Centre dialog
MyGUI::IntSize gameWindowSize = environment.mWindowManager->getGui()->getViewSize();
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;
setText("ReflectT", wm->getGameSettingString("sMessageQuestionAnswer1", ""));
getWidget(classImage, "ClassImage");
getWidget(className, "ClassName");
// TODO: These buttons should be managed by a Dialog class
MyGUI::ButtonPtr backButton;
getWidget(backButton, "BackButton");
backButton->eventMouseButtonClick = MyGUI::newDelegate(this, &GenerateClassResultDialog::onBackClicked);
MyGUI::ButtonPtr okButton;
getWidget(okButton, "OKButton");
okButton->eventMouseButtonClick = MyGUI::newDelegate(this, &GenerateClassResultDialog::onOkClicked);
}
std::string GenerateClassResultDialog::getClassId() const
{
return className->getCaption();
}
void GenerateClassResultDialog::setClassId(const std::string &classId)
{
currentClassId = classId;
classImage->setImageTexture(std::string("textures\\levelup\\") + currentClassId + ".dds");
ESMS::ESMStore &store = environment.mWorld->getStore();
className->setCaption(store.classes.find(currentClassId)->name);
}
// widget controls
void GenerateClassResultDialog::onOkClicked(MyGUI::Widget* _sender)
{
eventDone();
}
void GenerateClassResultDialog::onBackClicked(MyGUI::Widget* _sender)
{
eventBack();
}
/* PickClassDialog */
PickClassDialog::PickClassDialog(MWWorld::Environment& environment, MyGUI::IntSize gameWindowSize)
: Layout("openmw_chargen_class_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;
setText("SpecializationT", wm->getGameSettingString("sChooseClassMenu1", "Specialization"));
getWidget(specializationName, "SpecializationName");
setText("FavoriteAttributesT", wm->getGameSettingString("sChooseClassMenu2", "Favorite Attributes:"));
getWidget(favoriteAttribute0, "FavoriteAttribute0");
getWidget(favoriteAttribute1, "FavoriteAttribute1");
favoriteAttribute0->setWindowManager(wm);
favoriteAttribute1->setWindowManager(wm);
setText("MajorSkillT", wm->getGameSettingString("sChooseClassMenu3", "Major Skills:"));
getWidget(majorSkill0, "MajorSkill0");
getWidget(majorSkill1, "MajorSkill1");
getWidget(majorSkill2, "MajorSkill2");
getWidget(majorSkill3, "MajorSkill3");
getWidget(majorSkill4, "MajorSkill4");
majorSkill0->setWindowManager(wm);
majorSkill1->setWindowManager(wm);
majorSkill2->setWindowManager(wm);
majorSkill3->setWindowManager(wm);
majorSkill4->setWindowManager(wm);
setText("MinorSkillT", wm->getGameSettingString("sChooseClassMenu4", "Minor Skills:"));
getWidget(minorSkill0, "MinorSkill0");
getWidget(minorSkill1, "MinorSkill1");
getWidget(minorSkill2, "MinorSkill2");
getWidget(minorSkill3, "MinorSkill3");
getWidget(minorSkill4, "MinorSkill4");
minorSkill0->setWindowManager(wm);
minorSkill1->setWindowManager(wm);
minorSkill2->setWindowManager(wm);
minorSkill3->setWindowManager(wm);
minorSkill4->setWindowManager(wm);
getWidget(classList, "ClassList");
classList->setScrollVisible(true);
classList->eventListSelectAccept = MyGUI::newDelegate(this, &PickClassDialog::onSelectClass);
classList->eventListMouseItemActivate = MyGUI::newDelegate(this, &PickClassDialog::onSelectClass);
classList->eventListChangePosition = MyGUI::newDelegate(this, &PickClassDialog::onSelectClass);
getWidget(classImage, "ClassImage");
// TODO: These buttons should be managed by a Dialog class
MyGUI::ButtonPtr backButton;
getWidget(backButton, "BackButton");
backButton->eventMouseButtonClick = MyGUI::newDelegate(this, &PickClassDialog::onBackClicked);
MyGUI::ButtonPtr okButton;
getWidget(okButton, "OKButton");
okButton->eventMouseButtonClick = MyGUI::newDelegate(this, &PickClassDialog::onOkClicked);
updateClasses();
updateStats();
}
void PickClassDialog::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(382 - 18, 265, 53, 23));
okButton->setCoord(MyGUI::IntCoord(434 - 18, 265, 42 + 18, 23));
}
else
{
okButton->setCaption("OK");
backButton->setCoord(MyGUI::IntCoord(382, 265, 53, 23));
okButton->setCoord(MyGUI::IntCoord(434, 265, 42, 23));
}
}
void PickClassDialog::open()
{
updateClasses();
updateStats();
setVisible(true);
}
void PickClassDialog::setClassId(const std::string &classId)
{
currentClassId = classId;
classList->setIndexSelected(MyGUI::ITEM_NONE);
size_t count = classList->getItemCount();
for (size_t i = 0; i < count; ++i)
{
if (boost::iequals(*classList->getItemDataAt<std::string>(i), classId))
{
classList->setIndexSelected(i);
break;
}
}
updateStats();
}
// widget controls
void PickClassDialog::onOkClicked(MyGUI::Widget* _sender)
{
eventDone();
}
void PickClassDialog::onBackClicked(MyGUI::Widget* _sender)
{
eventBack();
}
void PickClassDialog::onSelectClass(MyGUI::List* _sender, size_t _index)
{
if (_index == MyGUI::ITEM_NONE)
return;
const std::string *classId = classList->getItemDataAt<std::string>(_index);
if (boost::iequals(currentClassId, *classId))
return;
currentClassId = *classId;
updateStats();
}
// update widget content
void PickClassDialog::updateClasses()
{
classList->removeAllItems();
ESMS::ESMStore &store = environment.mWorld->getStore();
ESMS::RecListT<ESM::Class>::MapType::const_iterator it = store.classes.list.begin();
ESMS::RecListT<ESM::Class>::MapType::const_iterator end = store.classes.list.end();
int index = 0;
for (; it != end; ++it)
{
const ESM::Class &klass = it->second;
bool playable = (klass.data.isPlayable != 0);
if (!playable) // Only display playable classes
continue;
const std::string &id = it->first;
classList->addItem(klass.name, id);
if (boost::iequals(id, currentClassId))
classList->setIndexSelected(index);
++index;
}
}
void PickClassDialog::updateStats()
{
if (currentClassId.empty())
return;
WindowManager *wm = environment.mWindowManager;
ESMS::ESMStore &store = environment.mWorld->getStore();
const ESM::Class *klass = store.classes.find(currentClassId);
ESM::Class::Specialization specialization = static_cast<ESM::Class::Specialization>(klass->data.specialization);
static const char *specIds[3] = {
"sSpecializationCombat",
"sSpecializationMagic",
"sSpecializationStealth"
};
specializationName->setCaption(wm->getGameSettingString(specIds[specialization], specIds[specialization]));
favoriteAttribute0->setAttributeId(klass->data.attribute[0]);
favoriteAttribute1->setAttributeId(klass->data.attribute[1]);
Widgets::MWSkillPtr majorSkills[5] = {
majorSkill0,
majorSkill1,
majorSkill2,
majorSkill3,
majorSkill4
};
Widgets::MWSkillPtr minorSkills[5] = {
minorSkill0,
minorSkill1,
minorSkill2,
minorSkill3,
minorSkill4
};
for (int i = 0; i < 5; ++i)
{
majorSkills[i]->setSkillNumber(klass->data.skills[i][0]);
minorSkills[i]->setSkillNumber(klass->data.skills[i][1]);
}
classImage->setImageTexture(std::string("textures\\levelup\\") + currentClassId + ".dds");
}
/* InfoBoxDialog */
void fitToText(MyGUI::StaticTextPtr widget)
{
MyGUI::IntCoord inner = widget->getTextRegion();
MyGUI::IntCoord outer = widget->getCoord();
MyGUI::IntSize size = widget->getTextSize();
size.width += outer.width - inner.width;
size.height += outer.height - inner.height;
widget->setSize(size);
}
void layoutVertically(MyGUI::WidgetPtr widget, int margin)
{
size_t count = widget->getChildCount();
int pos = 0;
pos += margin;
int width = 0;
for (unsigned i = 0; i < count; ++i)
{
MyGUI::WidgetPtr child = widget->getChildAt(i);
if (!child->isVisible())
continue;
child->setPosition(child->getLeft(), pos);
width = std::max(width, child->getWidth());
pos += child->getHeight() + margin;
}
width += margin*2;
widget->setSize(width, pos);
}
InfoBoxDialog::InfoBoxDialog(MWWorld::Environment& environment)
: Layout("openmw_infobox_layout.xml")
, environment(environment)
, currentButton(-1)
{
getWidget(textBox, "TextBox");
getWidget(text, "Text");
text->getSubWidgetText()->setWordWrap(true);
getWidget(buttonBar, "ButtonBar");
center();
}
void InfoBoxDialog::setText(const std::string &str)
{
text->setCaption(str);
textBox->setVisible(!str.empty());
fitToText(text);
}
std::string InfoBoxDialog::getText() const
{
return text->getCaption();
}
void InfoBoxDialog::setButtons(ButtonList &buttons)
{
for (std::vector<MyGUI::ButtonPtr>::iterator it = this->buttons.begin(); it != this->buttons.end(); ++it)
{
MyGUI::Gui::getInstance().destroyWidget(*it);
}
this->buttons.clear();
currentButton = -1;
// TODO: The buttons should be generated from a template in the layout file, ie. cloning an existing widget
MyGUI::ButtonPtr button;
MyGUI::IntCoord coord = MyGUI::IntCoord(0, 0, buttonBar->getWidth(), 10);
ButtonList::const_iterator end = buttons.end();
for (ButtonList::const_iterator it = buttons.begin(); it != end; ++it)
{
const std::string &text = *it;
button = buttonBar->createWidget<MyGUI::Button>("MW_Button", coord, MyGUI::Align::Top | MyGUI::Align::HCenter, "");
button->getSubWidgetText()->setWordWrap(true);
button->setCaption(text);
fitToText(button);
button->eventMouseButtonClick = MyGUI::newDelegate(this, &InfoBoxDialog::onButtonClicked);
coord.top += button->getHeight();
this->buttons.push_back(button);
}
}
void InfoBoxDialog::update()
{
// Fix layout
layoutVertically(textBox, 4);
layoutVertically(buttonBar, 6);
layoutVertically(mMainWidget, 4 + 6);
center();
}
int InfoBoxDialog::getChosenButton() const
{
return currentButton;
}
void InfoBoxDialog::onButtonClicked(MyGUI::WidgetPtr _sender)
{
std::vector<MyGUI::ButtonPtr>::const_iterator end = buttons.end();
int i = 0;
for (std::vector<MyGUI::ButtonPtr>::const_iterator it = buttons.begin(); it != end; ++it)
{
if (*it == _sender)
{
currentButton = i;
eventButtonSelected(_sender, i);
return;
}
++i;
}
}
void InfoBoxDialog::center()
{
// Centre dialog
MyGUI::IntSize gameWindowSize = environment.mWindowManager->getGui()->getViewSize();
MyGUI::IntCoord coord = mMainWidget->getCoord();
coord.left = (gameWindowSize.width - coord.width)/2;
coord.top = (gameWindowSize.height - coord.height)/2;
mMainWidget->setCoord(coord);
}
/* ClassChoiceDialog */
ClassChoiceDialog::ClassChoiceDialog(MWWorld::Environment& environment)
: InfoBoxDialog(environment)
{
WindowManager *mw = environment.mWindowManager;
setText("");
ButtonList buttons;
buttons.push_back(mw->getGameSettingString("sClassChoiceMenu1", ""));
buttons.push_back(mw->getGameSettingString("sClassChoiceMenu2", ""));
buttons.push_back(mw->getGameSettingString("sClassChoiceMenu3", ""));
buttons.push_back(mw->getGameSettingString("sBack", ""));
setButtons(buttons);
update();
}
/* CreateClassDialog */
CreateClassDialog::CreateClassDialog(MWWorld::Environment& environment, MyGUI::IntSize gameWindowSize)
: Layout("openmw_chargen_create_class_layout.xml")
, environment(environment)
, specDialog(nullptr)
, attribDialog(nullptr)
, skillDialog(nullptr)
, descDialog(nullptr)
{
// 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;
setText("SpecializationT", wm->getGameSettingString("sChooseClassMenu1", "Specialization"));
getWidget(specializationName, "SpecializationName");
specializationName->setCaption(wm->getGameSettingString(ESM::Class::gmstSpecializationIds[ESM::Class::Combat], ""));
specializationName->eventMouseButtonClick = MyGUI::newDelegate(this, &CreateClassDialog::onSpecializationClicked);
setText("FavoriteAttributesT", wm->getGameSettingString("sChooseClassMenu2", "Favorite Attributes:"));
getWidget(favoriteAttribute0, "FavoriteAttribute0");
getWidget(favoriteAttribute1, "FavoriteAttribute1");
favoriteAttribute0->setWindowManager(wm);
favoriteAttribute1->setWindowManager(wm);
favoriteAttribute0->eventClicked = MyGUI::newDelegate(this, &CreateClassDialog::onAttributeClicked);
favoriteAttribute1->eventClicked = MyGUI::newDelegate(this, &CreateClassDialog::onAttributeClicked);
setText("MajorSkillT", wm->getGameSettingString("sSkillClassMajor", ""));
getWidget(majorSkill0, "MajorSkill0");
getWidget(majorSkill1, "MajorSkill1");
getWidget(majorSkill2, "MajorSkill2");
getWidget(majorSkill3, "MajorSkill3");
getWidget(majorSkill4, "MajorSkill4");
skills.push_back(majorSkill0);
skills.push_back(majorSkill1);
skills.push_back(majorSkill2);
skills.push_back(majorSkill3);
skills.push_back(majorSkill4);
setText("MinorSkillT", wm->getGameSettingString("sSkillClassMinor", ""));
getWidget(minorSkill0, "MinorSkill0");
getWidget(minorSkill1, "MinorSkill1");
getWidget(minorSkill2, "MinorSkill2");
getWidget(minorSkill3, "MinorSkill3");
getWidget(minorSkill4, "MinorSkill4");
skills.push_back(minorSkill0);
skills.push_back(minorSkill1);
skills.push_back(minorSkill2);
skills.push_back(minorSkill3);
skills.push_back(minorSkill4);
std::vector<Widgets::MWSkillPtr>::const_iterator end = skills.end();
for (std::vector<Widgets::MWSkillPtr>::const_iterator it = skills.begin(); it != end; ++it)
{
(*it)->setWindowManager(wm);
(*it)->eventClicked = MyGUI::newDelegate(this, &CreateClassDialog::onSkillClicked);
}
setText("LabelT", wm->getGameSettingString("sName", ""));
getWidget(editName, "EditName");
// Make sure the edit box has focus
MyGUI::InputManager::getInstance().setKeyFocusWidget(editName);
// TODO: These buttons should be managed by a Dialog class
MyGUI::ButtonPtr descriptionButton;
getWidget(descriptionButton, "DescriptionButton");
descriptionButton->eventMouseButtonClick = MyGUI::newDelegate(this, &CreateClassDialog::onDescriptionClicked);
MyGUI::ButtonPtr backButton;
getWidget(backButton, "BackButton");
backButton->eventMouseButtonClick = MyGUI::newDelegate(this, &CreateClassDialog::onBackClicked);
MyGUI::ButtonPtr okButton;
getWidget(okButton, "OKButton");
okButton->eventMouseButtonClick = MyGUI::newDelegate(this, &CreateClassDialog::onOkClicked);
// Set default skills, attributes
favoriteAttribute0->setAttributeId(ESM::Attribute::Strength);
favoriteAttribute1->setAttributeId(ESM::Attribute::Agility);
majorSkill0->setSkillId(ESM::Skill::Block);
majorSkill1->setSkillId(ESM::Skill::Armorer);
majorSkill2->setSkillId(ESM::Skill::MediumArmor);
majorSkill3->setSkillId(ESM::Skill::HeavyArmor);
majorSkill4->setSkillId(ESM::Skill::BluntWeapon);
minorSkill0->setSkillId(ESM::Skill::LongBlade);
minorSkill1->setSkillId(ESM::Skill::Axe);
minorSkill2->setSkillId(ESM::Skill::Spear);
minorSkill3->setSkillId(ESM::Skill::Athletics);
minorSkill4->setSkillId(ESM::Skill::Enchant);
}
CreateClassDialog::~CreateClassDialog()
{
delete specDialog;
delete attribDialog;
delete skillDialog;
delete descDialog;
}
std::string CreateClassDialog::getName() const
{
return editName->getOnlyText();
}
std::string CreateClassDialog::getDescription() const
{
return description;
}
ESM::Class::Specialization CreateClassDialog::getSpecializationId() const
{
return specializationId;
}
std::vector<int> CreateClassDialog::getFavoriteAttributes() const
{
std::vector<int> v;
v.push_back(favoriteAttribute0->getAttributeId());
v.push_back(favoriteAttribute1->getAttributeId());
return v;
}
std::vector<ESM::Skill::SkillEnum> CreateClassDialog::getMajorSkills() const
{
std::vector<ESM::Skill::SkillEnum> v;
v.push_back(majorSkill0->getSkillId());
v.push_back(majorSkill1->getSkillId());
v.push_back(majorSkill2->getSkillId());
v.push_back(majorSkill3->getSkillId());
v.push_back(majorSkill4->getSkillId());
return v;
}
std::vector<ESM::Skill::SkillEnum> CreateClassDialog::getMinorSkills() const
{
std::vector<ESM::Skill::SkillEnum> v;
v.push_back(majorSkill0->getSkillId());
v.push_back(majorSkill1->getSkillId());
v.push_back(majorSkill2->getSkillId());
v.push_back(majorSkill3->getSkillId());
v.push_back(majorSkill4->getSkillId());
return v;
}
void CreateClassDialog::setNextButtonShow(bool shown)
{
MyGUI::ButtonPtr descriptionButton;
getWidget(descriptionButton, "DescriptionButton");
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
descriptionButton->setCoord(MyGUI::IntCoord(207 - 18, 158, 143, 23));
backButton->setCoord(MyGUI::IntCoord(356 - 18, 158, 53, 23));
okButton->setCoord(MyGUI::IntCoord(417 - 18, 158, 42 + 18, 23));
}
else
{
okButton->setCaption("OK");
descriptionButton->setCoord(MyGUI::IntCoord(207, 158, 143, 23));
backButton->setCoord(MyGUI::IntCoord(356, 158, 53, 23));
okButton->setCoord(MyGUI::IntCoord(417, 158, 42, 23));
}
}
void CreateClassDialog::open()
{
setVisible(true);
}
// widget controls
void CreateClassDialog::onDialogCancel()
{
if (specDialog)
specDialog->setVisible(false);
if (attribDialog)
attribDialog->setVisible(false);
if (skillDialog)
skillDialog->setVisible(false);
if (descDialog)
descDialog->setVisible(false);
// TODO: Delete dialogs here
}
void CreateClassDialog::onSpecializationClicked(MyGUI::WidgetPtr _sender)
{
if (specDialog)
delete specDialog;
specDialog = new SelectSpecializationDialog(environment, environment.mWindowManager->getGui()->getViewSize());
specDialog->eventCancel = MyGUI::newDelegate(this, &CreateClassDialog::onDialogCancel);
specDialog->eventItemSelected = MyGUI::newDelegate(this, &CreateClassDialog::onSpecializationSelected);
specDialog->setVisible(true);
}
void CreateClassDialog::onSpecializationSelected()
{
specializationId = specDialog->getSpecializationId();
specializationName->setCaption(environment.mWindowManager->getGameSettingString(ESM::Class::gmstSpecializationIds[specializationId], ""));
specDialog->setVisible(false);
}
void CreateClassDialog::onAttributeClicked(Widgets::MWAttributePtr _sender)
{
if (attribDialog)
delete attribDialog;
attribDialog = new SelectAttributeDialog(environment, environment.mWindowManager->getGui()->getViewSize());
attribDialog->setAffectedWidget(_sender);
attribDialog->eventCancel = MyGUI::newDelegate(this, &CreateClassDialog::onDialogCancel);
attribDialog->eventItemSelected = MyGUI::newDelegate(this, &CreateClassDialog::onAttributeSelected);
attribDialog->setVisible(true);
}
void CreateClassDialog::onAttributeSelected()
{
ESM::Attribute::AttributeID id = attribDialog->getAttributeId();
Widgets::MWAttributePtr attribute = attribDialog->getAffectedWidget();
if (attribute == favoriteAttribute0)
{
if (favoriteAttribute1->getAttributeId() == id)
favoriteAttribute1->setAttributeId(favoriteAttribute0->getAttributeId());
}
else if (attribute == favoriteAttribute1)
{
if (favoriteAttribute0->getAttributeId() == id)
favoriteAttribute0->setAttributeId(favoriteAttribute1->getAttributeId());
}
attribute->setAttributeId(id);
attribDialog->setVisible(false);
}
void CreateClassDialog::onSkillClicked(Widgets::MWSkillPtr _sender)
{
if (skillDialog)
delete skillDialog;
skillDialog = new SelectSkillDialog(environment, environment.mWindowManager->getGui()->getViewSize());
skillDialog->setAffectedWidget(_sender);
skillDialog->eventCancel = MyGUI::newDelegate(this, &CreateClassDialog::onDialogCancel);
skillDialog->eventItemSelected = MyGUI::newDelegate(this, &CreateClassDialog::onSkillSelected);
skillDialog->setVisible(true);
}
void CreateClassDialog::onSkillSelected()
{
ESM::Skill::SkillEnum id = skillDialog->getSkillId();
Widgets::MWSkillPtr skill = skillDialog->getAffectedWidget();
// Avoid duplicate skills by swapping any skill field that matches the selected one
std::vector<Widgets::MWSkillPtr>::const_iterator end = skills.end();
for (std::vector<Widgets::MWSkillPtr>::const_iterator it = skills.begin(); it != end; ++it)
{
if (*it == skill)
continue;
if ((*it)->getSkillId() == id)
{
(*it)->setSkillId(skill->getSkillId());
break;
}
}
skill->setSkillId(skillDialog->getSkillId());
skillDialog->setVisible(false);
}
void CreateClassDialog::onDescriptionClicked(MyGUI::Widget* _sender)
{
if (descDialog)
delete descDialog;
descDialog = new DescriptionDialog(environment, environment.mWindowManager->getGui()->getViewSize());
descDialog->setTextInput(description);
descDialog->eventDone = MyGUI::newDelegate(this, &CreateClassDialog::onDescriptionEntered);
descDialog->setVisible(true);
}
void CreateClassDialog::onDescriptionEntered()
{
description = descDialog->getTextInput();
descDialog->setVisible(false);
}
void CreateClassDialog::onOkClicked(MyGUI::Widget* _sender)
{
eventDone();
}
void CreateClassDialog::onBackClicked(MyGUI::Widget* _sender)
{
eventBack();
}
/* SelectSpecializationDialog */
SelectSpecializationDialog::SelectSpecializationDialog(MWWorld::Environment& environment, MyGUI::IntSize gameWindowSize)
: Layout("openmw_chargen_select_specialization_layout.xml")
{
// 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;
setText("LabelT", wm->getGameSettingString("sSpecializationMenu1", ""));
getWidget(specialization0, "Specialization0");
getWidget(specialization1, "Specialization1");
getWidget(specialization2, "Specialization2");
specialization0->setCaption(wm->getGameSettingString(ESM::Class::gmstSpecializationIds[ESM::Class::Combat], ""));
specialization0->eventMouseButtonClick = MyGUI::newDelegate(this, &SelectSpecializationDialog::onSpecializationClicked);
specialization1->setCaption(wm->getGameSettingString(ESM::Class::gmstSpecializationIds[ESM::Class::Magic], ""));
specialization1->eventMouseButtonClick = MyGUI::newDelegate(this, &SelectSpecializationDialog::onSpecializationClicked);
specialization2->setCaption(wm->getGameSettingString(ESM::Class::gmstSpecializationIds[ESM::Class::Stealth], ""));
specialization2->eventMouseButtonClick = MyGUI::newDelegate(this, &SelectSpecializationDialog::onSpecializationClicked);
specializationId = ESM::Class::Combat;
// TODO: These buttons should be managed by a Dialog class
MyGUI::ButtonPtr cancelButton;
getWidget(cancelButton, "CancelButton");
cancelButton->setCaption(wm->getGameSettingString("sCancel", ""));
cancelButton->eventMouseButtonClick = MyGUI::newDelegate(this, &SelectSpecializationDialog::onCancelClicked);
}
// widget controls
void SelectSpecializationDialog::onSpecializationClicked(MyGUI::WidgetPtr _sender)
{
if (_sender == specialization0)
specializationId = ESM::Class::Combat;
else if (_sender == specialization1)
specializationId = ESM::Class::Magic;
else if (_sender == specialization2)
specializationId = ESM::Class::Stealth;
else
return;
eventItemSelected();
}
void SelectSpecializationDialog::onCancelClicked(MyGUI::Widget* _sender)
{
eventCancel();
}
/* SelectAttributeDialog */
SelectAttributeDialog::SelectAttributeDialog(MWWorld::Environment& environment, MyGUI::IntSize gameWindowSize)
: Layout("openmw_chargen_select_attribute_layout.xml")
{
// 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;
setText("LabelT", wm->getGameSettingString("sAttributesMenu1", ""));
getWidget(attribute0, "Attribute0");
getWidget(attribute1, "Attribute1");
getWidget(attribute2, "Attribute2");
getWidget(attribute3, "Attribute3");
getWidget(attribute4, "Attribute4");
getWidget(attribute5, "Attribute5");
getWidget(attribute6, "Attribute6");
getWidget(attribute7, "Attribute7");
Widgets::MWAttributePtr attributes[8] = {
attribute0,
attribute1,
attribute2,
attribute3,
attribute4,
attribute5,
attribute6,
attribute7
};
for (int i = 0; i < 8; ++i)
{
attributes[i]->setWindowManager(wm);
attributes[i]->setAttributeId(ESM::Attribute::attributeIds[i]);
attributes[i]->eventClicked = MyGUI::newDelegate(this, &SelectAttributeDialog::onAttributeClicked);
}
// TODO: These buttons should be managed by a Dialog class
MyGUI::ButtonPtr cancelButton;
getWidget(cancelButton, "CancelButton");
cancelButton->setCaption(wm->getGameSettingString("sCancel", ""));
cancelButton->eventMouseButtonClick = MyGUI::newDelegate(this, &SelectAttributeDialog::onCancelClicked);
}
// widget controls
void SelectAttributeDialog::onAttributeClicked(Widgets::MWAttributePtr _sender)
{
// TODO: Change MWAttribute to set and get AttributeID enum instead of int
attributeId = static_cast<ESM::Attribute::AttributeID>(_sender->getAttributeId());
eventItemSelected();
}
void SelectAttributeDialog::onCancelClicked(MyGUI::Widget* _sender)
{
eventCancel();
}
/* SelectSkillDialog */
SelectSkillDialog::SelectSkillDialog(MWWorld::Environment& environment, MyGUI::IntSize gameWindowSize)
: Layout("openmw_chargen_select_skill_layout.xml")
{
// 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;
setText("LabelT", wm->getGameSettingString("sSkillsMenu1", ""));
setText("CombatLabelT", wm->getGameSettingString("sSpecializationCombat", ""));
setText("MagicLabelT", wm->getGameSettingString("sSpecializationMagic", ""));
setText("StealthLabelT", wm->getGameSettingString("sSpecializationStealth", ""));
getWidget(combatSkill0, "CombatSkill0");
getWidget(combatSkill1, "CombatSkill1");
getWidget(combatSkill2, "CombatSkill2");
getWidget(combatSkill3, "CombatSkill3");
getWidget(combatSkill4, "CombatSkill4");
getWidget(combatSkill5, "CombatSkill5");
getWidget(combatSkill6, "CombatSkill6");
getWidget(combatSkill7, "CombatSkill7");
getWidget(combatSkill8, "CombatSkill8");
getWidget(magicSkill0, "MagicSkill0");
getWidget(magicSkill1, "MagicSkill1");
getWidget(magicSkill2, "MagicSkill2");
getWidget(magicSkill3, "MagicSkill3");
getWidget(magicSkill4, "MagicSkill4");
getWidget(magicSkill5, "MagicSkill5");
getWidget(magicSkill6, "MagicSkill6");
getWidget(magicSkill7, "MagicSkill7");
getWidget(magicSkill8, "MagicSkill8");
getWidget(stealthSkill0, "StealthSkill0");
getWidget(stealthSkill1, "StealthSkill1");
getWidget(stealthSkill2, "StealthSkill2");
getWidget(stealthSkill3, "StealthSkill3");
getWidget(stealthSkill4, "StealthSkill4");
getWidget(stealthSkill5, "StealthSkill5");
getWidget(stealthSkill6, "StealthSkill6");
getWidget(stealthSkill7, "StealthSkill7");
getWidget(stealthSkill8, "StealthSkill8");
struct {Widgets::MWSkillPtr widget; ESM::Skill::SkillEnum skillId;} skills[3][9] = {
{
{combatSkill0, ESM::Skill::Block},
{combatSkill1, ESM::Skill::Armorer},
{combatSkill2, ESM::Skill::MediumArmor},
{combatSkill3, ESM::Skill::HeavyArmor},
{combatSkill4, ESM::Skill::BluntWeapon},
{combatSkill5, ESM::Skill::LongBlade},
{combatSkill6, ESM::Skill::Axe},
{combatSkill7, ESM::Skill::Spear},
{combatSkill8, ESM::Skill::Athletics}
},
{
{magicSkill0, ESM::Skill::Enchant},
{magicSkill1, ESM::Skill::Destruction},
{magicSkill2, ESM::Skill::Alteration},
{magicSkill3, ESM::Skill::Illusion},
{magicSkill4, ESM::Skill::Conjuration},
{magicSkill5, ESM::Skill::Mysticism},
{magicSkill6, ESM::Skill::Restoration},
{magicSkill7, ESM::Skill::Alchemy},
{magicSkill8, ESM::Skill::Unarmored}
},
{
{stealthSkill0, ESM::Skill::Security},
{stealthSkill1, ESM::Skill::Sneak},
{stealthSkill2, ESM::Skill::Acrobatics},
{stealthSkill3, ESM::Skill::LightArmor},
{stealthSkill4, ESM::Skill::ShortBlade},
{stealthSkill5 ,ESM::Skill::Marksman},
{stealthSkill6 ,ESM::Skill::Mercantile},
{stealthSkill7 ,ESM::Skill::Speechcraft},
{stealthSkill8 ,ESM::Skill::HandToHand}
}
};
for (int spec = 0; spec < 3; ++spec)
{
for (int i = 0; i < 9; ++i)
{
skills[spec][i].widget->setWindowManager(wm);
skills[spec][i].widget->setSkillId(skills[spec][i].skillId);
skills[spec][i].widget->eventClicked = MyGUI::newDelegate(this, &SelectSkillDialog::onSkillClicked);
}
}
// TODO: These buttons should be managed by a Dialog class
MyGUI::ButtonPtr cancelButton;
getWidget(cancelButton, "CancelButton");
cancelButton->setCaption(wm->getGameSettingString("sCancel", ""));
cancelButton->eventMouseButtonClick = MyGUI::newDelegate(this, &SelectSkillDialog::onCancelClicked);
}
// widget controls
void SelectSkillDialog::onSkillClicked(Widgets::MWSkillPtr _sender)
{
skillId = _sender->getSkillId();
eventItemSelected();
}
void SelectSkillDialog::onCancelClicked(MyGUI::Widget* _sender)
{
eventCancel();
}
/* DescriptionDialog */
DescriptionDialog::DescriptionDialog(MWWorld::Environment& environment, MyGUI::IntSize gameWindowSize)
: Layout("openmw_chargen_class_description_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);
getWidget(textEdit, "TextEdit");
// TODO: These buttons should be managed by a Dialog class
MyGUI::ButtonPtr okButton;
getWidget(okButton, "OKButton");
okButton->eventMouseButtonClick = MyGUI::newDelegate(this, &DescriptionDialog::onOkClicked);
okButton->setCaption(environment.mWindowManager->getGameSettingString("sInputMenu1", ""));
// Make sure the edit box has focus
MyGUI::InputManager::getInstance().setKeyFocusWidget(textEdit);
}
// widget controls
void DescriptionDialog::onOkClicked(MyGUI::Widget* _sender)
{
eventDone();
}

@ -0,0 +1,347 @@
#ifndef MWGUI_CLASS_H
#define MWGUI_CLASS_H
#include <components/esm_store/store.hpp>
#include <openengine/gui/layout.hpp>
#include <MyGUI.h>
#include "widgets.hpp"
namespace MWWorld
{
class Environment;
}
/*
This file contains the dialogs for choosing a class.
Layout is defined by resources/mygui/openmw_chargen_class_layout.xml.
*/
namespace MWGui
{
using namespace MyGUI;
class InfoBoxDialog : public OEngine::GUI::Layout
{
public:
InfoBoxDialog(MWWorld::Environment& environment);
typedef std::vector<std::string> ButtonList;
void setText(const std::string &str);
std::string getText() const;
void setButtons(ButtonList &buttons);
void update();
int getChosenButton() const;
// Events
typedef delegates::CDelegate2<MyGUI::WidgetPtr, int> EventHandle_WidgetInt;
/** Event : Button was clicked.\n
signature : void method(MyGUI::WidgetPtr widget, int index)\n
*/
EventHandle_WidgetInt eventButtonSelected;
protected:
void onButtonClicked(MyGUI::WidgetPtr _sender);
private:
void center();
MWWorld::Environment& environment;
int currentButton;
MyGUI::WidgetPtr textBox;
MyGUI::StaticTextPtr text;
MyGUI::WidgetPtr buttonBar;
std::vector<MyGUI::ButtonPtr> buttons;
};
// Lets the player choose between 3 ways of creating a class
class ClassChoiceDialog : public InfoBoxDialog
{
public:
// Corresponds to the buttons that can be clicked
enum ClassChoice
{
Class_Generate = 0,
Class_Pick = 1,
Class_Create = 2,
Class_Back = 3
};
ClassChoiceDialog(MWWorld::Environment& environment);
};
class GenerateClassResultDialog : public OEngine::GUI::Layout
{
public:
GenerateClassResultDialog(MWWorld::Environment& environment);
std::string getClassId() const;
void setClassId(const std::string &classId);
// 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 onOkClicked(MyGUI::Widget* _sender);
void onBackClicked(MyGUI::Widget* _sender);
private:
MWWorld::Environment& environment;
MyGUI::StaticImagePtr classImage;
MyGUI::StaticTextPtr className;
std::string currentClassId;
};
class PickClassDialog : public OEngine::GUI::Layout
{
public:
PickClassDialog(MWWorld::Environment& environment, MyGUI::IntSize gameWindowSize);
const std::string &getClassId() const { return currentClassId; }
void setClassId(const std::string &classId);
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 onSelectClass(MyGUI::List* _sender, size_t _index);
void onOkClicked(MyGUI::Widget* _sender);
void onBackClicked(MyGUI::Widget* _sender);
private:
void updateClasses();
void updateStats();
MWWorld::Environment& environment;
MyGUI::StaticImagePtr classImage;
MyGUI::ListPtr classList;
MyGUI::StaticTextPtr specializationName;
Widgets::MWAttributePtr favoriteAttribute0, favoriteAttribute1;
Widgets::MWSkillPtr majorSkill0, majorSkill1, majorSkill2, majorSkill3, majorSkill4;
Widgets::MWSkillPtr minorSkill0, minorSkill1, minorSkill2, minorSkill3, minorSkill4;
std::string currentClassId;
};
class SelectSpecializationDialog : public OEngine::GUI::Layout
{
public:
SelectSpecializationDialog(MWWorld::Environment& environment, MyGUI::IntSize gameWindowSize);
ESM::Class::Specialization getSpecializationId() const { return specializationId; }
// Events
typedef delegates::CDelegate0 EventHandle_Void;
/** Event : Cancel button clicked.\n
signature : void method()\n
*/
EventHandle_Void eventCancel;
/** Event : Dialog finished, specialization selected.\n
signature : void method()\n
*/
EventHandle_Void eventItemSelected;
protected:
void onSpecializationClicked(MyGUI::Widget* _sender);
void onCancelClicked(MyGUI::Widget* _sender);
private:
MyGUI::WidgetPtr specialization0, specialization1, specialization2;
ESM::Class::Specialization specializationId;
};
class SelectAttributeDialog : public OEngine::GUI::Layout
{
public:
SelectAttributeDialog(MWWorld::Environment& environment, MyGUI::IntSize gameWindowSize);
ESM::Attribute::AttributeID getAttributeId() const { return attributeId; }
Widgets::MWAttributePtr getAffectedWidget() const { return affectedWidget; }
void setAffectedWidget(Widgets::MWAttributePtr widget) { affectedWidget = widget; }
// Events
typedef delegates::CDelegate0 EventHandle_Void;
/** Event : Cancel button clicked.\n
signature : void method()\n
*/
EventHandle_Void eventCancel;
/** Event : Dialog finished, attribute selected.\n
signature : void method()\n
*/
EventHandle_Void eventItemSelected;
protected:
void onAttributeClicked(Widgets::MWAttributePtr _sender);
void onCancelClicked(MyGUI::Widget* _sender);
private:
Widgets::MWAttributePtr attribute0, attribute1, attribute2, attribute3,
attribute4, attribute5, attribute6, attribute7;
Widgets::MWAttributePtr affectedWidget;
ESM::Attribute::AttributeID attributeId;
};
class SelectSkillDialog : public OEngine::GUI::Layout
{
public:
SelectSkillDialog(MWWorld::Environment& environment, MyGUI::IntSize gameWindowSize);
ESM::Skill::SkillEnum getSkillId() const { return skillId; }
Widgets::MWSkillPtr getAffectedWidget() const { return affectedWidget; }
void setAffectedWidget(Widgets::MWSkillPtr widget) { affectedWidget = widget; }
// Events
typedef delegates::CDelegate0 EventHandle_Void;
/** Event : Cancel button clicked.\n
signature : void method()\n
*/
EventHandle_Void eventCancel;
/** Event : Dialog finished, skill selected.\n
signature : void method()\n
*/
EventHandle_Void eventItemSelected;
protected:
void onSkillClicked(Widgets::MWSkillPtr _sender);
void onCancelClicked(MyGUI::Widget* _sender);
private:
Widgets::MWSkillPtr combatSkill0, combatSkill1, combatSkill2, combatSkill3, combatSkill4,
combatSkill5, combatSkill6, combatSkill7, combatSkill8;
Widgets::MWSkillPtr magicSkill0, magicSkill1, magicSkill2, magicSkill3, magicSkill4,
magicSkill5, magicSkill6, magicSkill7, magicSkill8;
Widgets::MWSkillPtr stealthSkill0, stealthSkill1, stealthSkill2, stealthSkill3, stealthSkill4,
stealthSkill5, stealthSkill6, stealthSkill7, stealthSkill8;
Widgets::MWSkillPtr affectedWidget;
ESM::Skill::SkillEnum skillId;
};
class DescriptionDialog : public OEngine::GUI::Layout
{
public:
DescriptionDialog(MWWorld::Environment& environment, MyGUI::IntSize gameWindowSize);
std::string getTextInput() const { return textEdit ? textEdit->getOnlyText() : ""; }
void setTextInput(const std::string &text) { if (textEdit) textEdit->setOnlyText(text); }
// Events
typedef delegates::CDelegate0 EventHandle_Void;
/** Event : Dialog finished, OK button clicked.\n
signature : void method()\n
*/
EventHandle_Void eventDone;
protected:
void onOkClicked(MyGUI::Widget* _sender);
private:
MWWorld::Environment& environment;
MyGUI::EditPtr textEdit;
};
class CreateClassDialog : public OEngine::GUI::Layout
{
public:
CreateClassDialog(MWWorld::Environment& environment, MyGUI::IntSize gameWindowSize);
virtual ~CreateClassDialog();
std::string getName() const;
std::string getDescription() const;
ESM::Class::Specialization getSpecializationId() const;
std::vector<int> getFavoriteAttributes() const;
std::vector<ESM::Skill::SkillEnum> getMajorSkills() const;
std::vector<ESM::Skill::SkillEnum> getMinorSkills() const;
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 onOkClicked(MyGUI::Widget* _sender);
void onBackClicked(MyGUI::Widget* _sender);
void onSpecializationClicked(MyGUI::WidgetPtr _sender);
void onSpecializationSelected();
void onAttributeClicked(Widgets::MWAttributePtr _sender);
void onAttributeSelected();
void onSkillClicked(Widgets::MWSkillPtr _sender);
void onSkillSelected();
void onDescriptionClicked(MyGUI::Widget* _sender);
void onDescriptionEntered();
void onDialogCancel();
private:
MWWorld::Environment& environment;
MyGUI::EditPtr editName;
MyGUI::WidgetPtr specializationName;
Widgets::MWAttributePtr favoriteAttribute0, favoriteAttribute1;
Widgets::MWSkillPtr majorSkill0, majorSkill1, majorSkill2, majorSkill3, majorSkill4;
Widgets::MWSkillPtr minorSkill0, minorSkill1, minorSkill2, minorSkill3, minorSkill4;
std::vector<Widgets::MWSkillPtr> skills;
std::string description;
SelectSpecializationDialog *specDialog;
SelectAttributeDialog *attribDialog;
SelectSkillDialog *skillDialog;
DescriptionDialog *descDialog;
ESM::Class::Specialization specializationId;
};
}
#endif

@ -0,0 +1,412 @@
#include "layouts.hpp"
#include "../mwworld/class.hpp"
#include "../mwmechanics/mechanicsmanager.hpp"
#include "../mwgui/window_manager.hpp"
#include <algorithm>
#include <iterator>
#include <boost/lexical_cast.hpp>
using namespace MWGui;
const int StatsWindow::lineHeight = 18;
StatsWindow::StatsWindow (MWWorld::Environment& environment)
: Layout("openmw_stats_window_layout.xml")
, environment(environment)
, lastPos(0)
{
setCoord(0,0,498, 342);
const char *names[][2] =
{
{ "Attrib1", "sAttributeStrength" },
{ "Attrib2", "sAttributeIntelligence" },
{ "Attrib3", "sAttributeWillpower" },
{ "Attrib4", "sAttributeAgility" },
{ "Attrib5", "sAttributeSpeed" },
{ "Attrib6", "sAttributeEndurance" },
{ "Attrib7", "sAttributePersonality" },
{ "Attrib8", "sAttributeLuck" },
{ "Health_str", "sHealth" },
{ "Magicka_str", "sMagic" },
{ "Fatigue_str", "sFatigue" },
{ "Level_str", "sLevel" },
{ "Race_str", "sRace" },
{ "Class_str", "sClass" },
{ 0, 0 }
};
const ESMS::ESMStore &store = environment.mWorld->getStore();
for (int i=0; names[i][0]; ++i)
{
setText (names[i][0], store.gameSettings.find (names[i][1])->str);
}
getWidget(skillAreaWidget, "Skills");
getWidget(skillClientWidget, "SkillClient");
getWidget(skillScrollerWidget, "SkillScroller");
skillScrollerWidget->eventScrollChangePosition = MyGUI::newDelegate(this, &StatsWindow::onScrollChangePosition);
updateScroller();
for (int i = 0; i < ESM::Skill::Length; ++i)
{
skillValues.insert(std::pair<int, MWMechanics::Stat<float> >(i, MWMechanics::Stat<float>()));
skillWidgetMap.insert(std::pair<int, MyGUI::WidgetPtr>(i, nullptr));
}
static_cast<MyGUI::WindowPtr>(mMainWidget)->eventWindowChangeCoord = MyGUI::newDelegate(this, &StatsWindow::onWindowResize);
}
void StatsWindow::onScrollChangePosition(MyGUI::VScrollPtr scroller, size_t pos)
{
int diff = lastPos - pos;
// Adjust position of all widget according to difference
if (diff == 0)
return;
lastPos = pos;
std::vector<MyGUI::WidgetPtr>::const_iterator end = skillWidgets.end();
for (std::vector<MyGUI::WidgetPtr>::const_iterator it = skillWidgets.begin(); it != end; ++it)
{
(*it)->setCoord((*it)->getCoord() + MyGUI::IntPoint(0, diff));
}
}
void StatsWindow::onWindowResize(MyGUI::WidgetPtr window)
{
updateScroller();
}
void StatsWindow::setBar(const std::string& name, const std::string& tname, int val, int max)
{
MyGUI::ProgressPtr pt;
getWidget(pt, name);
pt->setProgressRange(max);
pt->setProgressPosition(val);
std::stringstream out;
out << val << "/" << max;
setText(tname, out.str().c_str());
}
void StatsWindow::setPlayerName(const std::string& playerName)
{
mMainWidget->setCaption(playerName);
}
void StatsWindow::setStyledText(MyGUI::WidgetPtr widget, ColorStyle style, const std::string &value)
{
widget->setCaption(value);
if (style == CS_Super)
widget->setTextColour(MyGUI::Colour(0, 1, 0));
else if (style == CS_Sub)
widget->setTextColour(MyGUI::Colour(1, 0, 0));
else
widget->setTextColour(MyGUI::Colour(1, 1, 1));
}
void StatsWindow::setValue (const std::string& id, const MWMechanics::Stat<int>& value)
{
static const char *ids[] =
{
"AttribVal1", "AttribVal2", "AttribVal3", "AttribVal4", "AttribVal5",
"AttribVal6", "AttribVal7", "AttribVal8",
0
};
for (int i=0; ids[i]; ++i)
if (ids[i]==id)
{
std::ostringstream valueString;
valueString << value.getModified();
setText (id, valueString.str());
if (value.getModified()>value.getBase())
setTextColor (id, 0, 1, 0);
else if (value.getModified()<value.getBase())
setTextColor (id, 1, 0, 0);
else
setTextColor (id, 1, 1, 1);
break;
}
}
void StatsWindow::setValue (const std::string& id, const MWMechanics::DynamicStat<int>& value)
{
static const char *ids[] =
{
"HBar", "MBar", "FBar",
0
};
for (int i=0; ids[i]; ++i)
if (ids[i]==id)
{
std::string id (ids[i]);
setBar (id, id + "T", value.getCurrent(), value.getModified());
}
}
void StatsWindow::setValue (const std::string& id, const std::string& value)
{
if (id=="name")
setPlayerName (value);
else if (id=="race")
setText ("RaceText", value);
else if (id=="class")
setText ("ClassText", value);
}
void StatsWindow::setValue (const std::string& id, int value)
{
if (id=="level")
{
std::ostringstream text;
text << value;
setText("LevelText", text.str());
}
}
void StatsWindow::setValue (const std::string& id, const MWMechanics::Stat<float>& value)
{
static struct {const char *id; ESM::Skill::SkillEnum skillId; } skillMap[] =
{
{"SkillBlock", ESM::Skill::Block},
{"SkillArmorer", ESM::Skill::Armorer},
{"SkillMediumArmor", ESM::Skill::MediumArmor},
{"SkillHeavyArmor", ESM::Skill::HeavyArmor},
{"SkillBluntWeapon", ESM::Skill::BluntWeapon},
{"SkillLongBlade", ESM::Skill::LongBlade},
{"SkillAxe", ESM::Skill::Axe},
{"SkillSpear", ESM::Skill::Spear},
{"SkillAthletics", ESM::Skill::Athletics},
{"SkillEnchant", ESM::Skill::Armorer},
{"SkillDestruction", ESM::Skill::Destruction},
{"SkillAlteration", ESM::Skill::Alteration},
{"SkillIllusion", ESM::Skill::Illusion},
{"SkillConjuration", ESM::Skill::Conjuration},
{"SkillMysticism", ESM::Skill::Mysticism},
{"SkillRestoration", ESM::Skill::Restoration},
{"SkillAlchemy", ESM::Skill::Alchemy},
{"SkillUnarmored", ESM::Skill::Unarmored},
{"SkillSecurity", ESM::Skill::Security},
{"SkillSneak", ESM::Skill::Sneak},
{"SkillAcrobatics", ESM::Skill::Acrobatics},
{"SkillLightArmor", ESM::Skill::LightArmor},
{"SkillShortBlade", ESM::Skill::ShortBlade},
{"SkillMarksman", ESM::Skill::Marksman},
{"SkillMercantile", ESM::Skill::Mercantile},
{"SkillSpeechcraft", ESM::Skill::Speechcraft},
{"SkillHandToHand", ESM::Skill::HandToHand},
};
for (int i = 0; i < sizeof(skillMap)/sizeof(skillMap[0]); ++i)
{
if (skillMap[i].id == id)
{
int skillId = skillMap[i].skillId;
skillValues[skillId] = value;
MyGUI::WidgetPtr widget = skillWidgetMap[skillId];
if (widget)
{
float modified = value.getModified(), base = value.getBase();
std::string text = boost::lexical_cast<std::string>(std::floor(modified));
ColorStyle style = CS_Normal;
if (modified > base)
style = CS_Super;
else if (modified < base)
style = CS_Sub;
setStyledText(widget, style, text);
}
break;
}
}
}
void StatsWindow::configureSkills (const std::vector<int>& major, const std::vector<int>& minor)
{
majorSkills = major;
minorSkills = minor;
// Update misc skills with the remaining skills not in major or minor
std::set<int> skillSet;
std::copy(major.begin(), major.end(), std::inserter(skillSet, skillSet.begin()));
std::copy(minor.begin(), minor.end(), std::inserter(skillSet, skillSet.begin()));
boost::array<ESM::Skill::SkillEnum, ESM::Skill::Length>::const_iterator end = ESM::Skill::skillIds.end();
miscSkills.clear();
for (boost::array<ESM::Skill::SkillEnum, ESM::Skill::Length>::const_iterator it = ESM::Skill::skillIds.begin(); it != end; ++it)
{
int skill = *it;
if (skillSet.find(skill) == skillSet.end())
miscSkills.push_back(skill);
}
}
void StatsWindow::setFactions (const std::vector<Faction>& factions)
{
this->factions = factions;
}
void StatsWindow::setBirthSign (const std::string& signId)
{
birthSignId = signId;
}
void StatsWindow::addSeparator(MyGUI::IntCoord &coord1, MyGUI::IntCoord &coord2)
{
MyGUI::StaticImagePtr separator = skillClientWidget->createWidget<MyGUI::StaticImage>("MW_HLine", MyGUI::IntCoord(10, coord1.top, coord1.width + coord2.width - 4, 18), MyGUI::Align::Default);
skillWidgets.push_back(separator);
coord1.top += separator->getHeight();
coord2.top += separator->getHeight();
}
void StatsWindow::addGroup(const std::string &label, MyGUI::IntCoord &coord1, MyGUI::IntCoord &coord2)
{
MyGUI::StaticTextPtr groupWidget = skillClientWidget->createWidget<MyGUI::StaticText>("SandBrightText", MyGUI::IntCoord(0, coord1.top, coord1.width + coord2.width, coord1.height), MyGUI::Align::Default);
groupWidget->setCaption(label);
skillWidgets.push_back(groupWidget);
coord1.top += lineHeight;
coord2.top += lineHeight;
}
MyGUI::WidgetPtr StatsWindow::addValueItem(const std::string text, const std::string &value, ColorStyle style, MyGUI::IntCoord &coord1, MyGUI::IntCoord &coord2)
{
MyGUI::StaticTextPtr skillNameWidget, skillValueWidget;
skillNameWidget = skillClientWidget->createWidget<MyGUI::StaticText>("SandText", coord1, MyGUI::Align::Default);
skillNameWidget->setCaption(text);
skillValueWidget = skillClientWidget->createWidget<MyGUI::StaticText>("SandTextRight", coord2, MyGUI::Align::Default);
setStyledText(skillValueWidget, style, value);
skillWidgets.push_back(skillNameWidget);
skillWidgets.push_back(skillValueWidget);
coord1.top += lineHeight;
coord2.top += lineHeight;
return skillValueWidget;
}
void StatsWindow::addItem(const std::string text, MyGUI::IntCoord &coord1, MyGUI::IntCoord &coord2)
{
MyGUI::StaticTextPtr skillNameWidget;
skillNameWidget = skillClientWidget->createWidget<MyGUI::StaticText>("SandText", coord1 + MyGUI::IntSize(coord2.width, 0), MyGUI::Align::Default);
skillNameWidget->setCaption(text);
skillWidgets.push_back(skillNameWidget);
coord1.top += lineHeight;
coord2.top += lineHeight;
}
void StatsWindow::addSkills(const SkillList &skills, const std::string &titleId, const std::string &titleDefault, MyGUI::IntCoord &coord1, MyGUI::IntCoord &coord2)
{
WindowManager *wm = environment.mWindowManager;
MWMechanics::MechanicsManager *mm = environment.mMechanicsManager;
ESMS::ESMStore &store = environment.mWorld->getStore();
// Add a line separator if there are items above
if (!skillWidgets.empty())
{
addSeparator(coord1, coord2);
}
addGroup(wm->getGameSettingString(titleId, titleDefault), coord1, coord2);
SkillList::const_iterator end = skills.end();
for (SkillList::const_iterator it = skills.begin(); it != end; ++it)
{
int skillId = *it;
if (skillId < 0 || skillId > ESM::Skill::Length) // Skip unknown skill indexes
continue;
assert(skillId >= 0 && skillId < ESM::Skill::Length);
const std::string &skillNameId = ESMS::Skill::sSkillNameIds[skillId];
const MWMechanics::Stat<float> &stat = skillValues.find(skillId)->second;
float base = stat.getBase();
float modified = stat.getModified();
ColorStyle style = CS_Normal;
if (modified > base)
style = CS_Super;
else if (modified < base)
style = CS_Sub;
MyGUI::WidgetPtr widget = addValueItem(wm->getGameSettingString(skillNameId, skillNameId), boost::lexical_cast<std::string>(static_cast<int>(modified)), style, coord1, coord2);
skillWidgetMap[skillId] = widget;
}
}
void StatsWindow::updateSkillArea()
{
for (std::vector<MyGUI::WidgetPtr>::iterator it = skillWidgets.begin(); it != skillWidgets.end(); ++it)
{
MyGUI::Gui::getInstance().destroyWidget(*it);
}
skillWidgets.clear();
const int valueSize = 40;
MyGUI::IntCoord coord1(10, 0, skillClientWidget->getWidth() - (10 + valueSize), 18);
MyGUI::IntCoord coord2(coord1.left + coord1.width, coord1.top, valueSize, coord1.height);
if (!majorSkills.empty())
addSkills(majorSkills, "sSkillClassMajor", "Major Skills", coord1, coord2);
if (!minorSkills.empty())
addSkills(minorSkills, "sSkillClassMinor", "Minor Skills", coord1, coord2);
if (!miscSkills.empty())
addSkills(miscSkills, "sSkillClassMisc", "Misc Skills", coord1, coord2);
WindowManager *wm = environment.mWindowManager;
ESMS::ESMStore &store = environment.mWorld->getStore();
if (!factions.empty())
{
// Add a line separator if there are items above
if (!skillWidgets.empty())
addSeparator(coord1, coord2);
addGroup(wm->getGameSettingString("sFaction", "Faction"), coord1, coord2);
FactionList::const_iterator end = factions.end();
for (FactionList::const_iterator it = factions.begin(); it != end; ++it)
{
const ESM::Faction *faction = store.factions.find(it->first);
addItem(faction->name, coord1, coord2);
// TODO: Faction rank should be placed in tooltip
}
}
if (!birthSignId.empty())
{
// Add a line separator if there are items above
if (!skillWidgets.empty())
addSeparator(coord1, coord2);
addGroup(wm->getGameSettingString("sSign", "Sign"), coord1, coord2);
const ESM::BirthSign *sign = store.birthSigns.find(birthSignId);
addItem(sign->name, coord1, coord2);
}
// Add a line separator if there are items above
if (!skillWidgets.empty())
addSeparator(coord1, coord2);
addValueItem(wm->getGameSettingString("sReputation", "Reputation"), boost::lexical_cast<std::string>(static_cast<int>(reputation)), CS_Normal, coord1, coord2);
addValueItem(wm->getGameSettingString("sBounty", "Bounty"), boost::lexical_cast<std::string>(static_cast<int>(bounty)), CS_Normal, coord1, coord2);
clientHeight = coord1.top;
updateScroller();
}
void StatsWindow::updateScroller()
{
skillScrollerWidget->setScrollRange(std::max(clientHeight - skillClientWidget->getHeight(), 0));
skillScrollerWidget->setScrollPage(std::max(skillClientWidget->getHeight() - lineHeight, 0));
}

@ -0,0 +1,364 @@
#ifndef MWGUI_LAYOUTS_H
#define MWGUI_LAYOUTS_H
#include <components/esm_store/store.hpp>
#include <openengine/gui/layout.hpp>
#include <boost/array.hpp>
#include <sstream>
#include <set>
#include <string>
#include <utility>
#include "../mwmechanics/stat.hpp"
#include "../mwworld/environment.hpp"
#include "../mwworld/world.hpp"
/*
This file contains classes corresponding to all the window layouts
defined in resources/mygui/ *.xml.
Each class inherites GUI::Layout and loads the XML file, and
provides some helper functions to manipulate the elements of the
window.
The windows are never created or destroyed (except at startup and
shutdown), they are only hid. You can control visibility with
setVisible().
*/
namespace MWGui
{
class HUD : public OEngine::GUI::Layout
{
public:
HUD(int width, int height)
: Layout("openmw_hud_layout.xml")
{
setCoord(0,0, width, height);
// Energy bars
getWidget(health, "Health");
getWidget(magicka, "Magicka");
getWidget(stamina, "Stamina");
// Item and spell images and status bars
getWidget(weapImage, "WeapImage");
getWidget(weapStatus, "WeapStatus");
getWidget(spellImage, "SpellImage");
getWidget(spellStatus, "SpellStatus");
getWidget(effectBox, "EffectBox");
getWidget(effect1, "Effect1");
getWidget(minimap, "MiniMap");
getWidget(compass, "Compass");
getWidget(crosshair, "Crosshair");
compass->setImageTexture("textures\\compass.dds");
crosshair->setImageTexture("textures\\target.dds");
// These are just demo values, you should replace these with
// real calls from outside the class later.
setWeapIcon("icons\\w\\tx_knife_iron.dds");
setWeapStatus(90, 100);
setSpellIcon("icons\\s\\b_tx_s_rstor_health.dds");
setSpellStatus(65, 100);
setEffect("icons\\s\\tx_s_chameleon.dds");
}
void setStats(int h, int hmax, int m, int mmax, int s, int smax)
{
health->setProgressRange(hmax);
health->setProgressPosition(h);
magicka->setProgressRange(mmax);
magicka->setProgressPosition(m);
stamina->setProgressRange(smax);
stamina->setProgressPosition(s);
}
void setWeapIcon(const char *str)
{ weapImage->setImageTexture(str); }
void setSpellIcon(const char *str)
{ spellImage->setImageTexture(str); }
void setWeapStatus(int s, int smax)
{
weapStatus->setProgressRange(smax);
weapStatus->setProgressPosition(s);
}
void setSpellStatus(int s, int smax)
{
spellStatus->setProgressRange(smax);
spellStatus->setProgressPosition(s);
}
void setEffect(const char *img)
{ effect1->setImageTexture(img); }
void setValue (const std::string& id, const MWMechanics::DynamicStat<int>& value)
{
static const char *ids[] =
{
"HBar", "MBar", "FBar",
0
};
for (int i=0; ids[i]; ++i)
if (ids[i]==id)
{
switch (i)
{
case 0:
health->setProgressRange (value.getModified());
health->setProgressPosition (value.getCurrent());
break;
case 1:
magicka->setProgressRange (value.getModified());
magicka->setProgressPosition (value.getCurrent());
break;
case 2:
stamina->setProgressRange (value.getModified());
stamina->setProgressPosition (value.getCurrent());
break;
}
}
}
MyGUI::ProgressPtr health, magicka, stamina;
MyGUI::StaticImagePtr weapImage, spellImage;
MyGUI::ProgressPtr weapStatus, spellStatus;
MyGUI::WidgetPtr effectBox;
MyGUI::StaticImagePtr effect1;
MyGUI::StaticImagePtr minimap;
MyGUI::StaticImagePtr compass;
MyGUI::StaticImagePtr crosshair;
};
class MapWindow : public OEngine::GUI::Layout
{
public:
MapWindow()
: Layout("openmw_map_window_layout.xml")
{
setCoord(500,0,320,300);
setText("WorldButton", "World");
setImage("Compass", "compass.dds");
// Obviously you should override this later on
setCellName("No Cell Loaded");
}
void setCellName(const std::string& cellName)
{
mMainWidget->setCaption(cellName);
}
};
class MainMenu : public OEngine::GUI::Layout
{
public:
MainMenu(int w, int h)
: Layout("openmw_mainmenu_layout.xml")
{
setCoord(0,0,w,h);
}
};
class StatsWindow : public OEngine::GUI::Layout
{
public:
typedef std::pair<std::string, int> Faction;
typedef std::vector<Faction> FactionList;
typedef std::vector<int> SkillList;
StatsWindow (MWWorld::Environment& environment);
void setBar(const std::string& name, const std::string& tname, int val, int max);
void setPlayerName(const std::string& playerName);
/// Set value for the given ID.
void setValue (const std::string& id, const MWMechanics::Stat<int>& value);
void setValue (const std::string& id, const MWMechanics::DynamicStat<int>& value);
void setValue (const std::string& id, const std::string& value);
void setValue (const std::string& id, int value);
void setValue (const std::string& id, const MWMechanics::Stat<float>& value);
void configureSkills (const SkillList& major, const SkillList& minor);
void setFactions (const std::vector<Faction>& factions);
void setBirthSign (const std::string &signId);
void setReputation (int reputation) { this->reputation = reputation; }
void setBounty (int bounty) { this->bounty = bounty; }
void updateSkillArea();
private:
enum ColorStyle
{
CS_Sub,
CS_Normal,
CS_Super
};
void setStyledText(MyGUI::WidgetPtr widget, ColorStyle style, const std::string &value);
void addSkills(const SkillList &skills, const std::string &titleId, const std::string &titleDefault, MyGUI::IntCoord &coord1, MyGUI::IntCoord &coord2);
void addSeparator(MyGUI::IntCoord &coord1, MyGUI::IntCoord &coord2);
void addGroup(const std::string &label, MyGUI::IntCoord &coord1, MyGUI::IntCoord &coord2);
MyGUI::WidgetPtr addValueItem(const std::string text, const std::string &value, ColorStyle style, MyGUI::IntCoord &coord1, MyGUI::IntCoord &coord2);
void addItem(const std::string text, MyGUI::IntCoord &coord1, MyGUI::IntCoord &coord2);
void updateScroller();
void onScrollChangePosition(MyGUI::VScrollPtr scroller, size_t pos);
void onWindowResize(MyGUI::WidgetPtr window);
static const int lineHeight;
MWWorld::Environment& environment;
MyGUI::WidgetPtr skillAreaWidget, skillClientWidget;
MyGUI::VScrollPtr skillScrollerWidget;
int lastPos, clientHeight;
SkillList majorSkills, minorSkills, miscSkills;
std::map<int, MWMechanics::Stat<float> > skillValues;
std::map<int, MyGUI::WidgetPtr> skillWidgetMap;
std::map<std::string, MyGUI::WidgetPtr> factionWidgetMap;
FactionList factions; ///< Stores a list of factions and the current rank
std::string birthSignId;
int reputation, bounty;
std::vector<MyGUI::WidgetPtr> skillWidgets; //< Skills and other information
};
#if 0
class InventoryWindow : public OEngine::GUI::Layout
{
public:
enum CategoryMode
{
CM_All = 0, // All items
CM_Weapon = 1, // Only weapons
CM_Apparel = 2, // Apparel
CM_Magic = 3, // Magic
CM_Misc = 4 // Misc
};
InventoryWindow ()
: Layout("openmw_inventory_window_layout.xml")
, categoryMode(CM_All)
// color should be fetched from skin
, activeColor(0, 0, 1)
, inactiveColor(0.7, 0.7, 0.7)
{
setCoord(0, 200, 600, 400);
// These are just demo values, you should replace these with
// real calls from outside the class later.
mMainWidget->setCaption("Glass Frostsword");
setText("EncumbranceBarT", "176/210");
MyGUI::ProgressPtr pt;
getWidget(pt, "EncumbranceBar");
pt->setProgressRange(210);
pt->setProgressPosition(176);
MyGUI::WidgetPtr avatar;
getWidget(avatar, "Avatar");
// Adjust armor rating text to bottom of avatar widget
MyGUI::StaticTextPtr armor_rating;
getWidget(armor_rating, "ArmorRating");
armor_rating->setCaption("Armor: 11");
MyGUI::IntCoord coord = armor_rating->getCoord();
coord.top = avatar->getCoord().height - 4 - coord.height;
armor_rating->setCoord(coord);
names[0] = "All";
names[1] = "Weapon";
names[2] = "Apparel";
names[3] = "Magic";
names[4] = "Misc";
boost::array<CategoryMode, 5> categories = { {
CM_All, CM_Weapon, CM_Apparel, CM_Magic, CM_Misc
} };
// Initialize buttons with text and adjust sizes, also mark All as active button
int margin = 2;
int last_x = 0;
for (int i = 0; i < categories.size(); ++i)
{
CategoryMode mode = categories[i];
std::string name = names[mode];
name += "Button";
setText(name, names[mode]);
getWidget(buttons[mode], name);
MyGUI::ButtonPtr &button_pt = buttons[mode];
if (mode == CM_All)
button_pt->setTextColour(activeColor);
else
button_pt->setTextColour(inactiveColor);
MyGUI::IntCoord coord = button_pt->getCoord();
coord.left = last_x;
last_x += coord.width + margin;
button_pt->setCoord(coord);
button_pt->eventMouseButtonClick = MyGUI::newDelegate(this, &InventoryWindow::onCategorySelected);
}
}
void setCategory(CategoryMode mode)
{
MyGUI::ButtonPtr pt = getCategoryButton(categoryMode);
pt->setTextColour(inactiveColor);
pt = getCategoryButton(mode);
pt->setTextColour(activeColor);
categoryMode = mode;
}
MyGUI::ButtonPtr getCategoryButton(CategoryMode mode)
{
return buttons[mode];
}
void onCategorySelected(MyGUI::Widget *widget)
{
boost::array<CategoryMode, 5> categories = { {
CM_All, CM_Weapon, CM_Apparel, CM_Magic, CM_Misc
} };
for (int i = 0; i < categories.size(); ++i)
{
CategoryMode mode = categories[i];
if (widget == buttons[mode])
{
setCategory(mode);
return;
}
}
}
CategoryMode categoryMode; // Current category filter
MyGUI::ButtonPtr buttons[5]; // Button pointers
std::string names[5]; // Names of category buttons
MyGUI::Colour activeColor;
MyGUI::Colour inactiveColor;
};
#endif
}
#endif

@ -0,0 +1,46 @@
#ifndef MWGUI_MODE_H
#define MWGUI_MODE_H
namespace MWGui
{
enum GuiMode
{
GM_Game, // Game mode, only HUD
GM_Inventory, // Inventory mode
GM_MainMenu, // Main menu mode
GM_Console, // Console mode
// None of the following are implemented yet
GM_Dialogue, // NPC interaction
GM_Barter,
GM_Rest,
// .. more here ..
// Startup character creation dialogs
GM_Name,
GM_Race,
GM_Birth,
GM_Class,
GM_ClassGenerate,
GM_ClassPick,
GM_ClassCreate,
GM_Review
};
// Windows shown in inventory mode
enum GuiWindow
{
GW_None = 0,
GW_Map = 0x01,
GW_Inventory = 0x02,
GW_Magic = 0x04,
GW_Stats = 0x08,
GW_ALL = 0xFF
};
}
#endif

@ -1,272 +0,0 @@
#ifndef MWGUI_LAYOUTS_H
#define MWGUI_LAYOUTS_H
#include <components/esm_store/store.hpp>
#include <openengine/gui/layout.hpp>
/*
This file contains classes corresponding to all the window layouts
defined in resources/mygui/ *.xml.
Each class inherites GUI::Layout and loads the XML file, and
provides some helper functions to manipulate the elements of the
window.
The windows are never created or destroyed (except at startup and
shutdown), they are only hid. You can control visibility with
setVisible().
*/
namespace MWGui
{
class HUD : public OEngine::GUI::Layout
{
public:
HUD(int width, int height)
: Layout("openmw_hud_layout.xml")
{
setCoord(0,0, width, height);
// Energy bars
getWidget(health, "Health");
getWidget(magicka, "Magicka");
getWidget(stamina, "Stamina");
// Item and spell images and status bars
getWidget(weapImage, "WeapImage");
getWidget(weapStatus, "WeapStatus");
getWidget(spellImage, "SpellImage");
getWidget(spellStatus, "SpellStatus");
getWidget(effectBox, "EffectBox");
getWidget(effect1, "Effect1");
getWidget(minimap, "MiniMap");
getWidget(compass, "Compass");
getWidget(crosshair, "Crosshair");
compass->setImageTexture("textures\\compass.dds");
crosshair->setImageTexture("textures\\target.dds");
// These are just demo values, you should replace these with
// real calls from outside the class later.
setWeapIcon("icons\\w\\tx_knife_iron.dds");
setWeapStatus(90, 100);
setSpellIcon("icons\\s\\b_tx_s_rstor_health.dds");
setSpellStatus(65, 100);
setEffect("icons\\s\\tx_s_chameleon.dds");
}
void setStats(int h, int hmax, int m, int mmax, int s, int smax)
{
health->setProgressRange(hmax);
health->setProgressPosition(h);
magicka->setProgressRange(mmax);
magicka->setProgressPosition(m);
stamina->setProgressRange(smax);
stamina->setProgressPosition(s);
}
void setWeapIcon(const char *str)
{ weapImage->setImageTexture(str); }
void setSpellIcon(const char *str)
{ spellImage->setImageTexture(str); }
void setWeapStatus(int s, int smax)
{
weapStatus->setProgressRange(smax);
weapStatus->setProgressPosition(s);
}
void setSpellStatus(int s, int smax)
{
spellStatus->setProgressRange(smax);
spellStatus->setProgressPosition(s);
}
void setEffect(const char *img)
{ effect1->setImageTexture(img); }
void setValue (const std::string& id, const MWMechanics::DynamicStat<int>& value)
{
static const char *ids[] =
{
"HBar", "MBar", "FBar",
0
};
for (int i=0; ids[i]; ++i)
if (ids[i]==id)
{
switch (i)
{
case 0:
health->setProgressRange (value.getModified());
health->setProgressPosition (value.getCurrent());
break;
case 1:
magicka->setProgressRange (value.getModified());
magicka->setProgressPosition (value.getCurrent());
break;
case 2:
stamina->setProgressRange (value.getModified());
stamina->setProgressPosition (value.getCurrent());
break;
}
}
}
MyGUI::ProgressPtr health, magicka, stamina;
MyGUI::StaticImagePtr weapImage, spellImage;
MyGUI::ProgressPtr weapStatus, spellStatus;
MyGUI::WidgetPtr effectBox;
MyGUI::StaticImagePtr effect1;
MyGUI::StaticImagePtr minimap;
MyGUI::StaticImagePtr compass;
MyGUI::StaticImagePtr crosshair;
};
class MapWindow : public OEngine::GUI::Layout
{
public:
MapWindow()
: Layout("openmw_map_window_layout.xml")
{
setCoord(500,0,320,300);
setText("WorldButton", "World");
setImage("Compass", "compass.dds");
// Obviously you should override this later on
setCellName("No Cell Loaded");
}
void setCellName(const std::string& cellName)
{
mMainWidget->setCaption(cellName);
}
};
class MainMenu : public OEngine::GUI::Layout
{
public:
MainMenu(int w, int h)
: Layout("openmw_mainmenu_layout.xml")
{
setCoord(0,0,w,h);
}
};
class StatsWindow : public OEngine::GUI::Layout
{
public:
void setBar(const std::string& name, const std::string& tname, int val, int max)
{
MyGUI::ProgressPtr pt;
getWidget(pt, name);
pt->setProgressRange(max);
pt->setProgressPosition(val);
std::stringstream out;
out << val << "/" << max;
setText(tname, out.str().c_str());
}
StatsWindow (const ESMS::ESMStore& store)
: Layout("openmw_stats_window_layout.xml")
{
setCoord(0,0,498, 342);
const char *names[][2] =
{
{ "Attrib1", "sAttributeStrength" },
{ "Attrib2", "sAttributeIntelligence" },
{ "Attrib3", "sAttributeWillpower" },
{ "Attrib4", "sAttributeAgility" },
{ "Attrib5", "sAttributeSpeed" },
{ "Attrib6", "sAttributeEndurance" },
{ "Attrib7", "sAttributePersonality" },
{ "Attrib8", "sAttributeLuck" },
{ "Health_str", "sHealth" },
{ "Magicka_str", "sMagic" },
{ "Fatigue_str", "sFatigue" },
{ "Level_str", "sLevel" },
{ "Race_str", "sRace" },
{ "Class_str", "sClass" },
{ 0, 0 }
};
for (int i=0; names[i][0]; ++i)
{
setText (names[i][0], store.gameSettings.find (names[i][1])->str);
}
// These are just demo values, you should replace these with
// real calls from outside the class later.
setPlayerName("ThePlayer");
setText("LevelText", "5");
setText("RaceText", "Wood Elf");
setText("ClassText", "Pilgrim");
}
void setPlayerName(const std::string& playerName)
{
mMainWidget->setCaption(playerName);
}
/// Set value for the given ID.
void setValue (const std::string& id, const MWMechanics::Stat<int>& value)
{
static const char *ids[] =
{
"AttribVal1", "AttribVal2", "AttribVal3", "AttribVal4", "AttribVal5",
"AttribVal6", "AttribVal7", "AttribVal8",
0
};
for (int i=0; ids[i]; ++i)
if (ids[i]==id)
{
std::ostringstream valueString;
valueString << value.getModified();
setText (id, valueString.str());
if (value.getModified()>value.getBase())
setTextColor (id, 0, 1, 0);
else if (value.getModified()<value.getBase())
setTextColor (id, 1, 0, 0);
else
setTextColor (id, 1, 1, 1);
break;
}
}
void setValue (const std::string& id, const MWMechanics::DynamicStat<int>& value)
{
static const char *ids[] =
{
"HBar", "MBar", "FBar",
0
};
for (int i=0; ids[i]; ++i)
if (ids[i]==id)
{
std::string id (ids[i]);
setBar (id, id + "T", value.getCurrent(), value.getModified());
}
}
};
}
#endif

@ -0,0 +1,310 @@
#include "race.hpp"
#include "../mwworld/environment.hpp"
#include "../mwworld/world.hpp"
#include "window_manager.hpp"
#include "widgets.hpp"
#include "components/esm_store/store.hpp"
#include <assert.h>
#include <iostream>
#include <iterator>
#include <boost/algorithm/string.hpp>
#include <boost/lexical_cast.hpp>
using namespace MWGui;
using namespace Widgets;
RaceDialog::RaceDialog(MWWorld::Environment& environment, MyGUI::IntSize gameWindowSize)
: Layout("openmw_chargen_race_layout.xml")
, environment(environment)
, genderIndex(0)
, faceIndex(0)
, hairIndex(0)
, faceCount(10)
, hairCount(14)
{
// Centre dialog
MyGUI::IntCoord coord = mMainWidget->getCoord();
coord.left = (gameWindowSize.width - coord.width)/2;
coord.top = (gameWindowSize.height - coord.height)/2;
mMainWidget->setCoord(coord);
// These are just demo values, you should replace these with
// real calls from outside the class later.
WindowManager *wm = environment.mWindowManager;
setText("AppearanceT", wm->getGameSettingString("sRaceMenu1", "Appearance"));
getWidget(appearanceBox, "AppearanceBox");
getWidget(headRotate, "HeadRotate");
headRotate->setScrollRange(50);
headRotate->setScrollPosition(20);
headRotate->setScrollViewPage(10);
headRotate->eventScrollChangePosition = MyGUI::newDelegate(this, &RaceDialog::onHeadRotate);
// Set up next/previous buttons
MyGUI::ButtonPtr prevButton, nextButton;
setText("GenderChoiceT", wm->getGameSettingString("sRaceMenu2", "Change Sex"));
getWidget(prevButton, "PrevGenderButton");
getWidget(nextButton, "NextGenderButton");
prevButton->eventMouseButtonClick = MyGUI::newDelegate(this, &RaceDialog::onSelectPreviousGender);
nextButton->eventMouseButtonClick = MyGUI::newDelegate(this, &RaceDialog::onSelectNextGender);
setText("FaceChoiceT", wm->getGameSettingString("sRaceMenu3", "Change Face"));
getWidget(prevButton, "PrevFaceButton");
getWidget(nextButton, "NextFaceButton");
prevButton->eventMouseButtonClick = MyGUI::newDelegate(this, &RaceDialog::onSelectPreviousFace);
nextButton->eventMouseButtonClick = MyGUI::newDelegate(this, &RaceDialog::onSelectNextFace);
setText("HairChoiceT", wm->getGameSettingString("sRaceMenu3", "Change Hair"));
getWidget(prevButton, "PrevHairButton");
getWidget(nextButton, "NextHairButton");
prevButton->eventMouseButtonClick = MyGUI::newDelegate(this, &RaceDialog::onSelectPreviousHair);
nextButton->eventMouseButtonClick = MyGUI::newDelegate(this, &RaceDialog::onSelectNextHair);
setText("RaceT", wm->getGameSettingString("sRaceMenu4", "Race"));
getWidget(raceList, "RaceList");
raceList->setScrollVisible(true);
raceList->eventListSelectAccept = MyGUI::newDelegate(this, &RaceDialog::onSelectRace);
raceList->eventListMouseItemActivate = MyGUI::newDelegate(this, &RaceDialog::onSelectRace);
raceList->eventListChangePosition = MyGUI::newDelegate(this, &RaceDialog::onSelectRace);
setText("SkillsT", wm->getGameSettingString("sBonusSkillTitle", "Skill Bonus"));
getWidget(skillList, "SkillList");
setText("SpellPowerT", wm->getGameSettingString("sRaceMenu7", "Specials"));
getWidget(spellPowerList, "SpellPowerList");
// TODO: These buttons should be managed by a Dialog class
MyGUI::ButtonPtr backButton;
getWidget(backButton, "BackButton");
backButton->eventMouseButtonClick = MyGUI::newDelegate(this, &RaceDialog::onBackClicked);
MyGUI::ButtonPtr okButton;
getWidget(okButton, "OKButton");
okButton->eventMouseButtonClick = MyGUI::newDelegate(this, &RaceDialog::onOkClicked);
updateRaces();
updateSkills();
updateSpellPowers();
}
void RaceDialog::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(471 - 18, 397, 53, 23));
okButton->setCoord(MyGUI::IntCoord(532 - 18, 397, 42 + 18, 23));
}
else
{
okButton->setCaption("OK");
backButton->setCoord(MyGUI::IntCoord(471, 397, 53, 23));
okButton->setCoord(MyGUI::IntCoord(532, 397, 42, 23));
}
}
void RaceDialog::open()
{
updateRaces();
updateSkills();
updateSpellPowers();
setVisible(true);
}
void RaceDialog::setRaceId(const std::string &raceId)
{
currentRaceId = raceId;
raceList->setIndexSelected(MyGUI::ITEM_NONE);
size_t count = raceList->getItemCount();
for (size_t i = 0; i < count; ++i)
{
if (boost::iequals(*raceList->getItemDataAt<std::string>(i), raceId))
{
raceList->setIndexSelected(i);
break;
}
}
updateSkills();
updateSpellPowers();
}
int wrap(int index, int max)
{
if (index < 0)
return max - 1;
else if (index >= max)
return 0;
else
return index;
}
// widget controls
void RaceDialog::onOkClicked(MyGUI::Widget* _sender)
{
eventDone();
}
void RaceDialog::onBackClicked(MyGUI::Widget* _sender)
{
eventBack();
}
void RaceDialog::onHeadRotate(MyGUI::VScroll*, size_t _position)
{
// TODO: Rotate head
}
void RaceDialog::onSelectPreviousGender(MyGUI::Widget*)
{
genderIndex = wrap(genderIndex - 1, 2);
}
void RaceDialog::onSelectNextGender(MyGUI::Widget*)
{
genderIndex = wrap(genderIndex + 1, 2);
}
void RaceDialog::onSelectPreviousFace(MyGUI::Widget*)
{
faceIndex = wrap(faceIndex - 1, faceCount);
}
void RaceDialog::onSelectNextFace(MyGUI::Widget*)
{
faceIndex = wrap(faceIndex + 1, faceCount);
}
void RaceDialog::onSelectPreviousHair(MyGUI::Widget*)
{
hairIndex = wrap(hairIndex - 1, hairCount);
}
void RaceDialog::onSelectNextHair(MyGUI::Widget*)
{
hairIndex = wrap(hairIndex - 1, hairCount);
}
void RaceDialog::onSelectRace(MyGUI::List* _sender, size_t _index)
{
if (_index == MyGUI::ITEM_NONE)
return;
const std::string *raceId = raceList->getItemDataAt<std::string>(_index);
if (boost::iequals(currentRaceId, *raceId))
return;
currentRaceId = *raceId;
updateSkills();
updateSpellPowers();
}
// update widget content
void RaceDialog::updateRaces()
{
raceList->removeAllItems();
ESMS::ESMStore &store = environment.mWorld->getStore();
ESMS::RecListT<ESM::Race>::MapType::const_iterator it = store.races.list.begin();
ESMS::RecListT<ESM::Race>::MapType::const_iterator end = store.races.list.end();
int index = 0;
for (; it != end; ++it)
{
const ESM::Race &race = it->second;
bool playable = race.data.flags & ESM::Race::Playable;
if (!playable) // Only display playable races
continue;
raceList->addItem(race.name, it->first);
if (boost::iequals(it->first, currentRaceId))
raceList->setIndexSelected(index);
++index;
}
}
void RaceDialog::updateSkills()
{
for (std::vector<MyGUI::WidgetPtr>::iterator it = skillItems.begin(); it != skillItems.end(); ++it)
{
MyGUI::Gui::getInstance().destroyWidget(*it);
}
skillItems.clear();
if (currentRaceId.empty())
return;
MWSkillPtr skillWidget;
const int lineHeight = 18;
MyGUI::IntCoord coord1(0, 0, skillList->getWidth(), 18);
WindowManager *wm = environment.mWindowManager;
ESMS::ESMStore &store = environment.mWorld->getStore();
const ESM::Race *race = store.races.find(currentRaceId);
int count = sizeof(race->data.bonus)/sizeof(race->data.bonus[0]); // TODO: Find a portable macro for this ARRAYSIZE?
for (int i = 0; i < count; ++i)
{
int skillId = race->data.bonus[i].skill;
if (skillId < 0 || skillId > ESM::Skill::Length) // Skip unknown skill indexes
continue;
skillWidget = skillList->createWidget<MWSkill>("MW_StatNameValue", coord1, MyGUI::Align::Default,
std::string("Skill") + boost::lexical_cast<std::string>(i));
skillWidget->setWindowManager(wm);
skillWidget->setSkillNumber(skillId);
skillWidget->setSkillValue(MWSkill::SkillValue(race->data.bonus[i].bonus));
skillItems.push_back(skillWidget);
coord1.top += lineHeight;
}
}
void RaceDialog::updateSpellPowers()
{
for (std::vector<MyGUI::WidgetPtr>::iterator it = spellPowerItems.begin(); it != spellPowerItems.end(); ++it)
{
MyGUI::Gui::getInstance().destroyWidget(*it);
}
spellPowerItems.clear();
if (currentRaceId.empty())
return;
MWSpellPtr spellPowerWidget;
const int lineHeight = 18;
MyGUI::IntCoord coord(0, 0, spellPowerList->getWidth(), 18);
ESMS::ESMStore &store = environment.mWorld->getStore();
const ESM::Race *race = store.races.find(currentRaceId);
std::vector<std::string>::const_iterator it = race->powers.list.begin();
std::vector<std::string>::const_iterator end = race->powers.list.end();
for (int i = 0; it != end; ++it)
{
const std::string &spellpower = *it;
spellPowerWidget = spellPowerList->createWidget<MWSpell>("MW_StatName", coord, MyGUI::Align::Default, std::string("SpellPower") + boost::lexical_cast<std::string>(i));
spellPowerWidget->setEnvironment(&environment);
spellPowerWidget->setSpellId(spellpower);
spellPowerItems.push_back(spellPowerWidget);
coord.top += lineHeight;
++i;
}
}

@ -0,0 +1,101 @@
#ifndef MWGUI_RACE_H
#define MWGUI_RACE_H
#include <components/esm_store/store.hpp>
#include <openengine/gui/layout.hpp>
#include <boost/array.hpp>
namespace MWWorld
{
class Environment;
}
/*
This file contains the dialog for choosing a race.
Layout is defined by resources/mygui/openmw_chargen_race_layout.xml.
*/
namespace MWGui
{
using namespace MyGUI;
class RaceDialog : public OEngine::GUI::Layout
{
public:
RaceDialog(MWWorld::Environment& environment, MyGUI::IntSize gameWindowSize);
enum Gender
{
GM_Male,
GM_Female
};
const std::string &getRaceId() const { return currentRaceId; }
Gender getGender() const { return genderIndex == 0 ? GM_Male : GM_Female; }
// getFace()
// getHair()
void setRaceId(const std::string &raceId);
void setGender(Gender gender) { genderIndex = gender == GM_Male ? 0 : 1; }
// setFace()
// setHair()
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 onHeadRotate(MyGUI::VScroll* _sender, size_t _position);
void onSelectPreviousGender(MyGUI::Widget* _sender);
void onSelectNextGender(MyGUI::Widget* _sender);
void onSelectPreviousFace(MyGUI::Widget* _sender);
void onSelectNextFace(MyGUI::Widget* _sender);
void onSelectPreviousHair(MyGUI::Widget* _sender);
void onSelectNextHair(MyGUI::Widget* _sender);
void onSelectRace(MyGUI::List* _sender, size_t _index);
void onOkClicked(MyGUI::Widget* _sender);
void onBackClicked(MyGUI::Widget* _sender);
private:
void updateRaces();
void updateSkills();
void updateSpellPowers();
MWWorld::Environment& environment;
MyGUI::CanvasPtr appearanceBox;
MyGUI::ListPtr raceList;
MyGUI::HScrollPtr headRotate;
MyGUI::WidgetPtr skillList;
std::vector<MyGUI::WidgetPtr> skillItems;
MyGUI::WidgetPtr spellPowerList;
std::vector<MyGUI::WidgetPtr> spellPowerItems;
int genderIndex, faceIndex, hairIndex;
int faceCount, hairCount;
std::string currentRaceId;
};
}
#endif

@ -0,0 +1,68 @@
#include "text_input.hpp"
#include "../mwworld/environment.hpp"
#include "../mwworld/world.hpp"
using namespace MWGui;
TextInputDialog::TextInputDialog(MWWorld::Environment& environment, MyGUI::IntSize gameWindowSize)
: Layout("openmw_text_input_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);
getWidget(textEdit, "TextEdit");
textEdit->eventEditSelectAccept = newDelegate(this, &TextInputDialog::onTextAccepted);
// TODO: These buttons should be managed by a Dialog class
MyGUI::ButtonPtr okButton;
getWidget(okButton, "OKButton");
okButton->eventMouseButtonClick = MyGUI::newDelegate(this, &TextInputDialog::onOkClicked);
// Make sure the edit box has focus
MyGUI::InputManager::getInstance().setKeyFocusWidget(textEdit);
}
void TextInputDialog::setNextButtonShow(bool shown)
{
MyGUI::ButtonPtr okButton;
getWidget(okButton, "OKButton");
if (shown)
{
okButton->setCaption("Next");
okButton->setCoord(MyGUI::IntCoord(264 - 18, 60, 42 + 18, 23));
}
else
{
okButton->setCaption("OK");
okButton->setCoord(MyGUI::IntCoord(264, 60, 42, 23));
}
}
void TextInputDialog::setTextLabel(const std::string &label)
{
setText("LabelT", label);
}
void TextInputDialog::open()
{
// Make sure the edit box has focus
MyGUI::InputManager::getInstance().setKeyFocusWidget(textEdit);
textEdit->setOnlyText("");
setVisible(true);
}
// widget controls
void TextInputDialog::onOkClicked(MyGUI::Widget* _sender)
{
eventDone();
}
void TextInputDialog::onTextAccepted(MyGUI::Edit* _sender)
{
eventDone();
}

@ -0,0 +1,48 @@
#ifndef MWGUI_TEXT_INPUT_H
#define MWGUI_TEXT_INPUT_H
#include <openengine/gui/layout.hpp>
namespace MWWorld
{
class Environment;
}
/*
*/
namespace MWGui
{
using namespace MyGUI;
class TextInputDialog : public OEngine::GUI::Layout
{
public:
TextInputDialog(MWWorld::Environment& environment, MyGUI::IntSize gameWindowSize);
std::string getTextInput() const { return textEdit ? textEdit->getOnlyText() : ""; }
void setTextInput(const std::string &text) { if (textEdit) textEdit->setOnlyText(text); }
void setNextButtonShow(bool shown);
void setTextLabel(const std::string &label);
void open();
// Events
typedef delegates::CDelegate0 EventHandle_Void;
/** Event : Dialog finished, OK button clicked.\n
signature : void method()\n
*/
EventHandle_Void eventDone;
protected:
void onOkClicked(MyGUI::Widget* _sender);
void onTextAccepted(MyGUI::Edit* _sender);
private:
MWWorld::Environment& environment;
MyGUI::EditPtr textEdit;
};
}
#endif

@ -0,0 +1,464 @@
#include "widgets.hpp"
#include "window_manager.hpp"
#include "../mwworld/environment.hpp"
#include "../mwworld/world.hpp"
#include "components/esm_store/store.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()
: manager(nullptr)
, skillId(ESM::Skill::Length)
, skillNameWidget(nullptr)
, skillValueWidget(nullptr)
{
}
void MWSkill::setSkillId(ESM::Skill::SkillEnum skill)
{
skillId = skill;
updateWidgets();
}
void MWSkill::setSkillNumber(int skill)
{
if (skill < 0)
setSkillId(ESM::Skill::Length);
else if (skill < ESM::Skill::Length)
setSkillId(static_cast<ESM::Skill::SkillEnum>(skill));
else
throw new std::runtime_error("Skill number out of range");
}
void MWSkill::setSkillValue(const SkillValue& value_)
{
value = value_;
updateWidgets();
}
void MWSkill::updateWidgets()
{
if (skillNameWidget && manager)
{
if (skillId == ESM::Skill::Length)
{
skillNameWidget->setCaption("");
}
else
{
const std::string &name = manager->getGameSettingString(ESM::Skill::sSkillNameIds[skillId], "");
skillNameWidget->setCaption(name);
}
}
if (skillValueWidget)
{
SkillValue::Type modified = value.getModified(), base = value.getBase();
skillValueWidget->setCaption(boost::lexical_cast<std::string>(modified));
if (modified > base)
skillValueWidget->setState("increased");
else if (modified < base)
skillValueWidget->setState("decreased");
else
skillValueWidget->setState("normal");
}
}
void MWSkill::onClicked(MyGUI::Widget* _sender)
{
eventClicked(this);
}
void MWSkill::_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);
}
MWSkill::~MWSkill()
{
shutdownWidgetSkin();
}
void MWSkill::baseChangeWidgetSkin(ResourceSkin* _info)
{
shutdownWidgetSkin();
Base::baseChangeWidgetSkin(_info);
initialiseWidgetSkin(_info);
}
void MWSkill::initialiseWidgetSkin(ResourceSkin* _info)
{
for (VectorWidgetPtr::iterator iter=mWidgetChildSkin.begin(); iter!=mWidgetChildSkin.end(); ++iter)
{
const std::string &name = *(*iter)->_getInternalData<std::string>();
if (name == "StatName")
{
MYGUI_DEBUG_ASSERT( ! skillNameWidget, "widget already assigned");
skillNameWidget = (*iter)->castType<StaticText>();
}
else if (name == "StatValue")
{
MYGUI_DEBUG_ASSERT( ! skillValueWidget, "widget already assigned");
skillValueWidget = (*iter)->castType<StaticText>();
}
else if (name == "StatNameButton")
{
MYGUI_DEBUG_ASSERT( ! skillNameWidget, "widget already assigned");
MyGUI::ButtonPtr button = (*iter)->castType<Button>();
skillNameWidget = button;
button->eventMouseButtonClick = MyGUI::newDelegate(this, &MWSkill::onClicked);
}
else if (name == "StatValueButton")
{
MYGUI_DEBUG_ASSERT( ! skillValueWidget, "widget already assigned");
MyGUI::ButtonPtr button = (*iter)->castType<Button>();
skillNameWidget = button;
button->eventMouseButtonClick = MyGUI::newDelegate(this, &MWSkill::onClicked);
}
}
}
void MWSkill::shutdownWidgetSkin()
{
}
/* MWAttribute */
MWAttribute::MWAttribute()
: manager(nullptr)
, id(-1)
, attributeNameWidget(nullptr)
, attributeValueWidget(nullptr)
{
}
void MWAttribute::setAttributeId(int attributeId)
{
id = attributeId;
updateWidgets();
}
void MWAttribute::setAttributeValue(const AttributeValue& value_)
{
value = value_;
updateWidgets();
}
void MWAttribute::onClicked(MyGUI::Widget* _sender)
{
eventClicked(this);
}
void MWAttribute::updateWidgets()
{
if (attributeNameWidget && manager)
{
if (id < 0 || id >= 8)
{
attributeNameWidget->setCaption("");
}
else
{
static const char *attributes[8] = {
"sAttributeStrength",
"sAttributeIntelligence",
"sAttributeWillpower",
"sAttributeAgility",
"sAttributeSpeed",
"sAttributeEndurance",
"sAttributePersonality",
"sAttributeLuck"
};
const std::string &name = manager->getGameSettingString(attributes[id], "");
attributeNameWidget->setCaption(name);
}
}
if (attributeValueWidget)
{
AttributeValue::Type modified = value.getModified(), base = value.getBase();
attributeValueWidget->setCaption(boost::lexical_cast<std::string>(modified));
if (modified > base)
attributeValueWidget->setState("increased");
else if (modified < base)
attributeValueWidget->setState("decreased");
else
attributeValueWidget->setState("normal");
}
}
void MWAttribute::_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);
}
MWAttribute::~MWAttribute()
{
shutdownWidgetSkin();
}
void MWAttribute::baseChangeWidgetSkin(ResourceSkin* _info)
{
shutdownWidgetSkin();
Base::baseChangeWidgetSkin(_info);
initialiseWidgetSkin(_info);
}
void MWAttribute::initialiseWidgetSkin(ResourceSkin* _info)
{
for (VectorWidgetPtr::iterator iter=mWidgetChildSkin.begin(); iter!=mWidgetChildSkin.end(); ++iter)
{
const std::string &name = *(*iter)->_getInternalData<std::string>();
if (name == "StatName")
{
MYGUI_DEBUG_ASSERT( ! attributeNameWidget, "widget already assigned");
attributeNameWidget = (*iter)->castType<StaticText>();
}
else if (name == "StatValue")
{
MYGUI_DEBUG_ASSERT( ! attributeValueWidget, "widget already assigned");
attributeValueWidget = (*iter)->castType<StaticText>();
}
else if (name == "StatNameButton")
{
MYGUI_DEBUG_ASSERT( ! attributeNameWidget, "widget already assigned");
MyGUI::ButtonPtr button = (*iter)->castType<Button>();
attributeNameWidget = button;
button->eventMouseButtonClick = MyGUI::newDelegate(this, &MWAttribute::onClicked);
}
else if (name == "StatValue")
{
MYGUI_DEBUG_ASSERT( ! attributeValueWidget, "widget already assigned");
MyGUI::ButtonPtr button = (*iter)->castType<Button>();
attributeNameWidget = button;
button->eventMouseButtonClick = MyGUI::newDelegate(this, &MWAttribute::onClicked);
}
}
}
void MWAttribute::shutdownWidgetSkin()
{
}
/* MWSpell */
MWSpell::MWSpell()
: env(nullptr)
, spellNameWidget(nullptr)
{
}
void MWSpell::setSpellId(const std::string &spellId)
{
id = 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)
{
ESMS::ESMStore &store = env->mWorld->getStore();
const ESM::Spell *spell = store.spells.search(id);
if (spell)
spellNameWidget->setCaption(spell->name);
else
spellNameWidget->setCaption("");
}
}
void MWSpell::_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);
}
MWSpell::~MWSpell()
{
shutdownWidgetSkin();
}
void MWSpell::baseChangeWidgetSkin(ResourceSkin* _info)
{
shutdownWidgetSkin();
Base::baseChangeWidgetSkin(_info);
initialiseWidgetSkin(_info);
}
void MWSpell::initialiseWidgetSkin(ResourceSkin* _info)
{
for (VectorWidgetPtr::iterator iter=mWidgetChildSkin.begin(); iter!=mWidgetChildSkin.end(); ++iter)
{
const std::string &name = *(*iter)->_getInternalData<std::string>();
if (name == "StatName")
{
MYGUI_DEBUG_ASSERT( ! spellNameWidget, "widget already assigned");
spellNameWidget = (*iter)->castType<StaticText>();
}
}
}
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()
{
}

@ -0,0 +1,196 @@
#ifndef MWGUI_WIDGETS_H
#define MWGUI_WIDGETS_H
#include <components/esm_store/store.hpp>
#include <MyGUI.h>
#include "../mwmechanics/stat.hpp"
namespace MWWorld
{
class Environment;
}
/*
This file contains various custom widgets used in OpenMW.
*/
namespace MWGui
{
using namespace MyGUI;
class WindowManager;
namespace Widgets
{
void fixTexturePath(std::string &path);
class MYGUI_EXPORT MWSkill : public Widget
{
MYGUI_RTTI_DERIVED( MWSkill );
public:
MWSkill();
typedef MWMechanics::Stat<float> SkillValue;
void setWindowManager(WindowManager *m) { manager = m; }
void setSkillId(ESM::Skill::SkillEnum skillId);
void setSkillNumber(int skillId);
void setSkillValue(const SkillValue& value);
WindowManager *getWindowManager() const { return manager; }
ESM::Skill::SkillEnum getSkillId() const { return skillId; }
const SkillValue& getSkillValue() const { return value; }
// Events
typedef delegates::CDelegate1<MWSkill*> EventHandle_SkillVoid;
/** Event : Skill clicked.\n
signature : void method(MWSkill* _sender)\n
*/
EventHandle_SkillVoid eventClicked;
/*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 ~MWSkill();
void baseChangeWidgetSkin(ResourceSkin* _info);
void onClicked(MyGUI::Widget* _sender);
private:
void initialiseWidgetSkin(ResourceSkin* _info);
void shutdownWidgetSkin();
void updateWidgets();
WindowManager *manager;
ESM::Skill::SkillEnum skillId;
SkillValue value;
MyGUI::WidgetPtr skillNameWidget, skillValueWidget;
};
typedef MWSkill* MWSkillPtr;
class MYGUI_EXPORT MWAttribute : public Widget
{
MYGUI_RTTI_DERIVED( MWAttribute );
public:
MWAttribute();
typedef MWMechanics::Stat<int> AttributeValue;
void setWindowManager(WindowManager *m) { manager = m; }
void setAttributeId(int attributeId);
void setAttributeValue(const AttributeValue& value);
WindowManager *getWindowManager() const { return manager; }
int getAttributeId() const { return id; }
const AttributeValue& getAttributeValue() const { return value; }
// Events
typedef delegates::CDelegate1<MWAttribute*> EventHandle_AttributeVoid;
/** Event : Attribute clicked.\n
signature : void method(MWAttribute* _sender)\n
*/
EventHandle_AttributeVoid eventClicked;
/*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 ~MWAttribute();
void baseChangeWidgetSkin(ResourceSkin* _info);
void onClicked(MyGUI::Widget* _sender);
private:
void initialiseWidgetSkin(ResourceSkin* _info);
void shutdownWidgetSkin();
void updateWidgets();
WindowManager *manager;
int id;
AttributeValue value;
MyGUI::WidgetPtr attributeNameWidget, attributeValueWidget;
};
typedef MWAttribute* MWAttributePtr;
class MWSpellEffect;
class MYGUI_EXPORT MWSpell : public Widget
{
MYGUI_RTTI_DERIVED( MWSpell );
public:
MWSpell();
typedef MWMechanics::Stat<int> SpellValue;
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; }
/*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 ~MWSpell();
void baseChangeWidgetSkin(ResourceSkin* _info);
private:
void initialiseWidgetSkin(ResourceSkin* _info);
void shutdownWidgetSkin();
void updateWidgets();
MWWorld::Environment *env;
std::string id;
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;
}
}
#endif

@ -1,5 +1,12 @@
#include "window_manager.hpp"
#include "mw_layouts.hpp"
#include "layouts.hpp"
#include "text_input.hpp"
#include "race.hpp"
#include "class.hpp"
#include "birth.hpp"
#include "../mwmechanics/mechanicsmanager.hpp"
#include "../mwinput/inputmanager.hpp"
#include "console.hpp"
@ -11,7 +18,24 @@ using namespace MWGui;
WindowManager::WindowManager(MyGUI::Gui *_gui, MWWorld::Environment& environment,
const Compiler::Extensions& extensions, bool newGame)
: gui(_gui), mode(GM_Game), shown(GW_ALL), allowed(newGame ? GW_None : GW_ALL)
: environment(environment)
, nameDialog(nullptr)
, raceDialog(nullptr)
, classChoiceDialog(nullptr)
, generateClassQuestionDialog(nullptr)
, generateClassResultDialog(nullptr)
, pickClassDialog(nullptr)
, createClassDialog(nullptr)
, birthSignDialog(nullptr)
, nameChosen(false)
, raceChosen(false)
, classChosen(false)
, birthSignChosen(false)
, reviewNext(false)
, gui(_gui)
, mode(GM_Game)
, shown(GW_ALL)
, allowed(newGame ? GW_None : GW_ALL)
{
// Get size info from the Gui object
assert(gui);
@ -21,7 +45,10 @@ WindowManager::WindowManager(MyGUI::Gui *_gui, MWWorld::Environment& environment
hud = new HUD(w,h);
menu = new MainMenu(w,h);
map = new MapWindow();
stats = new StatsWindow (environment.mWorld->getStore());
stats = new StatsWindow (environment);
#if 0
inventory = new InventoryWindow ();
#endif
console = new Console(w,h, environment, extensions);
// The HUD is always on
@ -38,6 +65,18 @@ WindowManager::~WindowManager()
delete map;
delete menu;
delete stats;
#if 0
delete inventory;
#endif
delete nameDialog;
delete raceDialog;
delete classChoiceDialog;
delete generateClassQuestionDialog;
delete generateClassResultDialog;
delete pickClassDialog;
delete createClassDialog;
delete birthSignDialog;
}
void WindowManager::updateVisible()
@ -46,6 +85,9 @@ void WindowManager::updateVisible()
map->setVisible(false);
menu->setVisible(false);
stats->setVisible(false);
#if 0
inventory->setVisible(false);
#endif
console->disable();
// Mouse is visible whenever we're not in game mode
@ -70,6 +112,79 @@ void WindowManager::updateVisible()
return;
}
if (mode == GM_Name)
{
if (!nameDialog)
nameDialog = new TextInputDialog(environment, gui->getViewSize());
std::string sName = getGameSettingString("sName", "Name");
nameDialog->setTextLabel(sName);
nameDialog->setNextButtonShow(nameChosen);
nameDialog->eventDone = MyGUI::newDelegate(this, &WindowManager::onNameDialogDone);
nameDialog->open();
return;
}
if (mode == GM_Race)
{
if (!raceDialog)
raceDialog = new RaceDialog(environment, gui->getViewSize());
raceDialog->setNextButtonShow(raceChosen);
raceDialog->eventDone = MyGUI::newDelegate(this, &WindowManager::onRaceDialogDone);
raceDialog->eventBack = MyGUI::newDelegate(this, &WindowManager::onRaceDialogBack);
raceDialog->open();
return;
}
if (mode == GM_Class)
{
if (classChoiceDialog)
delete classChoiceDialog;
classChoiceDialog = new ClassChoiceDialog(environment);
classChoiceDialog->eventButtonSelected = MyGUI::newDelegate(this, &WindowManager::onClassChoice);
return;
}
if (mode == GM_ClassGenerate)
{
generateClassStep = 0;
showClassQuestionDialog();
return;
}
if (mode == GM_ClassPick)
{
if (!pickClassDialog)
pickClassDialog = new PickClassDialog(environment, gui->getViewSize());
pickClassDialog->setNextButtonShow(classChosen);
pickClassDialog->eventDone = MyGUI::newDelegate(this, &WindowManager::onPickClassDialogDone);
pickClassDialog->eventBack = MyGUI::newDelegate(this, &WindowManager::onPickClassDialogBack);
pickClassDialog->open();
return;
}
if (mode == GM_ClassCreate)
{
if (createClassDialog)
delete createClassDialog;
createClassDialog = new CreateClassDialog(environment, gui->getViewSize());
createClassDialog->eventDone = MyGUI::newDelegate(this, &WindowManager::onCreateClassDialogDone);
createClassDialog->eventBack = MyGUI::newDelegate(this, &WindowManager::onCreateClassDialogBack);
createClassDialog->open();
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
@ -79,12 +194,18 @@ void WindowManager::updateVisible()
int eff = shown & allowed;
// Show the windows we want
map -> setVisible( eff & GW_Map );
stats -> setVisible( eff & GW_Stats );
map -> setVisible( (eff & GW_Map) != 0 );
stats -> setVisible( (eff & GW_Stats) != 0 );
#if 0
// inventory -> setVisible( eff & GW_Inventory );
#endif
return;
}
// All other modes are ignored
// Unsupported mode, switch back to game
// Note: The call will eventually end up this method again but
// will stop at the check if(mode == GM_Game) above.
environment.mInputManager->setGuiMode(GM_Game);
}
void WindowManager::setValue (const std::string& id, const MWMechanics::Stat<int>& value)
@ -92,12 +213,57 @@ void WindowManager::setValue (const std::string& id, const MWMechanics::Stat<int
stats->setValue (id, value);
}
void WindowManager::setValue (const std::string& id, const MWMechanics::Stat<float>& value)
{
stats->setValue (id, value);
}
void WindowManager::setValue (const std::string& id, const MWMechanics::DynamicStat<int>& value)
{
stats->setValue (id, value);
hud->setValue (id, value);
}
void WindowManager::setValue (const std::string& id, const std::string& value)
{
stats->setValue (id, value);
}
void WindowManager::setValue (const std::string& id, int value)
{
stats->setValue (id, value);
}
void WindowManager::configureSkills (const SkillList& major, const SkillList& minor)
{
stats->configureSkills (major, minor);
}
void WindowManager::setFactions (const FactionList& factions)
{
stats->setFactions (factions);
}
void WindowManager::setBirthSign (const std::string &signId)
{
stats->setBirthSign (signId);
}
void WindowManager::setReputation (int reputation)
{
stats->setReputation (reputation);
}
void WindowManager::setBounty (int bounty)
{
stats->setBounty (bounty);
}
void WindowManager::updateSkillArea()
{
stats->updateSkillArea();
}
void WindowManager::messageBox (const std::string& message, const std::vector<std::string>& buttons)
{
std::cout << "message box: " << message << std::endl;
@ -109,3 +275,339 @@ void WindowManager::messageBox (const std::string& message, const std::vector<st
std::cout << std::endl;
}
}
const std::string &WindowManager::getGameSettingString(const std::string &id, const std::string &default_)
{
const ESM::GameSetting *setting = environment.mWorld->getStore().gameSettings.search(id);
if (setting && setting->type == ESM::VT_String)
return setting->str;
return default_;
}
void WindowManager::updateCharacterGeneration()
{
if (raceDialog)
{
// TOOD: Uncomment when methods in mechanics manager is implemented
//raceDialog->setRace(environment.mMechanicsManager->getPlayerRace());
//raceDialog->setGender(environment.mMechanicsManager->getPlayerMale() ? RaceDialog::GM_Male : RaceDialog::GM_Female);
// TODO: Face/Hair
}
}
void WindowManager::onNameDialogDone()
{
nameDialog->eventDone = MWGui::TextInputDialog::EventHandle_Void();
bool goNext = nameChosen; // Go to next dialog if name was previously chosen
nameChosen = true;
if (nameDialog)
{
nameDialog->setVisible(false);
environment.mMechanicsManager->setPlayerName(nameDialog->getTextInput());
}
updateCharacterGeneration();
if (reviewNext)
environment.mInputManager->setGuiMode(GM_Review);
else if (goNext)
environment.mInputManager->setGuiMode(GM_Race);
else
environment.mInputManager->setGuiMode(GM_Game);
}
void WindowManager::onRaceDialogDone()
{
raceDialog->eventDone = MWGui::RaceDialog::EventHandle_Void();
bool goNext = raceChosen; // Go to next dialog if race was previously chosen
raceChosen = true;
if (raceDialog)
{
raceDialog->setVisible(false);
environment.mMechanicsManager->setPlayerRace(raceDialog->getRaceId(), raceDialog->getGender() == RaceDialog::GM_Male);
}
updateCharacterGeneration();
if (reviewNext)
environment.mInputManager->setGuiMode(GM_Review);
else if (goNext)
environment.mInputManager->setGuiMode(GM_Class);
else
environment.mInputManager->setGuiMode(GM_Game);
}
void WindowManager::onRaceDialogBack()
{
if (raceDialog)
{
raceDialog->setVisible(false);
environment.mMechanicsManager->setPlayerRace(raceDialog->getRaceId(), raceDialog->getGender() == RaceDialog::GM_Male);
}
updateCharacterGeneration();
environment.mInputManager->setGuiMode(GM_Name);
}
void WindowManager::onClassChoice(MyGUI::WidgetPtr, int _index)
{
classChoiceDialog->setVisible(false);
// classChoiceDialog = nullptr;
if (_index == ClassChoiceDialog::Class_Generate)
{
environment.mInputManager->setGuiMode(GM_ClassGenerate);
}
else if (_index == ClassChoiceDialog::Class_Pick)
{
environment.mInputManager->setGuiMode(GM_ClassPick);
}
else if (_index == ClassChoiceDialog::Class_Create)
{
environment.mInputManager->setGuiMode(GM_ClassCreate);
}
else if (_index == ClassChoiceDialog::Class_Back)
{
environment.mInputManager->setGuiMode(GM_Race);
}
}
namespace MWGui
{
struct Step
{
const char* text;
const char* buttons[3];
};
}
void WindowManager::showClassQuestionDialog()
{
static boost::array<Step, 2> steps = { {
{"On a clear day you chance upon a strange animal, its legs trapped in a hunter's clawsnare. Judging from the bleeding, it will not survive long.",
{"Use herbs from your pack to put it to sleep?",
"Do not interfere in the natural evolution of events, but rather take the opportunity to learn more about a strange animal that you have never seen before?",
"Draw your dagger, mercifully endings its life with a single thrust?"}
},
{"Your mother sends you to the market with a list of goods to buy. After you finish you find that by mistake a shopkeeper has given you too much money back in exchange for one of the items.",
{"Return to the store and give the shopkeeper his hard-earned money, explaining to him the mistake?",
"Pocket the extra money, knowing that shopkeepers in general tend to overcharge customers anyway?",
"Decide to put the extra money to good use and purchase items that would help your family?"}
},
} };
if (generateClassStep == steps.size())
{
// TODO: Calculate this in mechanics manager
generateClass = "acrobat";
if (generateClassResultDialog)
delete generateClassResultDialog;
generateClassResultDialog = new GenerateClassResultDialog(environment);
generateClassResultDialog->setClassId(generateClass);
generateClassResultDialog->eventBack = MyGUI::newDelegate(this, &WindowManager::onGenerateClassBack);
generateClassResultDialog->eventDone = MyGUI::newDelegate(this, &WindowManager::onGenerateClassDone);
generateClassResultDialog->setVisible(true);
return;
}
if (generateClassStep > steps.size())
{
environment.mInputManager->setGuiMode(GM_Class);
return;
}
if (!generateClassQuestionDialog)
generateClassQuestionDialog = new InfoBoxDialog(environment);
InfoBoxDialog::ButtonList buttons;
generateClassQuestionDialog->setText(steps[generateClassStep].text);
buttons.push_back(steps[generateClassStep].buttons[0]);
buttons.push_back(steps[generateClassStep].buttons[1]);
buttons.push_back(steps[generateClassStep].buttons[2]);
generateClassQuestionDialog->setButtons(buttons);
generateClassQuestionDialog->update();
generateClassQuestionDialog->eventButtonSelected = MyGUI::newDelegate(this, &WindowManager::onClassQuestionChosen);
generateClassQuestionDialog->setVisible(true);
}
void WindowManager::onClassQuestionChosen(MyGUI::Widget* _sender, int _index)
{
generateClassQuestionDialog->setVisible(false);
if (_index < 0 || _index >= 3)
{
environment.mInputManager->setGuiMode(GM_Class);
return;
}
++generateClassStep;
showClassQuestionDialog();
}
void WindowManager::onGenerateClassBack()
{
bool goNext = classChosen; // Go to next dialog if class was previously chosen
classChosen = true;
if (generateClassResultDialog)
{
generateClassResultDialog->setVisible(false);
}
environment.mMechanicsManager->setPlayerClass(generateClass);
updateCharacterGeneration();
environment.mInputManager->setGuiMode(GM_Class);
}
void WindowManager::onGenerateClassDone()
{
bool goNext = classChosen; // Go to next dialog if class was previously chosen
classChosen = true;
if (generateClassResultDialog)
{
generateClassResultDialog->setVisible(false);
}
environment.mMechanicsManager->setPlayerClass(generateClass);
updateCharacterGeneration();
if (reviewNext)
environment.mInputManager->setGuiMode(GM_Review);
else if (goNext)
environment.mInputManager->setGuiMode(GM_Birth);
else
environment.mInputManager->setGuiMode(GM_Game);
}
void WindowManager::onPickClassDialogDone()
{
pickClassDialog->eventDone = MWGui::PickClassDialog::EventHandle_Void();
bool goNext = classChosen; // Go to next dialog if class was previously chosen
classChosen = true;
if (pickClassDialog)
{
pickClassDialog->setVisible(false);
environment.mMechanicsManager->setPlayerClass(pickClassDialog->getClassId());
}
updateCharacterGeneration();
if (reviewNext)
environment.mInputManager->setGuiMode(GM_Review);
else if (goNext)
environment.mInputManager->setGuiMode(GM_Birth);
else
environment.mInputManager->setGuiMode(GM_Game);
}
void WindowManager::onPickClassDialogBack()
{
if (pickClassDialog)
{
pickClassDialog->setVisible(false);
environment.mMechanicsManager->setPlayerClass(pickClassDialog->getClassId());
}
updateCharacterGeneration();
environment.mInputManager->setGuiMode(GM_Class);
}
void WindowManager::onCreateClassDialogDone()
{
createClassDialog->eventDone = MWGui::CreateClassDialog::EventHandle_Void();
bool goNext = classChosen; // Go to next dialog if class was previously chosen
classChosen = true;
if (createClassDialog)
{
createClassDialog->setVisible(false);
// TODO: The ESM::Class should have methods to set these values to ensure correct data is assigned
ESM::Class klass;
klass.name = createClassDialog->getName();
klass.description = createClassDialog->getDescription();
klass.data.specialization = createClassDialog->getSpecializationId();
klass.data.isPlayable = 0x1;
std::vector<int> attributes = createClassDialog->getFavoriteAttributes();
assert(attributes.size() == 2);
klass.data.attribute[0] = attributes[0];
klass.data.attribute[1] = attributes[1];
std::vector<ESM::Skill::SkillEnum> majorSkills = createClassDialog->getMajorSkills();
std::vector<ESM::Skill::SkillEnum> minorSkills = createClassDialog->getMinorSkills();
assert(majorSkills.size() >= sizeof(klass.data.skills)/sizeof(klass.data.skills[0]));
assert(minorSkills.size() >= sizeof(klass.data.skills)/sizeof(klass.data.skills[0]));
for (size_t i = 0; i < sizeof(klass.data.skills)/sizeof(klass.data.skills[0]); ++i)
{
klass.data.skills[i][1] = majorSkills[i];
klass.data.skills[i][0] = minorSkills[i];
}
environment.mMechanicsManager->setPlayerClass(klass);
}
updateCharacterGeneration();
if (reviewNext)
environment.mInputManager->setGuiMode(GM_Review);
else if (goNext)
environment.mInputManager->setGuiMode(GM_Birth);
else
environment.mInputManager->setGuiMode(GM_Game);
}
void WindowManager::onCreateClassDialogBack()
{
if (pickClassDialog)
{
pickClassDialog->setVisible(false);
environment.mMechanicsManager->setPlayerClass(pickClassDialog->getClassId());
}
updateCharacterGeneration();
environment.mInputManager->setGuiMode(GM_Class);
}
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);
}

@ -12,12 +12,15 @@
#include <string>
#include <vector>
#include <set>
#include "../mwmechanics/stat.hpp"
#include "mode.hpp"
namespace MyGUI
{
class Gui;
class Widget;
}
namespace Compiler
@ -36,52 +39,52 @@ namespace MWGui
class MapWindow;
class MainMenu;
class StatsWindow;
class InventoryWindow;
class Console;
enum GuiMode
{
GM_Game, // Game mode, only HUD
GM_Inventory, // Inventory mode
GM_MainMenu, // Main menu mode
GM_Console, // Console mode
// None of the following are implemented yet
GM_Dialogue, // NPC interaction
GM_Barter,
GM_Rest,
// .. more here ..
// Startup character creation dialogs
GM_Name,
GM_Race,
GM_Birth,
GM_Class,
GM_Review
};
// Windows shown in inventory mode
enum GuiWindow
{
GW_None = 0,
GW_Map = 0x01,
GW_Inventory = 0x02,
GW_Magic = 0x04,
GW_Stats = 0x08,
GW_ALL = 0xFF
};
class TextInputDialog;
class InfoBoxDialog;
class RaceDialog;
class ClassChoiceDialog;
class GenerateClassResultDialog;
class PickClassDialog;
class CreateClassDialog;
class BirthDialog;
class WindowManager
{
MWWorld::Environment& environment;
HUD *hud;
MapWindow *map;
MainMenu *menu;
StatsWindow *stats;
#if 0
InventoryWindow *inventory;
#endif
Console *console;
// Character creation
TextInputDialog *nameDialog;
RaceDialog *raceDialog;
ClassChoiceDialog *classChoiceDialog;
InfoBoxDialog *generateClassQuestionDialog;
GenerateClassResultDialog *generateClassResultDialog;
PickClassDialog *pickClassDialog;
CreateClassDialog *createClassDialog;
BirthDialog *birthSignDialog;
// Which dialogs have been shown, controls back/next/ok buttons
bool nameChosen;
bool raceChosen;
bool classChosen;
bool birthSignChosen;
bool reviewNext;
///< If true then any click on Next will cause the summary to be shown
// Keeps track of current step in Generate Class dialogs
unsigned generateClassStep;
std::string generateClass;
MyGUI::Gui *gui;
// Current gui mode
@ -140,13 +143,85 @@ namespace MWGui
MyGUI::Gui* getGui() const { return gui; }
typedef std::pair<std::string, int> Faction;
typedef std::vector<Faction> FactionList;
typedef std::vector<int> SkillList;
void setValue (const std::string& id, const MWMechanics::Stat<int>& value);
///< Set value for the given ID.
void setValue (const std::string& id, const MWMechanics::Stat<float>& value);
///< Set value for the given ID.
void setValue (const std::string& id, const MWMechanics::DynamicStat<int>& value);
///< Set value for the given ID.
void setValue (const std::string& id, const std::string& value);
///< set value for the given ID.
void setValue (const std::string& id, int value);
///< set value for the given ID.
void configureSkills (const SkillList& major, const SkillList& minor);
///< configure skill groups, each set contains the skill ID for that group.
void setFactions (const FactionList& factions);
///< set faction and rank to display on stat window, use an empty vector to disable
void setBirthSign (const std::string &signId);
///< set birth sign to display on stat window, use an empty string to disable.
void setReputation (int reputation);
///< set the current reputation value
void setBounty (int bounty);
///< set the current bounty value
void updateSkillArea();
///< update display of skills, factions, birth sign, reputation and bounty
void messageBox (const std::string& message, const std::vector<std::string>& buttons);
/**
* Fetches a GMST string from the store, if there is no setting with the given
* ID or it is not a string the default string is returned.
*
* @param id Identifier for the GMST setting, e.g. "aName"
* @param default Default value if the GMST setting cannot be used.
*/
const std::string &getGameSettingString(const std::string &id, const std::string &default_);
private:
void updateCharacterGeneration();
void checkCharacterGeneration(GuiMode mode);
// Character generation: Name dialog
void onNameDialogDone();
// Character generation: Race dialog
void onRaceDialogDone();
void onRaceDialogBack();
// Character generation: Choose class process
void onClassChoice(MyGUI::Widget* _sender, int _index);
// Character generation: Generate Class
void showClassQuestionDialog();
void onClassQuestionChosen(MyGUI::Widget* _sender, int _index);
void onGenerateClassBack();
void onGenerateClassDone();
// Character generation: Pick Class dialog
void onPickClassDialogDone();
void onPickClassDialogBack();
// Character generation: Create Class dialog
void onCreateClassDialogDone();
void onCreateClassDialogBack();
// Character generation: Birth sign dialog
void onBirthSignDialogDone();
void onBirthSignDialogBack();
};
}
#endif

@ -79,34 +79,6 @@ namespace MWInput
ogre.screenshot(buf);
}
// Switch between gui modes. Besides controlling the Gui windows
// this also makes sure input is directed to the right place
void setGuiMode(MWGui::GuiMode mode)
{
// Tell the GUI what to show (this also takes care of the mouse
// pointer)
windows.setMode(mode);
// Are we in GUI mode now?
if(windows.isGuiMode())
{
// Disable mouse look
mouse->setCamera(NULL);
// Enable GUI events
guiEvents->enabled = true;
}
else
{
// Start mouse-looking again. TODO: This should also allow
// for other ways to disable mouselook, like paralyzation.
mouse->setCamera(player.getCamera());
// Disable GUI events
guiEvents->enabled = false;
}
}
// Called when the user presses the button to toggle the inventory
// screen.
void toggleInventory()
@ -275,6 +247,34 @@ namespace MWInput
return true;
}
// Switch between gui modes. Besides controlling the Gui windows
// this also makes sure input is directed to the right place
void setGuiMode(MWGui::GuiMode mode)
{
// Tell the GUI what to show (this also takes care of the mouse
// pointer)
windows.setMode(mode);
// Are we in GUI mode now?
if(windows.isGuiMode())
{
// Disable mouse look
mouse->setCamera(NULL);
// Enable GUI events
guiEvents->enabled = true;
}
else
{
// Start mouse-looking again. TODO: This should also allow
// for other ways to disable mouselook, like paralyzation.
mouse->setCamera(player.getCamera());
// Disable GUI events
guiEvents->enabled = false;
}
}
};
MWInputManager::MWInputManager(OEngine::Render::OgreRenderer &ogre,
@ -290,4 +290,9 @@ namespace MWInput
{
delete impl;
}
void MWInputManager::setGuiMode(MWGui::GuiMode mode)
{
impl->setGuiMode(mode);
}
}

@ -1,6 +1,8 @@
#ifndef _MWINPUT_MWINPUTMANAGER_H
#define _MWINPUT_MWINPUTMANAGER_H
#include "../mwgui/mode.hpp"
namespace OEngine
{
namespace Render
@ -45,6 +47,8 @@ namespace MWInput
bool debug,
OMW::Engine& engine);
~MWInputManager();
void setGuiMode(MWGui::GuiMode mode);
};
}
#endif

@ -1,7 +1,11 @@
#ifndef GAME_MWMECHANICS_CREATURESTATS_H
#define GAME_MWMECHANICS_CREATURESTATS_H
#include <set>
#include <string>
#include "stat.hpp"
#include "magiceffects.hpp"
namespace MWMechanics
{
@ -9,8 +13,10 @@ namespace MWMechanics
{
Stat<int> mAttributes[8];
DynamicStat<int> mDynamic[3]; // health, magicka, fatigue
int mLevel;
std::set<std::string> mAbilities;
MagicEffects mMagicEffects;
};
}
#endif

@ -0,0 +1,118 @@
#include "magiceffects.hpp"
#include <stdexcept>
#include <components/esm/defs.hpp>
namespace MWMechanics
{
EffectKey::EffectKey() : mId (0), mArg (-1) {}
EffectKey::EffectKey (const ESM::ENAMstruct& effect)
{
mId = effect.effectID;
mArg = -1;
if (effect.skill!=-1)
mArg = effect.skill;
if (effect.attribute!=-1)
{
if (mArg!=-1)
throw std::runtime_error (
"magic effect can't have both a skill and an attribute argument");
mArg = effect.attribute;
}
}
bool operator< (const EffectKey& left, const EffectKey& right)
{
if (left.mId<right.mId)
return true;
if (left.mId>right.mId)
return false;
return left.mArg<right.mArg;
}
EffectParam::EffectParam() : mMagnitude (0) {}
EffectParam& EffectParam::operator+= (const EffectParam& param)
{
mMagnitude += param.mMagnitude;
return *this;
}
EffectParam& EffectParam::operator-= (const EffectParam& param)
{
mMagnitude -= param.mMagnitude;
return *this;
}
void MagicEffects::add (const EffectKey& key, const EffectParam& param)
{
Collection::iterator iter = mCollection.find (key);
if (iter==mCollection.end())
{
mCollection.insert (std::make_pair (key, param));
}
else
{
iter->second += param;
}
}
EffectParam MagicEffects::get (const EffectKey& key) const
{
Collection::const_iterator iter = mCollection.find (key);
if (iter==mCollection.end())
{
return EffectParam();
}
else
{
return iter->second;
}
}
MagicEffects MagicEffects::diff (const MagicEffects& prev, const MagicEffects& now)
{
MagicEffects result;
// adding/changing
for (Collection::const_iterator iter (now.Begin()); iter!=now.End(); ++iter)
{
Collection::const_iterator other = prev.mCollection.find (iter->first);
if (other==prev.End())
{
// adding
result.add (iter->first, iter->second);
}
else
{
// changing
result.add (iter->first, iter->second - other->second);
}
}
// removing
for (Collection::const_iterator iter (prev.Begin()); iter!=prev.End(); ++iter)
{
Collection::const_iterator other = now.mCollection.find (iter->first);
if (other==prev.End())
{
result.add (iter->first, EffectParam() - iter->second);
}
}
return result;
}
}

@ -0,0 +1,77 @@
#ifndef GAME_MWMECHANICS_MAGICEFFECTS_H
#define GAME_MWMECHANICS_MAGICEFFECTS_H
#include <map>
namespace ESM
{
struct ENAMstruct;
}
namespace MWMechanics
{
struct EffectKey
{
int mId;
int mArg; // skill or ability
EffectKey();
EffectKey (int id, int arg = -1) : mId (id), mArg (arg) {}
EffectKey (const ESM::ENAMstruct& effect);
};
bool operator< (const EffectKey& left, const EffectKey& right);
struct EffectParam
{
int mMagnitude;
EffectParam();
EffectParam& operator+= (const EffectParam& param);
EffectParam& operator-= (const EffectParam& param);
};
inline EffectParam operator+ (const EffectParam& left, const EffectParam& right)
{
EffectParam param (left);
return param += right;
}
inline EffectParam operator- (const EffectParam& left, const EffectParam& right)
{
EffectParam param (left);
return param -= right;
}
/// \brief Effects currently affecting a NPC or creature
class MagicEffects
{
public:
typedef std::map<EffectKey, EffectParam> Collection;
private:
Collection mCollection;
public:
Collection::const_iterator Begin() const { return mCollection.begin(); }
Collection::const_iterator End() const { return mCollection.end(); }
void add (const EffectKey& key, const EffectParam& param);
EffectParam get (const EffectKey& key) const;
///< This function can safely be used for keys that are not present.
static MagicEffects diff (const MagicEffects& prev, const MagicEffects& now);
///< Return changes from \a prev to \a now.
};
}
#endif

@ -6,14 +6,224 @@
#include "../mwgui/window_manager.hpp"
#include "../mwworld/class.hpp"
#include "../mwworld/environment.hpp"
#include "../mwworld/world.hpp"
namespace MWMechanics
{
MechanicsManager::MechanicsManager (const ESMS::ESMStore& store,
MWGui::WindowManager& windowManager)
: mStore (store), mWindowManager (windowManager)
void MechanicsManager::buildPlayer()
{
MWWorld::Ptr ptr = mEnvironment.mWorld->getPlayerPos().getPlayer();
MWMechanics::CreatureStats& creatureStats = MWWorld::Class::get (ptr).getCreatureStats (ptr);
MWMechanics::NpcStats& npcStats = MWWorld::Class::get (ptr).getNpcStats (ptr);
const ESM::NPC *player = ptr.get<ESM::NPC>()->base;
// reset
creatureStats.mLevel = player->npdt52.level;
creatureStats.mAbilities.clear();
creatureStats.mMagicEffects = MagicEffects();
for (int i=0; i<27; ++i)
npcStats.mSkill[i].setBase (player->npdt52.skills[i]);
// race
if (mRaceSelected)
{
const ESM::Race *race =
mEnvironment.mWorld->getStore().races.find (
mEnvironment.mWorld->getPlayerPos().getRace());
bool male = mEnvironment.mWorld->getPlayerPos().isMale();
for (int i=0; i<8; ++i)
{
const ESM::Race::MaleFemale *attribute = 0;
switch (i)
{
case 0: attribute = &race->data.strength; break;
case 1: attribute = &race->data.intelligence; break;
case 2: attribute = &race->data.willpower; break;
case 3: attribute = &race->data.agility; break;
case 4: attribute = &race->data.speed; break;
case 5: attribute = &race->data.endurance; break;
case 6: attribute = &race->data.personality; break;
case 7: attribute = &race->data.luck; break;
}
creatureStats.mAttributes[i].setBase (
static_cast<int> (male ? attribute->male : attribute->female));
}
for (int i=0; i<7; ++i)
{
int index = race->data.bonus[i].skill;
if (index>=0 && index<27)
{
npcStats.mSkill[index].setBase (
npcStats.mSkill[index].getBase() + race->data.bonus[i].bonus);
}
}
for (std::vector<std::string>::const_iterator iter (race->powers.list.begin());
iter!=race->powers.list.end(); ++iter)
{
insertSpell (*iter, ptr);
}
}
// birthsign
if (!mEnvironment.mWorld->getPlayerPos().getBirthsign().empty())
{
const ESM::BirthSign *sign =
mEnvironment.mWorld->getStore().birthSigns.find (
mEnvironment.mWorld->getPlayerPos().getBirthsign());
for (std::vector<std::string>::const_iterator iter (sign->powers.list.begin());
iter!=sign->powers.list.end(); ++iter)
{
insertSpell (*iter, ptr);
}
}
// class
if (mClassSelected)
{
const ESM::Class& class_ = mEnvironment.mWorld->getPlayerPos().getClass();
for (int i=0; i<2; ++i)
{
int attribute = class_.data.attribute[i];
if (attribute>=0 && attribute<8)
{
creatureStats.mAttributes[attribute].setBase (
creatureStats.mAttributes[attribute].getBase() + 10);
}
}
for (int i=0; i<2; ++i)
{
int bonus = i==0 ? 10 : 25;
for (int i2=0; i2<5; ++i2)
{
int index = class_.data.skills[i2][i];
if (index>=0 && index<27)
{
npcStats.mSkill[index].setBase (
npcStats.mSkill[index].getBase() + bonus);
}
}
}
typedef ESMS::IndexListT<ESM::Skill>::MapType ContainerType;
const ContainerType& skills = mEnvironment.mWorld->getStore().skills.list;
for (ContainerType::const_iterator iter (skills.begin()); iter!=skills.end(); ++iter)
{
if (iter->second.data.specialization==class_.data.specialization)
{
int index = iter->first;
if (index>=0 && index<27)
{
npcStats.mSkill[index].setBase (
npcStats.mSkill[index].getBase() + 5);
}
}
}
}
// magic effects
adjustMagicEffects (ptr);
// calculate dynamic stats
int strength = creatureStats.mAttributes[0].getBase();
int intelligence = creatureStats.mAttributes[1].getBase();
int willpower = creatureStats.mAttributes[2].getBase();
int agility = creatureStats.mAttributes[3].getBase();
int endurance = creatureStats.mAttributes[5].getBase();
double magickaFactor = creatureStats.mMagicEffects.get (EffectKey (84)).mMagnitude*0.1 + 0.5;
creatureStats.mDynamic[0].setBase (static_cast<int> (0.5 * (strength + endurance)));
creatureStats.mDynamic[1].setBase (static_cast<int> (intelligence +
magickaFactor * intelligence));
creatureStats.mDynamic[2].setBase (strength+willpower+agility+endurance);
for (int i=0; i<3; ++i)
creatureStats.mDynamic[i].setCurrent (creatureStats.mDynamic[i].getModified());
}
void MechanicsManager::insertSpell (const std::string& id, MWWorld::Ptr& creature)
{
MWMechanics::CreatureStats& creatureStats =
MWWorld::Class::get (creature).getCreatureStats (creature);
const ESM::Spell *spell = mEnvironment.mWorld->getStore().spells.find (id);
switch (spell->data.type)
{
case ESM::Spell::ST_Ability:
if (creatureStats.mAbilities.find (id)==creatureStats.mAbilities.end())
{
creatureStats.mAbilities.insert (id);
}
break;
// TODO ST_SPELL, ST_Blight, ST_Disease, ST_Curse, ST_Power
default:
std::cout
<< "adding unsupported spell type (" << spell->data.type
<< ") to creature: " << id << std::endl;
}
}
void MechanicsManager::adjustMagicEffects (MWWorld::Ptr& creature)
{
MWMechanics::CreatureStats& creatureStats =
MWWorld::Class::get (creature).getCreatureStats (creature);
MagicEffects now;
for (std::set<std::string>::const_iterator iter (creatureStats.mAbilities.begin());
iter!=creatureStats.mAbilities.end(); ++iter)
{
const ESM::Spell *spell = mEnvironment.mWorld->getStore().spells.find (*iter);
for (std::vector<ESM::ENAMstruct>::const_iterator iter = spell->effects.list.begin();
iter!=spell->effects.list.end(); ++iter)
{
if (iter->range==0) // self
{
EffectParam param;
param.mMagnitude = iter->magnMax; // TODO calculate magnitude
now.add (EffectKey (*iter), param);
}
}
}
// TODO add effects from other spell types, active spells and equipment
MagicEffects diff = MagicEffects::diff (creatureStats.mMagicEffects, now);
creatureStats.mMagicEffects = now;
// TODO apply diff to other stats
}
MechanicsManager::MechanicsManager (MWWorld::Environment& environment)
: mEnvironment (environment), mUpdatePlayer (true), mClassSelected (false),
mRaceSelected (false)
{
buildPlayer();
}
void MechanicsManager::addActor (const MWWorld::Ptr& ptr)
@ -51,6 +261,9 @@ namespace MWMechanics
MWMechanics::CreatureStats& stats =
MWWorld::Class::get (mWatched).getCreatureStats (mWatched);
MWMechanics::NpcStats& npcStats =
MWWorld::Class::get (mWatched).getNpcStats (mWatched);
static const char *attributeNames[8] =
{
"AttribVal1", "AttribVal2", "AttribVal3", "AttribVal4", "AttribVal5",
@ -62,13 +275,24 @@ namespace MWMechanics
"HBar", "MBar", "FBar"
};
static const char *skillNames[27] =
{
"SkillBlock", "SkillArmorer", "SkillMediumArmor", "SkillHeavyArmor",
"SkillBluntWeapon", "SkillLongBlade", "SkillAxe", "SkillSpear",
"SkillAthletics", "SkillEnchant", "SkillDestruction", "SkillAlteration",
"SkillIllusion", "SkillConjuration", "SkillMysticism", "SkillRestoration",
"SkillAlchemy", "SkillUnarmored", "SkillSecurity", "SkillSneak",
"SkillAcrobatics", "SkillLightArmor", "SkillShortBlade", "SkillMarksman",
"SkillMercantile", "SkillSpeechcraft", "SkillHandToHand",
};
for (int i=0; i<8; ++i)
{
if (stats.mAttributes[i]!=mWatchedCreature.mAttributes[i])
{
mWatchedCreature.mAttributes[i] = stats.mAttributes[i];
mWindowManager.setValue (attributeNames[i], stats.mAttributes[i]);
mEnvironment.mWindowManager->setValue (attributeNames[i], stats.mAttributes[i]);
}
}
@ -78,9 +302,89 @@ namespace MWMechanics
{
mWatchedCreature.mDynamic[i] = stats.mDynamic[i];
mWindowManager.setValue (dynamicNames[i], stats.mDynamic[i]);
mEnvironment.mWindowManager->setValue (dynamicNames[i], stats.mDynamic[i]);
}
}
bool update = false;
for (int i=0; i<27; ++i)
{
if (npcStats.mSkill[i]!=mWatchedNpc.mSkill[i])
{
update = true;
mWatchedNpc.mSkill[i] = npcStats.mSkill[i];
mEnvironment.mWindowManager->setValue (skillNames[i], npcStats.mSkill[i]);
}
}
if (update)
mEnvironment.mWindowManager->updateSkillArea();
mEnvironment.mWindowManager->setValue ("level", stats.mLevel);
}
if (mUpdatePlayer)
{
// basic player profile; should not change anymore after the creation phase is finished.
mEnvironment.mWindowManager->setValue ("name", mEnvironment.mWorld->getPlayerPos().getName());
mEnvironment.mWindowManager->setValue ("race",
mEnvironment.mWorld->getStore().races.find (mEnvironment.mWorld->getPlayerPos().
getRace())->name);
mEnvironment.mWindowManager->setValue ("class",
mEnvironment.mWorld->getPlayerPos().getClass().name);
mUpdatePlayer = false;
MWGui::WindowManager::SkillList majorSkills (5);
MWGui::WindowManager::SkillList minorSkills (5);
for (int i=0; i<5; ++i)
{
minorSkills[i] = mEnvironment.mWorld->getPlayerPos().getClass().data.skills[i][0];
majorSkills[i] = mEnvironment.mWorld->getPlayerPos().getClass().data.skills[i][1];
}
mEnvironment.mWindowManager->configureSkills (majorSkills, minorSkills);
}
}
void MechanicsManager::setPlayerName (const std::string& name)
{
mEnvironment.mWorld->getPlayerPos().setName (name);
mUpdatePlayer = true;
}
void MechanicsManager::setPlayerRace (const std::string& race, bool male)
{
mEnvironment.mWorld->getPlayerPos().setGender (male);
mEnvironment.mWorld->getPlayerPos().setRace (race);
mRaceSelected = true;
buildPlayer();
mUpdatePlayer = true;
}
void MechanicsManager::setPlayerBirthsign (const std::string& id)
{
mEnvironment.mWorld->getPlayerPos().setBirthsign (id);
buildPlayer();
}
void MechanicsManager::setPlayerClass (const std::string& id)
{
mEnvironment.mWorld->getPlayerPos().setClass (*mEnvironment.mWorld->getStore().classes.find (id));
mClassSelected = true;
buildPlayer();
mUpdatePlayer = true;
}
void MechanicsManager::setPlayerClass (const ESM::Class& class_)
{
mEnvironment.mWorld->getPlayerPos().setClass (class_);
mClassSelected = true;
buildPlayer();
mUpdatePlayer = true;
}
}

@ -6,50 +6,71 @@
#include "../mwworld/ptr.hpp"
#include "creaturestats.hpp"
#include "npcstats.hpp"
namespace ESMS
namespace MWWorld
{
struct ESMStore;
}
namespace MWGui
{
class WindowManager;
class Environment;
}
namespace MWMechanics
{
class MechanicsManager
{
const ESMS::ESMStore& mStore;
MWGui::WindowManager& mWindowManager;
MWWorld::Environment& mEnvironment;
std::set<MWWorld::Ptr> mActors;
MWWorld::Ptr mWatched;
CreatureStats mWatchedCreature;
NpcStats mWatchedNpc;
bool mUpdatePlayer;
bool mClassSelected;
bool mRaceSelected;
void buildPlayer();
///< build player according to stored class/race/birthsign information. Will
/// default to the values of the ESM::NPC object, if no explicit information is given.
void insertSpell (const std::string& id, MWWorld::Ptr& creature);
void adjustMagicEffects (MWWorld::Ptr& creature);
public:
MechanicsManager (const ESMS::ESMStore& store, MWGui::WindowManager& windowManager);
MechanicsManager (MWWorld::Environment& environment);
void configureGUI();
void addActor (const MWWorld::Ptr& ptr);
///< Register an actor for stats management
void removeActor (const MWWorld::Ptr& ptr);
///< Deregister an actor for stats management
void dropActors (const MWWorld::Ptr::CellStore *cellStore);
///< Deregister all actors in the given cell.
void watchActor (const MWWorld::Ptr& ptr);
///< On each update look for changes in a previously registered actor and update the
/// GUI accordingly.
void update();
///< Update actor stats
void setPlayerName (const std::string& name);
///< Set player name.
void setPlayerRace (const std::string& id, bool male);
///< Set player race.
void setPlayerBirthsign (const std::string& id);
///< Set player birthsign.
void setPlayerClass (const std::string& id);
///< Set player class to stock class.
void setPlayerClass (const ESM::Class& class_);
///< Set player class to custom class.
};
}
#endif

@ -3,6 +3,8 @@
#include <map>
#include "stat.hpp"
namespace MWMechanics
{
/// \brief Additional stats for NPCs
@ -14,6 +16,8 @@ namespace MWMechanics
// NPCs other than the player can only have one faction. But for the sake of consistency
// we use the same data structure for the PC and the NPCs.
std::map<std::string, int> mFactionRank;
Stat<float> mSkill[27];
};
}

@ -12,8 +12,11 @@ namespace MWMechanics
T mModified;
public:
typedef T Type;
Stat() : mBase (0), mModified (0) {}
Stat(T base) : mBase (base), mModified (base) {}
Stat(T base, T modified) : mBase (base), mModified (modified) {}
const T& getBase() const
{
@ -86,8 +89,12 @@ namespace MWMechanics
T mCurrent;
public:
typedef T Type;
DynamicStat() : mCurrent (0) {}
DynamicStat(T current) : mCurrent (current) {}
DynamicStat(T base, T modified, T current) : mStatic(base, modified), mCurrent (current) {}
DynamicStat(const Stat<T> &stat, T current) : mStatic(stat), mCurrent (current) {}
const T& getBase() const
{

@ -5,6 +5,22 @@
namespace MWRender
{
PlayerPos::PlayerPos (Ogre::Camera *cam, const ESM::NPC *player, MWWorld::World& world) :
mCellStore (0), camera(cam), mWorld (world), mClass (0)
{
mPlayer.base = player;
mName = player->name;
mMale = !(player->flags & ESM::NPC::Female);
mRace = player->race;
mPlayer.ref.pos.pos[0] = mPlayer.ref.pos.pos[1] = mPlayer.ref.pos.pos[2] = 0;
mClass = new ESM::Class (*world.getStore().classes.find (player->cls));
}
PlayerPos::~PlayerPos()
{
delete mClass;
}
void PlayerPos::setPos(float x, float y, float z, bool updateCamera)
{
mWorld.moveObject (getPlayer(), x, y, z);
@ -15,4 +31,11 @@ namespace MWRender
mPlayer.ref.pos.pos[2],
-mPlayer.ref.pos.pos[1]));
}
void PlayerPos::setClass (const ESM::Class& class_)
{
ESM::Class *new_class = new ESM::Class (class_);
delete mClass;
mClass = new_class;
}
}

@ -24,14 +24,17 @@ namespace MWRender
MWWorld::Ptr::CellStore *mCellStore;
Ogre::Camera *camera;
MWWorld::World& mWorld;
std::string mName;
bool mMale;
std::string mRace;
std::string mBirthsign;
ESM::Class *mClass;
public:
PlayerPos(Ogre::Camera *cam, const ESM::NPC *player, MWWorld::World& world) :
mCellStore (0), camera(cam), mWorld (world)
{
mPlayer.base = player;
mPlayer.ref.pos.pos[0] = mPlayer.ref.pos.pos[1] = mPlayer.ref.pos.pos[2] = 0;
}
PlayerPos(Ogre::Camera *cam, const ESM::NPC *player, MWWorld::World& world);
~PlayerPos();
// Set the player position. Uses Morrowind coordinates.
void setPos(float _x, float _y, float _z, bool updateCamera = false);
@ -73,6 +76,53 @@ namespace MWRender
MWWorld::Ptr ptr (&mPlayer, mCellStore);
return ptr;
}
void setName (const std::string& name)
{
mName = name;
}
void setGender (bool male)
{
mMale = male;
}
void setRace (const std::string& race)
{
mRace = race;
}
void setBirthsign (const std::string& birthsign)
{
mBirthsign = birthsign;
}
void setClass (const ESM::Class& class_);
std::string getName() const
{
return mName;
}
bool isMale() const
{
return mMale;
}
std::string getRace() const
{
return mRace;
}
std::string getBirthsign() const
{
return mBirthsign;
}
const ESM::Class& getClass() const
{
return *mClass;
}
};
}
#endif

@ -95,4 +95,10 @@ op 0x2000085-0x200008b: Disable Controls
op 0x200008c: Unlock
op 0x200008d: Unlock, explicit reference
op 0x200008e: COE
opcodes 0x200008f-0x3ffffff unused
op 0x200008e-0x20000a8: GetSkill
op 0x20000a9-0x20000c3: GetSkill, explicit reference
op 0x20000c4-0x20000de: SetSkill
op 0x20000df-0x20000f9: SetSkill, explicit reference
op 0x20000fa-0x2000114: ModSkill
op 0x2000115-0x200012f: ModSKill, explicit reference
opcodes 0x2000130-0x3ffffff unused

@ -8,6 +8,7 @@
#include <components/interpreter/opcodes.hpp>
#include "../mwgui/window_manager.hpp"
#include "../mwinput/inputmanager.hpp"
#include "interpretercontext.hpp"
@ -47,7 +48,7 @@ namespace MWScript
InterpreterContext& context =
static_cast<InterpreterContext&> (runtime.getContext());
context.getWindowManager().setMode(mDialogue);
context.getInputManager().setGuiMode(mDialogue);
}
};

@ -11,6 +11,8 @@
#include "../mwgui/window_manager.hpp"
#include "../mwinput/inputmanager.hpp"
#include "locals.hpp"
#include "globalscripts.hpp"
@ -263,6 +265,11 @@ namespace MWScript
return *mEnvironment.mWindowManager;
}
MWInput::MWInputManager& InterpreterContext::getInputManager()
{
return *mEnvironment.mInputManager;
}
MWWorld::World& InterpreterContext::getWorld()
{
return *mEnvironment.mWorld;

@ -15,6 +15,11 @@ namespace MWSound
class SoundManager;
}
namespace MWInput
{
struct MWInputManager;
}
namespace MWScript
{
struct Locals;
@ -107,6 +112,8 @@ namespace MWScript
MWGui::WindowManager& getWindowManager();
MWInput::MWInputManager& getInputManager();
MWWorld::Ptr getReference();
///< Reference, that the script is running from (can be empty)
};

@ -468,6 +468,160 @@ namespace MWScript
}
};
class OpGetSkill : public Interpreter::Opcode0
{
int mIndex;
public:
OpGetSkill (int index) : mIndex (index) {}
virtual void execute (Interpreter::Runtime& runtime)
{
MWScript::InterpreterContext& context
= static_cast<MWScript::InterpreterContext&> (runtime.getContext());
MWWorld::Ptr ptr = context.getReference();
Interpreter::Type_Integer value =
MWWorld::Class::get (ptr).getNpcStats (ptr).mSkill[mIndex].
getModified();
runtime.push (value);
}
};
class OpGetSkillExplicit : public Interpreter::Opcode0
{
int mIndex;
public:
OpGetSkillExplicit (int index) : mIndex (index) {}
virtual void execute (Interpreter::Runtime& runtime)
{
MWScript::InterpreterContext& context
= static_cast<MWScript::InterpreterContext&> (runtime.getContext());
std::string id = runtime.getStringLiteral (runtime[0].mInteger);
runtime.pop();
MWWorld::Ptr ptr = context.getWorld().getPtr (id, false);
Interpreter::Type_Integer value =
MWWorld::Class::get (ptr).getNpcStats (ptr).mSkill[mIndex].
getModified();
runtime.push (value);
}
};
class OpSetSkill : public Interpreter::Opcode0
{
int mIndex;
public:
OpSetSkill (int index) : mIndex (index) {}
virtual void execute (Interpreter::Runtime& runtime)
{
MWScript::InterpreterContext& context
= static_cast<MWScript::InterpreterContext&> (runtime.getContext());
Interpreter::Type_Integer value = runtime[0].mInteger;
runtime.pop();
MWWorld::Ptr ptr = context.getReference();
MWWorld::Class::get (ptr).getNpcStats (ptr).mSkill[mIndex].
setModified (value, 0);
}
};
class OpSetSkillExplicit : public Interpreter::Opcode0
{
int mIndex;
public:
OpSetSkillExplicit (int index) : mIndex (index) {}
virtual void execute (Interpreter::Runtime& runtime)
{
MWScript::InterpreterContext& context
= static_cast<MWScript::InterpreterContext&> (runtime.getContext());
std::string id = runtime.getStringLiteral (runtime[0].mInteger);
runtime.pop();
Interpreter::Type_Integer value = runtime[0].mInteger;
runtime.pop();
MWWorld::Ptr ptr = context.getWorld().getPtr (id, false);
MWWorld::Class::get (ptr).getNpcStats (ptr).mSkill[mIndex].
setModified (value, 0);
}
};
class OpModSkill : public Interpreter::Opcode0
{
int mIndex;
public:
OpModSkill (int index) : mIndex (index) {}
virtual void execute (Interpreter::Runtime& runtime)
{
MWScript::InterpreterContext& context
= static_cast<MWScript::InterpreterContext&> (runtime.getContext());
Interpreter::Type_Integer value = runtime[0].mInteger;
runtime.pop();
MWWorld::Ptr ptr = context.getReference();
value += MWWorld::Class::get (ptr).getNpcStats (ptr).mSkill[mIndex].
getModified();
MWWorld::Class::get (ptr).getNpcStats (ptr).mSkill[mIndex].
setModified (value, 0, 100);
}
};
class OpModSkillExplicit : public Interpreter::Opcode0
{
int mIndex;
public:
OpModSkillExplicit (int index) : mIndex (index) {}
virtual void execute (Interpreter::Runtime& runtime)
{
MWScript::InterpreterContext& context
= static_cast<MWScript::InterpreterContext&> (runtime.getContext());
std::string id = runtime.getStringLiteral (runtime[0].mInteger);
runtime.pop();
Interpreter::Type_Integer value = runtime[0].mInteger;
runtime.pop();
MWWorld::Ptr ptr = context.getWorld().getPtr (id, false);
value +=
MWWorld::Class::get (ptr).getNpcStats (ptr).mSkill[mIndex].
getModified();
MWWorld::Class::get (ptr).getNpcStats (ptr).mSkill[mIndex].
setModified (value, 0, 100);
}
};
const int numberOfAttributes = 8;
const int opcodeGetAttribute = 0x2000027;
@ -490,6 +644,15 @@ namespace MWScript
const int opcodeGetDynamicGetRatio = 0x200006f;
const int opcodeGetDynamicGetRatioExplicit = 0x2000072;
const int numberOfSkills = 27;
const int opcodeGetSkill = 0x200008e;
const int opcodeGetSkillExplicit = 0x20000a9;
const int opcodeSetSkill = 0x20000c4;
const int opcodeSetSkillExplicit = 0x20000df;
const int opcodeModSkill = 0x20000fa;
const int opcodeModSkillExplicit = 0x2000115;
void registerExtensions (Compiler::Extensions& extensions)
{
static const char *attributes[numberOfAttributes] =
@ -503,6 +666,16 @@ namespace MWScript
"health", "magicka", "fatigue"
};
static const char *skills[numberOfSkills] =
{
"block", "armorer", "mediumarmor", "heavyarmor", "bluntweapon",
"longblade", "axe", "spear", "athletics", "enchant", "destruction",
"alteration", "illusion", "conjuration", "mysticism",
"restoration", "alchemy", "unarmored", "security", "sneak",
"acrobatics", "lightarmor", "shortblade", "marksman",
"merchantile", "speechcraft", "handtohand"
};
std::string get ("get");
std::string set ("set");
std::string mod ("mod");
@ -537,7 +710,18 @@ namespace MWScript
extensions.registerFunction (get + dynamics[i] + getRatio, 'f', "",
opcodeGetDynamicGetRatio+i, opcodeGetDynamicGetRatioExplicit+i);
}
for (int i=0; i<numberOfSkills; ++i)
{
extensions.registerFunction (get + skills[i], 'l', "",
opcodeGetSkill+i, opcodeGetSkillExplicit+i);
extensions.registerInstruction (set + skills[i], "l",
opcodeSetSkill+i, opcodeSetSkillExplicit+i);
extensions.registerInstruction (mod + skills[i], "l",
opcodeModSkill+i, opcodeModSkillExplicit+i);
}
}
@ -581,6 +765,18 @@ namespace MWScript
interpreter.installSegment5 (opcodeGetDynamicGetRatioExplicit+i,
new OpGetDynamicGetRatioExplicit (i));
}
for (int i=0; i<numberOfSkills; ++i)
{
interpreter.installSegment5 (opcodeGetSkill+i, new OpGetSkill (i));
interpreter.installSegment5 (opcodeGetSkillExplicit+i, new OpGetSkillExplicit (i));
interpreter.installSegment5 (opcodeSetSkill+i, new OpSetSkill (i));
interpreter.installSegment5 (opcodeSetSkillExplicit+i, new OpSetSkillExplicit (i));
interpreter.installSegment5 (opcodeModSkill+i, new OpModSkill (i));
interpreter.installSegment5 (opcodeModSkillExplicit+i, new OpModSkillExplicit (i));
}
}
}
}

@ -26,6 +26,11 @@ namespace MWDialogue
class DialogueManager;
}
namespace MWInput
{
struct MWInputManager;
}
namespace MWWorld
{
class World;
@ -36,7 +41,8 @@ namespace MWWorld
public:
Environment()
: mWorld (0), mSoundManager (0), mGlobalScripts (0), mWindowManager (0),
mMechanicsManager (0), mDialogueManager (0), mFrameDuration (0)
mMechanicsManager (0), mDialogueManager (0), mFrameDuration (0),
mInputManager (0)
{}
World *mWorld;
@ -46,6 +52,9 @@ namespace MWWorld
MWMechanics::MechanicsManager *mMechanicsManager;
MWDialogue::DialogueManager *mDialogueManager;
float mFrameDuration;
// For setting GUI mode
MWInput::MWInputManager *mInputManager;
};
}

@ -0,0 +1,36 @@
#include "attr.hpp"
using namespace ESM;
const Attribute::AttributeID Attribute::attributeIds[Attribute::Length] = {
Attribute::Strength,
Attribute::Intelligence,
Attribute::Willpower,
Attribute::Agility,
Attribute::Speed,
Attribute::Endurance,
Attribute::Personality,
Attribute::Luck
};
const std::string Attribute::gmstAttributeIds[Attribute::Length] = {
"sAttributeStrength",
"sAttributeIntelligence",
"sAttributeWillpower",
"sAttributeAgility",
"sAttributeSpeed",
"sAttributeEndurance",
"sAttributePersonality",
"sAttributeLuck"
};
const std::string Attribute::gmstAttributeDescIds[Attribute::Length] = {
"sStrDesc",
"sIntDesc",
"sWilDesc",
"sAgiDesc",
"sSpdDesc",
"sEndDesc",
"sPerDesc",
"sLucDesc"
};

@ -0,0 +1,42 @@
#ifndef _ESM_ATTR_H
#define _ESM_ATTR_H
#include <string>
namespace ESM {
/*
* Attribute definitions
*/
struct Attribute
{
enum AttributeID
{
Strength = 0,
Intelligence = 1,
Willpower = 2,
Agility = 3,
Speed = 4,
Endurance = 5,
Personality = 6,
Luck = 7,
Length
};
AttributeID id;
std::string name, description;
static const AttributeID attributeIds[Length];
static const std::string gmstAttributeIds[Length];
static const std::string gmstAttributeDescIds[Length];
Attribute(AttributeID id, const std::string &name, const std::string &description)
: id(id)
, name(name)
, description(description)
{
}
};
}
#endif

@ -0,0 +1,15 @@
#include "loadclas.hpp"
using namespace ESM;
const Class::Specialization Class::specializationIds[3] = {
Class::Combat,
Class::Magic,
Class::Stealth
};
const char *Class::gmstSpecializationIds[3] = {
"sSpecializationCombat",
"sSpecializationMagic",
"sSpecializationStealth"
};

@ -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.
*/
@ -61,10 +68,10 @@ struct ENAMstruct
// Which skills/attributes are affected (for restore/drain spells
// etc.)
char skill, attribute; // -1 if N/A
signed 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
@ -77,7 +84,7 @@ struct EffectList
void load(ESMReader &esm)
{
ENAMstruct s;
ENAMstruct s;
while(esm.isNextSub("ENAM"))
{
esm.getHT(s, 24);

@ -35,6 +35,16 @@ struct Class
RepairItem = 0x20000
};
enum Specialization
{
Combat = 0,
Magic = 1,
Stealth = 2
};
static const Specialization specializationIds[3];
static const char *gmstSpecializationIds[3];
struct CLDTstruct
{
int attribute[2]; // Attributes that get class bonus

@ -0,0 +1,33 @@
#include "loadskil.hpp"
namespace ESMS
{
const std::string Skill::sSkillNames[Length] = {
"Block",
"Armorer",
"Medium Armor",
"Heavy Armor",
"Blunt Weapon",
"Long Blade",
"Axe",
"Spear",
"Athletics",
"Enchant",
"Destruction",
"Alteration",
"Illusion",
"Conjuration",
"Mysticism",
"Restoration",
"Alchemy",
"Unarmored",
"Security",
"Sneak",
"Acrobatics",
"Light Armor",
"Short Blade",
"Marksman",
"Speechcraft",
"Hand To Hand",
};
}

@ -1,6 +1,8 @@
#ifndef _ESM_SKIL_H
#define _ESM_SKIL_H
#include <boost/array.hpp>
#include "esm_reader.hpp"
#include "defs.hpp"
@ -30,8 +32,43 @@ struct Skill
std::string description;
enum SkillEnum
{
Block = 0,
Armorer = 1,
MediumArmor = 2,
HeavyArmor = 3,
BluntWeapon = 4,
LongBlade = 5,
Axe = 6,
Spear = 7,
Athletics = 8,
Enchant = 9,
Destruction = 10,
Alteration = 11,
Illusion = 12,
Conjuration = 13,
Mysticism = 14,
Restoration = 15,
Alchemy = 16,
Unarmored = 17,
Security = 18,
Sneak = 19,
Acrobatics = 20,
LightArmor = 21,
ShortBlade = 22,
Marksman = 23,
Mercantile = 24,
Speechcraft = 25,
HandToHand = 26,
Length
};
static const std::string sSkillNameIds[Length];
static const boost::array<SkillEnum, Length> skillIds;
void load(ESMReader &esm)
{
esm.getHNT(index, "INDX");
esm.getHNT(data, "SKDT", 24);
description = esm.getHNOString("DESC");
}

@ -43,6 +43,9 @@
#include "loadstat.hpp"
#include "loadweap.hpp"
// Special records which are not loaded from ESM
#include "attr.hpp"
namespace ESM {
// Integer versions of all the record names, used for faster lookup

@ -0,0 +1,63 @@
#include "loadskil.hpp"
namespace ESM
{
const std::string Skill::sSkillNameIds[Length] = {
"sSkillBlock",
"sSkillArmorer",
"sSkillMediumarmor",
"sSkillHeavyarmor",
"sSkillBluntweapon",
"sSkillLongblade",
"sSkillAxe",
"sSkillSpear",
"sSkillAthletics",
"sSkillEnchant",
"sSkillDestruction",
"sSkillAlteration",
"sSkillIllusion",
"sSkillConjuration",
"sSkillMysticism",
"sSkillRestoration",
"sSkillAlchemy",
"sSkillUnarmored",
"sSkillSecurity",
"sSkillSneak",
"sSkillAcrobatics",
"sSkillLightarmor",
"sSkillShortblade",
"sSkillMarksman",
"sSkillMercantile",
"sSkillSpeechcraft",
"sSkillHandtohand",
};
const boost::array<Skill::SkillEnum, Skill::Length> Skill::skillIds = {{
Block,
Armorer,
MediumArmor,
HeavyArmor,
BluntWeapon,
LongBlade,
Axe,
Spear,
Athletics,
Enchant,
Destruction,
Alteration,
Illusion,
Conjuration,
Mysticism,
Restoration,
Alchemy,
Unarmored,
Security,
Sneak,
Acrobatics,
LightArmor,
ShortBlade,
Marksman,
Mercantile,
Speechcraft,
HandToHand
}};
}

@ -49,10 +49,14 @@ namespace ESMS
// Find the given object ID, or return NULL if not found.
const X* search(const std::string &id) const
{
std::string id2 = toLower (id);
if(list.find(id2) == list.end())
return NULL;
return &list.find(id2)->second;
std::string id2 = toLower (id);
typename MapType::const_iterator iter = list.find (id2);
if (iter == list.end())
return NULL;
return &iter->second;
}
// Find the given object ID (throws an exception if not found)
@ -87,10 +91,13 @@ namespace ESMS
// Find the given object ID, or return NULL if not found.
const X* search(const std::string &id) const
{
std::string id2 = toLower (id);
if(list.find(id2) == list.end())
return NULL;
return &list.find(id2)->second;
std::string id2 = toLower (id);
typename MapType::const_iterator iter = list.find (id2);
if (iter == list.end())
return NULL;
return &iter->second;
}
// Find the given object ID (throws an exception if not found)
@ -129,10 +136,14 @@ namespace ESMS
// Find the given object ID, or return NULL if not found.
const X* search(const std::string &id) const
{
std::string id2 = toLower (id);
if(list.find(id2) == list.end())
return NULL;
return &list.find(id2)->second;
std::string id2 = toLower (id);
typename MapType::const_iterator iter = list.find (id2);
if (iter == list.end())
return NULL;
return &iter->second;
}
// Find the given object ID (throws an exception if not found)
@ -359,10 +370,14 @@ namespace ESMS
// Find the given object ID, or return NULL if not found.
const X* search(const std::string &id) const
{
std::string id2 = toLower (id);
if(list.find(id2) == list.end())
return NULL;
return &list.find(id2)->second;
std::string id2 = toLower (id);
typename MapType::const_iterator iter = list.find (id2);
if (iter == list.end())
return NULL;
return &iter->second;
}
// Find the given object ID (throws an exception if not found)
@ -379,12 +394,55 @@ namespace ESMS
int getSize() { return list.size(); }
};
template <typename X>
struct IndexListT
{
typedef std::map<int, X> MapType;
MapType list;
void load(ESMReader &esm)
{
X ref;
ref.load (esm);
int index = ref.index;
list[index] = ref;
}
int getSize()
{
return list.size();
}
// Find the given object ID, or return NULL if not found.
const X* search (int id) const
{
typename MapType::const_iterator iter = list.find (id);
if (iter == list.end())
return NULL;
return &iter->second;
}
// Find the given object ID (throws an exception if not found)
const X* find (int id) const
{
const X *object = search (id);
if (!object)
{
std::ostringstream error;
error << "object " << id << " not found";
throw std::runtime_error (error.str());
}
return object;
}
};
/* We need special lists for:
Magic effects
Skills
Dialog / Info combo
Scripts
Land
Path grids
Land textures

@ -46,15 +46,21 @@ void ESMStore::load(ESMReader &esm)
{
std::cerr << "error: info record without dialog" << std::endl;
esm.skipRecord();
continue;
}
}
else if (n.val==ESM::REC_MGEF)
{
magicEffects.load (esm);
}
else if (n.val==ESM::REC_SKIL)
{
skills.load (esm);
}
else
{
// Not found (this would be an error later)
esm.skipRecord();
missing.insert(n.toString());
continue;
}
}
else
@ -84,6 +90,12 @@ void ESMStore::load(ESMReader &esm)
}
}
for (int i = 0; i < Attribute::Length; ++i)
{
Attribute::AttributeID id = Attribute::attributeIds[i];
attributes.list.insert(std::make_pair(id, Attribute(id, Attribute::gmstAttributeIds[i], Attribute::gmstAttributeDescIds[i])));
}
/* This information isn't needed on screen. But keep the code around
for debugging purposes later.

@ -72,10 +72,13 @@ namespace ESMS
LandList lands;
LTexList landTexts;
ScriptListT<Script> scripts;
//RecListT<MagicEffect> magicEffects;
//RecListT<Skill> skills;
IndexListT<MagicEffect> magicEffects;
IndexListT<Skill> skills;
//RecListT<PathGrid> pathgrids;
// Special entry which is hardcoded and not loaded from an ESM
IndexListT<Attribute> attributes;
// Lookup of all IDs. Makes looking up references faster. Just
// maps the id name to the record type.
typedef std::map<std::string, int> AllMap;
@ -128,7 +131,6 @@ namespace ESMS
recLists[REC_REGN] = &regions;
recLists[REC_REPA] = &repairs;
recLists[REC_SCPT] = &scripts;
//recLists[REC_SKIL] = &skills;
recLists[REC_SNDG] = &soundGens;
recLists[REC_SOUN] = &sounds;
recLists[REC_SPEL] = &spells;

@ -4,7 +4,7 @@ IF(MSVC)
add_definitions("-D_SCL_SECURE_NO_WARNINGS /wd4305 /wd4244" )
ENDIF(MSVC)
ADD_DEFINITIONS(-DCAELUM_LIB)
ADD_DEFINITIONS(-DCAELUM_STATIC)
INCLUDE_DIRECTORIES(
${CMAKE_HOME_DIRECTORY}/extern/caelum/include
${OGRE_INCLUDE_DIR}/Ogre

@ -32,7 +32,10 @@ along with Caelum. If not, see <http://www.gnu.org/licenses/>.
// Define the dll export qualifier if compiling for Windows
#if OGRE_PLATFORM == OGRE_PLATFORM_WIN32
#ifdef CAELUM_LIB
#ifdef CAELUM_STATIC
// Don't use dll export qualifier when built as a static lib
#define CAELUM_EXPORT
#elif CAELUM_LIB
#define CAELUM_EXPORT __declspec (dllexport)
#else
#ifdef __MINGW32__

@ -30,14 +30,29 @@ configure_file("${SDIR}/Comic.TTF" "${DDIR}/Comic.TTF" COPYONLY)
configure_file("${SDIR}/core.skin" "${DDIR}/core.skin" COPYONLY)
configure_file("${SDIR}/core.xml" "${DDIR}/core.xml" COPYONLY)
configure_file("${SDIR}/mwpointer.png" "${DDIR}/mwpointer.png" COPYONLY)
configure_file("${SDIR}/mwgui.png" "${DDIR}/mwgui.png" COPYONLY)
configure_file("${SDIR}/openmw_box.skin.xml" "${DDIR}/openmw_box.skin.xml" COPYONLY)
configure_file("${SDIR}/openmw_button.skin.xml" "${DDIR}/openmw_button.skin.xml" COPYONLY)
configure_file("${SDIR}/openmw_list.skin.xml" "${DDIR}/openmw_list.skin.xml" COPYONLY)
configure_file("${SDIR}/openmw_edit.skin.xml" "${DDIR}/openmw_edit.skin.xml" COPYONLY)
configure_file("${SDIR}/openmw_console_layout.xml" "${DDIR}/openmw_console_layout.xml" COPYONLY)
configure_file("${SDIR}/openmw_console.skin.xml" "${DDIR}/openmw_console.skin.xml" COPYONLY)
configure_file("${SDIR}/openmw.font.xml" "${DDIR}/openmw.font.xml" COPYONLY)
configure_file("${SDIR}/openmw_hud_box.skin.xml" "${DDIR}/openmw_hud_box.skin.xml" COPYONLY)
configure_file("${SDIR}/openmw_hud_energybar.skin.xml" "${DDIR}/openmw_hud_energybar.skin.xml" COPYONLY)
configure_file("${SDIR}/openmw_hud_layout.xml" "${DDIR}/openmw_hud_layout.xml" COPYONLY)
configure_file("${SDIR}/openmw_text_input_layout.xml" "${DDIR}/openmw_text_input_layout.xml" COPYONLY)
configure_file("${SDIR}/openmw_infobox_layout.xml" "${DDIR}/openmw_infobox_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_generate_class_result_layout.xml" "${DDIR}/openmw_chargen_generate_class_result_layout.xml" COPYONLY)
configure_file("${SDIR}/openmw_chargen_create_class_layout.xml" "${DDIR}/openmw_chargen_create_class_layout.xml" COPYONLY)
configure_file("${SDIR}/openmw_chargen_select_specialization_layout.xml" "${DDIR}/openmw_chargen_select_specialization_layout.xml" COPYONLY)
configure_file("${SDIR}/openmw_chargen_select_attribute_layout.xml" "${DDIR}/openmw_chargen_select_attribute_layout.xml" COPYONLY)
configure_file("${SDIR}/openmw_chargen_select_skill_layout.xml" "${DDIR}/openmw_chargen_select_skill_layout.xml" COPYONLY)
configure_file("${SDIR}/openmw_chargen_class_description_layout.xml" "${DDIR}/openmw_chargen_class_description_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)
configure_file("${SDIR}/openmw_mainmenu_skin.xml" "${DDIR}/openmw_mainmenu_skin.xml" COPYONLY)

@ -11,6 +11,8 @@
<List file="openmw_text.skin.xml" group="General"/>
<List file="openmw_windows.skin.xml" group="General"/>
<List file="openmw_button.skin.xml" group="General"/>
<List file="openmw_list.skin.xml" group="General"/>
<List file="openmw_edit.skin.xml" group="General"/>
<List file="openmw_box.skin.xml" group="General"/>
<List file="openmw_progress.skin.xml" group="General"/>
<List file="openmw_hud_energybar.skin.xml" group="General"/>

Binary file not shown.

After

Width:  |  Height:  |  Size: 13 KiB

@ -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>

@ -0,0 +1,18 @@
<?xml version="1.0" encoding="UTF-8"?>
<MyGUI type="Layout">
<Widget type="Window" skin="MW_Dialog" layer="Windows" position="0 0 249 249" name="_Main">
<!-- Edit box -->
<Widget type="Edit" skin="MW_TextBoxEdit" position="14 14 220 192" name="TextEdit" align="ALIGN_LEFT ALIGN_TOP STRETCH">
<Property key="Edit_MultiLine" value="1" />
<Property key="Edit_VisibleVScroll" value="1" />
<Property key="Edit_WordWrap" value="1" />
</Widget>
<!-- Dialog buttons -->
<Widget type="Button" skin="MW_Button" position="177 214 57 24" name="OKButton">
<Property key="Widget_Caption" value="Enter"/>
</Widget>
</Widget>
</MyGUI>

@ -0,0 +1,65 @@
<?xml version="1.0" encoding="UTF-8"?>
<MyGUI type="Layout">
<!-- correct size is 491 302, adjust when skin is changed to a dialog -->
<Widget type="Window" skin="MW_Window" layer="Windows" position="0 0 499 330" name="_Main">
<!-- Class list -->
<Widget type="List" skin="MW_List" position="14 13 181 131" name="ClassList" />
<!-- Class image -->
<Widget type="Widget" skin="MW_Box" position="212 9 265 138" align="ALIGN_LEFT ALIGN_TOP">
<Widget type="StaticImage" skin="StaticImage" position="2 2 261 134" name="ClassImage" align="ALIGN_LEFT ALIGN_TOP" />
</Widget>
<!-- Specialization -->
<Widget type="Widget" skin="" position="15 152 484 178" align="ALIGN_LEFT ALIGN_TOP">
<Widget type="StaticText" skin="HeaderText" position="0 0 162 18" name="SpecializationT" align="ALIGN_LEFT ALIGN_TOP">
<Property key="Widget_Caption" value="Specialization:"/>
<Property key="Widget_AlignText" value="ALIGN_LEFT ALIGN_TOP"/>
</Widget>
<Widget type="StaticText" skin="SandText" position="0 18 162 18" name="SpecializationName" align="ALIGN_LEFT ALIGN_TOP">
<Property key="Widget_AlignText" value="ALIGN_LEFT ALIGN_TOP"/>
</Widget>
<!-- Favorite Attributes -->
<Widget type="StaticText" skin="HeaderText" position="0 41 162 18" name="FavoriteAttributesT" align="ALIGN_LEFT ALIGN_TOP">
<Property key="Widget_Caption" value="Favorite Attributes:"/>
<Property key="Widget_AlignText" value="ALIGN_LEFT ALIGN_TOP"/>
</Widget>
<Widget type="MWAttribute" skin="MW_StatName" position="0 59 162 18" name="FavoriteAttribute0" align="ALIGN_LEFT ALIGN_TOP" />
<Widget type="MWAttribute" skin="MW_StatName" position="0 77 162 18" name="FavoriteAttribute1" align="ALIGN_LEFT ALIGN_TOP" />
<!-- Major Skills -->
<Widget type="StaticText" skin="HeaderText" position="162 0 162 18" name="MajorSkillT" align="ALIGN_LEFT ALIGN_TOP">
<Property key="Widget_Caption" value="Major Skills:"/>
<Property key="Widget_AlignText" value="ALIGN_LEFT ALIGN_TOP"/>
</Widget>
<Widget type="MWSkill" skin="MW_StatName" position="162 18 162 18" name="MajorSkill0" align="ALIGN_LEFT ALIGN_TOP" />
<Widget type="MWSkill" skin="MW_StatName" position="162 36 162 18" name="MajorSkill1" align="ALIGN_LEFT ALIGN_TOP" />
<Widget type="MWSkill" skin="MW_StatName" position="162 54 162 18" name="MajorSkill2" align="ALIGN_LEFT ALIGN_TOP" />
<Widget type="MWSkill" skin="MW_StatName" position="162 72 162 18" name="MajorSkill3" align="ALIGN_LEFT ALIGN_TOP" />
<Widget type="MWSkill" skin="MW_StatName" position="162 90 162 18" name="MajorSkill4" align="ALIGN_LEFT ALIGN_TOP" />
<!-- Minor Skills -->
<Widget type="StaticText" skin="HeaderText" position="325 0 162 18" name="MinorSkillT" align="ALIGN_LEFT ALIGN_TOP">
<Property key="Widget_Caption" value="Minor Skills:"/>
<Property key="Widget_AlignText" value="ALIGN_LEFT ALIGN_TOP"/>
</Widget>
<Widget type="MWSkill" skin="MW_StatName" position="325 18 162 18" name="MinorSkill0" align="ALIGN_LEFT ALIGN_TOP" />
<Widget type="MWSkill" skin="MW_StatName" position="325 36 162 18" name="MinorSkill1" align="ALIGN_LEFT ALIGN_TOP" />
<Widget type="MWSkill" skin="MW_StatName" position="325 54 162 18" name="MinorSkill2" align="ALIGN_LEFT ALIGN_TOP" />
<Widget type="MWSkill" skin="MW_StatName" position="325 72 162 18" name="MinorSkill3" align="ALIGN_LEFT ALIGN_TOP" />
<Widget type="MWSkill" skin="MW_StatName" position="325 90 162 18" name="MinorSkill4" align="ALIGN_LEFT ALIGN_TOP" />
</Widget>
<!-- Dialog buttons -->
<Widget type="Button" skin="MW_Button" position="382 265 53 23" name="BackButton">
<Property key="Widget_Caption" value="Back"/>
</Widget>
<Widget type="Button" skin="MW_Button" position="434 265 42 23" name="OKButton">
<Property key="Widget_Caption" value="OK"/>
</Widget>
</Widget>
</MyGUI>

@ -0,0 +1,70 @@
<?xml version="1.0" encoding="UTF-8"?>
<MyGUI type="Layout">
<!-- correct size is 474 192, adjust when skin is changed to a dialog -->
<Widget type="Window" skin="MW_Window" layer="Windows" position="0 0 482 220" name="_Main">
<!-- content, used to adjust offsets while the window skin is used -->
<Widget type="Widget" skin="" position="0 0 474 192" align="ALIGN_STRETCH">
<!-- Class name -->
<Widget type="StaticText" skin="ProgressText" position="12 12 48 30" name="LabelT" align="ALIGN_LEFT ALIGN_TOP">
<Property key="Widget_Caption" value="Name"/>
<Property key="Widget_AlignText" value="ALIGN_LEFT ALIGN_VCENTRE"/>
</Widget>
<Widget type="Edit" skin="MW_TextEdit" position="62 12 250 30" name="EditName" align="ALIGN_HSTRETCH ALIGN_TOP"/>
<Widget type="Widget" skin="" position="12 46 480 110" align="ALIGN_STRETCH">
<!-- Specialization -->
<Widget type="StaticText" skin="HeaderText" position="0 0 156 18" name="SpecializationT" align="ALIGN_LEFT ALIGN_TOP">
<Property key="Widget_Caption" value="Specialization:"/>
<Property key="Widget_AlignText" value="ALIGN_LEFT ALIGN_TOP"/>
</Widget>
<Widget type="StaticText" skin="SandText" position="0 18 156 18" name="SpecializationName" align="ALIGN_LEFT ALIGN_TOP">
<Property key="Widget_AlignText" value="ALIGN_LEFT ALIGN_TOP"/>
</Widget>
<!-- Favorite Attributes -->
<Widget type="StaticText" skin="HeaderText" position="0 41 156 18" name="FavoriteAttributesT" align="ALIGN_LEFT ALIGN_TOP">
<Property key="Widget_Caption" value="Favorite Attributes:"/>
<Property key="Widget_AlignText" value="ALIGN_LEFT ALIGN_TOP"/>
</Widget>
<Widget type="MWAttribute" skin="MW_StatNameButton" position="0 59 156 18" name="FavoriteAttribute0" align="ALIGN_LEFT ALIGN_TOP" />
<Widget type="MWAttribute" skin="MW_StatNameButton" position="0 77 156 18" name="FavoriteAttribute1" align="ALIGN_LEFT ALIGN_TOP" />
<!-- Major Skills -->
<Widget type="StaticText" skin="HeaderText" position="156 0 158 18" name="MajorSkillT" align="ALIGN_LEFT ALIGN_TOP">
<Property key="Widget_Caption" value="Major Skills:"/>
<Property key="Widget_AlignText" value="ALIGN_LEFT ALIGN_TOP"/>
</Widget>
<Widget type="MWSkill" skin="MW_StatNameButton" position="156 18 158 18" name="MajorSkill0" align="ALIGN_LEFT ALIGN_TOP" />
<Widget type="MWSkill" skin="MW_StatNameButton" position="156 36 158 18" name="MajorSkill1" align="ALIGN_LEFT ALIGN_TOP" />
<Widget type="MWSkill" skin="MW_StatNameButton" position="156 54 158 18" name="MajorSkill2" align="ALIGN_LEFT ALIGN_TOP" />
<Widget type="MWSkill" skin="MW_StatNameButton" position="156 72 158 18" name="MajorSkill3" align="ALIGN_LEFT ALIGN_TOP" />
<Widget type="MWSkill" skin="MW_StatNameButton" position="156 90 158 18" name="MajorSkill4" align="ALIGN_LEFT ALIGN_TOP" />
<!-- Minor Skills -->
<Widget type="StaticText" skin="HeaderText" position="314 0 140 18" name="MinorSkillT" align="ALIGN_LEFT ALIGN_TOP">
<Property key="Widget_Caption" value="Minor Skills:"/>
<Property key="Widget_AlignText" value="ALIGN_LEFT ALIGN_TOP"/>
</Widget>
<Widget type="MWSkill" skin="MW_StatNameButton" position="314 18 140 18" name="MinorSkill0" align="ALIGN_LEFT ALIGN_TOP" />
<Widget type="MWSkill" skin="MW_StatNameButton" position="314 36 140 18" name="MinorSkill1" align="ALIGN_LEFT ALIGN_TOP" />
<Widget type="MWSkill" skin="MW_StatNameButton" position="314 54 140 18" name="MinorSkill2" align="ALIGN_LEFT ALIGN_TOP" />
<Widget type="MWSkill" skin="MW_StatNameButton" position="314 72 140 18" name="MinorSkill3" align="ALIGN_LEFT ALIGN_TOP" />
<Widget type="MWSkill" skin="MW_StatNameButton" position="314 90 140 18" name="MinorSkill4" align="ALIGN_LEFT ALIGN_TOP" />
</Widget>
<!-- Dialog buttons -->
<Widget type="Button" skin="MW_Button" position="207 158 143 23" name="DescriptionButton">
<Property key="Widget_Caption" value="Class Description"/>
</Widget>
<Widget type="Button" skin="MW_Button" position="356 158 53 23" name="BackButton">
<Property key="Widget_Caption" value="Back"/>
</Widget>
<Widget type="Button" skin="MW_Button" position="417 158 42 23" name="OKButton">
<Property key="Widget_Caption" value="OK"/>
</Widget>
</Widget>
</Widget>
</MyGUI>

@ -0,0 +1,28 @@
<?xml version="1.0" encoding="UTF-8"?>
<MyGUI type="Layout">
<Widget type="Window" skin="MW_Dialog" layer="Windows" position="0 0 330 217" name="_Main">
<!-- Class image -->
<Widget type="Widget" skin="MW_Box" position="32 10 265 138" align="ALIGN_LEFT ALIGN_TOP">
<Widget type="StaticImage" skin="StaticImage" position="2 2 261 134" name="ClassImage" align="ALIGN_LEFT ALIGN_TOP" />
</Widget>
<!-- Class text -->
<Widget type="StaticText" skin="SandText" position="32 152 265 18" name="ReflectT" align="ALIGN_LEFT ALIGN_TOP">
<Property key="Widget_Caption" value="Your personality and past reflect a:"/>
<Property key="Widget_AlignText" value="ALIGN_TOP ALIGN_HCENTER"/>
</Widget>
<Widget type="StaticText" skin="SandText" position="32 170 265 18" name="ClassName" align="ALIGN_LEFT ALIGN_TOP">
<Property key="Widget_Caption" value="[Class]"/>
<Property key="Widget_AlignText" value="ALIGN_TOP ALIGN_HCENTER"/>
</Widget>
<!-- Dialog buttons -->
<Widget type="Button" skin="MW_Button" position="220 184 53 23" name="BackButton">
<Property key="Widget_Caption" value="Back"/>
</Widget>
<Widget type="Button" skin="MW_Button" position="277 184 42 23" name="OKButton">
<Property key="Widget_Caption" value="OK"/>
</Widget>
</Widget>
</MyGUI>

@ -0,0 +1,71 @@
<?xml version="1.0" encoding="UTF-8"?>
<MyGUI type="Layout">
<!-- correct size is 588 433, adjust when skin is changed to a dialog -->
<Widget type="Window" skin="MW_Window" layer="Windows" position="0 0 596 461" name="_Main">
<!-- Appearance -->
<Widget type="StaticText" skin="HeaderText" position="8 16 241 18" name="AppearanceT" align="ALIGN_LEFT ALIGN_TOP">
<Property key="Widget_Caption" value="Appearance"/>
<Property key="Widget_AlignText" value="ALIGN_LEFT ALIGN_TOP"/>
</Widget>
<Widget type="Canvas" skin="MW_Box" position="8 39 241 230" name="AppearanceBox"/>
<!-- Sliders -->
<!-- Rotation of head -->
<Widget type="HScroll" skin="MW_HScroll" position="8 276 241 14" name="HeadRotate"/>
<!-- Gender choice -->
<Widget type="Button" skin="MW_ScrollLeft" position="8 298 14 14" name="PrevGenderButton"/>
<Widget type="StaticText" skin="HeaderText" position="14 298 227 14" name="GenderChoiceT">
<Property key="Widget_Caption" value="Change Sex"/>
</Widget>
<Widget type="Button" skin="MW_ScrollRight" position="235 298 14 14" name="NextGenderButton"/>
<!-- Face choice -->
<Widget type="Button" skin="MW_ScrollLeft" position="8 320 14 14" name="PrevFaceButton"/>
<Widget type="StaticText" skin="HeaderText" position="14 320 227 14" name="FaceChoiceT">
<Property key="Widget_Caption" value="Change Face"/>
</Widget>
<Widget type="Button" skin="MW_ScrollRight" position="235 320 14 14" name="NextFaceButton"/>
<!-- Hair choice -->
<Widget type="Button" skin="MW_ScrollLeft" position="8 342 14 14" name="PrevHairButton"/>
<Widget type="StaticText" skin="HeaderText" position="14 342 227 14" name="HairChoiceT">
<Property key="Widget_Caption" value="Change Hair"/>
</Widget>
<Widget type="Button" skin="MW_ScrollRight" position="235 342 14 14" name="NextHairButton"/>
<!-- Race -->
<Widget type="StaticText" skin="HeaderText" position="261 16 132 18" name="RaceT" align="ALIGN_LEFT ALIGN_TOP">
<Property key="Widget_Caption" value="Race"/>
<Property key="Widget_AlignText" value="ALIGN_LEFT ALIGN_TOP"/>
</Widget>
<Widget type="List" skin="MW_List" position="264 39 132 161" name="RaceList">
</Widget>
<!-- Spell powers -->
<Widget type="StaticText" skin="HeaderText" position="261 200 132 18" name="SpellPowerT" align="ALIGN_LEFT ALIGN_TOP">
<Property key="Widget_Caption" value="Specials"/>
<Property key="Widget_AlignText" value="ALIGN_LEFT ALIGN_TOP"/>
</Widget>
<!-- Spell power sub-widgets will be placed here, no skin to make it invisible -->
<Widget type="Widget" skin="" position="261 220 132 140" name="SpellPowerList" />
<!-- Skill bonus -->
<Widget type="StaticText" skin="HeaderText" position="403 39 159 18" name="SkillsT" align="ALIGN_LEFT ALIGN_TOP">
<Property key="Widget_Caption" value="Skill Bonus"/>
<Property key="Widget_AlignText" value="ALIGN_LEFT ALIGN_TOP"/>
</Widget>
<!-- Skill bonus sub-widgets will be placed here, no skin to make it invisible -->
<Widget type="Widget" skin="" position="403 59 159 360" name="SkillList" />
<!-- Dialog buttons -->
<Widget type="Button" skin="MW_Button" position="471 397 53 23" name="BackButton">
<Property key="Widget_Caption" value="Back"/>
</Widget>
<Widget type="Button" skin="MW_Button" position="532 397 42 23" name="OKButton">
<Property key="Widget_Caption" value="OK"/>
</Widget>
</Widget>
</MyGUI>

@ -0,0 +1,29 @@
<?xml version="1.0" encoding="UTF-8"?>
<MyGUI type="Layout">
<Widget type="Window" skin="MW_Dialog" layer="Windows" position="0 0 217 234" name="_Main">
<Widget type="Widget" skin="" position="14 14 186 203" align="ALIGN_STRETCH">
<!-- Label -->
<Widget type="StaticText" skin="HeaderText" position="0 0 186 18" name="LabelT" align="ALIGN_LEFT ALIGN_TOP">
<Property key="Widget_Caption" value="Choose a Specialization"/>
<Property key="Widget_AlignText" value="ALIGN_LEFT ALIGN_TOP"/>
</Widget>
<!-- Attribute list -->
<Widget type="MWAttribute" skin="MW_StatNameButtonC" position="0 28 186 18" name="Attribute0" align="ALIGN_LEFT ALIGN_TOP" />
<Widget type="MWAttribute" skin="MW_StatNameButtonC" position="0 46 186 18" name="Attribute1" align="ALIGN_LEFT ALIGN_TOP" />
<Widget type="MWAttribute" skin="MW_StatNameButtonC" position="0 64 186 18" name="Attribute2" align="ALIGN_LEFT ALIGN_TOP" />
<Widget type="MWAttribute" skin="MW_StatNameButtonC" position="0 82 186 18" name="Attribute3" align="ALIGN_LEFT ALIGN_TOP" />
<Widget type="MWAttribute" skin="MW_StatNameButtonC" position="0 100 186 18" name="Attribute4" align="ALIGN_LEFT ALIGN_TOP" />
<Widget type="MWAttribute" skin="MW_StatNameButtonC" position="0 118 186 18" name="Attribute5" align="ALIGN_LEFT ALIGN_TOP" />
<Widget type="MWAttribute" skin="MW_StatNameButtonC" position="0 136 186 18" name="Attribute6" align="ALIGN_LEFT ALIGN_TOP" />
<Widget type="MWAttribute" skin="MW_StatNameButtonC" position="0 154 186 18" name="Attribute7" align="ALIGN_LEFT ALIGN_TOP" />
<!-- Dialog buttons -->
<Widget type="Button" skin="MW_Button" position="120 180 66 21" name="CancelButton">
<Property key="Widget_Caption" value="Cancel"/>
</Widget>
</Widget>
</Widget>
</MyGUI>

@ -0,0 +1,64 @@
<?xml version="1.0" encoding="UTF-8"?>
<MyGUI type="Layout">
<Widget type="Window" skin="MW_Dialog" layer="Windows" position="0 0 477 270" name="_Main">
<Widget type="Widget" skin="" position="17 14 447 239" align="ALIGN_STRETCH">
<!-- Label -->
<Widget type="StaticText" skin="HeaderText" position="0 0 447 18" name="LabelT" align="ALIGN_HCENTRE ALIGN_TOP">
<Property key="Widget_Caption" value="Choose a Skill"/>
<Property key="Widget_AlignText" value="ALIGN_HCENTRE ALIGN_TOP"/>
</Widget>
<!-- Combat list -->
<Widget type="StaticText" skin="HeaderText" position="0 32 154 18" name="CombatLabelT" align="ALIGN_LEFT ALIGN_TOP">
<Property key="Widget_Caption" value="Combat"/>
<Property key="Widget_AlignText" value="ALIGN_LEFT ALIGN_TOP"/>
</Widget>
<Widget type="MWSkill" skin="MW_StatNameButton" position="0 50 154 18" name="CombatSkill0" align="ALIGN_LEFT ALIGN_TOP" />
<Widget type="MWSkill" skin="MW_StatNameButton" position="0 68 154 18" name="CombatSkill1" align="ALIGN_LEFT ALIGN_TOP" />
<Widget type="MWSkill" skin="MW_StatNameButton" position="0 86 154 18" name="CombatSkill2" align="ALIGN_LEFT ALIGN_TOP" />
<Widget type="MWSkill" skin="MW_StatNameButton" position="0 104 154 18" name="CombatSkill3" align="ALIGN_LEFT ALIGN_TOP" />
<Widget type="MWSkill" skin="MW_StatNameButton" position="0 122 154 18" name="CombatSkill4" align="ALIGN_LEFT ALIGN_TOP" />
<Widget type="MWSkill" skin="MW_StatNameButton" position="0 140 154 18" name="CombatSkill5" align="ALIGN_LEFT ALIGN_TOP" />
<Widget type="MWSkill" skin="MW_StatNameButton" position="0 158 154 18" name="CombatSkill6" align="ALIGN_LEFT ALIGN_TOP" />
<Widget type="MWSkill" skin="MW_StatNameButton" position="0 176 154 18" name="CombatSkill7" align="ALIGN_LEFT ALIGN_TOP" />
<Widget type="MWSkill" skin="MW_StatNameButton" position="0 194 154 18" name="CombatSkill8" align="ALIGN_LEFT ALIGN_TOP" />
<!-- Magic list -->
<Widget type="StaticText" skin="HeaderText" position="158 32 154 18" name="MagicLabelT" align="ALIGN_LEFT ALIGN_TOP">
<Property key="Widget_Caption" value="Magic"/>
<Property key="Widget_AlignText" value="ALIGN_LEFT ALIGN_TOP"/>
</Widget>
<Widget type="MWSkill" skin="MW_StatNameButton" position="158 50 154 18" name="MagicSkill0" align="ALIGN_LEFT ALIGN_TOP" />
<Widget type="MWSkill" skin="MW_StatNameButton" position="158 68 154 18" name="MagicSkill1" align="ALIGN_LEFT ALIGN_TOP" />
<Widget type="MWSkill" skin="MW_StatNameButton" position="158 86 154 18" name="MagicSkill2" align="ALIGN_LEFT ALIGN_TOP" />
<Widget type="MWSkill" skin="MW_StatNameButton" position="158 104 154 18" name="MagicSkill3" align="ALIGN_LEFT ALIGN_TOP" />
<Widget type="MWSkill" skin="MW_StatNameButton" position="158 122 154 18" name="MagicSkill4" align="ALIGN_LEFT ALIGN_TOP" />
<Widget type="MWSkill" skin="MW_StatNameButton" position="158 140 154 18" name="MagicSkill5" align="ALIGN_LEFT ALIGN_TOP" />
<Widget type="MWSkill" skin="MW_StatNameButton" position="158 158 154 18" name="MagicSkill6" align="ALIGN_LEFT ALIGN_TOP" />
<Widget type="MWSkill" skin="MW_StatNameButton" position="158 176 154 18" name="MagicSkill7" align="ALIGN_LEFT ALIGN_TOP" />
<Widget type="MWSkill" skin="MW_StatNameButton" position="158 194 154 18" name="MagicSkill8" align="ALIGN_LEFT ALIGN_TOP" />
<!-- Stealth list -->
<Widget type="StaticText" skin="HeaderText" position="316 32 131 18" name="StealthLabelT" align="ALIGN_LEFT ALIGN_TOP">
<Property key="Widget_Caption" value="Stealth"/>
<Property key="Widget_AlignText" value="ALIGN_LEFT ALIGN_TOP"/>
</Widget>
<Widget type="MWSkill" skin="MW_StatNameButton" position="316 50 131 18" name="StealthSkill0" align="ALIGN_LEFT ALIGN_TOP" />
<Widget type="MWSkill" skin="MW_StatNameButton" position="316 68 131 18" name="StealthSkill1" align="ALIGN_LEFT ALIGN_TOP" />
<Widget type="MWSkill" skin="MW_StatNameButton" position="316 86 131 18" name="StealthSkill2" align="ALIGN_LEFT ALIGN_TOP" />
<Widget type="MWSkill" skin="MW_StatNameButton" position="316 104 131 18" name="StealthSkill3" align="ALIGN_LEFT ALIGN_TOP" />
<Widget type="MWSkill" skin="MW_StatNameButton" position="316 122 131 18" name="StealthSkill4" align="ALIGN_LEFT ALIGN_TOP" />
<Widget type="MWSkill" skin="MW_StatNameButton" position="316 140 131 18" name="StealthSkill5" align="ALIGN_LEFT ALIGN_TOP" />
<Widget type="MWSkill" skin="MW_StatNameButton" position="316 158 131 18" name="StealthSkill6" align="ALIGN_LEFT ALIGN_TOP" />
<Widget type="MWSkill" skin="MW_StatNameButton" position="316 176 131 18" name="StealthSkill7" align="ALIGN_LEFT ALIGN_TOP" />
<Widget type="MWSkill" skin="MW_StatNameButton" position="316 194 131 18" name="StealthSkill8" align="ALIGN_LEFT ALIGN_TOP" />
<!-- Dialog buttons -->
<Widget type="Button" skin="MW_Button" position="381 218 66 21" name="CancelButton">
<Property key="Widget_Caption" value="Cancel"/>
</Widget>
</Widget>
</Widget>
</MyGUI>

@ -0,0 +1,31 @@
<?xml version="1.0" encoding="UTF-8"?>
<MyGUI type="Layout">
<!-- correct size is 247 144, adjust when skin is changed to a dialog -->
<Widget type="Window" skin="MW_Dialog" layer="Windows" position="0 0 247 144" name="_Main">
<Widget type="Widget" skin="" position="14 14 216 113" align="ALIGN_STRETCH">
<!-- Label -->
<Widget type="StaticText" skin="HeaderText" position="0 0 216 18" name="LabelT" align="ALIGN_LEFT ALIGN_TOP">
<Property key="Widget_Caption" value="Choose a Specialization"/>
<Property key="Widget_AlignText" value="ALIGN_LEFT ALIGN_TOP"/>
</Widget>
<!-- Specialization list -->
<Widget type="StaticText" skin="SandText" position="0 28 216 18" name="Specialization0" align="ALIGN_LEFT ALIGN_TOP">
<Property key="Widget_AlignText" value="ALIGN_TOP ALIGN_HCENTRE"/>
</Widget>
<Widget type="StaticText" skin="SandText" position="0 46 216 18" name="Specialization1" align="ALIGN_LEFT ALIGN_TOP">
<Property key="Widget_AlignText" value="ALIGN_TOP ALIGN_HCENTRE"/>
</Widget>
<Widget type="StaticText" skin="SandText" position="0 64 216 18" name="Specialization2" align="ALIGN_LEFT ALIGN_TOP">
<Property key="Widget_AlignText" value="ALIGN_TOP ALIGN_HCENTRE"/>
</Widget>
<!-- Dialog buttons -->
<Widget type="Button" skin="MW_Button" position="150 90 66 21" name="CancelButton">
<Property key="Widget_Caption" value="Cancel"/>
</Widget>
</Widget>
</Widget>
</MyGUI>

@ -0,0 +1,57 @@
<?xml version="1.0" encoding="UTF-8"?>
<MyGUI type="Skin">
<!-- Text edit widget -->
<Skin name = "MW_TextEditClient" size = "10 10">
<Property key="FontName" value = "MyGUI_CoreFont.18"/>
<Property key="FontHeight" value = "18" />
<Property key="AlignText" value = "ALIGN_LEFT ALIGN_VCENTER" />
<Property key="Colour" value = "0.6 0.6 0.6" />
<BasisSkin type="EditText" offset = "0 0 10 10" align = "Stretch"/>
</Skin>
<Skin name = "MW_TextBoxEditClient" size = "10 10">
<Property key="FontName" value = "MyGUI_CoreFont.18"/>
<Property key="FontHeight" value = "18" />
<Property key="AlignText" value = "ALIGN_LEFT ALIGN_TOP" />
<Property key="Colour" value = "0.6 0.6 0.6" />
<BasisSkin type="EditText" offset = "0 0 10 10" align = "Stretch"/>
</Skin>
<Skin name = "MW_TextEdit" size = "512 20" texture="mwgui.png">
<BasisSkin type="SubSkin" offset = "0 0 512 2" align = "ALIGN_TOP ALIGN_HSTRETCH">
<State name="normal" offset = "2 2 512 2"/>
</BasisSkin>
<BasisSkin type="SubSkin" offset = "0 2 2 16" align = "ALIGN_LEFT ALIGN_VSTRETCH">
<State name="normal" offset = "2 4 2 16"/>
</BasisSkin>
<BasisSkin type="SubSkin" offset = "510 2 2 16" align = "ALIGN_RIGHT ALIGN_VSTRETCH">
<State name="normal" offset = "512 4 2 16"/>
</BasisSkin>
<BasisSkin type="SubSkin" offset = "0 18 512 2" align = "ALIGN_BOTTOM ALIGN_HSTRETCH">
<State name="normal" offset = "2 20 512 2"/>
</BasisSkin>
<Child type="Widget" skin="MW_TextEditClient" offset = "2 2 508 18" align = "Stretch" name = "Client"/>
</Skin>
<Skin name = "MW_TextBoxEdit" size = "512 20" texture="mwgui.png">
<BasisSkin type="SubSkin" offset = "0 0 512 2" align = "ALIGN_TOP ALIGN_HSTRETCH">
<State name="normal" offset = "2 2 512 2"/>
</BasisSkin>
<BasisSkin type="SubSkin" offset = "0 2 2 16" align = "ALIGN_LEFT ALIGN_VSTRETCH">
<State name="normal" offset = "2 4 2 16"/>
</BasisSkin>
<BasisSkin type="SubSkin" offset = "510 2 2 16" align = "ALIGN_RIGHT ALIGN_VSTRETCH">
<State name="normal" offset = "512 4 2 16"/>
</BasisSkin>
<BasisSkin type="SubSkin" offset = "0 18 512 2" align = "ALIGN_BOTTOM ALIGN_HSTRETCH">
<State name="normal" offset = "2 20 512 2"/>
</BasisSkin>
<Child type="Widget" skin="MW_TextBoxEditClient" offset = "2 2 490 18" align = "Stretch" name = "Client"/>
<Child type="VScroll" skin="MW_VScroll" offset = "494 3 14 14" align = "Right VStretch" name = "VScroll"/>
</Skin>
</MyGUI>

@ -0,0 +1,16 @@
<?xml version="1.0" encoding="UTF-8"?>
<MyGUI type="Layout">
<Widget type="Window" skin="MW_Dialog" layer="Windows" position="0 0 545 265" name="_Main">
<!-- Edit box -->
<Widget type="Widget" skin="MW_Box" position="14 14 516 70" name="TextBox" align="ALIGN_TOP ALIGN_HCENTER">
<Widget type="StaticText" skin="SandText" position="4 4 508 62" name="Text" align="ALIGN_TOP ALIGN_HCENTER">
<Property key="Edit_WordWrap" value="1" />
</Widget>
</Widget>
<!-- Button bar, buttons are created as children -->
<Widget type="Widget" skin="" position="72 98 400 150" name="ButtonBar" align="ALIGN_TOP ALIGN_HCENTER" />
</Widget>
</MyGUI>

@ -0,0 +1,29 @@
<?xml version="1.0" encoding="UTF-8"?>
<MyGUI type="Layout">
<Widget type="Window" skin="MW_Window" layer="Windows" position="0 0 600 300" name="_Main">
<!-- Player enumbrance -->
<Widget type="Progress" skin="MW_Progress_Blue" position="8 8 212 18" name="EncumbranceBar">
<Widget type="StaticText" skin="ProgressText" position="0 0 212 18" align="Center" name="EncumbranceBarT"/>
</Widget>
<!-- Avatar -->
<Widget type="Widget" skin="MW_Box" position="8 32 212 166" name="Avatar">
<Widget type="StaticText" skin="ProgressText" position="0 -8 212 18" align="HCenter Bottom" name="ArmorRating"/>
</Widget>
<!-- Items in inventory -->
<Widget type="Widget" skin="MW_Box" position="228 32 300 166" name="Items"/>
<!-- Categories -->
<Widget type="Widget" position="228 8 300 18" align="ALIGN_TOP ALIGN_LEFT" name="Categories">
<Widget type="Button" skin="MW_Button" position="0 0 30 18" name="AllButton"/>
<Widget type="Button" skin="MW_Button" position="134 0 60 18" name="WeaponButton"/>
<Widget type="Button" skin="MW_Button" position="98 0 60 18" name="ApparelButton"/>
<Widget type="Button" skin="MW_Button" position="160 0 50 18" name="MagicButton"/>
<Widget type="Button" skin="MW_Button" position="214 0 45 18" name="MiscButton"/>
</Widget>
</Widget>
</MyGUI>

@ -0,0 +1,256 @@
<?xml version="1.0" encoding="UTF-8"?>
<MyGUI type="Skin">
<!-- scroll tracker -->
<Skin name = "MW_ScrollTrack" size = "16 20" texture="mwgui.png">
<BasisSkin type="SubSkin" offset = "0 0 16 2" align = "ALIGN_TOP ALIGN_HSTRETCH">
<State name="normal" offset = "38 24 16 2"/>
</BasisSkin>
<BasisSkin type="SubSkin" offset = "0 2 16 16" align = "ALIGN_STRETCH">
<State name="normal" offset = "38 26 16 16"/>
</BasisSkin>
<BasisSkin type="SubSkin" offset = "0 18 16 2" align = "ALIGN_BOTTOM ALIGN_HSTRETCH">
<State name="normal" offset = "38 42 16 2"/>
</BasisSkin>
</Skin>
<Skin name = "MW_ScrollUp" size = "16 20" texture="mwgui.png">
<!-- border -->
<BasisSkin type="SubSkin" offset = "0 0 16 2" align = "ALIGN_TOP ALIGN_HSTRETCH">
<State name="normal" offset = "20 24 16 2"/>
</BasisSkin>
<BasisSkin type="SubSkin" offset = "0 2 2 16" align = "ALIGN_LEFT ALIGN_VSTRETCH">
<State name="normal" offset = "20 26 2 16"/>
</BasisSkin>
<BasisSkin type="SubSkin" offset = "14 2 2 16" align = "ALIGN_RIGHT ALIGN_VSTRETCH">
<State name="normal" offset = "34 26 2 16"/>
</BasisSkin>
<BasisSkin type="SubSkin" offset = "0 18 16 2" align = "ALIGN_BOTTOM ALIGN_HSTRETCH">
<State name="normal" offset = "20 42 16 2"/>
</BasisSkin>
<!-- arrow -->
<BasisSkin type="SubSkin" offset = "2 2 12 16" align = "ALIGN_STRETCH">
<State name="normal" offset = "56 24 8 8"/>
</BasisSkin>
</Skin>
<Skin name = "MW_ScrollDown" size = "16 20" texture="mwgui.png">
<!-- border -->
<BasisSkin type="SubSkin" offset = "0 0 16 2" align = "ALIGN_TOP ALIGN_HSTRETCH">
<State name="normal" offset = "20 24 16 2"/>
</BasisSkin>
<BasisSkin type="SubSkin" offset = "0 2 2 16" align = "ALIGN_LEFT ALIGN_VSTRETCH">
<State name="normal" offset = "20 26 2 16"/>
</BasisSkin>
<BasisSkin type="SubSkin" offset = "14 2 2 16" align = "ALIGN_RIGHT ALIGN_VSTRETCH">
<State name="normal" offset = "34 26 2 16"/>
</BasisSkin>
<BasisSkin type="SubSkin" offset = "0 18 16 2" align = "ALIGN_BOTTOM ALIGN_HSTRETCH">
<State name="normal" offset = "20 42 16 2"/>
</BasisSkin>
<!-- arrow -->
<BasisSkin type="SubSkin" offset = "2 2 12 16" align = "ALIGN_STRETCH">
<State name="normal" offset = "56 44 8 8"/>
</BasisSkin>
</Skin>
<Skin name = "MW_ScrollLeft" size = "16 20" texture="mwgui.png">
<!-- border -->
<BasisSkin type="SubSkin" offset = "0 0 16 2" align = "ALIGN_TOP ALIGN_HSTRETCH">
<State name="normal" offset = "20 24 16 2"/>
</BasisSkin>
<BasisSkin type="SubSkin" offset = "0 2 2 16" align = "ALIGN_LEFT ALIGN_VSTRETCH">
<State name="normal" offset = "20 26 2 16"/>
</BasisSkin>
<BasisSkin type="SubSkin" offset = "14 2 2 16" align = "ALIGN_RIGHT ALIGN_VSTRETCH">
<State name="normal" offset = "34 26 2 16"/>
</BasisSkin>
<BasisSkin type="SubSkin" offset = "0 18 16 2" align = "ALIGN_BOTTOM ALIGN_HSTRETCH">
<State name="normal" offset = "20 42 16 2"/>
</BasisSkin>
<!-- arrow -->
<BasisSkin type="SubSkin" offset = "2 2 12 16" align = "ALIGN_STRETCH">
<State name="normal" offset = "56 54 8 8"/>
</BasisSkin>
</Skin>
<Skin name = "MW_ScrollRight" size = "16 20" texture="mwgui.png">
<!-- border -->
<BasisSkin type="SubSkin" offset = "0 0 16 2" align = "ALIGN_TOP ALIGN_HSTRETCH">
<State name="normal" offset = "20 24 16 2"/>
</BasisSkin>
<BasisSkin type="SubSkin" offset = "0 2 2 16" align = "ALIGN_LEFT ALIGN_VSTRETCH">
<State name="normal" offset = "20 26 2 16"/>
</BasisSkin>
<BasisSkin type="SubSkin" offset = "14 2 2 16" align = "ALIGN_RIGHT ALIGN_VSTRETCH">
<State name="normal" offset = "34 26 2 16"/>
</BasisSkin>
<BasisSkin type="SubSkin" offset = "0 18 16 2" align = "ALIGN_BOTTOM ALIGN_HSTRETCH">
<State name="normal" offset = "20 42 16 2"/>
</BasisSkin>
<!-- arrow -->
<BasisSkin type="SubSkin" offset = "2 2 12 16" align = "ALIGN_STRETCH">
<State name="normal" offset = "56 34 8 8"/>
</BasisSkin>
</Skin>
<Skin name = "MW_HScrollBackground" size = "512 20" texture="mwgui.png">
<BasisSkin type="SubSkin" offset = "0 0 512 2" align = "ALIGN_TOP ALIGN_HSTRETCH">
<State name="normal" offset = "2 2 512 2"/>
</BasisSkin>
<BasisSkin type="SubSkin" offset = "0 2 2 16" align = "ALIGN_LEFT ALIGN_VSTRETCH">
<State name="normal" offset = "2 4 2 16"/>
</BasisSkin>
<BasisSkin type="SubSkin" offset = "510 2 2 16" align = "ALIGN_RIGHT ALIGN_VSTRETCH">
<State name="normal" offset = "512 4 2 16"/>
</BasisSkin>
<BasisSkin type="SubSkin" offset = "0 18 512 2" align = "ALIGN_BOTTOM ALIGN_HSTRETCH">
<State name="normal" offset = "2 20 512 2"/>
</BasisSkin>
</Skin>
<Skin name = "MW_VScrollBackground" size = "16 512" texture="mwgui.png">
<BasisSkin type="SubSkin" offset = "0 0 16 2" align = "ALIGN_TOP ALIGN_HSTRETCH">
<State name="normal" offset = "2 24 16 2"/>
</BasisSkin>
<BasisSkin type="SubSkin" offset = "0 2 2 512" align = "ALIGN_LEFT ALIGN_VSTRETCH">
<State name="normal" offset = "2 26 2 512"/>
</BasisSkin>
<BasisSkin type="SubSkin" offset = "14 2 2 512" align = "ALIGN_RIGHT ALIGN_VSTRETCH">
<State name="normal" offset = "16 26 2 512"/>
</BasisSkin>
<BasisSkin type="SubSkin" offset = "0 512 16 2" align = "ALIGN_BOTTOM ALIGN_HSTRETCH">
<State name="normal" offset = "2 538 16 2"/>
</BasisSkin>
</Skin>
<Skin name = "MW_ScrollEmptyPart" size = "16 16" >
</Skin>
<!-- Morrowind has a 1 pixel gap between the left arrow and the inner bar, this skin does not replicate that -->
<Skin name = "MW_HScroll" size = "90 14">
<Property key="TrackRangeMargins" value = "14 14" />
<Property key="MinTrackSize" value = "14" />
<!-- Background widget trick that must go first to be placed behind Track and FirstPart/SecondPart widgets, provides the bar texture -->
<Child type="Button" skin="MW_HScrollBackground" offset = "14 0 62 14" align = "ALIGN_STRETCH" name = "Background"/>
<Child type="Button" skin="MW_ScrollLeft" offset = "0 0 14 14" align = "ALIGN_LEFT ALIGN_VSTRETCH" name = "Start"/>
<Child type="Button" skin="MW_ScrollRight" offset = "76 0 14 14" align = "ALIGN_RIGHT ALIGN_VSTRETCH" name = "End"/>
<!-- These are only provided to get mouse input, they should have no skin and be transparent -->
<Child type="Button" skin="MW_ScrollEmptyPart" offset = "14 0 24 14" align = "ALIGN_TOP ALIGN_HSTRETCH" name = "FirstPart"/>
<Child type="Button" skin="MW_ScrollEmptyPart" offset = "52 0 24 14" align = "ALIGN_TOP ALIGN_HSTRETCH" name = "SecondPart"/>
<!-- Tracker must be last to be on top and receive mouse events -->
<Child type="Button" skin="MW_ScrollTrack" offset = "38 0 14 14" align = "ALIGN_TOP ALIGN_VSTRETCH" name = "Track"/>
</Skin>
<!-- Morrowind has a 1 pixel gap between the top arrow and the inner bar, this skin does not replicate that -->
<Skin name = "MW_VScroll" size = "14 90">
<Property key="TrackRangeMargins" value = "14 14" />
<Property key="MinTrackSize" value = "14" />
<!-- Background widget trick that must go first to be placed behind Track and FirstPart/SecondPart widgets, provides the bar texture -->
<Child type="Button" skin="MW_VScrollBackground" offset = "0 14 14 62" align = "ALIGN_STRETCH" name = "Background"/>
<Child type="Button" skin="MW_ScrollUp" offset = "0 0 14 14" align = "ALIGN_TOP ALIGN_HSTRETCH" name = "Start"/>
<Child type="Button" skin="MW_ScrollDown" offset = "0 76 14 14" align = "ALIGN_BOTTOM ALIGN_HSTRETCH" name = "End"/>
<!-- These are only provided to get mouse input, they should have no skin and be transparent -->
<Child type="Button" skin="MW_ScrollEmptyPart" offset = "0 14 24 14" align = "ALIGN_LEFT ALIGN_VSTRETCH" name = "FirstPart"/>
<Child type="Button" skin="MW_ScrollEmptyPart" offset = "0 52 24 14" align = "ALIGN_LEFT ALIGN_VSTRETCH" name = "SecondPart"/>
<!-- Tracker must be last to be on top and receive mouse events -->
<Child type="Button" skin="MW_ScrollTrack" offset = "0 38 14 14" align = "ALIGN_TOP ALIGN_HSTRETCH" name = "Track"/>
</Skin>
<Skin name = "HeaderText" size = "16 16">
<Property key="FontName" value = "MyGUI_CoreFont.18"/>
<Property key="FontHeight" value = "18" />
<Property key="AlignText" value = "ALIGN_CENTER" />
<Property key="Colour" value = "0.82 0.74 0.58" />
<BasisSkin type="SimpleText" offset = "0 0 16 16" align = "ALIGN_STRETCH"/>
</Skin>
<!-- list and multilist skins -->
<Skin name = "MW_ListLine" size = "5 5" texture="mwgui.png">
<Property key="FontName" value = "MyGUI_CoreFont.18" />
<Property key="FontHeight" value = "18" />
<Property key="AlignText" value = "ALIGN_LEFT ALIGN_VCENTER" />
<Property key="Colour" value = "0.70 0.57 0.33" />
<BasisSkin type="SimpleText" offset = "2 0 1 5" align = "ALIGN_STRETCH">
<State name="normal" colour = "0.70 0.57 0.33"/>
<State name="active" colour = "0.70 0.57 0.33"/>
<State name="pressed" colour = "0.33 0.38 0.67"/>
<State name="select" colour = "0.33 0.38 0.67"/>
</BasisSkin>
</Skin>
<Skin name = "MW_List" size = "516 516" align = "ALIGN_LEFT ALIGN_TOP" texture="mwgui.png">
<Property key="NeedKey" value = "true" />
<Property key="SkinLine" value = "MW_ListLine" />
<Property key="HeightLine" value = "20" />
<Child type="VScroll" skin="MW_VScroll" offset = "498 3 14 509" align = "ALIGN_RIGHT ALIGN_VSTRETCH" name = "VScroll">
</Child>
<Child type="Widget" skin="DefaultClient" offset = "3 3 493 509" align = "ALIGN_STRETCH" name = "Client">
</Child>
<Child type="Widget" skin="IB_T" offset="2 0 512 2" align="ALIGN_TOP ALIGN_HSTRETCH"/>
<Child type="Widget" skin="IB_B" offset="2 514 512 2" align="ALIGN_BOTTOM ALIGN_HSTRETCH"/>
<Child type="Widget" skin="IB_L" offset="0 2 2 512" align="ALIGN_LEFT ALIGN_VSTRETCH"/>
<Child type="Widget" skin="IB_R" offset="514 2 2 512" align="ALIGN_RIGHT ALIGN_VSTRETCH"/>
<Child type="Widget" skin="IB_TL" offset="0 0 2 2" align="ALIGN_TOP ALIGN_LEFT"/>
<Child type="Widget" skin="IB_TR" offset="514 0 2 2" align="ALIGN_TOP ALIGN_RIGHT"/>
<Child type="Widget" skin="IB_BL" offset="0 514 2 2" align="ALIGN_BOTTOM ALIGN_LEFT"/>
<Child type="Widget" skin="IB_BR" offset="514 514 2 2" align="ALIGN_BOTTOM ALIGN_RIGHT"/>
</Skin>
<Skin name = "MW_MultiSubList" size = "516 516" align = "ALIGN_LEFT ALIGN_TOP">
<Property key="NeedKey" value = "true" />
<Property key="SkinLine" value = "MW_ListLine" />
<Property key="HeightLine" value = "20" />
<Child type="VScroll" skin="VScroll" offset = "498 3 14 509" align = "ALIGN_RIGHT ALIGN_VSTRETCH" name = "VScroll">
</Child>
<Child type="Widget" skin="Default" offset = "3 3 493 509" align = "ALIGN_STRETCH" name = "Client">
</Child>
<_BasisSkin type="MainSkin" offset = "0 0 0 0" align = "ALIGN_LEFT ALIGN_TOP"/>
</Skin>
<Skin name = "MW_MultiList" size = "516 516" align = "ALIGN_LEFT ALIGN_TOP">
<Property key="NeedKey" value = "true" />
<Property key="SkinButton" value = "ButtonSmall" />
<Property key="_SkinButtonEmpty" value = "Edit" />
<Property key="HeightButton" value = "20" />
<Property key="SkinList" value = "MW_MultiSubList" />
<Child type="Widget" skin="DefaultClient" offset = "3 3 516 516" align = "ALIGN_STRETCH" name = "Client">
</Child>
<Child type="Widget" skin="IB_T" offset="2 0 512 2" align="ALIGN_TOP ALIGN_HSTRETCH"/>
<Child type="Widget" skin="IB_B" offset="2 514 512 2" align="ALIGN_BOTTOM ALIGN_HSTRETCH"/>
<Child type="Widget" skin="IB_L" offset="0 2 2 512" align="ALIGN_LEFT ALIGN_VSTRETCH"/>
<Child type="Widget" skin="IB_R" offset="514 2 2 512" align="ALIGN_RIGHT ALIGN_VSTRETCH"/>
<Child type="Widget" skin="IB_TL" offset="0 0 2 2" align="ALIGN_TOP ALIGN_LEFT"/>
<Child type="Widget" skin="IB_TR" offset="514 0 2 2" align="ALIGN_TOP ALIGN_RIGHT"/>
<Child type="Widget" skin="IB_BL" offset="0 514 2 2" align="ALIGN_BOTTOM ALIGN_LEFT"/>
<Child type="Widget" skin="IB_BR" offset="514 514 2 2" align="ALIGN_BOTTOM ALIGN_RIGHT"/>
</Skin>
<!-- textures/menu_thin_border_top.dds -->
<Skin name = "MW_HLine" size = "512 18" texture="mwgui.png">
<BasisSkin type="SubSkin" offset = "0 8 512 2" align = "ALIGN_TOP ALIGN_HSTRETCH">
<State name="normal" offset = "20 106 512 2"/>
</BasisSkin>
</Skin>
</MyGUI>

@ -52,7 +52,10 @@
<Widget type="StaticText" skin="SandTextRight" position="104 130 104 18" name="AttribVal8"/>
</Widget>
<Widget type="Widget" skin="MW_Box" position="228 8 248 292" align="ALIGN_LEFT ALIGN_VSTRETCH">
<!-- Player skills, factions, birthsign and reputation -->
<Widget type="Widget" skin="MW_Box" position="228 8 248 292" align="ALIGN_LEFT ALIGN_VSTRETCH" name="Skills">
<Widget type="Widget" skin="" position="4 4 222 284" align="ALIGN_STRETCH" name="SkillClient" />
<Widget type="VScroll" skin="MW_VScroll" position="230 4 14 284" align="ALIGN_RIGHT ALIGN_VSTRETCH" name="SkillScroller" />
</Widget>
</Widget>
</MyGUI>

@ -17,11 +17,31 @@
<BasisSkin type="SimpleText" offset = "0 0 16 16" align = "ALIGN_STRETCH"/>
</Skin>
<Skin name = "SandTextC" size = "16 16">
<Property key="FontName" value = "MyGUI_CoreFont.18" />
<Property key="FontHeight" value = "18" />
<Property key="AlignText" value = "TOP HCENTER" />
<Property key="Colour" value = "0.75 0.6 0.35" />
<BasisSkin type="SimpleText" offset = "0 0 16 16" align = "ALIGN_STRETCH"/>
</Skin>
<Skin name = "SandTextRight" size = "16 16">
<Property key="FontName" value = "MyGUI_CoreFont.18" />
<Property key="FontHeight" value = "18" />
<Property key="AlignText" value = "ALIGN_RIGHT ALIGN_BOTTOM" />
<Property key="Colour" value = "0.75 0.6 0.35" />
<BasisSkin type="SimpleText" offset = "0 0 16 16" align = "ALIGN_STRETCH">
<State name="normal" colour = "0.75 0.6 0.35"/>
<State name="increased" colour = "0.757 0.679 0.539"/>
<State name="decreased" colour = "0.785 0.363 0.308"/>
</BasisSkin>
</Skin>
<Skin name = "SandBrightText" size = "16 16">
<Property key="FontName" value = "MyGUI_CoreFont.18" />
<Property key="FontHeight" value = "18" />
<Property key="AlignText" value = "ALIGN_LEFT ALIGN_BOTTOM" />
<Property key="Colour" value = "0.85 0.76 0.60" />
<BasisSkin type="SimpleText" offset = "0 0 16 16" align = "ALIGN_STRETCH"/>
</Skin>
@ -40,4 +60,35 @@
<Property key="Colour" value = "1 1 1" />
<BasisSkin type="SimpleText" offset = "0 0 16 16" align = "ALIGN_STRETCH"/>
</Skin>
<Skin name = "MW_StatName" size = "200 18">
<Child type="StaticText" skin="SandText" offset = "0 0 200 18" align = "ALIGN_LEFT ALIGN_HSTRETCH" name = "StatName" />
</Skin>
<Skin name = "MW_StatNameC" size = "200 18">
<Child type="StaticTextC" skin="SandText" offset = "0 0 200 18" align = "LEFT HSTRETCH" name = "StatName" />
</Skin>
<Skin name = "MW_StatNameValue" size = "200 18">
<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_StatNameButtonC" size = "200 18">
<Child type="Button" skin="SandTextC" offset = "0 0 200 18" align = "LEFT HSTRETCH" name = "StatNameButton" />
</Skin>
<Skin name = "MW_StatNameButton" size = "200 18">
<Child type="Button" skin="SandText" offset = "0 0 200 18" align = "ALIGN_LEFT ALIGN_HSTRETCH" name = "StatNameButton" />
</Skin>
<Skin name = "MW_StatNameValueButton" size = "200 18">
<Child type="Button" skin="SandText" offset = "0 0 160 18" align = "ALIGN_LEFT ALIGN_HSTRETCH" name = "StatNameButton" />
<Child type="Button" skin="SandTextRight" offset = "160 0 40 18" align = "ALIGN_RIGHT ALIGN_TOP" name = "StatValueButton" />
</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>

@ -0,0 +1,18 @@
<?xml version="1.0" encoding="UTF-8"?>
<MyGUI type="Layout">
<!-- correct size is 320 97, adjust when skin is changed to a dialog -->
<Widget type="Window" skin="MW_Window" layer="Windows" position="0 0 328 127" name="_Main">
<!-- Appearance -->
<Widget type="StaticText" skin="ProgressText" position="10 12 300 18" name="LabelT" align="ALIGN_LEFT ALIGN_TOP">
<Property key="Widget_AlignText" value="ALIGN_LEFT ALIGN_TOP"/>
</Widget>
<Widget type="Edit" skin="MW_TextEdit" position="10 28 300 30" name="TextEdit" align="ALIGN_LEFT ALIGN_TOP"/>
<!-- Dialog buttons -->
<Widget type="Button" skin="MW_Button" position="264 60 42 23" name="OKButton">
<Property key="Widget_Caption" value="OK"/>
</Widget>
</Widget>
</MyGUI>

@ -1,13 +1,68 @@
<?xml version="1.0" encoding="UTF-8"?>
<MyGUI type="Skin">
<!-- Defines a pure black background -->
<!-- Defines a transparent background -->
<Skin name = "BlackBG" size = "8 8" texture = "transparent.png">
<BasisSkin type="MainSkin" offset = "0 0 8 8">
<State name="normal" offset = "0 0 8 8"/>
</BasisSkin>
</Skin>
<!-- Defines a pure black background -->
<Skin name = "DialogBG" size = "8 8" texture = "black.png">
<BasisSkin type="MainSkin" offset = "0 0 8 8">
<State name="normal" offset = "0 0 8 8"/>
</BasisSkin>
</Skin>
<!-- These define the dialog borders -->
<Skin name="DB_B" size="512 4" texture="textures\menu_thick_border_bottom.dds">
<BasisSkin type="MainSkin" offset = "0 0 512 4">
<State name="normal" offset = "0 0 512 4"/>
</BasisSkin>
</Skin>
<Skin name="DB_R" size="4 512" texture="textures\menu_thick_border_right.dds">
<BasisSkin type="MainSkin" offset = "0 0 4 512">
<State name="normal" offset = "0 0 4 512"/>
</BasisSkin>
</Skin>
<Skin name="DB_T" size="512 4" texture="textures\menu_thick_border_top.dds">
<BasisSkin type="MainSkin" offset = "0 0 512 4">
<State name="normal" offset = "0 0 512 4"/>
</BasisSkin>
</Skin>
<Skin name="DB_L" size="4 512" texture="textures\menu_thick_border_left.dds">
<BasisSkin type="MainSkin" offset = "0 0 4 512">
<State name="normal" offset = "0 0 4 512"/>
</BasisSkin>
</Skin>
<!-- Dialog border corners -->
<Skin name="DB_BR" size="4 4" texture="textures\menu_thick_border_bottom_right_corner.dds">
<BasisSkin type="MainSkin" offset = "0 0 4 4">
<State name="normal" offset = "0 0 4 4"/>
</BasisSkin>
</Skin>
<Skin name="DB_BL" size="4 4" texture="textures\menu_thick_border_bottom_left_corner.dds">
<Property key="Pointer" value = "dresize2" />
<BasisSkin type="MainSkin" offset = "0 0 4 4">
<State name="normal" offset = "0 0 4 4"/>
</BasisSkin>
</Skin>
<Skin name="DB_TR" size="4 4" texture="textures\menu_thick_border_top_right_corner.dds">
<BasisSkin type="MainSkin" offset = "0 0 4 4">
<State name="normal" offset = "0 0 4 4"/>
</BasisSkin>
</Skin>
<Skin name="DB_TL" size="4 4" texture="textures\menu_thick_border_top_left_corner.dds">
<BasisSkin type="MainSkin" offset = "0 0 4 4">
<State name="normal" offset = "0 0 4 4"/>
</BasisSkin>
</Skin>
<!-- These define the window borders -->
<Skin name="TB_B" size="512 4" texture="textures\menu_thick_border_bottom.dds">
<Property key="Pointer" value = "vresize" />
@ -241,4 +296,40 @@
<Property key="Scale" value = "1 1 0 0"/>
</Child>
</Skin>
<Skin name = "MW_Dialog" size = "256 54">
<Property key="FontName" value = "MyGUI_CoreFont.18" />
<Property key="FontHeight" value = "18" />
<Property key="AlignText" value = "ALIGN_CENTER" />
<Property key="Colour" value = "0.8 0.8 0.8" />
<Child type="Widget" skin="DialogBG" offset = "4 4 248 46" align = "ALIGN_STRETCH" name = "Client"/>
<!-- Outer borders -->
<Child type="Widget" skin="DB_T" offset="4 0 248 4" align="ALIGN_TOP ALIGN_HSTRETCH" name="Border">
<Property key="Scale" value = "0 1 0 -1"/>
</Child>
<Child type="Widget" skin="DB_L" offset="0 4 4 46" align="ALIGN_LEFT ALIGN_VSTRETCH" name="Border">
<Property key="Scale" value = "1 0 -1 0"/>
</Child>
<Child type="Widget" skin="DB_B" offset="4 50 248 4" align="ALIGN_BOTTOM ALIGN_HSTRETCH" name="Border">
<Property key="Scale" value = "0 0 0 1"/>
</Child>
<Child type="Widget" skin="DB_R" offset="252 4 4 46" align="ALIGN_RIGHT ALIGN_VSTRETCH" name="Border">
<Property key="Scale" value = "0 0 1 0"/>
</Child>
<Child type="Widget" skin="DB_BR" offset="252 50 4 4" align="ALIGN_RIGHT ALIGN_BOTTOM" name="Border">
<Property key="Scale" value = "0 0 1 1"/>
</Child>
<Child type="Widget" skin="DB_BL" offset="0 50 4 4" align="ALIGN_LEFT ALIGN_BOTTOM" name="Border">
<Property key="Scale" value = "1 0 -1 1"/>
</Child>
<Child type="Widget" skin="DB_TR" offset="252 0 4 4" align="ALIGN_RIGHT ALIGN_TOP" name="Border">
<Property key="Scale" value = "0 1 1 -1"/>
</Child>
<Child type="Widget" skin="DB_TL" offset="0 0 4 4" align="ALIGN_LEFT ALIGN_TOP" name="Border">
<Property key="Scale" value = "1 1 -1 -1"/>
</Child>
</Skin>
</MyGUI>

Loading…
Cancel
Save