mirror of
https://github.com/TES3MP/openmw-tes3mp.git
synced 2025-01-16 18:19:55 +00:00
Merge pull request #1134 from MiroslavR/review-spells
Show starting abilities, powers and spells in stat-review window
This commit is contained in:
commit
4a62273d6e
8 changed files with 210 additions and 69 deletions
|
@ -132,6 +132,12 @@ namespace MWGui
|
|||
mReviewDialog->configureSkills(major, minor);
|
||||
}
|
||||
|
||||
void CharacterCreation::onFrame(float duration)
|
||||
{
|
||||
if (mReviewDialog)
|
||||
mReviewDialog->onFrame(duration);
|
||||
}
|
||||
|
||||
void CharacterCreation::spawnDialog(const char id)
|
||||
{
|
||||
try
|
||||
|
|
|
@ -50,6 +50,8 @@ namespace MWGui
|
|||
void setValue(const ESM::Skill::SkillEnum parSkill, const MWMechanics::SkillValue& value);
|
||||
void configureSkills (const SkillList& major, const SkillList& minor);
|
||||
|
||||
void onFrame(float duration);
|
||||
|
||||
private:
|
||||
osg::Group* mParent;
|
||||
Resource::ResourceSystem* mResourceSystem;
|
||||
|
|
|
@ -10,6 +10,7 @@
|
|||
#include "../mwbase/world.hpp"
|
||||
#include "../mwbase/windowmanager.hpp"
|
||||
#include "../mwworld/esmstore.hpp"
|
||||
#include "../mwmechanics/autocalcspell.hpp"
|
||||
|
||||
#include "tooltips.hpp"
|
||||
|
||||
|
@ -29,7 +30,8 @@ namespace MWGui
|
|||
const int ReviewDialog::sLineHeight = 18;
|
||||
|
||||
ReviewDialog::ReviewDialog()
|
||||
: WindowModal("openmw_chargen_review.layout")
|
||||
: WindowModal("openmw_chargen_review.layout"),
|
||||
mUpdateSkillArea(false)
|
||||
{
|
||||
// Centre dialog
|
||||
center();
|
||||
|
@ -102,7 +104,16 @@ namespace MWGui
|
|||
void ReviewDialog::open()
|
||||
{
|
||||
WindowModal::open();
|
||||
updateSkillArea();
|
||||
mUpdateSkillArea = true;
|
||||
}
|
||||
|
||||
void ReviewDialog::onFrame(float /*duration*/)
|
||||
{
|
||||
if (mUpdateSkillArea)
|
||||
{
|
||||
updateSkillArea();
|
||||
mUpdateSkillArea = false;
|
||||
}
|
||||
}
|
||||
|
||||
void ReviewDialog::setPlayerName(const std::string &name)
|
||||
|
@ -121,6 +132,8 @@ namespace MWGui
|
|||
ToolTips::createRaceToolTip(mRaceWidget, race);
|
||||
mRaceWidget->setCaption(race->mName);
|
||||
}
|
||||
|
||||
mUpdateSkillArea = true;
|
||||
}
|
||||
|
||||
void ReviewDialog::setClass(const ESM::Class& class_)
|
||||
|
@ -141,6 +154,8 @@ namespace MWGui
|
|||
mBirthSignWidget->setCaption(sign->mName);
|
||||
ToolTips::createBirthsignToolTip(mBirthSignWidget, mBirthSignId);
|
||||
}
|
||||
|
||||
mUpdateSkillArea = true;
|
||||
}
|
||||
|
||||
void ReviewDialog::setHealth(const MWMechanics::DynamicStat<float>& value)
|
||||
|
@ -170,7 +185,11 @@ namespace MWGui
|
|||
if (attr == mAttributeWidgets.end())
|
||||
return;
|
||||
|
||||
attr->second->setAttributeValue(value);
|
||||
if (attr->second->getAttributeValue() != value)
|
||||
{
|
||||
attr->second->setAttributeValue(value);
|
||||
mUpdateSkillArea = true;
|
||||
}
|
||||
}
|
||||
|
||||
void ReviewDialog::setSkillValue(ESM::Skill::SkillEnum skillId, const MWMechanics::SkillValue& value)
|
||||
|
@ -191,6 +210,7 @@ namespace MWGui
|
|||
widget->_setWidgetState(state);
|
||||
}
|
||||
|
||||
mUpdateSkillArea = true;
|
||||
}
|
||||
|
||||
void ReviewDialog::configureSkills(const std::vector<int>& major, const std::vector<int>& minor)
|
||||
|
@ -211,7 +231,7 @@ namespace MWGui
|
|||
mMiscSkills.push_back(skill);
|
||||
}
|
||||
|
||||
updateSkillArea();
|
||||
mUpdateSkillArea = true;
|
||||
}
|
||||
|
||||
void ReviewDialog::addSeparator(MyGUI::IntCoord &coord1, MyGUI::IntCoord &coord2)
|
||||
|
@ -245,7 +265,7 @@ namespace MWGui
|
|||
skillNameWidget->setCaption(text);
|
||||
skillNameWidget->eventMouseWheel += MyGUI::newDelegate(this, &ReviewDialog::onMouseWheel);
|
||||
|
||||
skillValueWidget = mSkillView->createWidget<MyGUI::TextBox>("SandTextRight", coord2, MyGUI::Align::Top | MyGUI::Align::Right);
|
||||
skillValueWidget = mSkillView->createWidget<MyGUI::TextBox>("SandTextRight", coord2, MyGUI::Align::Default);
|
||||
skillValueWidget->setCaption(value);
|
||||
skillValueWidget->_setWidgetState(state);
|
||||
skillValueWidget->eventMouseWheel += MyGUI::newDelegate(this, &ReviewDialog::onMouseWheel);
|
||||
|
@ -273,6 +293,20 @@ namespace MWGui
|
|||
coord2.top += sLineHeight;
|
||||
}
|
||||
|
||||
void ReviewDialog::addItem(const ESM::Spell* spell, MyGUI::IntCoord& coord1, MyGUI::IntCoord& coord2)
|
||||
{
|
||||
Widgets::MWSpellPtr widget = mSkillView->createWidget<Widgets::MWSpell>("MW_StatName", coord1 + MyGUI::IntSize(coord2.width, 0), MyGUI::Align::Default);
|
||||
widget->setSpellId(spell->mId);
|
||||
widget->setUserString("ToolTipType", "Spell");
|
||||
widget->setUserString("Spell", spell->mId);
|
||||
widget->eventMouseWheel += MyGUI::newDelegate(this, &ReviewDialog::onMouseWheel);
|
||||
|
||||
mSkillWidgets.push_back(widget);
|
||||
|
||||
coord1.top += sLineHeight;
|
||||
coord2.top += sLineHeight;
|
||||
}
|
||||
|
||||
void ReviewDialog::addSkills(const SkillList &skills, const std::string &titleId, const std::string &titleDefault, MyGUI::IntCoord &coord1, MyGUI::IntCoord &coord2)
|
||||
{
|
||||
// Add a line separator if there are items above
|
||||
|
@ -332,6 +366,80 @@ namespace MWGui
|
|||
if (!mMiscSkills.empty())
|
||||
addSkills(mMiscSkills, "sSkillClassMisc", "Misc Skills", coord1, coord2);
|
||||
|
||||
// starting spells
|
||||
std::vector<std::string> spells;
|
||||
|
||||
const ESM::Race* race = NULL;
|
||||
if (!mRaceId.empty())
|
||||
race = MWBase::Environment::get().getWorld()->getStore().get<ESM::Race>().find(mRaceId);
|
||||
|
||||
int skills[ESM::Skill::Length];
|
||||
for (int i=0; i<ESM::Skill::Length; ++i)
|
||||
skills[i] = mSkillValues.find(i)->second.getBase();
|
||||
|
||||
int attributes[ESM::Attribute::Length];
|
||||
for (int i=0; i<ESM::Attribute::Length; ++i)
|
||||
attributes[i] = mAttributeWidgets[i]->getAttributeValue().getBase();
|
||||
|
||||
std::vector<std::string> selectedSpells = MWMechanics::autoCalcPlayerSpells(skills, attributes, race);
|
||||
for (std::vector<std::string>::iterator iter = selectedSpells.begin(); iter != selectedSpells.end(); ++iter)
|
||||
{
|
||||
std::string lower = Misc::StringUtils::lowerCase(*iter);
|
||||
if (std::find(spells.begin(), spells.end(), lower) == spells.end())
|
||||
spells.push_back(lower);
|
||||
}
|
||||
|
||||
if (race)
|
||||
{
|
||||
for (std::vector<std::string>::const_iterator iter = race->mPowers.mList.begin();
|
||||
iter != race->mPowers.mList.end(); ++iter)
|
||||
{
|
||||
std::string lower = Misc::StringUtils::lowerCase(*iter);
|
||||
if (std::find(spells.begin(), spells.end(), lower) == spells.end())
|
||||
spells.push_back(lower);
|
||||
}
|
||||
}
|
||||
|
||||
if (!mBirthSignId.empty())
|
||||
{
|
||||
const ESM::BirthSign* sign = MWBase::Environment::get().getWorld()->getStore().get<ESM::BirthSign>().find(mBirthSignId);
|
||||
for (std::vector<std::string>::const_iterator iter = sign->mPowers.mList.begin();
|
||||
iter != sign->mPowers.mList.end(); ++iter)
|
||||
{
|
||||
std::string lower = Misc::StringUtils::lowerCase(*iter);
|
||||
if (std::find(spells.begin(), spells.end(), lower) == spells.end())
|
||||
spells.push_back(lower);
|
||||
}
|
||||
}
|
||||
|
||||
if (!mSkillWidgets.empty())
|
||||
addSeparator(coord1, coord2);
|
||||
addGroup(MWBase::Environment::get().getWindowManager()->getGameSettingString("sTypeAbility", "Abilities"), coord1, coord2);
|
||||
for (std::vector<std::string>::const_iterator iter = spells.begin(); iter != spells.end(); ++iter)
|
||||
{
|
||||
const ESM::Spell* spell = MWBase::Environment::get().getWorld()->getStore().get<ESM::Spell>().find(*iter);
|
||||
if (spell->mData.mType == ESM::Spell::ST_Ability)
|
||||
addItem(spell, coord1, coord2);
|
||||
}
|
||||
|
||||
addSeparator(coord1, coord2);
|
||||
addGroup(MWBase::Environment::get().getWindowManager()->getGameSettingString("sTypePower", "Powers"), coord1, coord2);
|
||||
for (std::vector<std::string>::const_iterator iter = spells.begin(); iter != spells.end(); ++iter)
|
||||
{
|
||||
const ESM::Spell* spell = MWBase::Environment::get().getWorld()->getStore().get<ESM::Spell>().find(*iter);
|
||||
if (spell->mData.mType == ESM::Spell::ST_Power)
|
||||
addItem(spell, coord1, coord2);
|
||||
}
|
||||
|
||||
addSeparator(coord1, coord2);
|
||||
addGroup(MWBase::Environment::get().getWindowManager()->getGameSettingString("sTypeSpell", "Spells"), coord1, coord2);
|
||||
for (std::vector<std::string>::const_iterator iter = spells.begin(); iter != spells.end(); ++iter)
|
||||
{
|
||||
const ESM::Spell* spell = MWBase::Environment::get().getWorld()->getStore().get<ESM::Spell>().find(*iter);
|
||||
if (spell->mData.mType == ESM::Spell::ST_Spell)
|
||||
addItem(spell, coord1, coord2);
|
||||
}
|
||||
|
||||
// Canvas size must be expressed with VScroll disabled, otherwise MyGUI would expand the scroll area when the scrollbar is hidden
|
||||
mSkillView->setVisibleVScroll(false);
|
||||
mSkillView->setCanvasSize (mSkillView->getWidth(), std::max(mSkillView->getHeight(), coord1.top));
|
||||
|
|
|
@ -6,6 +6,11 @@
|
|||
#include "windowbase.hpp"
|
||||
#include "widgets.hpp"
|
||||
|
||||
namespace ESM
|
||||
{
|
||||
class Spell;
|
||||
}
|
||||
|
||||
namespace MWGui
|
||||
{
|
||||
class WindowManager;
|
||||
|
@ -42,6 +47,8 @@ namespace MWGui
|
|||
|
||||
virtual void open();
|
||||
|
||||
void onFrame(float duration);
|
||||
|
||||
// Events
|
||||
typedef MyGUI::delegates::CMultiDelegate0 EventHandle_Void;
|
||||
typedef MyGUI::delegates::CMultiDelegate1<int> EventHandle_Int;
|
||||
|
@ -75,6 +82,7 @@ namespace MWGui
|
|||
void addGroup(const std::string &label, MyGUI::IntCoord &coord1, MyGUI::IntCoord &coord2);
|
||||
MyGUI::TextBox* addValueItem(const std::string& text, const std::string &value, const std::string& state, MyGUI::IntCoord &coord1, MyGUI::IntCoord &coord2);
|
||||
void addItem(const std::string& text, MyGUI::IntCoord &coord1, MyGUI::IntCoord &coord2);
|
||||
void addItem(const ESM::Spell* spell, MyGUI::IntCoord &coord1, MyGUI::IntCoord &coord2);
|
||||
void updateSkillArea();
|
||||
|
||||
static const int sLineHeight;
|
||||
|
@ -92,6 +100,8 @@ namespace MWGui
|
|||
std::string mName, mRaceId, mBirthSignId;
|
||||
ESM::Class mKlass;
|
||||
std::vector<MyGUI::Widget*> mSkillWidgets; //< Skills and other information
|
||||
|
||||
bool mUpdateSkillArea;
|
||||
};
|
||||
}
|
||||
#endif
|
||||
|
|
|
@ -1006,6 +1006,9 @@ namespace MWGui
|
|||
mScreenFader->update(frameDuration);
|
||||
|
||||
mDebugWindow->onFrame(frameDuration);
|
||||
|
||||
if (mCharGen)
|
||||
mCharGen->onFrame(frameDuration);
|
||||
}
|
||||
|
||||
void WindowManager::changeCell(const MWWorld::CellStore* cell)
|
||||
|
|
|
@ -141,6 +141,79 @@ namespace MWMechanics
|
|||
return selectedSpells;
|
||||
}
|
||||
|
||||
std::vector<std::string> autoCalcPlayerSpells(const int* actorSkills, const int* actorAttributes, const ESM::Race* race)
|
||||
{
|
||||
const MWWorld::ESMStore& esmStore = MWBase::Environment::get().getWorld()->getStore();
|
||||
|
||||
static const float fPCbaseMagickaMult = esmStore.get<ESM::GameSetting>().find("fPCbaseMagickaMult")->getFloat();
|
||||
|
||||
float baseMagicka = fPCbaseMagickaMult * actorAttributes[ESM::Attribute::Intelligence];
|
||||
bool reachedLimit = false;
|
||||
const ESM::Spell* weakestSpell = NULL;
|
||||
int minCost = INT_MAX;
|
||||
|
||||
std::vector<std::string> selectedSpells;
|
||||
|
||||
|
||||
const MWWorld::Store<ESM::Spell> &spells =
|
||||
esmStore.get<ESM::Spell>();
|
||||
for (MWWorld::Store<ESM::Spell>::iterator iter = spells.begin(); iter != spells.end(); ++iter)
|
||||
{
|
||||
const ESM::Spell* spell = &*iter;
|
||||
|
||||
if (spell->mData.mType != ESM::Spell::ST_Spell)
|
||||
continue;
|
||||
if (!(spell->mData.mFlags & ESM::Spell::F_PCStart))
|
||||
continue;
|
||||
if (reachedLimit && spell->mData.mCost <= minCost)
|
||||
continue;
|
||||
if (race && std::find(race->mPowers.mList.begin(), race->mPowers.mList.end(), spell->mId) != race->mPowers.mList.end())
|
||||
continue;
|
||||
if (baseMagicka < spell->mData.mCost)
|
||||
continue;
|
||||
|
||||
static const float fAutoPCSpellChance = esmStore.get<ESM::GameSetting>().find("fAutoPCSpellChance")->getFloat();
|
||||
if (calcAutoCastChance(spell, actorSkills, actorAttributes, -1) < fAutoPCSpellChance)
|
||||
continue;
|
||||
|
||||
if (!attrSkillCheck(spell, actorSkills, actorAttributes))
|
||||
continue;
|
||||
|
||||
selectedSpells.push_back(spell->mId);
|
||||
|
||||
if (reachedLimit)
|
||||
{
|
||||
std::vector<std::string>::iterator it = std::find(selectedSpells.begin(), selectedSpells.end(), weakestSpell->mId);
|
||||
if (it != selectedSpells.end())
|
||||
selectedSpells.erase(it);
|
||||
|
||||
minCost = INT_MAX;
|
||||
for (std::vector<std::string>::iterator weakIt = selectedSpells.begin(); weakIt != selectedSpells.end(); ++weakIt)
|
||||
{
|
||||
const ESM::Spell* testSpell = esmStore.get<ESM::Spell>().find(*weakIt);
|
||||
if (testSpell->mData.mCost < minCost)
|
||||
{
|
||||
minCost = testSpell->mData.mCost;
|
||||
weakestSpell = testSpell;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (spell->mData.mCost < minCost)
|
||||
{
|
||||
weakestSpell = spell;
|
||||
minCost = weakestSpell->mData.mCost;
|
||||
}
|
||||
static const unsigned int iAutoPCSpellMax = esmStore.get<ESM::GameSetting>().find("iAutoPCSpellMax")->getInt();
|
||||
if (selectedSpells.size() == iAutoPCSpellMax)
|
||||
reachedLimit = true;
|
||||
}
|
||||
}
|
||||
|
||||
return selectedSpells;
|
||||
}
|
||||
|
||||
bool attrSkillCheck (const ESM::Spell* spell, const int* actorSkills, const int* actorAttributes)
|
||||
{
|
||||
const std::vector<ESM::ENAMstruct>& effects = spell->mEffects.mList;
|
||||
|
|
|
@ -16,6 +16,8 @@ namespace MWMechanics
|
|||
|
||||
std::vector<std::string> autoCalcNpcSpells(const int* actorSkills, const int* actorAttributes, const ESM::Race* race);
|
||||
|
||||
std::vector<std::string> autoCalcPlayerSpells(const int* actorSkills, const int* actorAttributes, const ESM::Race* race);
|
||||
|
||||
// Helpers
|
||||
|
||||
bool attrSkillCheck (const ESM::Spell* spell, const int* actorSkills, const int* actorAttributes);
|
||||
|
|
|
@ -198,15 +198,6 @@ namespace MWMechanics
|
|||
}
|
||||
|
||||
// F_PCStart spells
|
||||
static const float fPCbaseMagickaMult = esmStore.get<ESM::GameSetting>().find("fPCbaseMagickaMult")->getFloat();
|
||||
|
||||
float baseMagicka = fPCbaseMagickaMult * creatureStats.getAttribute(ESM::Attribute::Intelligence).getBase();
|
||||
bool reachedLimit = false;
|
||||
const ESM::Spell* weakestSpell = NULL;
|
||||
int minCost = INT_MAX;
|
||||
|
||||
std::vector<std::string> selectedSpells;
|
||||
|
||||
const ESM::Race* race = NULL;
|
||||
if (mRaceSelected)
|
||||
race = esmStore.get<ESM::Race>().find(player->mRace);
|
||||
|
@ -219,61 +210,7 @@ namespace MWMechanics
|
|||
for (int i=0; i<ESM::Attribute::Length; ++i)
|
||||
attributes[i] = npcStats.getAttribute(i).getBase();
|
||||
|
||||
const MWWorld::Store<ESM::Spell> &spells =
|
||||
esmStore.get<ESM::Spell>();
|
||||
for (MWWorld::Store<ESM::Spell>::iterator iter = spells.begin(); iter != spells.end(); ++iter)
|
||||
{
|
||||
const ESM::Spell* spell = &*iter;
|
||||
|
||||
if (spell->mData.mType != ESM::Spell::ST_Spell)
|
||||
continue;
|
||||
if (!(spell->mData.mFlags & ESM::Spell::F_PCStart))
|
||||
continue;
|
||||
if (reachedLimit && spell->mData.mCost <= minCost)
|
||||
continue;
|
||||
if (race && std::find(race->mPowers.mList.begin(), race->mPowers.mList.end(), spell->mId) != race->mPowers.mList.end())
|
||||
continue;
|
||||
if (baseMagicka < spell->mData.mCost)
|
||||
continue;
|
||||
|
||||
static const float fAutoPCSpellChance = esmStore.get<ESM::GameSetting>().find("fAutoPCSpellChance")->getFloat();
|
||||
if (calcAutoCastChance(spell, skills, attributes, -1) < fAutoPCSpellChance)
|
||||
continue;
|
||||
|
||||
if (!attrSkillCheck(spell, skills, attributes))
|
||||
continue;
|
||||
|
||||
selectedSpells.push_back(spell->mId);
|
||||
|
||||
if (reachedLimit)
|
||||
{
|
||||
std::vector<std::string>::iterator it = std::find(selectedSpells.begin(), selectedSpells.end(), weakestSpell->mId);
|
||||
if (it != selectedSpells.end())
|
||||
selectedSpells.erase(it);
|
||||
|
||||
minCost = INT_MAX;
|
||||
for (std::vector<std::string>::iterator weakIt = selectedSpells.begin(); weakIt != selectedSpells.end(); ++weakIt)
|
||||
{
|
||||
const ESM::Spell* testSpell = esmStore.get<ESM::Spell>().find(*weakIt);
|
||||
if (testSpell->mData.mCost < minCost)
|
||||
{
|
||||
minCost = testSpell->mData.mCost;
|
||||
weakestSpell = testSpell;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (spell->mData.mCost < minCost)
|
||||
{
|
||||
weakestSpell = spell;
|
||||
minCost = weakestSpell->mData.mCost;
|
||||
}
|
||||
static const unsigned int iAutoPCSpellMax = esmStore.get<ESM::GameSetting>().find("iAutoPCSpellMax")->getInt();
|
||||
if (selectedSpells.size() == iAutoPCSpellMax)
|
||||
reachedLimit = true;
|
||||
}
|
||||
}
|
||||
std::vector<std::string> selectedSpells = autoCalcPlayerSpells(skills, attributes, race);
|
||||
|
||||
for (std::vector<std::string>::iterator it = selectedSpells.begin(); it != selectedSpells.end(); ++it)
|
||||
creatureStats.getSpells().add(*it);
|
||||
|
|
Loading…
Reference in a new issue