#include "npcstats.hpp" #include #include #include #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), mBounty (0) , mLevelProgress(0), mDisposition(0), mVampire (0), mReputation(0), mWerewolf (false), mWerewolfKills (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; } std::set& MWMechanics::NpcStats::getExpelled() { return mExpelled; } const std::map& MWMechanics::NpcStats::getFactionRanks() const { return mFactionRank; } bool MWMechanics::NpcStats::isSameFaction (const NpcStats& npcStats) const { for (std::map::const_iterator iter (mFactionRank.begin()); iter!=mFactionRank.end(); ++iter) if (npcStats.mFactionRank.find (iter->first)!=npcStats.mFactionRank.end()) return true; return false; } 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"); if (skillFactor==0) return 0; } 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] + "}") % static_cast (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::const_iterator iter = mFactionReputation.find (faction); if (iter==mFactionReputation.end()) return 0; return iter->second; } void MWMechanics::NpcStats::setFactionReputation (const std::string& faction, int value) { mFactionReputation[faction] = value; } bool MWMechanics::NpcStats::isVampire() const { return mVampire; } void MWMechanics::NpcStats::setVampire (bool set) { mVampire = set; } int MWMechanics::NpcStats::getReputation() const { return mReputation; } void MWMechanics::NpcStats::setReputation(int reputation) { mReputation = reputation; } bool MWMechanics::NpcStats::hasSkillsForRank (const std::string& factionId, int rank) const { if (rank<0 || rank>=10) throw std::runtime_error ("rank index out of range"); const ESM::Faction& faction = *MWBase::Environment::get().getWorld()->getStore().get().find (factionId); std::vector skills; for (int i=0; i<6; ++i) skills.push_back (static_cast (getSkill (faction.mData.mSkillID[i]).getModified())); std::sort (skills.begin(), skills.end()); std::vector::const_reverse_iterator iter = skills.rbegin(); const ESM::RankData& rankData = faction.mData.mRankData[rank]; if (*iter=rankData.mSkill2; } bool MWMechanics::NpcStats::isWerewolf() const { return mWerewolf; } void MWMechanics::NpcStats::setWerewolf (bool set) { mWerewolf = set; } int MWMechanics::NpcStats::getWerewolfKills() const { return mWerewolfKills; }