1
0
Fork 1
mirror of https://github.com/TES3MP/openmw-tes3mp.git synced 2025-01-16 10:19:55 +00:00
openmw-tes3mp/apps/openmw/mwgui/race.cpp

406 lines
12 KiB
C++
Raw Normal View History

#include "race.hpp"
#include <iostream>
#include <iterator>
#include <boost/algorithm/string.hpp>
#include <boost/lexical_cast.hpp>
#include <boost/format.hpp>
2012-10-01 15:17:04 +00:00
#include "../mwworld/esmstore.hpp"
#include "../mwbase/environment.hpp"
#include "../mwbase/world.hpp"
#include "../mwbase/windowmanager.hpp"
#include "widgets.hpp"
#include "tooltips.hpp"
using namespace MWGui;
using namespace Widgets;
RaceDialog::RaceDialog(MWBase::WindowManager& parWindowManager)
: WindowBase("openmw_chargen_race.layout", parWindowManager)
, mGenderIndex(0)
, mFaceIndex(0)
, mHairIndex(0)
, mFaceCount(10)
, mHairCount(14)
2012-09-13 17:03:31 +00:00
, mCurrentAngle(0)
{
2010-09-15 19:48:10 +00:00
// Centre dialog
2010-11-06 10:26:45 +00:00
center();
2010-09-14 19:55:41 +00:00
setText("AppearanceT", mWindowManager.getGameSettingString("sRaceMenu1", "Appearance"));
2012-09-13 17:03:31 +00:00
getWidget(mPreviewImage, "PreviewImage");
getWidget(mHeadRotate, "HeadRotate");
mHeadRotate->setScrollRange(50);
mHeadRotate->setScrollPosition(25);
mHeadRotate->setScrollViewPage(10);
mHeadRotate->eventScrollChangePosition += MyGUI::newDelegate(this, &RaceDialog::onHeadRotate);
2010-09-14 19:55:41 +00:00
// Set up next/previous buttons
MyGUI::ButtonPtr prevButton, nextButton;
setText("GenderChoiceT", mWindowManager.getGameSettingString("sRaceMenu2", "Change Sex"));
2010-09-14 19:55:41 +00:00
getWidget(prevButton, "PrevGenderButton");
getWidget(nextButton, "NextGenderButton");
prevButton->eventMouseButtonClick += MyGUI::newDelegate(this, &RaceDialog::onSelectPreviousGender);
nextButton->eventMouseButtonClick += MyGUI::newDelegate(this, &RaceDialog::onSelectNextGender);
2010-09-14 19:55:41 +00:00
setText("FaceChoiceT", mWindowManager.getGameSettingString("sRaceMenu3", "Change Face"));
2010-09-14 19:55:41 +00:00
getWidget(prevButton, "PrevFaceButton");
getWidget(nextButton, "NextFaceButton");
prevButton->eventMouseButtonClick += MyGUI::newDelegate(this, &RaceDialog::onSelectPreviousFace);
nextButton->eventMouseButtonClick += MyGUI::newDelegate(this, &RaceDialog::onSelectNextFace);
2010-09-14 19:55:41 +00:00
setText("HairChoiceT", mWindowManager.getGameSettingString("sRaceMenu4", "Change Hair"));
2010-09-14 19:55:41 +00:00
getWidget(prevButton, "PrevHairButton");
getWidget(nextButton, "NextHairButton");
prevButton->eventMouseButtonClick += MyGUI::newDelegate(this, &RaceDialog::onSelectPreviousHair);
nextButton->eventMouseButtonClick += MyGUI::newDelegate(this, &RaceDialog::onSelectNextHair);
2010-09-14 19:55:41 +00:00
setText("RaceT", mWindowManager.getGameSettingString("sRaceMenu4", "Race"));
getWidget(mRaceList, "RaceList");
mRaceList->setScrollVisible(true);
mRaceList->eventListSelectAccept += MyGUI::newDelegate(this, &RaceDialog::onSelectRace);
mRaceList->eventListMouseItemActivate += MyGUI::newDelegate(this, &RaceDialog::onSelectRace);
mRaceList->eventListChangePosition += MyGUI::newDelegate(this, &RaceDialog::onSelectRace);
setText("SkillsT", mWindowManager.getGameSettingString("sBonusSkillTitle", "Skill Bonus"));
getWidget(mSkillList, "SkillList");
setText("SpellPowerT", mWindowManager.getGameSettingString("sRaceMenu7", "Specials"));
getWidget(mSpellPowerList, "SpellPowerList");
MyGUI::ButtonPtr backButton;
getWidget(backButton, "BackButton");
backButton->eventMouseButtonClick += MyGUI::newDelegate(this, &RaceDialog::onBackClicked);
MyGUI::ButtonPtr okButton;
getWidget(okButton, "OKButton");
2012-04-16 15:46:54 +00:00
okButton->setCaption(mWindowManager.getGameSettingString("sOK", ""));
okButton->eventMouseButtonClick += MyGUI::newDelegate(this, &RaceDialog::onOkClicked);
2012-11-04 10:37:47 +00:00
okButton->setEnabled(false);
updateRaces();
updateSkills();
updateSpellPowers();
}
void RaceDialog::setNextButtonShow(bool shown)
{
MyGUI::ButtonPtr okButton;
getWidget(okButton, "OKButton");
if (shown)
okButton->setCaption(mWindowManager.getGameSettingString("sNext", ""));
else
okButton->setCaption(mWindowManager.getGameSettingString("sOK", ""));
}
void RaceDialog::open()
{
updateRaces();
updateSkills();
updateSpellPowers();
2012-09-23 22:42:05 +00:00
mPreview = new MWRender::RaceSelectionPreview();
MWBase::Environment::get().getWorld ()->setupExternalRendering (*mPreview);
mPreview->update (0);
2012-11-10 17:54:43 +00:00
const ESM::NPC proto = mPreview->getPrototype();
setRaceId(proto.mRace);
2012-11-10 17:30:16 +00:00
recountParts();
2012-11-10 17:54:43 +00:00
std::string index = proto.mHead.substr(proto.mHead.size() - 2, 2);
mFaceIndex = boost::lexical_cast<int>(index) - 1;
index = proto.mHair.substr(proto.mHair.size() - 2, 2);
mHairIndex = boost::lexical_cast<int>(index) - 1;
2012-09-23 22:42:05 +00:00
mPreviewImage->setImageTexture ("CharacterHeadPreview");
}
void RaceDialog::setRaceId(const std::string &raceId)
{
mCurrentRaceId = raceId;
mRaceList->setIndexSelected(MyGUI::ITEM_NONE);
size_t count = mRaceList->getItemCount();
for (size_t i = 0; i < count; ++i)
{
if (boost::iequals(*mRaceList->getItemDataAt<std::string>(i), raceId))
{
mRaceList->setIndexSelected(i);
MyGUI::ButtonPtr okButton;
getWidget(okButton, "OKButton");
2012-11-04 10:37:47 +00:00
okButton->setEnabled(true);
break;
}
}
2010-09-14 19:55:41 +00:00
updateSkills();
updateSpellPowers();
}
int wrap(int index, int max)
{
2010-09-14 19:55:41 +00:00
if (index < 0)
return max - 1;
else if (index >= max)
return 0;
else
return index;
}
2012-11-10 17:30:16 +00:00
int countParts(const std::string &part, const std::string &race, bool male)
{
const MWWorld::Store<ESM::BodyPart> &store =
MWBase::Environment::get().getWorld()->getStore().get<ESM::BodyPart>();
std::string prefix =
"b_n_" + race + ((male) ? "_m_" : "_f_") + part;
std::string suffix;
suffix.reserve(prefix.size() + 3);
int count = -1;
do {
++count;
suffix = "_" + (boost::format("%02d") % (count + 1)).str();
}
while (store.search(prefix + suffix) != 0);
if (count == 0 && part == "hair") {
count = -1;
do {
++count;
suffix = (boost::format("%02d") % (count + 1)).str();
}
while (store.search(prefix + suffix) != 0);
}
return count;
}
2012-09-23 22:42:05 +00:00
void RaceDialog::close()
{
delete mPreview;
mPreview = 0;
}
// widget controls
void RaceDialog::onOkClicked(MyGUI::Widget* _sender)
{
if(mRaceList->getIndexSelected() == MyGUI::ITEM_NONE)
2012-11-02 20:43:07 +00:00
return;
eventDone(this);
}
void RaceDialog::onBackClicked(MyGUI::Widget* _sender)
{
eventBack();
}
2012-03-22 14:23:23 +00:00
void RaceDialog::onHeadRotate(MyGUI::ScrollBar*, size_t _position)
{
2012-09-13 17:03:31 +00:00
float angle = (float(_position) / 49.f - 0.5) * 3.14 * 2;
float diff = angle - mCurrentAngle;
2012-09-23 22:42:05 +00:00
mPreview->update (diff);
2012-09-13 17:03:31 +00:00
mCurrentAngle += diff;
}
void RaceDialog::onSelectPreviousGender(MyGUI::Widget*)
{
mGenderIndex = wrap(mGenderIndex - 1, 2);
2012-11-10 17:30:16 +00:00
recountParts();
updatePreview();
}
void RaceDialog::onSelectNextGender(MyGUI::Widget*)
{
mGenderIndex = wrap(mGenderIndex + 1, 2);
2012-11-10 17:30:16 +00:00
recountParts();
updatePreview();
}
void RaceDialog::onSelectPreviousFace(MyGUI::Widget*)
{
mFaceIndex = wrap(mFaceIndex - 1, mFaceCount);
2012-11-10 17:30:16 +00:00
updatePreview();
}
void RaceDialog::onSelectNextFace(MyGUI::Widget*)
{
mFaceIndex = wrap(mFaceIndex + 1, mFaceCount);
2012-11-10 17:30:16 +00:00
updatePreview();
}
void RaceDialog::onSelectPreviousHair(MyGUI::Widget*)
{
mHairIndex = wrap(mHairIndex - 1, mHairCount);
2012-11-10 17:30:16 +00:00
updatePreview();
}
void RaceDialog::onSelectNextHair(MyGUI::Widget*)
{
2012-11-10 17:54:43 +00:00
mHairIndex = wrap(mHairIndex + 1, mHairCount);
2012-11-10 17:30:16 +00:00
updatePreview();
}
2012-03-22 14:28:06 +00:00
void RaceDialog::onSelectRace(MyGUI::ListBox* _sender, size_t _index)
{
if (_index == MyGUI::ITEM_NONE)
return;
MyGUI::ButtonPtr okButton;
getWidget(okButton, "OKButton");
2012-11-04 10:37:47 +00:00
okButton->setEnabled(true);
const std::string *raceId = mRaceList->getItemDataAt<std::string>(_index);
if (boost::iequals(mCurrentRaceId, *raceId))
return;
mCurrentRaceId = *raceId;
2012-11-10 17:30:16 +00:00
recountParts();
updatePreview();
updateSkills();
updateSpellPowers();
}
2012-11-10 17:30:16 +00:00
void RaceDialog::recountParts()
{
mFaceIndex = 0;
mHairIndex = 0;
mFaceCount = countParts("head", mCurrentRaceId, mGenderIndex == 0);
mHairCount = countParts("hair", mCurrentRaceId, mGenderIndex == 0);
}
// update widget content
void RaceDialog::updatePreview()
{
ESM::NPC record = mPreview->getPrototype();
record.mRace = mCurrentRaceId;
record.setIsMale(mGenderIndex == 0);
std::string prefix =
"b_n_" + mCurrentRaceId + ((record.isMale()) ? "_m_" : "_f_");
std::string headIndex = (boost::format("%02d") % (mFaceIndex + 1)).str();
std::string hairIndex = (boost::format("%02d") % (mHairIndex + 1)).str();
record.mHead = prefix + "head_" + headIndex;
record.mHair = prefix + "hair_" + hairIndex;
const MWWorld::Store<ESM::BodyPart> &parts =
MWBase::Environment::get().getWorld()->getStore().get<ESM::BodyPart>();
if (parts.search(record.mHair) == 0) {
record.mHair = prefix + "hair" + hairIndex;
}
mPreview->setPrototype(record);
}
void RaceDialog::updateRaces()
{
mRaceList->removeAllItems();
const MWWorld::Store<ESM::Race> &races =
MWBase::Environment::get().getWorld()->getStore().get<ESM::Race>();
2011-04-21 08:49:45 +00:00
2010-09-14 19:55:41 +00:00
int index = 0;
MWWorld::Store<ESM::Race>::iterator it = races.begin();
for (; it != races.end(); ++it)
2010-09-14 19:55:41 +00:00
{
bool playable = it->mData.mFlags & ESM::Race::Playable;
2010-09-14 13:00:04 +00:00
if (!playable) // Only display playable races
continue;
mRaceList->addItem(it->mName, it->mId);
if (boost::iequals(it->mId, mCurrentRaceId))
mRaceList->setIndexSelected(index);
2010-09-14 19:55:41 +00:00
++index;
}
}
void RaceDialog::updateSkills()
{
for (std::vector<MyGUI::WidgetPtr>::iterator it = mSkillItems.begin(); it != mSkillItems.end(); ++it)
2010-09-14 19:55:41 +00:00
{
MyGUI::Gui::getInstance().destroyWidget(*it);
}
mSkillItems.clear();
if (mCurrentRaceId.empty())
return;
MWSkillPtr skillWidget;
2010-09-14 19:55:41 +00:00
const int lineHeight = 18;
MyGUI::IntCoord coord1(0, 0, mSkillList->getWidth(), 18);
2012-10-01 15:17:04 +00:00
const MWWorld::ESMStore &store = MWBase::Environment::get().getWorld()->getStore();
const ESM::Race *race = store.get<ESM::Race>().find(mCurrentRaceId);
2012-09-17 07:37:50 +00:00
int count = sizeof(race->mData.mBonus)/sizeof(race->mData.mBonus[0]); // TODO: Find a portable macro for this ARRAYSIZE?
for (int i = 0; i < count; ++i)
2010-09-14 19:55:41 +00:00
{
2012-09-17 07:37:50 +00:00
int skillId = race->mData.mBonus[i].mSkill;
if (skillId < 0 || skillId > ESM::Skill::Length) // Skip unknown skill indexes
continue;
skillWidget = mSkillList->createWidget<MWSkill>("MW_StatNameValue", coord1, MyGUI::Align::Default,
std::string("Skill") + boost::lexical_cast<std::string>(i));
skillWidget->setWindowManager(&mWindowManager);
skillWidget->setSkillNumber(skillId);
2012-09-17 07:37:50 +00:00
skillWidget->setSkillValue(MWSkill::SkillValue(race->mData.mBonus[i].mBonus));
ToolTips::createSkillToolTip(skillWidget, skillId);
mSkillItems.push_back(skillWidget);
2010-09-14 19:55:41 +00:00
coord1.top += lineHeight;
}
}
void RaceDialog::updateSpellPowers()
{
for (std::vector<MyGUI::WidgetPtr>::iterator it = mSpellPowerItems.begin(); it != mSpellPowerItems.end(); ++it)
2010-09-14 19:55:41 +00:00
{
MyGUI::Gui::getInstance().destroyWidget(*it);
}
mSpellPowerItems.clear();
if (mCurrentRaceId.empty())
return;
MWSpellPtr spellPowerWidget;
2010-09-14 19:55:41 +00:00
const int lineHeight = 18;
MyGUI::IntCoord coord(0, 0, mSpellPowerList->getWidth(), 18);
2012-10-01 15:17:04 +00:00
const MWWorld::ESMStore &store = MWBase::Environment::get().getWorld()->getStore();
const ESM::Race *race = store.get<ESM::Race>().find(mCurrentRaceId);
2012-09-17 07:37:50 +00:00
std::vector<std::string>::const_iterator it = race->mPowers.mList.begin();
std::vector<std::string>::const_iterator end = race->mPowers.mList.end();
2010-09-14 19:55:41 +00:00
for (int i = 0; it != end; ++it)
{
const std::string &spellpower = *it;
spellPowerWidget = mSpellPowerList->createWidget<MWSpell>("MW_StatName", coord, MyGUI::Align::Default, std::string("SpellPower") + boost::lexical_cast<std::string>(i));
spellPowerWidget->setWindowManager(&mWindowManager);
spellPowerWidget->setSpellId(spellpower);
spellPowerWidget->setUserString("ToolTipType", "Spell");
spellPowerWidget->setUserString("Spell", spellpower);
mSpellPowerItems.push_back(spellPowerWidget);
2010-09-14 19:55:41 +00:00
coord.top += lineHeight;
++i;
2010-09-14 19:55:41 +00:00
}
}