diff --git a/apps/openmw/mwgui/charactercreation.cpp b/apps/openmw/mwgui/charactercreation.cpp index 9a1b43678..d72e6627f 100644 --- a/apps/openmw/mwgui/charactercreation.cpp +++ b/apps/openmw/mwgui/charactercreation.cpp @@ -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 diff --git a/apps/openmw/mwgui/charactercreation.hpp b/apps/openmw/mwgui/charactercreation.hpp index 75f3a7016..0130222f3 100644 --- a/apps/openmw/mwgui/charactercreation.hpp +++ b/apps/openmw/mwgui/charactercreation.hpp @@ -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; diff --git a/apps/openmw/mwgui/review.cpp b/apps/openmw/mwgui/review.cpp index d7d6c3cdb..d2971a093 100644 --- a/apps/openmw/mwgui/review.cpp +++ b/apps/openmw/mwgui/review.cpp @@ -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& 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& major, const std::vector& 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("SandTextRight", coord2, MyGUI::Align::Top | MyGUI::Align::Right); + skillValueWidget = mSkillView->createWidget("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("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 spells; + + const ESM::Race* race = NULL; + if (!mRaceId.empty()) + race = MWBase::Environment::get().getWorld()->getStore().get().find(mRaceId); + + int skills[ESM::Skill::Length]; + for (int i=0; isecond.getBase(); + + int attributes[ESM::Attribute::Length]; + for (int i=0; igetAttributeValue().getBase(); + + std::vector selectedSpells = MWMechanics::autoCalcPlayerSpells(skills, attributes, race); + for (std::vector::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::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().find(mBirthSignId); + for (std::vector::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::const_iterator iter = spells.begin(); iter != spells.end(); ++iter) + { + const ESM::Spell* spell = MWBase::Environment::get().getWorld()->getStore().get().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::const_iterator iter = spells.begin(); iter != spells.end(); ++iter) + { + const ESM::Spell* spell = MWBase::Environment::get().getWorld()->getStore().get().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::const_iterator iter = spells.begin(); iter != spells.end(); ++iter) + { + const ESM::Spell* spell = MWBase::Environment::get().getWorld()->getStore().get().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)); diff --git a/apps/openmw/mwgui/review.hpp b/apps/openmw/mwgui/review.hpp index 111d7de1d..5d57aeb8b 100644 --- a/apps/openmw/mwgui/review.hpp +++ b/apps/openmw/mwgui/review.hpp @@ -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 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 mSkillWidgets; //< Skills and other information + + bool mUpdateSkillArea; }; } #endif diff --git a/apps/openmw/mwgui/windowmanagerimp.cpp b/apps/openmw/mwgui/windowmanagerimp.cpp index 73a8c8763..e71bcb61a 100644 --- a/apps/openmw/mwgui/windowmanagerimp.cpp +++ b/apps/openmw/mwgui/windowmanagerimp.cpp @@ -1009,6 +1009,9 @@ namespace MWGui mScreenFader->update(frameDuration); mDebugWindow->onFrame(frameDuration); + + if (mCharGen) + mCharGen->onFrame(frameDuration); } void WindowManager::changeCell(const MWWorld::CellStore* cell) diff --git a/apps/openmw/mwmechanics/autocalcspell.cpp b/apps/openmw/mwmechanics/autocalcspell.cpp index b798ff5dc..af814edb0 100644 --- a/apps/openmw/mwmechanics/autocalcspell.cpp +++ b/apps/openmw/mwmechanics/autocalcspell.cpp @@ -141,6 +141,79 @@ namespace MWMechanics return selectedSpells; } + std::vector 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().find("fPCbaseMagickaMult")->getFloat(); + + float baseMagicka = fPCbaseMagickaMult * actorAttributes[ESM::Attribute::Intelligence]; + bool reachedLimit = false; + const ESM::Spell* weakestSpell = NULL; + int minCost = INT_MAX; + + std::vector selectedSpells; + + + const MWWorld::Store &spells = + esmStore.get(); + for (MWWorld::Store::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().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::iterator it = std::find(selectedSpells.begin(), selectedSpells.end(), weakestSpell->mId); + if (it != selectedSpells.end()) + selectedSpells.erase(it); + + minCost = INT_MAX; + for (std::vector::iterator weakIt = selectedSpells.begin(); weakIt != selectedSpells.end(); ++weakIt) + { + const ESM::Spell* testSpell = esmStore.get().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().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& effects = spell->mEffects.mList; diff --git a/apps/openmw/mwmechanics/autocalcspell.hpp b/apps/openmw/mwmechanics/autocalcspell.hpp index 1912c75c4..6bf3e834b 100644 --- a/apps/openmw/mwmechanics/autocalcspell.hpp +++ b/apps/openmw/mwmechanics/autocalcspell.hpp @@ -16,6 +16,8 @@ namespace MWMechanics std::vector autoCalcNpcSpells(const int* actorSkills, const int* actorAttributes, const ESM::Race* race); +std::vector autoCalcPlayerSpells(const int* actorSkills, const int* actorAttributes, const ESM::Race* race); + // Helpers bool attrSkillCheck (const ESM::Spell* spell, const int* actorSkills, const int* actorAttributes); diff --git a/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp b/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp index 815b45158..52ae9d12d 100644 --- a/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp +++ b/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp @@ -198,15 +198,6 @@ namespace MWMechanics } // F_PCStart spells - static const float fPCbaseMagickaMult = esmStore.get().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 selectedSpells; - const ESM::Race* race = NULL; if (mRaceSelected) race = esmStore.get().find(player->mRace); @@ -219,61 +210,7 @@ namespace MWMechanics for (int i=0; i &spells = - esmStore.get(); - for (MWWorld::Store::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().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::iterator it = std::find(selectedSpells.begin(), selectedSpells.end(), weakestSpell->mId); - if (it != selectedSpells.end()) - selectedSpells.erase(it); - - minCost = INT_MAX; - for (std::vector::iterator weakIt = selectedSpells.begin(); weakIt != selectedSpells.end(); ++weakIt) - { - const ESM::Spell* testSpell = esmStore.get().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().find("iAutoPCSpellMax")->getInt(); - if (selectedSpells.size() == iAutoPCSpellMax) - reachedLimit = true; - } - } + std::vector selectedSpells = autoCalcPlayerSpells(skills, attributes, race); for (std::vector::iterator it = selectedSpells.begin(); it != selectedSpells.end(); ++it) creatureStats.getSpells().add(*it); diff --git a/apps/openmw/mwrender/npcanimation.cpp b/apps/openmw/mwrender/npcanimation.cpp index 8574939af..d9dd1a89e 100644 --- a/apps/openmw/mwrender/npcanimation.cpp +++ b/apps/openmw/mwrender/npcanimation.cpp @@ -403,6 +403,9 @@ void NpcAnimation::rebuild() { updateNpcBase(); + if (mAlpha != 1.f) + mResourceSystem->getSceneManager()->recreateShaders(mObjectRoot); + MWBase::Environment::get().getMechanicsManager()->forceStateUpdate(mPtr); } @@ -503,10 +506,10 @@ void NpcAnimation::updateNpcBase() if(!isWerewolf) { - if(Misc::StringUtils::lowerCase(mNpc->mRace).find("argonian") != std::string::npos) - addAnimSource("meshes\\xargonian_swimkna.nif"); if(mNpc->mModel.length() > 0) addAnimSource(Misc::ResourceHelpers::correctActorModelPath("meshes\\" + mNpc->mModel, mResourceSystem->getVFS())); + if(Misc::StringUtils::lowerCase(mNpc->mRace).find("argonian") != std::string::npos) + addAnimSource("meshes\\xargonian_swimkna.nif"); } } else