#include "npcstats.hpp" #include #include #include #include #include #include #include "../mwworld/esmstore.hpp" #include "../mwbase/environment.hpp" #include "../mwbase/world.hpp" #include "../mwbase/windowmanager.hpp" #include "../mwbase/soundmanager.hpp" MWMechanics::NpcStats::NpcStats() : mMovementFlags (0), mDrawState (DrawState_Nothing) , mLevelProgress(0) { mSkillIncreases.resize (ESM::Attribute::Length); for (int i=0; i& MWMechanics::NpcStats::getSkill (int index) const { if (index<0 || index>=27) throw std::runtime_error ("skill index out of range"); return mSkill[index]; } MWMechanics::Stat& MWMechanics::NpcStats::getSkill (int index) { if (index<0 || index>=27) throw std::runtime_error ("skill index out of range"); return mSkill[index]; } std::map& MWMechanics::NpcStats::getFactionRanks() { return mFactionRank; } const std::map& MWMechanics::NpcStats::getFactionRanks() const { return mFactionRank; } float MWMechanics::NpcStats::getSkillGain (int skillIndex, const ESM::Class& class_, int usageType, int level) const { if (level<0) level = static_cast (getSkill (skillIndex).getBase()); const ESM::Skill *skill = MWBase::Environment::get().getWorld()->getStore().get().find (skillIndex); float skillFactor = 1; if (usageType>=4) throw std::runtime_error ("skill usage type out of range"); if (usageType>0) { skillFactor = skill->mData.mUseValue[usageType]; if (skillFactor<=0) throw std::runtime_error ("invalid skill gain factor"); } const MWWorld::Store &gmst = MWBase::Environment::get().getWorld()->getStore().get(); float typeFactor = gmst.find ("fMiscSkillBonus")->getFloat(); for (int i=0; i<5; ++i) if (class_.mData.mSkills[i][0]==skillIndex) { typeFactor = gmst.find ("fMinorSkillBonus")->getFloat(); break; } for (int i=0; i<5; ++i) if (class_.mData.mSkills[i][1]==skillIndex) { typeFactor = gmst.find ("fMajorSkillBonus")->getFloat(); break; } if (typeFactor<=0) throw std::runtime_error ("invalid skill type factor"); float specialisationFactor = 1; if (skill->mData.mSpecialization==class_.mData.mSpecialization) { specialisationFactor = gmst.find ("fSpecialSkillBonus")->getFloat(); if (specialisationFactor<=0) throw std::runtime_error ("invalid skill specialisation factor"); } return 1.0 / (level +1) * (1.0 / (skillFactor)) * typeFactor * specialisationFactor; } void MWMechanics::NpcStats::useSkill (int skillIndex, const ESM::Class& class_, int usageType) { float base = getSkill (skillIndex).getBase(); int level = static_cast (base); base += getSkillGain (skillIndex, class_, usageType); if (static_cast (base)!=level) { // skill leveled up increaseSkill(skillIndex, class_, false); } else getSkill (skillIndex).setBase (base); } void MWMechanics::NpcStats::increaseSkill(int skillIndex, const ESM::Class &class_, bool preserveProgress) { float base = getSkill (skillIndex).getBase(); int level = static_cast (base); if (level >= 100) return; if (preserveProgress) base += 1; else base = level+1; // if this is a major or minor skill of the class, increase level progress bool levelProgress = false; for (int i=0; i<2; ++i) for (int j=0; j<5; ++j) { int skill = class_.mData.mSkills[j][i]; if (skill == skillIndex) levelProgress = true; } mLevelProgress += levelProgress; // check the attribute this skill belongs to const ESM::Skill* skill = MWBase::Environment::get().getWorld ()->getStore ().get().find(skillIndex); ++mSkillIncreases[skill->mData.mAttribute]; // Play sound & skill progress notification /// \todo check if character is the player, if levelling is ever implemented for NPCs MWBase::Environment::get().getSoundManager ()->playSound ("skillraise", 1, 1); std::stringstream message; message << boost::format(MWBase::Environment::get().getWindowManager ()->getGameSettingString ("sNotifyMessage39", "")) % std::string("#{" + ESM::Skill::sSkillNameIds[skillIndex] + "}") % base; MWBase::Environment::get().getWindowManager ()->messageBox(message.str(), std::vector()); if (mLevelProgress >= 10) { // levelup is possible now MWBase::Environment::get().getWindowManager ()->messageBox ("#{sLevelUpMsg}", std::vector()); } getSkill (skillIndex).setBase (base); } int MWMechanics::NpcStats::getLevelProgress () const { return mLevelProgress; } void MWMechanics::NpcStats::levelUp() { mLevelProgress -= 10; for (int i=0; i