1
0
mirror of https://gitlab.com/OpenMW/openmw.git synced 2025-02-11 15:40:39 +00:00
OpenMW/apps/openmw/mwgui/levelupdialog.cpp

Ignoring revisions in .git-blame-ignore-revs. Click here to bypass and see the normal blame view.

367 lines
13 KiB
C++
Raw Normal View History

2012-09-14 19:44:00 +02:00
#include "levelupdialog.hpp"
2015-01-10 02:50:43 +01:00
#include <MyGUI_Button.h>
#include <MyGUI_EditBox.h>
#include <MyGUI_ImageBox.h>
2023-06-19 20:41:54 +02:00
#include <MyGUI_ScrollView.h>
#include <MyGUI_TextBox.h>
2023-11-23 19:52:18 +01:00
#include <MyGUI_UString.h>
2012-09-14 19:44:00 +02:00
2016-01-06 12:46:06 +01:00
#include <components/fallback/fallback.hpp>
#include <components/widgets/box.hpp>
2016-01-06 12:46:06 +01:00
2012-09-14 19:44:00 +02:00
#include "../mwbase/environment.hpp"
#include "../mwbase/soundmanager.hpp"
2012-09-14 19:44:00 +02:00
#include "../mwbase/windowmanager.hpp"
2012-09-15 17:12:42 +02:00
#include "../mwbase/world.hpp"
#include "../mwworld/class.hpp"
#include "../mwworld/esmstore.hpp"
2012-09-15 17:12:42 +02:00
2015-08-21 21:12:39 +12:00
#include "../mwmechanics/actorutil.hpp"
2012-09-15 17:12:42 +02:00
#include "../mwmechanics/creaturestats.hpp"
#include "../mwmechanics/npcstats.hpp"
#include "../mwsound/constants.hpp"
#include "class.hpp"
namespace
{
constexpr unsigned int sMaxCoins = 3;
2023-06-21 22:11:01 +02:00
constexpr int sColumnOffsets[] = { 32, 218 };
}
2012-09-14 19:44:00 +02:00
namespace MWGui
{
LevelupDialog::LevelupDialog()
: WindowBase("openmw_levelup_dialog.layout")
, mCoinCount(sMaxCoins)
2012-09-14 19:44:00 +02:00
{
getWidget(mOkButton, "OkButton");
getWidget(mClassImage, "ClassImage");
getWidget(mLevelText, "LevelText");
getWidget(mLevelDescription, "LevelDescription");
getWidget(mCoinBox, "Coins");
2014-09-03 03:03:03 +02:00
getWidget(mAssignWidget, "AssignWidget");
2012-09-14 19:44:00 +02:00
mOkButton->eventMouseButtonClick += MyGUI::newDelegate(this, &LevelupDialog::onOkButtonClicked);
{
const auto& store = MWBase::Environment::get().getESMStore()->get<ESM::Attribute>();
const size_t perCol
2023-06-21 22:11:01 +02:00
= static_cast<size_t>(std::ceil(store.getSize() / static_cast<float>(std::size(sColumnOffsets))));
size_t i = 0;
for (const ESM::Attribute& attribute : store)
{
2023-06-21 22:11:01 +02:00
const int offset = sColumnOffsets[i / perCol];
const int row = static_cast<int>(i % perCol);
2023-06-19 20:41:54 +02:00
Widgets widgets;
widgets.mMultiplier = mAssignWidget->createWidget<MyGUI::TextBox>(
"SandTextVCenter", { offset, 20 * row, 100, 20 }, MyGUI::Align::Default);
auto* hbox = mAssignWidget->createWidget<Gui::HBox>(
{}, { offset + 20, 20 * row, 200, 20 }, MyGUI::Align::Default);
widgets.mButton = hbox->createWidget<Gui::AutoSizedButton>("SandTextButton", {}, MyGUI::Align::Default);
widgets.mButton->setUserData(attribute.mId);
widgets.mButton->eventMouseButtonClick += MyGUI::newDelegate(this, &LevelupDialog::onAttributeClicked);
widgets.mButton->setUserString("TextPadding", "0 0");
widgets.mButton->setUserString("ToolTipType", "Layout");
widgets.mButton->setUserString("ToolTipLayout", "AttributeToolTip");
widgets.mButton->setUserString("Caption_AttributeName", attribute.mName);
widgets.mButton->setUserString("Caption_AttributeDescription", attribute.mDescription);
widgets.mButton->setUserString("ImageTexture_AttributeImage", attribute.mIcon);
widgets.mButton->setCaption(attribute.mName);
widgets.mValue = hbox->createWidget<Gui::AutoSizedTextBox>("SandText", {}, MyGUI::Align::Default);
2023-06-19 20:41:54 +02:00
mAttributeWidgets.emplace(attribute.mId, widgets);
++i;
}
2023-06-19 20:41:54 +02:00
mAssignWidget->setVisibleVScroll(false);
mAssignWidget->setCanvasSize(MyGUI::IntSize(
mAssignWidget->getWidth(), std::max(mAssignWidget->getHeight(), static_cast<int>(20 * perCol))));
mAssignWidget->setVisibleVScroll(true);
mAssignWidget->setViewOffset(MyGUI::IntPoint());
2012-09-14 19:44:00 +02:00
}
for (unsigned int i = 0; i < sMaxCoins; ++i)
2012-09-15 17:12:42 +02:00
{
MyGUI::ImageBox* image = mCoinBox->createWidget<MyGUI::ImageBox>(
"ImageBox", MyGUI::IntCoord(0, 0, 16, 16), MyGUI::Align::Default);
2012-09-15 17:12:42 +02:00
image->setImageTexture("icons\\tx_goldicon.dds");
mCoins.push_back(image);
}
2012-09-14 19:44:00 +02:00
center();
2012-09-15 17:12:42 +02:00
}
void LevelupDialog::setAttributeValues()
{
MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayerPtr();
MWMechanics::CreatureStats& creatureStats = player.getClass().getCreatureStats(player);
MWMechanics::NpcStats& pcStats = player.getClass().getNpcStats(player);
2012-09-15 17:12:42 +02:00
for (const ESM::Attribute& attribute : MWBase::Environment::get().getESMStore()->get<ESM::Attribute>())
2012-09-15 17:12:42 +02:00
{
int val = creatureStats.getAttribute(attribute.mId).getBase();
if (std::find(mSpentAttributes.begin(), mSpentAttributes.end(), attribute.mId) != mSpentAttributes.end())
2012-09-15 17:12:42 +02:00
{
val += pcStats.getLevelupAttributeMultiplier(attribute.mId);
2012-09-15 17:12:42 +02:00
}
if (val >= 100)
val = 100;
mAttributeWidgets[attribute.mId].mValue->setCaption(MyGUI::utility::toString(val));
2012-09-15 17:12:42 +02:00
}
}
void LevelupDialog::resetCoins()
2012-09-15 17:12:42 +02:00
{
constexpr int coinSpacing = 33;
int curX = mCoinBox->getWidth() / 2 - (coinSpacing * (mCoinCount - 1) + 16 * mCoinCount) / 2;
for (unsigned int i = 0; i < sMaxCoins; ++i)
2012-09-15 17:12:42 +02:00
{
MyGUI::ImageBox* image = mCoins[i];
image->detachFromWidget();
image->attachToWidget(mCoinBox);
if (i < mCoinCount)
{
mCoins[i]->setVisible(true);
image->setCoord(MyGUI::IntCoord(curX, 0, 16, 16));
curX += 16 + coinSpacing;
}
else
mCoins[i]->setVisible(false);
2012-09-15 17:12:42 +02:00
}
}
void LevelupDialog::assignCoins()
2012-09-15 17:12:42 +02:00
{
resetCoins();
for (size_t i = 0; i < mSpentAttributes.size(); ++i)
2012-09-15 17:12:42 +02:00
{
MyGUI::ImageBox* image = mCoins[i];
image->detachFromWidget();
2014-09-03 03:03:03 +02:00
image->attachToWidget(mAssignWidget);
const auto& attribute = mSpentAttributes[i];
const auto& widgets = mAttributeWidgets[attribute];
2012-09-15 17:12:42 +02:00
2023-06-19 20:41:54 +02:00
const int xdiff = widgets.mMultiplier->getCaption().empty() ? 0 : 20;
const auto* hbox = widgets.mButton->getParent();
2012-09-15 17:12:42 +02:00
2023-06-19 20:41:54 +02:00
MyGUI::IntPoint pos = hbox->getPosition();
pos.left -= 22 + xdiff;
pos.top += (hbox->getHeight() - image->getHeight()) / 2;
2012-09-15 17:12:42 +02:00
image->setPosition(pos);
}
2012-09-14 19:44:00 +02:00
2012-09-15 17:12:42 +02:00
setAttributeValues();
2012-09-14 19:44:00 +02:00
}
void LevelupDialog::onOpen()
2012-09-14 19:44:00 +02:00
{
2012-11-08 16:37:57 +04:00
MWBase::World* world = MWBase::Environment::get().getWorld();
MWWorld::Ptr player = world->getPlayerPtr();
const MWMechanics::CreatureStats& creatureStats = player.getClass().getCreatureStats(player);
const MWMechanics::NpcStats& pcStats = player.getClass().getNpcStats(player);
2012-09-15 17:12:42 +02:00
setClassImage(mClassImage,
ESM::RefId::stringRefId(
getLevelupClassImage(pcStats.getSkillIncreasesForSpecialization(ESM::Class::Specialization::Combat),
pcStats.getSkillIncreasesForSpecialization(ESM::Class::Specialization::Magic),
pcStats.getSkillIncreasesForSpecialization(ESM::Class::Specialization::Stealth))));
2012-09-15 17:12:42 +02:00
int level = creatureStats.getLevel() + 1;
2015-01-10 02:50:43 +01:00
mLevelText->setCaptionWithReplacing("#{sLevelUpMenu1} " + MyGUI::utility::toString(level));
2012-09-15 17:12:42 +02:00
2022-08-28 17:20:49 +02:00
std::string_view levelupdescription;
levelupdescription = Fallback::Map::getString("Level_Up_Level" + MyGUI::utility::toString(level));
2022-08-28 17:20:49 +02:00
if (levelupdescription.empty())
levelupdescription = Fallback::Map::getString("Level_Up_Default");
mLevelDescription->setCaption(MyGUI::UString(levelupdescription));
unsigned int availableAttributes = 0;
for (const ESM::Attribute& attribute : MWBase::Environment::get().getESMStore()->get<ESM::Attribute>())
2012-09-15 17:12:42 +02:00
{
const auto& widgets = mAttributeWidgets[attribute.mId];
if (pcStats.getAttribute(attribute.mId).getBase() < 100)
{
widgets.mButton->setEnabled(true);
widgets.mValue->setEnabled(true);
availableAttributes++;
float mult = pcStats.getLevelupAttributeMultiplier(attribute.mId);
mult = std::min(mult, 100 - pcStats.getAttribute(attribute.mId).getBase());
if (mult <= 1)
widgets.mMultiplier->setCaption({});
else
widgets.mMultiplier->setCaption("x" + MyGUI::utility::toString(mult));
}
else
{
widgets.mButton->setEnabled(false);
widgets.mValue->setEnabled(false);
widgets.mMultiplier->setCaption({});
}
}
mCoinCount = std::min(sMaxCoins, availableAttributes);
mSpentAttributes.clear();
resetCoins();
setAttributeValues();
center();
// Play LevelUp Music
2023-09-19 19:29:26 +04:00
MWBase::Environment::get().getSoundManager()->streamMusic(MWSound::triumphMusic, MWSound::MusicType::Normal);
2012-09-14 19:44:00 +02:00
}
void LevelupDialog::onOkButtonClicked(MyGUI::Widget* sender)
2012-09-14 19:44:00 +02:00
{
2015-08-21 21:12:39 +12:00
MWWorld::Ptr player = MWMechanics::getPlayer();
MWMechanics::NpcStats& pcStats = player.getClass().getNpcStats(player);
2012-09-15 17:12:42 +02:00
if (mSpentAttributes.size() < mCoinCount)
MWBase::Environment::get().getWindowManager()->messageBox("#{sNotifyMessage36}");
2012-09-15 17:12:42 +02:00
else
{
// increase attributes
for (unsigned int i = 0; i < mCoinCount; ++i)
2012-09-15 17:12:42 +02:00
{
MWMechanics::AttributeValue attribute = pcStats.getAttribute(mSpentAttributes[i]);
attribute.setBase(attribute.getBase() + pcStats.getLevelupAttributeMultiplier(mSpentAttributes[i]));
2012-09-15 17:12:42 +02:00
if (attribute.getBase() >= 100)
attribute.setBase(100);
pcStats.setAttribute(mSpentAttributes[i], attribute);
2012-09-15 17:12:42 +02:00
}
pcStats.levelUp();
2012-09-15 17:12:42 +02:00
MWBase::Environment::get().getWindowManager()->removeGuiMode(GM_Levelup);
2012-09-15 17:12:42 +02:00
}
2012-09-14 19:44:00 +02:00
}
void LevelupDialog::onAttributeClicked(MyGUI::Widget* sender)
2012-09-14 19:44:00 +02:00
{
auto attribute = *sender->getUserData<ESM::Attribute::AttributeID>();
2012-09-15 17:12:42 +02:00
auto found = std::find(mSpentAttributes.begin(), mSpentAttributes.end(), attribute);
2012-09-15 17:12:42 +02:00
if (found != mSpentAttributes.end())
mSpentAttributes.erase(found);
2012-09-15 17:12:42 +02:00
else
{
if (mSpentAttributes.size() == mCoinCount)
mSpentAttributes[mCoinCount - 1] = attribute;
2012-09-15 17:12:42 +02:00
else
mSpentAttributes.push_back(attribute);
}
assignCoins();
2012-09-14 19:44:00 +02:00
}
std::string_view LevelupDialog::getLevelupClassImage(
const int combatIncreases, const int magicIncreases, const int stealthIncreases)
{
std::string_view ret = "acrobat";
int total = combatIncreases + magicIncreases + stealthIncreases;
if (total == 0)
return ret;
int combatFraction = static_cast<int>(static_cast<float>(combatIncreases) / total * 10.f);
int magicFraction = static_cast<int>(static_cast<float>(magicIncreases) / total * 10.f);
int stealthFraction = static_cast<int>(static_cast<float>(stealthIncreases) / total * 10.f);
if (combatFraction > 7)
ret = "warrior";
else if (magicFraction > 7)
ret = "mage";
else if (stealthFraction > 7)
ret = "thief";
switch (combatFraction)
{
case 7:
ret = "warrior";
break;
case 6:
if (stealthFraction == 1)
ret = "barbarian";
else if (stealthFraction == 3)
ret = "crusader";
else
ret = "knight";
break;
case 5:
if (stealthFraction == 3)
ret = "scout";
else
ret = "archer";
break;
case 4:
ret = "rogue";
break;
default:
break;
}
switch (magicFraction)
{
case 7:
ret = "mage";
break;
case 6:
if (combatFraction == 2)
ret = "sorcerer";
else if (combatIncreases == 3)
ret = "healer";
else
ret = "battlemage";
break;
case 5:
ret = "witchhunter";
break;
case 4:
ret = "spellsword";
// In vanilla there's also code for "nightblade", however it seems to be unreachable.
break;
default:
break;
}
switch (stealthFraction)
{
case 7:
ret = "thief";
break;
case 6:
if (magicFraction == 1)
ret = "agent";
else if (magicIncreases == 3)
ret = "assassin";
else
ret = "acrobat";
break;
case 5:
if (magicIncreases == 3)
ret = "monk";
else
ret = "pilgrim";
break;
case 3:
2016-06-26 15:17:52 +02:00
if (magicFraction == 3)
ret = "bard";
break;
default:
break;
}
return ret;
}
2012-09-14 19:44:00 +02:00
}