mirror of
https://github.com/OpenMW/openmw.git
synced 2025-02-28 15:09:43 +00:00
Merge branch 'clickbait' into 'master'
Mostly dehardcode skills See merge request OpenMW/openmw!3112
This commit is contained in:
commit
807893eb45
69 changed files with 543 additions and 646 deletions
|
@ -43,20 +43,13 @@ namespace MWClass
|
||||||
return;
|
return;
|
||||||
|
|
||||||
MWBase::SoundManager* sndMgr = MWBase::Environment::get().getSoundManager();
|
MWBase::SoundManager* sndMgr = MWBase::Environment::get().getSoundManager();
|
||||||
switch (shield->getClass().getEquipmentSkill(*shield))
|
const ESM::RefId skill = shield->getClass().getEquipmentSkill(*shield);
|
||||||
{
|
if (skill == ESM::Skill::LightArmor)
|
||||||
case ESM::Skill::LightArmor:
|
sndMgr->playSound3D(ptr, ESM::RefId::stringRefId("Light Armor Hit"), 1.0f, 1.0f);
|
||||||
sndMgr->playSound3D(ptr, ESM::RefId::stringRefId("Light Armor Hit"), 1.0f, 1.0f);
|
else if (skill == ESM::Skill::MediumArmor)
|
||||||
break;
|
sndMgr->playSound3D(ptr, ESM::RefId::stringRefId("Medium Armor Hit"), 1.0f, 1.0f);
|
||||||
case ESM::Skill::MediumArmor:
|
else if (skill == ESM::Skill::HeavyArmor)
|
||||||
sndMgr->playSound3D(ptr, ESM::RefId::stringRefId("Medium Armor Hit"), 1.0f, 1.0f);
|
sndMgr->playSound3D(ptr, ESM::RefId::stringRefId("Heavy Armor Hit"), 1.0f, 1.0f);
|
||||||
break;
|
|
||||||
case ESM::Skill::HeavyArmor:
|
|
||||||
sndMgr->playSound3D(ptr, ESM::RefId::stringRefId("Heavy Armor Hit"), 1.0f, 1.0f);
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
osg::Vec3f Actor::getRotationVector(const MWWorld::Ptr& ptr) const
|
osg::Vec3f Actor::getRotationVector(const MWWorld::Ptr& ptr) const
|
||||||
|
|
|
@ -112,7 +112,7 @@ namespace MWClass
|
||||||
return std::make_pair(slots_, false);
|
return std::make_pair(slots_, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
int Armor::getEquipmentSkill(const MWWorld::ConstPtr& ptr) const
|
ESM::RefId Armor::getEquipmentSkill(const MWWorld::ConstPtr& ptr) const
|
||||||
{
|
{
|
||||||
const MWWorld::LiveCellRef<ESM::Armor>* ref = ptr.get<ESM::Armor>();
|
const MWWorld::LiveCellRef<ESM::Armor>* ref = ptr.get<ESM::Armor>();
|
||||||
|
|
||||||
|
@ -150,7 +150,7 @@ namespace MWClass
|
||||||
}
|
}
|
||||||
|
|
||||||
if (typeGmst.empty())
|
if (typeGmst.empty())
|
||||||
return -1;
|
return {};
|
||||||
|
|
||||||
const MWWorld::Store<ESM::GameSetting>& gmst
|
const MWWorld::Store<ESM::GameSetting>& gmst
|
||||||
= MWBase::Environment::get().getESMStore()->get<ESM::GameSetting>();
|
= MWBase::Environment::get().getESMStore()->get<ESM::GameSetting>();
|
||||||
|
@ -178,7 +178,7 @@ namespace MWClass
|
||||||
|
|
||||||
const ESM::RefId& Armor::getUpSoundId(const MWWorld::ConstPtr& ptr) const
|
const ESM::RefId& Armor::getUpSoundId(const MWWorld::ConstPtr& ptr) const
|
||||||
{
|
{
|
||||||
int es = getEquipmentSkill(ptr);
|
const ESM::RefId es = getEquipmentSkill(ptr);
|
||||||
static const ESM::RefId lightUp = ESM::RefId::stringRefId("Item Armor Light Up");
|
static const ESM::RefId lightUp = ESM::RefId::stringRefId("Item Armor Light Up");
|
||||||
static const ESM::RefId mediumUp = ESM::RefId::stringRefId("Item Armor Medium Up");
|
static const ESM::RefId mediumUp = ESM::RefId::stringRefId("Item Armor Medium Up");
|
||||||
static const ESM::RefId heavyUp = ESM::RefId::stringRefId("Item Armor Heavy Up");
|
static const ESM::RefId heavyUp = ESM::RefId::stringRefId("Item Armor Heavy Up");
|
||||||
|
@ -193,7 +193,7 @@ namespace MWClass
|
||||||
|
|
||||||
const ESM::RefId& Armor::getDownSoundId(const MWWorld::ConstPtr& ptr) const
|
const ESM::RefId& Armor::getDownSoundId(const MWWorld::ConstPtr& ptr) const
|
||||||
{
|
{
|
||||||
int es = getEquipmentSkill(ptr);
|
const ESM::RefId es = getEquipmentSkill(ptr);
|
||||||
static const ESM::RefId lightDown = ESM::RefId::stringRefId("Item Armor Light Down");
|
static const ESM::RefId lightDown = ESM::RefId::stringRefId("Item Armor Light Down");
|
||||||
static const ESM::RefId mediumDown = ESM::RefId::stringRefId("Item Armor Medium Down");
|
static const ESM::RefId mediumDown = ESM::RefId::stringRefId("Item Armor Medium Down");
|
||||||
static const ESM::RefId heavyDown = ESM::RefId::stringRefId("Item Armor Heavy Down");
|
static const ESM::RefId heavyDown = ESM::RefId::stringRefId("Item Armor Heavy Down");
|
||||||
|
@ -232,7 +232,7 @@ namespace MWClass
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
int armorType = getEquipmentSkill(ptr);
|
const ESM::RefId armorType = getEquipmentSkill(ptr);
|
||||||
if (armorType == ESM::Skill::LightArmor)
|
if (armorType == ESM::Skill::LightArmor)
|
||||||
typeText = "#{sLight}";
|
typeText = "#{sLight}";
|
||||||
else if (armorType == ESM::Skill::MediumArmor)
|
else if (armorType == ESM::Skill::MediumArmor)
|
||||||
|
@ -297,7 +297,7 @@ namespace MWClass
|
||||||
{
|
{
|
||||||
const MWWorld::LiveCellRef<ESM::Armor>* ref = ptr.get<ESM::Armor>();
|
const MWWorld::LiveCellRef<ESM::Armor>* ref = ptr.get<ESM::Armor>();
|
||||||
|
|
||||||
int armorSkillType = getEquipmentSkill(ptr);
|
const ESM::RefId armorSkillType = getEquipmentSkill(ptr);
|
||||||
float armorSkill = actor.getClass().getSkill(actor, armorSkillType);
|
float armorSkill = actor.getClass().getSkill(actor, armorSkillType);
|
||||||
|
|
||||||
int iBaseArmorSkill = MWBase::Environment::get()
|
int iBaseArmorSkill = MWBase::Environment::get()
|
||||||
|
|
|
@ -41,9 +41,7 @@ namespace MWClass
|
||||||
///< \return first: Return IDs of the slot this object can be equipped in; second: can object
|
///< \return first: Return IDs of the slot this object can be equipped in; second: can object
|
||||||
/// stay stacked when equipped?
|
/// stay stacked when equipped?
|
||||||
|
|
||||||
int getEquipmentSkill(const MWWorld::ConstPtr& ptr) const override;
|
ESM::RefId getEquipmentSkill(const MWWorld::ConstPtr& ptr) const override;
|
||||||
/// Return the index of the skill this item corresponds to when equipped or -1, if there is
|
|
||||||
/// no such skill.
|
|
||||||
|
|
||||||
MWGui::ToolTipInfo getToolTipInfo(const MWWorld::ConstPtr& ptr, int count) const override;
|
MWGui::ToolTipInfo getToolTipInfo(const MWWorld::ConstPtr& ptr, int count) const override;
|
||||||
///< @return the content of the tool tip to be displayed. raises exception if the object has no tooltip.
|
///< @return the content of the tool tip to be displayed. raises exception if the object has no tooltip.
|
||||||
|
|
|
@ -101,14 +101,14 @@ namespace MWClass
|
||||||
return std::make_pair(slots_, false);
|
return std::make_pair(slots_, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
int Clothing::getEquipmentSkill(const MWWorld::ConstPtr& ptr) const
|
ESM::RefId Clothing::getEquipmentSkill(const MWWorld::ConstPtr& ptr) const
|
||||||
{
|
{
|
||||||
const MWWorld::LiveCellRef<ESM::Clothing>* ref = ptr.get<ESM::Clothing>();
|
const MWWorld::LiveCellRef<ESM::Clothing>* ref = ptr.get<ESM::Clothing>();
|
||||||
|
|
||||||
if (ref->mBase->mData.mType == ESM::Clothing::Shoes)
|
if (ref->mBase->mData.mType == ESM::Clothing::Shoes)
|
||||||
return ESM::Skill::Unarmored;
|
return ESM::Skill::Unarmored;
|
||||||
|
|
||||||
return -1;
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
int Clothing::getValue(const MWWorld::ConstPtr& ptr) const
|
int Clothing::getValue(const MWWorld::ConstPtr& ptr) const
|
||||||
|
|
|
@ -33,9 +33,7 @@ namespace MWClass
|
||||||
///< \return first: Return IDs of the slot this object can be equipped in; second: can object
|
///< \return first: Return IDs of the slot this object can be equipped in; second: can object
|
||||||
/// stay stacked when equipped?
|
/// stay stacked when equipped?
|
||||||
|
|
||||||
int getEquipmentSkill(const MWWorld::ConstPtr& ptr) const override;
|
ESM::RefId getEquipmentSkill(const MWWorld::ConstPtr& ptr) const override;
|
||||||
/// Return the index of the skill this item corresponds to when equipped or -1, if there is
|
|
||||||
/// no such skill.
|
|
||||||
|
|
||||||
MWGui::ToolTipInfo getToolTipInfo(const MWWorld::ConstPtr& ptr, int count) const override;
|
MWGui::ToolTipInfo getToolTipInfo(const MWWorld::ConstPtr& ptr, int count) const override;
|
||||||
///< @return the content of the tool tip to be displayed. raises exception if the object has no tooltip.
|
///< @return the content of the tool tip to be displayed. raises exception if the object has no tooltip.
|
||||||
|
|
|
@ -762,11 +762,11 @@ namespace MWClass
|
||||||
throw std::runtime_error("Unexpected soundgen type: " + std::string(name));
|
throw std::runtime_error("Unexpected soundgen type: " + std::string(name));
|
||||||
}
|
}
|
||||||
|
|
||||||
float Creature::getSkill(const MWWorld::Ptr& ptr, int skill) const
|
float Creature::getSkill(const MWWorld::Ptr& ptr, ESM::RefId id) const
|
||||||
{
|
{
|
||||||
MWWorld::LiveCellRef<ESM::Creature>* ref = ptr.get<ESM::Creature>();
|
MWWorld::LiveCellRef<ESM::Creature>* ref = ptr.get<ESM::Creature>();
|
||||||
|
|
||||||
const ESM::Skill* skillRecord = MWBase::Environment::get().getESMStore()->get<ESM::Skill>().find(skill);
|
const ESM::Skill* skillRecord = MWBase::Environment::get().getESMStore()->get<ESM::Skill>().find(id);
|
||||||
|
|
||||||
switch (skillRecord->mData.mSpecialization)
|
switch (skillRecord->mData.mSpecialization)
|
||||||
{
|
{
|
||||||
|
|
|
@ -115,7 +115,7 @@ namespace MWClass
|
||||||
bool canSwim(const MWWorld::ConstPtr& ptr) const override;
|
bool canSwim(const MWWorld::ConstPtr& ptr) const override;
|
||||||
bool canWalk(const MWWorld::ConstPtr& ptr) const override;
|
bool canWalk(const MWWorld::ConstPtr& ptr) const override;
|
||||||
|
|
||||||
float getSkill(const MWWorld::Ptr& ptr, int skill) const override;
|
float getSkill(const MWWorld::Ptr& ptr, ESM::RefId id) const override;
|
||||||
|
|
||||||
/// Get a blood texture suitable for \a ptr (see Blood Texture 0-2 in Morrowind.ini)
|
/// Get a blood texture suitable for \a ptr (see Blood Texture 0-2 in Morrowind.ini)
|
||||||
int getBloodTexture(const MWWorld::ConstPtr& ptr) const override;
|
int getBloodTexture(const MWWorld::ConstPtr& ptr) const override;
|
||||||
|
|
|
@ -111,20 +111,18 @@ namespace
|
||||||
{
|
{
|
||||||
float modifierSum = 0;
|
float modifierSum = 0;
|
||||||
|
|
||||||
for (int j = 0; j < ESM::Skill::Length; ++j)
|
for (const ESM::Skill& skill : MWBase::Environment::get().getESMStore()->get<ESM::Skill>())
|
||||||
{
|
{
|
||||||
const ESM::Skill* skill = MWBase::Environment::get().getESMStore()->get<ESM::Skill>().find(j);
|
if (skill.mData.mAttribute != attribute)
|
||||||
|
|
||||||
if (skill->mData.mAttribute != attribute)
|
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
// is this a minor or major skill?
|
// is this a minor or major skill?
|
||||||
float add = 0.2f;
|
float add = 0.2f;
|
||||||
for (const auto& skills : class_->mData.mSkills)
|
for (const auto& skills : class_->mData.mSkills)
|
||||||
{
|
{
|
||||||
if (skills[0] == j)
|
if (skills[0] == skill.mIndex)
|
||||||
add = 0.5;
|
add = 0.5;
|
||||||
if (skills[1] == j)
|
if (skills[1] == skill.mIndex)
|
||||||
add = 1.0;
|
add = 1.0;
|
||||||
}
|
}
|
||||||
modifierSum += add;
|
modifierSum += add;
|
||||||
|
@ -181,15 +179,15 @@ namespace
|
||||||
|
|
||||||
for (const auto& skills : class_->mData.mSkills)
|
for (const auto& skills : class_->mData.mSkills)
|
||||||
{
|
{
|
||||||
int index = skills[i];
|
ESM::RefId id = ESM::Skill::indexToRefId(skills[i]);
|
||||||
if (index >= 0 && index < ESM::Skill::Length)
|
if (!id.empty())
|
||||||
{
|
{
|
||||||
npcStats.getSkill(index).setBase(npcStats.getSkill(index).getBase() + bonus);
|
npcStats.getSkill(id).setBase(npcStats.getSkill(id).getBase() + bonus);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for (int skillIndex = 0; skillIndex < ESM::Skill::Length; ++skillIndex)
|
for (const ESM::Skill& skill : MWBase::Environment::get().getESMStore()->get<ESM::Skill>())
|
||||||
{
|
{
|
||||||
float majorMultiplier = 0.1f;
|
float majorMultiplier = 0.1f;
|
||||||
float specMultiplier = 0.0f;
|
float specMultiplier = 0.0f;
|
||||||
|
@ -198,14 +196,14 @@ namespace
|
||||||
int specBonus = 0;
|
int specBonus = 0;
|
||||||
|
|
||||||
auto bonusIt = std::find_if(race->mData.mBonus.begin(), race->mData.mBonus.end(),
|
auto bonusIt = std::find_if(race->mData.mBonus.begin(), race->mData.mBonus.end(),
|
||||||
[skillIndex](const auto& bonus) { return bonus.mSkill == skillIndex; });
|
[&](const auto& bonus) { return bonus.mSkill == skill.mIndex; });
|
||||||
if (bonusIt != race->mData.mBonus.end())
|
if (bonusIt != race->mData.mBonus.end())
|
||||||
raceBonus = bonusIt->mBonus;
|
raceBonus = bonusIt->mBonus;
|
||||||
|
|
||||||
for (const auto& skills : class_->mData.mSkills)
|
for (const auto& skills : class_->mData.mSkills)
|
||||||
{
|
{
|
||||||
// is this a minor or major skill?
|
// is this a minor or major skill?
|
||||||
if (std::find(skills.begin(), skills.end(), skillIndex) != skills.end())
|
if (std::find(skills.begin(), skills.end(), skill.mIndex) != skills.end())
|
||||||
{
|
{
|
||||||
majorMultiplier = 1.0f;
|
majorMultiplier = 1.0f;
|
||||||
break;
|
break;
|
||||||
|
@ -213,30 +211,25 @@ namespace
|
||||||
}
|
}
|
||||||
|
|
||||||
// is this skill in the same Specialization as the class?
|
// is this skill in the same Specialization as the class?
|
||||||
const ESM::Skill* skill = MWBase::Environment::get().getESMStore()->get<ESM::Skill>().find(skillIndex);
|
if (skill.mData.mSpecialization == class_->mData.mSpecialization)
|
||||||
if (skill->mData.mSpecialization == class_->mData.mSpecialization)
|
|
||||||
{
|
{
|
||||||
specMultiplier = 0.5f;
|
specMultiplier = 0.5f;
|
||||||
specBonus = 5;
|
specBonus = 5;
|
||||||
}
|
}
|
||||||
|
|
||||||
npcStats.getSkill(skillIndex)
|
npcStats.getSkill(skill.mId).setBase(
|
||||||
.setBase(std::min(round_ieee_754(npcStats.getSkill(skillIndex).getBase() + 5 + raceBonus + specBonus
|
std::min(round_ieee_754(npcStats.getSkill(skill.mId).getBase() + 5 + raceBonus + specBonus
|
||||||
+ (int(level) - 1) * (majorMultiplier + specMultiplier)),
|
+ (int(level) - 1) * (majorMultiplier + specMultiplier)),
|
||||||
100)); // Must gracefully handle level 0
|
100)); // Must gracefully handle level 0
|
||||||
}
|
}
|
||||||
|
|
||||||
int skills[ESM::Skill::Length];
|
|
||||||
for (int i = 0; i < ESM::Skill::Length; ++i)
|
|
||||||
skills[i] = npcStats.getSkill(i).getBase();
|
|
||||||
|
|
||||||
int attributes[ESM::Attribute::Length];
|
int attributes[ESM::Attribute::Length];
|
||||||
for (int i = 0; i < ESM::Attribute::Length; ++i)
|
for (int i = 0; i < ESM::Attribute::Length; ++i)
|
||||||
attributes[i] = npcStats.getAttribute(i).getBase();
|
attributes[i] = npcStats.getAttribute(i).getBase();
|
||||||
|
|
||||||
if (!spellsInitialised)
|
if (!spellsInitialised)
|
||||||
{
|
{
|
||||||
std::vector<ESM::RefId> spells = MWMechanics::autoCalcNpcSpells(skills, attributes, race);
|
std::vector<ESM::RefId> spells = MWMechanics::autoCalcNpcSpells(npcStats.getSkills(), attributes, race);
|
||||||
npcStats.getSpells().addAllToInstance(spells);
|
npcStats.getSpells().addAllToInstance(spells);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -315,7 +308,7 @@ namespace MWClass
|
||||||
gold = ref->mBase->mNpdt.mGold;
|
gold = ref->mBase->mNpdt.mGold;
|
||||||
|
|
||||||
for (size_t i = 0; i < ref->mBase->mNpdt.mSkills.size(); ++i)
|
for (size_t i = 0; i < ref->mBase->mNpdt.mSkills.size(); ++i)
|
||||||
data->mNpcStats.getSkill(i).setBase(ref->mBase->mNpdt.mSkills[i]);
|
data->mNpcStats.getSkill(ESM::Skill::indexToRefId(i)).setBase(ref->mBase->mNpdt.mSkills[i]);
|
||||||
|
|
||||||
data->mNpcStats.setAttribute(ESM::Attribute::Strength, ref->mBase->mNpdt.mStrength);
|
data->mNpcStats.setAttribute(ESM::Attribute::Strength, ref->mBase->mNpdt.mStrength);
|
||||||
data->mNpcStats.setAttribute(ESM::Attribute::Intelligence, ref->mBase->mNpdt.mIntelligence);
|
data->mNpcStats.setAttribute(ESM::Attribute::Intelligence, ref->mBase->mNpdt.mIntelligence);
|
||||||
|
@ -589,7 +582,7 @@ namespace MWClass
|
||||||
victim = result.first;
|
victim = result.first;
|
||||||
hitPosition = result.second;
|
hitPosition = result.second;
|
||||||
|
|
||||||
int weapskill = ESM::Skill::HandToHand;
|
ESM::RefId weapskill = ESM::Skill::HandToHand;
|
||||||
if (!weapon.isEmpty())
|
if (!weapon.isEmpty())
|
||||||
weapskill = weapon.getClass().getEquipmentSkill(weapon);
|
weapskill = weapon.getClass().getEquipmentSkill(weapon);
|
||||||
|
|
||||||
|
@ -658,7 +651,7 @@ namespace MWClass
|
||||||
|
|
||||||
if (ptr == MWMechanics::getPlayer())
|
if (ptr == MWMechanics::getPlayer())
|
||||||
{
|
{
|
||||||
int weapskill = ESM::Skill::HandToHand;
|
ESM::RefId weapskill = ESM::Skill::HandToHand;
|
||||||
if (!weapon.isEmpty())
|
if (!weapon.isEmpty())
|
||||||
weapskill = weapon.getClass().getEquipmentSkill(weapon);
|
weapskill = weapon.getClass().getEquipmentSkill(weapon);
|
||||||
skillUsageSucceeded(ptr, weapskill, 0);
|
skillUsageSucceeded(ptr, weapskill, 0);
|
||||||
|
@ -849,21 +842,16 @@ namespace MWClass
|
||||||
armor = *inv.unequipItem(armor);
|
armor = *inv.unequipItem(armor);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ESM::RefId skill = armor.getClass().getEquipmentSkill(armor);
|
||||||
if (ptr == MWMechanics::getPlayer())
|
if (ptr == MWMechanics::getPlayer())
|
||||||
skillUsageSucceeded(ptr, armor.getClass().getEquipmentSkill(armor), 0);
|
skillUsageSucceeded(ptr, skill, 0);
|
||||||
|
|
||||||
switch (armor.getClass().getEquipmentSkill(armor))
|
if (skill == ESM::Skill::LightArmor)
|
||||||
{
|
sndMgr->playSound3D(ptr, ESM::RefId::stringRefId("Light Armor Hit"), 1.0f, 1.0f);
|
||||||
case ESM::Skill::LightArmor:
|
else if (skill == ESM::Skill::MediumArmor)
|
||||||
sndMgr->playSound3D(ptr, ESM::RefId::stringRefId("Light Armor Hit"), 1.0f, 1.0f);
|
sndMgr->playSound3D(ptr, ESM::RefId::stringRefId("Medium Armor Hit"), 1.0f, 1.0f);
|
||||||
break;
|
else if (skill == ESM::Skill::HeavyArmor)
|
||||||
case ESM::Skill::MediumArmor:
|
sndMgr->playSound3D(ptr, ESM::RefId::stringRefId("Heavy Armor Hit"), 1.0f, 1.0f);
|
||||||
sndMgr->playSound3D(ptr, ESM::RefId::stringRefId("Medium Armor Hit"), 1.0f, 1.0f);
|
|
||||||
break;
|
|
||||||
case ESM::Skill::HeavyArmor:
|
|
||||||
sndMgr->playSound3D(ptr, ESM::RefId::stringRefId("Heavy Armor Hit"), 1.0f, 1.0f);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
else if (ptr == MWMechanics::getPlayer())
|
else if (ptr == MWMechanics::getPlayer())
|
||||||
skillUsageSucceeded(ptr, ESM::Skill::Unarmored, 0);
|
skillUsageSucceeded(ptr, ESM::Skill::Unarmored, 0);
|
||||||
|
@ -1161,7 +1149,7 @@ namespace MWClass
|
||||||
return cast.cast(recordId);
|
return cast.cast(recordId);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Npc::skillUsageSucceeded(const MWWorld::Ptr& ptr, int skill, int usageType, float extraFactor) const
|
void Npc::skillUsageSucceeded(const MWWorld::Ptr& ptr, ESM::RefId skill, int usageType, float extraFactor) const
|
||||||
{
|
{
|
||||||
MWMechanics::NpcStats& stats = getNpcStats(ptr);
|
MWMechanics::NpcStats& stats = getNpcStats(ptr);
|
||||||
|
|
||||||
|
@ -1311,18 +1299,13 @@ namespace MWClass
|
||||||
if (boots == inv.end() || boots->getType() != ESM::Armor::sRecordId)
|
if (boots == inv.end() || boots->getType() != ESM::Armor::sRecordId)
|
||||||
return (name == "left") ? footBareLeft : footBareRight;
|
return (name == "left") ? footBareLeft : footBareRight;
|
||||||
|
|
||||||
switch (boots->getClass().getEquipmentSkill(*boots))
|
ESM::RefId skill = boots->getClass().getEquipmentSkill(*boots);
|
||||||
{
|
if (skill == ESM::Skill::LightArmor)
|
||||||
case ESM::Skill::LightArmor:
|
return (name == "left") ? footLightLeft : footLightRight;
|
||||||
return (name == "left") ? footLightLeft : footLightRight;
|
else if (skill == ESM::Skill::MediumArmor)
|
||||||
break;
|
return (name == "left") ? footMediumLeft : footMediumRight;
|
||||||
case ESM::Skill::MediumArmor:
|
else if (skill == ESM::Skill::HeavyArmor)
|
||||||
return (name == "left") ? footMediumLeft : footMediumRight;
|
return (name == "left") ? footHeavyLeft : footHeavyRight;
|
||||||
break;
|
|
||||||
case ESM::Skill::HeavyArmor:
|
|
||||||
return (name == "left") ? footHeavyLeft : footHeavyRight;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return ESM::RefId();
|
return ESM::RefId();
|
||||||
}
|
}
|
||||||
|
@ -1355,9 +1338,9 @@ namespace MWClass
|
||||||
return MWWorld::Ptr(cell.insert(ref), &cell);
|
return MWWorld::Ptr(cell.insert(ref), &cell);
|
||||||
}
|
}
|
||||||
|
|
||||||
float Npc::getSkill(const MWWorld::Ptr& ptr, int skill) const
|
float Npc::getSkill(const MWWorld::Ptr& ptr, ESM::RefId id) const
|
||||||
{
|
{
|
||||||
return getNpcStats(ptr).getSkill(skill).getModified();
|
return getNpcStats(ptr).getSkill(id).getModified();
|
||||||
}
|
}
|
||||||
|
|
||||||
int Npc::getBloodTexture(const MWWorld::ConstPtr& ptr) const
|
int Npc::getBloodTexture(const MWWorld::ConstPtr& ptr) const
|
||||||
|
|
|
@ -120,7 +120,7 @@ namespace MWClass
|
||||||
/// @param rendering Indicates if the scale to adjust is for the rendering mesh, or for the collision mesh
|
/// @param rendering Indicates if the scale to adjust is for the rendering mesh, or for the collision mesh
|
||||||
|
|
||||||
void skillUsageSucceeded(
|
void skillUsageSucceeded(
|
||||||
const MWWorld::Ptr& ptr, int skill, int usageType, float extraFactor = 1.f) const override;
|
const MWWorld::Ptr& ptr, ESM::RefId skill, int usageType, float extraFactor = 1.f) const override;
|
||||||
///< Inform actor \a ptr that a skill use has succeeded.
|
///< Inform actor \a ptr that a skill use has succeeded.
|
||||||
|
|
||||||
bool isEssential(const MWWorld::ConstPtr& ptr) const override;
|
bool isEssential(const MWWorld::ConstPtr& ptr) const override;
|
||||||
|
@ -134,7 +134,7 @@ namespace MWClass
|
||||||
|
|
||||||
std::string getModel(const MWWorld::ConstPtr& ptr) const override;
|
std::string getModel(const MWWorld::ConstPtr& ptr) const override;
|
||||||
|
|
||||||
float getSkill(const MWWorld::Ptr& ptr, int skill) const override;
|
float getSkill(const MWWorld::Ptr& ptr, ESM::RefId id) const override;
|
||||||
|
|
||||||
/// Get a blood texture suitable for \a ptr (see Blood Texture 0-2 in Morrowind.ini)
|
/// Get a blood texture suitable for \a ptr (see Blood Texture 0-2 in Morrowind.ini)
|
||||||
int getBloodTexture(const MWWorld::ConstPtr& ptr) const override;
|
int getBloodTexture(const MWWorld::ConstPtr& ptr) const override;
|
||||||
|
|
|
@ -108,7 +108,7 @@ namespace MWClass
|
||||||
return std::make_pair(slots_, stack);
|
return std::make_pair(slots_, stack);
|
||||||
}
|
}
|
||||||
|
|
||||||
int Weapon::getEquipmentSkill(const MWWorld::ConstPtr& ptr) const
|
ESM::RefId Weapon::getEquipmentSkill(const MWWorld::ConstPtr& ptr) const
|
||||||
{
|
{
|
||||||
const MWWorld::LiveCellRef<ESM::Weapon>* ref = ptr.get<ESM::Weapon>();
|
const MWWorld::LiveCellRef<ESM::Weapon>* ref = ptr.get<ESM::Weapon>();
|
||||||
int type = ref->mBase->mData.mType;
|
int type = ref->mBase->mData.mType;
|
||||||
|
|
|
@ -42,9 +42,7 @@ namespace MWClass
|
||||||
///< \return first: Return IDs of the slot this object can be equipped in; second: can object
|
///< \return first: Return IDs of the slot this object can be equipped in; second: can object
|
||||||
/// stay stacked when equipped?
|
/// stay stacked when equipped?
|
||||||
|
|
||||||
int getEquipmentSkill(const MWWorld::ConstPtr& ptr) const override;
|
ESM::RefId getEquipmentSkill(const MWWorld::ConstPtr& ptr) const override;
|
||||||
/// Return the index of the skill this item corresponds to when equipped or -1, if there is
|
|
||||||
/// no such skill.
|
|
||||||
|
|
||||||
int getValue(const MWWorld::ConstPtr& ptr) const override;
|
int getValue(const MWWorld::ConstPtr& ptr) const override;
|
||||||
///< Return trade value of the object. Throws an exception, if the object can't be traded.
|
///< Return trade value of the object. Throws an exception, if the object can't be traded.
|
||||||
|
|
|
@ -5,6 +5,7 @@
|
||||||
#include <components/esm3/loadcrea.hpp>
|
#include <components/esm3/loadcrea.hpp>
|
||||||
#include <components/esm3/loadfact.hpp>
|
#include <components/esm3/loadfact.hpp>
|
||||||
#include <components/esm3/loadmgef.hpp>
|
#include <components/esm3/loadmgef.hpp>
|
||||||
|
#include <components/esm3/loadskil.hpp>
|
||||||
|
|
||||||
#include "../mwbase/dialoguemanager.hpp"
|
#include "../mwbase/dialoguemanager.hpp"
|
||||||
#include "../mwbase/environment.hpp"
|
#include "../mwbase/environment.hpp"
|
||||||
|
@ -385,9 +386,10 @@ int MWDialogue::Filter::getSelectStructInteger(const SelectWrapper& select) cons
|
||||||
return player.getClass().getCreatureStats(player).getAttribute(select.getArgument()).getModified();
|
return player.getClass().getCreatureStats(player).getAttribute(select.getArgument()).getModified();
|
||||||
|
|
||||||
case SelectWrapper::Function_PcSkill:
|
case SelectWrapper::Function_PcSkill:
|
||||||
|
{
|
||||||
return static_cast<int>(player.getClass().getNpcStats(player).getSkill(select.getArgument()).getModified());
|
ESM::RefId skill = ESM::Skill::indexToRefId(select.getArgument());
|
||||||
|
return static_cast<int>(player.getClass().getNpcStats(player).getSkill(skill).getModified());
|
||||||
|
}
|
||||||
case SelectWrapper::Function_FriendlyHit:
|
case SelectWrapper::Function_FriendlyHit:
|
||||||
{
|
{
|
||||||
int hits = mActor.getClass().getCreatureStats(mActor).getFriendlyHits();
|
int hits = mActor.getClass().getCreatureStats(mActor).getFriendlyHits();
|
||||||
|
|
|
@ -99,7 +99,7 @@ namespace MWGui
|
||||||
mPlayerAttributes.emplace(attribute.mId, MWMechanics::AttributeValue());
|
mPlayerAttributes.emplace(attribute.mId, MWMechanics::AttributeValue());
|
||||||
|
|
||||||
for (const auto& skill : store.get<ESM::Skill>())
|
for (const auto& skill : store.get<ESM::Skill>())
|
||||||
mPlayerSkillValues.emplace(skill.second.mIndex, MWMechanics::SkillValue());
|
mPlayerSkillValues.emplace(skill.mId, MWMechanics::SkillValue());
|
||||||
}
|
}
|
||||||
|
|
||||||
void CharacterCreation::setValue(std::string_view id, const MWMechanics::AttributeValue& value)
|
void CharacterCreation::setValue(std::string_view id, const MWMechanics::AttributeValue& value)
|
||||||
|
@ -138,14 +138,14 @@ namespace MWGui
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void CharacterCreation::setValue(const ESM::Skill::SkillEnum parSkill, const MWMechanics::SkillValue& value)
|
void CharacterCreation::setValue(ESM::RefId id, const MWMechanics::SkillValue& value)
|
||||||
{
|
{
|
||||||
mPlayerSkillValues[parSkill] = value;
|
mPlayerSkillValues[id] = value;
|
||||||
if (mReviewDialog)
|
if (mReviewDialog)
|
||||||
mReviewDialog->setSkillValue(parSkill, value);
|
mReviewDialog->setSkillValue(id, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
void CharacterCreation::configureSkills(const SkillList& major, const SkillList& minor)
|
void CharacterCreation::configureSkills(const std::vector<ESM::RefId>& major, const std::vector<ESM::RefId>& minor)
|
||||||
{
|
{
|
||||||
if (mReviewDialog)
|
if (mReviewDialog)
|
||||||
mReviewDialog->configureSkills(major, minor);
|
mReviewDialog->configureSkills(major, minor);
|
||||||
|
@ -275,10 +275,9 @@ namespace MWGui
|
||||||
mReviewDialog->setAttribute(
|
mReviewDialog->setAttribute(
|
||||||
static_cast<ESM::Attribute::AttributeID>(attributePair.first), attributePair.second);
|
static_cast<ESM::Attribute::AttributeID>(attributePair.first), attributePair.second);
|
||||||
}
|
}
|
||||||
for (auto& skillPair : mPlayerSkillValues)
|
for (const auto& [skill, value] : mPlayerSkillValues)
|
||||||
{
|
{
|
||||||
mReviewDialog->setSkillValue(
|
mReviewDialog->setSkillValue(skill, value);
|
||||||
static_cast<ESM::Skill::SkillEnum>(skillPair.first), skillPair.second);
|
|
||||||
}
|
}
|
||||||
mReviewDialog->configureSkills(mPlayerMajorSkills, mPlayerMinorSkills);
|
mReviewDialog->configureSkills(mPlayerMajorSkills, mPlayerMinorSkills);
|
||||||
|
|
||||||
|
@ -476,14 +475,14 @@ namespace MWGui
|
||||||
assert(attributes.size() == klass.mData.mAttribute.size());
|
assert(attributes.size() == klass.mData.mAttribute.size());
|
||||||
std::copy(attributes.begin(), attributes.end(), klass.mData.mAttribute.begin());
|
std::copy(attributes.begin(), attributes.end(), klass.mData.mAttribute.begin());
|
||||||
|
|
||||||
std::vector<ESM::Skill::SkillEnum> majorSkills = mCreateClassDialog->getMajorSkills();
|
std::vector<ESM::RefId> majorSkills = mCreateClassDialog->getMajorSkills();
|
||||||
std::vector<ESM::Skill::SkillEnum> minorSkills = mCreateClassDialog->getMinorSkills();
|
std::vector<ESM::RefId> minorSkills = mCreateClassDialog->getMinorSkills();
|
||||||
assert(majorSkills.size() >= klass.mData.mSkills.size());
|
assert(majorSkills.size() >= klass.mData.mSkills.size());
|
||||||
assert(minorSkills.size() >= klass.mData.mSkills.size());
|
assert(minorSkills.size() >= klass.mData.mSkills.size());
|
||||||
for (size_t i = 0; i < klass.mData.mSkills.size(); ++i)
|
for (size_t i = 0; i < klass.mData.mSkills.size(); ++i)
|
||||||
{
|
{
|
||||||
klass.mData.mSkills[i][1] = majorSkills[i];
|
klass.mData.mSkills[i][1] = majorSkills[i].getIf<ESM::IndexRefId>()->getValue();
|
||||||
klass.mData.mSkills[i][0] = minorSkills[i];
|
klass.mData.mSkills[i][0] = minorSkills[i].getIf<ESM::IndexRefId>()->getValue();
|
||||||
}
|
}
|
||||||
|
|
||||||
MWBase::Environment::get().getMechanicsManager()->setPlayerClass(klass);
|
MWBase::Environment::get().getMechanicsManager()->setPlayerClass(klass);
|
||||||
|
|
|
@ -38,8 +38,6 @@ namespace MWGui
|
||||||
class CharacterCreation : public StatsListener
|
class CharacterCreation : public StatsListener
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
typedef std::vector<int> SkillList;
|
|
||||||
|
|
||||||
CharacterCreation(osg::Group* parent, Resource::ResourceSystem* resourceSystem);
|
CharacterCreation(osg::Group* parent, Resource::ResourceSystem* resourceSystem);
|
||||||
virtual ~CharacterCreation();
|
virtual ~CharacterCreation();
|
||||||
|
|
||||||
|
@ -48,8 +46,8 @@ namespace MWGui
|
||||||
|
|
||||||
void setValue(std::string_view id, const MWMechanics::AttributeValue& value) override;
|
void setValue(std::string_view id, const MWMechanics::AttributeValue& value) override;
|
||||||
void setValue(std::string_view id, const MWMechanics::DynamicStat<float>& value) override;
|
void setValue(std::string_view id, const MWMechanics::DynamicStat<float>& value) override;
|
||||||
void setValue(const ESM::Skill::SkillEnum parSkill, const MWMechanics::SkillValue& value) override;
|
void setValue(ESM::RefId id, const MWMechanics::SkillValue& value) override;
|
||||||
void configureSkills(const SkillList& major, const SkillList& minor) override;
|
void configureSkills(const std::vector<ESM::RefId>& major, const std::vector<ESM::RefId>& minor) override;
|
||||||
|
|
||||||
void onFrame(float duration);
|
void onFrame(float duration);
|
||||||
|
|
||||||
|
@ -57,9 +55,9 @@ namespace MWGui
|
||||||
osg::Group* mParent;
|
osg::Group* mParent;
|
||||||
Resource::ResourceSystem* mResourceSystem;
|
Resource::ResourceSystem* mResourceSystem;
|
||||||
|
|
||||||
SkillList mPlayerMajorSkills, mPlayerMinorSkills;
|
std::vector<ESM::RefId> mPlayerMajorSkills, mPlayerMinorSkills;
|
||||||
std::map<int, MWMechanics::AttributeValue> mPlayerAttributes;
|
std::map<int, MWMechanics::AttributeValue> mPlayerAttributes;
|
||||||
std::map<int, MWMechanics::SkillValue> mPlayerSkillValues;
|
std::map<ESM::RefId, MWMechanics::SkillValue> mPlayerSkillValues;
|
||||||
|
|
||||||
// Dialogs
|
// Dialogs
|
||||||
std::unique_ptr<TextInputDialog> mNameDialog;
|
std::unique_ptr<TextInputDialog> mNameDialog;
|
||||||
|
|
|
@ -3,6 +3,7 @@
|
||||||
#include <MyGUI_Gui.h>
|
#include <MyGUI_Gui.h>
|
||||||
#include <MyGUI_ImageBox.h>
|
#include <MyGUI_ImageBox.h>
|
||||||
#include <MyGUI_ListBox.h>
|
#include <MyGUI_ListBox.h>
|
||||||
|
#include <MyGUI_ScrollView.h>
|
||||||
|
|
||||||
#include "../mwbase/environment.hpp"
|
#include "../mwbase/environment.hpp"
|
||||||
#include "../mwbase/windowmanager.hpp"
|
#include "../mwbase/windowmanager.hpp"
|
||||||
|
@ -266,10 +267,12 @@ namespace MWGui
|
||||||
|
|
||||||
for (size_t i = 0; i < klass->mData.mSkills.size(); ++i)
|
for (size_t i = 0; i < klass->mData.mSkills.size(); ++i)
|
||||||
{
|
{
|
||||||
mMinorSkill[i]->setSkillNumber(klass->mData.mSkills[i][0]);
|
ESM::RefId minor = ESM::Skill::indexToRefId(klass->mData.mSkills[i][0]);
|
||||||
mMajorSkill[i]->setSkillNumber(klass->mData.mSkills[i][1]);
|
ESM::RefId major = ESM::Skill::indexToRefId(klass->mData.mSkills[i][1]);
|
||||||
ToolTips::createSkillToolTip(mMinorSkill[i], klass->mData.mSkills[i][0]);
|
mMinorSkill[i]->setSkillId(minor);
|
||||||
ToolTips::createSkillToolTip(mMajorSkill[i], klass->mData.mSkills[i][1]);
|
mMajorSkill[i]->setSkillId(major);
|
||||||
|
ToolTips::createSkillToolTip(mMinorSkill[i], minor);
|
||||||
|
ToolTips::createSkillToolTip(mMajorSkill[i], major);
|
||||||
}
|
}
|
||||||
|
|
||||||
setClassImage(mClassImage, mCurrentClassId);
|
setClassImage(mClassImage, mCurrentClassId);
|
||||||
|
@ -514,24 +517,24 @@ namespace MWGui
|
||||||
return v;
|
return v;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector<ESM::Skill::SkillEnum> CreateClassDialog::getMajorSkills() const
|
std::vector<ESM::RefId> CreateClassDialog::getMajorSkills() const
|
||||||
{
|
{
|
||||||
std::vector<ESM::Skill::SkillEnum> v;
|
std::vector<ESM::RefId> v;
|
||||||
v.reserve(5);
|
v.reserve(mMajorSkill.size());
|
||||||
for (int i = 0; i < 5; i++)
|
for (const auto& widget : mMajorSkill)
|
||||||
{
|
{
|
||||||
v.push_back(mMajorSkill[i]->getSkillId());
|
v.push_back(widget->getSkillId());
|
||||||
}
|
}
|
||||||
return v;
|
return v;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector<ESM::Skill::SkillEnum> CreateClassDialog::getMinorSkills() const
|
std::vector<ESM::RefId> CreateClassDialog::getMinorSkills() const
|
||||||
{
|
{
|
||||||
std::vector<ESM::Skill::SkillEnum> v;
|
std::vector<ESM::RefId> v;
|
||||||
v.reserve(5);
|
v.reserve(mMinorSkill.size());
|
||||||
for (int i = 0; i < 5; i++)
|
for (const auto& widget : mMinorSkill)
|
||||||
{
|
{
|
||||||
v.push_back(mMinorSkill[i]->getSkillId());
|
v.push_back(widget->getSkillId());
|
||||||
}
|
}
|
||||||
return v;
|
return v;
|
||||||
}
|
}
|
||||||
|
@ -624,7 +627,7 @@ namespace MWGui
|
||||||
|
|
||||||
void CreateClassDialog::onSkillSelected()
|
void CreateClassDialog::onSkillSelected()
|
||||||
{
|
{
|
||||||
ESM::Skill::SkillEnum id = mSkillDialog->getSkillId();
|
ESM::RefId id = mSkillDialog->getSkillId();
|
||||||
|
|
||||||
// Avoid duplicate skills by swapping any skill field that matches the selected one
|
// Avoid duplicate skills by swapping any skill field that matches the selected one
|
||||||
for (Widgets::MWSkillPtr& skill : mSkills)
|
for (Widgets::MWSkillPtr& skill : mSkills)
|
||||||
|
@ -793,43 +796,33 @@ namespace MWGui
|
||||||
// Centre dialog
|
// Centre dialog
|
||||||
center();
|
center();
|
||||||
|
|
||||||
for (int i = 0; i < 9; i++)
|
std::array<std::pair<MyGUI::ScrollView*, MyGUI::IntCoord>, 3> specializations;
|
||||||
|
getWidget(specializations[ESM::Class::Combat].first, "CombatSkills");
|
||||||
|
getWidget(specializations[ESM::Class::Magic].first, "MagicSkills");
|
||||||
|
getWidget(specializations[ESM::Class::Stealth].first, "StealthSkills");
|
||||||
|
for (auto& [widget, coord] : specializations)
|
||||||
{
|
{
|
||||||
char theIndex = '0' + i;
|
coord.width = widget->getCoord().width;
|
||||||
getWidget(mCombatSkill[i], std::string("CombatSkill").append(1, theIndex));
|
coord.height = 18;
|
||||||
getWidget(mMagicSkill[i], std::string("MagicSkill").append(1, theIndex));
|
while (widget->getChildCount() > 0)
|
||||||
getWidget(mStealthSkill[i], std::string("StealthSkill").append(1, theIndex));
|
MyGUI::Gui::getInstance().destroyWidget(widget->getChildAt(0));
|
||||||
}
|
}
|
||||||
|
for (const ESM::Skill& skill : MWBase::Environment::get().getESMStore()->get<ESM::Skill>())
|
||||||
struct
|
|
||||||
{
|
{
|
||||||
Widgets::MWSkillPtr widget;
|
auto& [widget, coord] = specializations[skill.mData.mSpecialization];
|
||||||
ESM::Skill::SkillEnum skillId;
|
auto* skillWidget
|
||||||
} mSkills[3][9]
|
= widget->createWidget<Widgets::MWSkill>("MW_StatNameButton", coord, MyGUI::Align::Default);
|
||||||
= { { { mCombatSkill[0], ESM::Skill::Block }, { mCombatSkill[1], ESM::Skill::Armorer },
|
coord.top += coord.height;
|
||||||
{ mCombatSkill[2], ESM::Skill::MediumArmor }, { mCombatSkill[3], ESM::Skill::HeavyArmor },
|
skillWidget->setSkillId(skill.mId);
|
||||||
{ mCombatSkill[4], ESM::Skill::BluntWeapon }, { mCombatSkill[5], ESM::Skill::LongBlade },
|
skillWidget->eventClicked += MyGUI::newDelegate(this, &SelectSkillDialog::onSkillClicked);
|
||||||
{ mCombatSkill[6], ESM::Skill::Axe }, { mCombatSkill[7], ESM::Skill::Spear },
|
ToolTips::createSkillToolTip(skillWidget, skill.mId);
|
||||||
{ mCombatSkill[8], ESM::Skill::Athletics } },
|
}
|
||||||
{ { mMagicSkill[0], ESM::Skill::Enchant }, { mMagicSkill[1], ESM::Skill::Destruction },
|
for (const auto& [widget, coord] : specializations)
|
||||||
{ mMagicSkill[2], ESM::Skill::Alteration }, { mMagicSkill[3], ESM::Skill::Illusion },
|
|
||||||
{ mMagicSkill[4], ESM::Skill::Conjuration }, { mMagicSkill[5], ESM::Skill::Mysticism },
|
|
||||||
{ mMagicSkill[6], ESM::Skill::Restoration }, { mMagicSkill[7], ESM::Skill::Alchemy },
|
|
||||||
{ mMagicSkill[8], ESM::Skill::Unarmored } },
|
|
||||||
{ { mStealthSkill[0], ESM::Skill::Security }, { mStealthSkill[1], ESM::Skill::Sneak },
|
|
||||||
{ mStealthSkill[2], ESM::Skill::Acrobatics }, { mStealthSkill[3], ESM::Skill::LightArmor },
|
|
||||||
{ mStealthSkill[4], ESM::Skill::ShortBlade }, { mStealthSkill[5], ESM::Skill::Marksman },
|
|
||||||
{ mStealthSkill[6], ESM::Skill::Mercantile }, { mStealthSkill[7], ESM::Skill::Speechcraft },
|
|
||||||
{ mStealthSkill[8], ESM::Skill::HandToHand } } };
|
|
||||||
|
|
||||||
for (int spec = 0; spec < 3; ++spec)
|
|
||||||
{
|
{
|
||||||
for (int i = 0; i < 9; ++i)
|
widget->setVisibleVScroll(false);
|
||||||
{
|
widget->setCanvasSize(MyGUI::IntSize(widget->getWidth(), std::max(widget->getHeight(), coord.top)));
|
||||||
mSkills[spec][i].widget->setSkillId(mSkills[spec][i].skillId);
|
widget->setVisibleVScroll(true);
|
||||||
mSkills[spec][i].widget->eventClicked += MyGUI::newDelegate(this, &SelectSkillDialog::onSkillClicked);
|
widget->setViewOffset(MyGUI::IntPoint());
|
||||||
ToolTips::createSkillToolTip(mSkills[spec][i].widget, mSkills[spec][i].widget->getSkillId());
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
MyGUI::Button* cancelButton;
|
MyGUI::Button* cancelButton;
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
#ifndef MWGUI_CLASS_H
|
#ifndef MWGUI_CLASS_H
|
||||||
#define MWGUI_CLASS_H
|
#define MWGUI_CLASS_H
|
||||||
|
|
||||||
|
#include <array>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
|
|
||||||
#include <MyGUI_EditBox.h>
|
#include <MyGUI_EditBox.h>
|
||||||
|
@ -218,7 +219,7 @@ namespace MWGui
|
||||||
|
|
||||||
bool exit() override;
|
bool exit() override;
|
||||||
|
|
||||||
ESM::Skill::SkillEnum getSkillId() const { return mSkillId; }
|
ESM::RefId getSkillId() const { return mSkillId; }
|
||||||
|
|
||||||
// Events
|
// Events
|
||||||
typedef MyGUI::delegates::CMultiDelegate0 EventHandle_Void;
|
typedef MyGUI::delegates::CMultiDelegate0 EventHandle_Void;
|
||||||
|
@ -238,11 +239,7 @@ namespace MWGui
|
||||||
void onCancelClicked(MyGUI::Widget* _sender);
|
void onCancelClicked(MyGUI::Widget* _sender);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
Widgets::MWSkillPtr mCombatSkill[9];
|
ESM::RefId mSkillId;
|
||||||
Widgets::MWSkillPtr mMagicSkill[9];
|
|
||||||
Widgets::MWSkillPtr mStealthSkill[9];
|
|
||||||
|
|
||||||
ESM::Skill::SkillEnum mSkillId;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
class DescriptionDialog : public WindowModal
|
class DescriptionDialog : public WindowModal
|
||||||
|
@ -278,8 +275,8 @@ namespace MWGui
|
||||||
std::string getDescription() const;
|
std::string getDescription() const;
|
||||||
ESM::Class::Specialization getSpecializationId() const;
|
ESM::Class::Specialization getSpecializationId() const;
|
||||||
std::vector<int> getFavoriteAttributes() const;
|
std::vector<int> getFavoriteAttributes() const;
|
||||||
std::vector<ESM::Skill::SkillEnum> getMajorSkills() const;
|
std::vector<ESM::RefId> getMajorSkills() const;
|
||||||
std::vector<ESM::Skill::SkillEnum> getMinorSkills() const;
|
std::vector<ESM::RefId> getMinorSkills() const;
|
||||||
|
|
||||||
void setNextButtonShow(bool shown);
|
void setNextButtonShow(bool shown);
|
||||||
|
|
||||||
|
@ -318,8 +315,8 @@ namespace MWGui
|
||||||
MyGUI::EditBox* mEditName;
|
MyGUI::EditBox* mEditName;
|
||||||
MyGUI::TextBox* mSpecializationName;
|
MyGUI::TextBox* mSpecializationName;
|
||||||
Widgets::MWAttributePtr mFavoriteAttribute0, mFavoriteAttribute1;
|
Widgets::MWAttributePtr mFavoriteAttribute0, mFavoriteAttribute1;
|
||||||
Widgets::MWSkillPtr mMajorSkill[5];
|
std::array<Widgets::MWSkillPtr, 5> mMajorSkill;
|
||||||
Widgets::MWSkillPtr mMinorSkill[5];
|
std::array<Widgets::MWSkillPtr, 5> mMinorSkill;
|
||||||
std::vector<Widgets::MWSkillPtr> mSkills;
|
std::vector<Widgets::MWSkillPtr> mSkills;
|
||||||
std::string mDescription;
|
std::string mDescription;
|
||||||
|
|
||||||
|
|
|
@ -93,11 +93,11 @@ namespace MWGui
|
||||||
for (int day = 0; day < mDays; ++day)
|
for (int day = 0; day < mDays; ++day)
|
||||||
{
|
{
|
||||||
auto& prng = MWBase::Environment::get().getWorld()->getPrng();
|
auto& prng = MWBase::Environment::get().getWorld()->getPrng();
|
||||||
const ESM::Skill* skill = skillStore.find(Misc::Rng::rollDice(ESM::Skill::Length, prng));
|
const ESM::Skill* skill = skillStore.searchRandom({}, prng);
|
||||||
skills.insert(skill);
|
skills.insert(skill);
|
||||||
|
|
||||||
MWMechanics::SkillValue& value = player.getClass().getNpcStats(player).getSkill(skill->mIndex);
|
MWMechanics::SkillValue& value = player.getClass().getNpcStats(player).getSkill(skill->mId);
|
||||||
if (skill->mIndex == ESM::Skill::Security || skill->mIndex == ESM::Skill::Sneak)
|
if (skill->mId == ESM::Skill::Security || skill->mId == ESM::Skill::Sneak)
|
||||||
value.setBase(std::min(100.f, value.getBase() + 1));
|
value.setBase(std::min(100.f, value.getBase() + 1));
|
||||||
else
|
else
|
||||||
value.setBase(std::max(0.f, value.getBase() - 1));
|
value.setBase(std::max(0.f, value.getBase() - 1));
|
||||||
|
@ -116,9 +116,9 @@ namespace MWGui
|
||||||
|
|
||||||
for (const ESM::Skill* skill : skills)
|
for (const ESM::Skill* skill : skills)
|
||||||
{
|
{
|
||||||
int skillValue = player.getClass().getNpcStats(player).getSkill(skill->mIndex).getBase();
|
int skillValue = player.getClass().getNpcStats(player).getSkill(skill->mId).getBase();
|
||||||
std::string skillMsg = gmst.find("sNotifyMessage44")->mValue.getString();
|
std::string skillMsg = gmst.find("sNotifyMessage44")->mValue.getString();
|
||||||
if (skill->mIndex == ESM::Skill::Sneak || skill->mIndex == ESM::Skill::Security)
|
if (skill->mId == ESM::Skill::Sneak || skill->mId == ESM::Skill::Security)
|
||||||
skillMsg = gmst.find("sNotifyMessage39")->mValue.getString();
|
skillMsg = gmst.find("sNotifyMessage39")->mValue.getString();
|
||||||
|
|
||||||
skillMsg = Misc::StringUtils::format(skillMsg, skill->mName, skillValue);
|
skillMsg = Misc::StringUtils::format(skillMsg, skill->mName, skillValue);
|
||||||
|
|
|
@ -414,13 +414,14 @@ namespace MWGui
|
||||||
const ESM::Race* race = store.get<ESM::Race>().find(mCurrentRaceId);
|
const ESM::Race* race = store.get<ESM::Race>().find(mCurrentRaceId);
|
||||||
for (const auto& bonus : race->mData.mBonus)
|
for (const auto& bonus : race->mData.mBonus)
|
||||||
{
|
{
|
||||||
if (bonus.mSkill < 0 || bonus.mSkill >= ESM::Skill::Length) // Skip unknown skill indexes
|
ESM::RefId skill = ESM::Skill::indexToRefId(bonus.mSkill);
|
||||||
|
if (skill.empty()) // Skip unknown skill indexes
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
skillWidget = mSkillList->createWidget<Widgets::MWSkill>("MW_StatNameValue", coord1, MyGUI::Align::Default);
|
skillWidget = mSkillList->createWidget<Widgets::MWSkill>("MW_StatNameValue", coord1, MyGUI::Align::Default);
|
||||||
skillWidget->setSkillId(ESM::Skill::SkillEnum(bonus.mSkill));
|
skillWidget->setSkillId(skill);
|
||||||
skillWidget->setSkillValue(Widgets::MWSkill::SkillValue(static_cast<float>(bonus.mBonus), 0.f));
|
skillWidget->setSkillValue(Widgets::MWSkill::SkillValue(static_cast<float>(bonus.mBonus), 0.f));
|
||||||
ToolTips::createSkillToolTip(skillWidget, bonus.mSkill);
|
ToolTips::createSkillToolTip(skillWidget, skill);
|
||||||
|
|
||||||
mSkillItems.push_back(skillWidget);
|
mSkillItems.push_back(skillWidget);
|
||||||
|
|
||||||
|
|
|
@ -90,10 +90,10 @@ namespace MWGui
|
||||||
getWidget(mSkillView, "SkillView");
|
getWidget(mSkillView, "SkillView");
|
||||||
mSkillView->eventMouseWheel += MyGUI::newDelegate(this, &ReviewDialog::onMouseWheel);
|
mSkillView->eventMouseWheel += MyGUI::newDelegate(this, &ReviewDialog::onMouseWheel);
|
||||||
|
|
||||||
for (int i = 0; i < ESM::Skill::Length; ++i)
|
for (const ESM::Skill& skill : MWBase::Environment::get().getESMStore()->get<ESM::Skill>())
|
||||||
{
|
{
|
||||||
mSkillValues.insert(std::make_pair(i, MWMechanics::SkillValue()));
|
mSkillValues.emplace(skill.mId, MWMechanics::SkillValue());
|
||||||
mSkillWidgetMap.insert(std::make_pair(i, static_cast<MyGUI::TextBox*>(nullptr)));
|
mSkillWidgetMap.emplace(skill.mId, static_cast<MyGUI::TextBox*>(nullptr));
|
||||||
}
|
}
|
||||||
|
|
||||||
MyGUI::Button* backButton;
|
MyGUI::Button* backButton;
|
||||||
|
@ -204,13 +204,14 @@ namespace MWGui
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void ReviewDialog::setSkillValue(ESM::Skill::SkillEnum skillId, const MWMechanics::SkillValue& value)
|
void ReviewDialog::setSkillValue(ESM::RefId id, const MWMechanics::SkillValue& value)
|
||||||
{
|
{
|
||||||
mSkillValues[skillId] = value;
|
mSkillValues[id] = value;
|
||||||
MyGUI::TextBox* widget = mSkillWidgetMap[skillId];
|
MyGUI::TextBox* widget = mSkillWidgetMap[id];
|
||||||
if (widget)
|
if (widget)
|
||||||
{
|
{
|
||||||
float modified = static_cast<float>(value.getModified()), base = static_cast<float>(value.getBase());
|
float modified = value.getModified();
|
||||||
|
float base = value.getBase();
|
||||||
std::string text = MyGUI::utility::toString(std::floor(modified));
|
std::string text = MyGUI::utility::toString(std::floor(modified));
|
||||||
std::string state = "normal";
|
std::string state = "normal";
|
||||||
if (modified > base)
|
if (modified > base)
|
||||||
|
@ -225,21 +226,21 @@ namespace MWGui
|
||||||
mUpdateSkillArea = true;
|
mUpdateSkillArea = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void ReviewDialog::configureSkills(const std::vector<int>& major, const std::vector<int>& minor)
|
void ReviewDialog::configureSkills(const std::vector<ESM::RefId>& major, const std::vector<ESM::RefId>& minor)
|
||||||
{
|
{
|
||||||
mMajorSkills = major;
|
mMajorSkills = major;
|
||||||
mMinorSkills = minor;
|
mMinorSkills = minor;
|
||||||
|
|
||||||
// Update misc skills with the remaining skills not in major or minor
|
// Update misc skills with the remaining skills not in major or minor
|
||||||
std::set<int> skillSet;
|
std::set<ESM::RefId> skillSet;
|
||||||
std::copy(major.begin(), major.end(), std::inserter(skillSet, skillSet.begin()));
|
std::copy(major.begin(), major.end(), std::inserter(skillSet, skillSet.begin()));
|
||||||
std::copy(minor.begin(), minor.end(), std::inserter(skillSet, skillSet.begin()));
|
std::copy(minor.begin(), minor.end(), std::inserter(skillSet, skillSet.begin()));
|
||||||
mMiscSkills.clear();
|
mMiscSkills.clear();
|
||||||
const auto& store = MWBase::Environment::get().getWorld()->getStore().get<ESM::Skill>();
|
const auto& store = MWBase::Environment::get().getWorld()->getStore().get<ESM::Skill>();
|
||||||
for (const auto& skill : store)
|
for (const ESM::Skill& skill : store)
|
||||||
{
|
{
|
||||||
if (!skillSet.contains(skill.second.mIndex))
|
if (!skillSet.contains(skill.mId))
|
||||||
mMiscSkills.push_back(skill.second.mIndex);
|
mMiscSkills.push_back(skill.mId);
|
||||||
}
|
}
|
||||||
|
|
||||||
mUpdateSkillArea = true;
|
mUpdateSkillArea = true;
|
||||||
|
@ -327,8 +328,8 @@ namespace MWGui
|
||||||
coord2.top += lineHeight;
|
coord2.top += lineHeight;
|
||||||
}
|
}
|
||||||
|
|
||||||
void ReviewDialog::addSkills(const SkillList& skills, const std::string& titleId, const std::string& titleDefault,
|
void ReviewDialog::addSkills(const std::vector<ESM::RefId>& skills, const std::string& titleId,
|
||||||
MyGUI::IntCoord& coord1, MyGUI::IntCoord& coord2)
|
const std::string& titleDefault, MyGUI::IntCoord& coord1, MyGUI::IntCoord& coord2)
|
||||||
{
|
{
|
||||||
// Add a line separator if there are items above
|
// Add a line separator if there are items above
|
||||||
if (!mSkillWidgets.empty())
|
if (!mSkillWidgets.empty())
|
||||||
|
@ -339,12 +340,12 @@ namespace MWGui
|
||||||
addGroup(
|
addGroup(
|
||||||
MWBase::Environment::get().getWindowManager()->getGameSettingString(titleId, titleDefault), coord1, coord2);
|
MWBase::Environment::get().getWindowManager()->getGameSettingString(titleId, titleDefault), coord1, coord2);
|
||||||
|
|
||||||
for (const int& skillId : skills)
|
for (const ESM::RefId& skillId : skills)
|
||||||
{
|
{
|
||||||
const ESM::Skill* skill = MWBase::Environment::get().getESMStore()->get<ESM::Skill>().search(skillId);
|
const ESM::Skill* skill = MWBase::Environment::get().getESMStore()->get<ESM::Skill>().search(skillId);
|
||||||
if (!skill) // Skip unknown skill indexes
|
if (!skill) // Skip unknown skills
|
||||||
continue;
|
continue;
|
||||||
const MWMechanics::SkillValue& stat = mSkillValues.find(skillId)->second;
|
const MWMechanics::SkillValue& stat = mSkillValues.find(skill->mId)->second;
|
||||||
int base = stat.getBase();
|
int base = stat.getBase();
|
||||||
int modified = stat.getModified();
|
int modified = stat.getModified();
|
||||||
|
|
||||||
|
@ -358,10 +359,10 @@ namespace MWGui
|
||||||
|
|
||||||
for (int i = 0; i < 2; ++i)
|
for (int i = 0; i < 2; ++i)
|
||||||
{
|
{
|
||||||
ToolTips::createSkillToolTip(mSkillWidgets[mSkillWidgets.size() - 1 - i], skillId);
|
ToolTips::createSkillToolTip(mSkillWidgets[mSkillWidgets.size() - 1 - i], skill->mId);
|
||||||
}
|
}
|
||||||
|
|
||||||
mSkillWidgetMap[skillId] = widget;
|
mSkillWidgetMap[skill->mId] = widget;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -393,15 +394,11 @@ namespace MWGui
|
||||||
if (!mRaceId.empty())
|
if (!mRaceId.empty())
|
||||||
race = MWBase::Environment::get().getESMStore()->get<ESM::Race>().find(mRaceId);
|
race = MWBase::Environment::get().getESMStore()->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];
|
int attributes[ESM::Attribute::Length];
|
||||||
for (int i = 0; i < ESM::Attribute::Length; ++i)
|
for (int i = 0; i < ESM::Attribute::Length; ++i)
|
||||||
attributes[i] = mAttributeWidgets[i]->getAttributeValue().getBase();
|
attributes[i] = mAttributeWidgets[i]->getAttributeValue().getBase();
|
||||||
|
|
||||||
std::vector<ESM::RefId> selectedSpells = MWMechanics::autoCalcPlayerSpells(skills, attributes, race);
|
std::vector<ESM::RefId> selectedSpells = MWMechanics::autoCalcPlayerSpells(mSkillValues, attributes, race);
|
||||||
for (ESM::RefId& spellId : selectedSpells)
|
for (ESM::RefId& spellId : selectedSpells)
|
||||||
{
|
{
|
||||||
if (std::find(spells.begin(), spells.end(), spellId) == spells.end())
|
if (std::find(spells.begin(), spells.end(), spellId) == spells.end())
|
||||||
|
|
|
@ -24,7 +24,6 @@ namespace MWGui
|
||||||
CLASS_DIALOG,
|
CLASS_DIALOG,
|
||||||
BIRTHSIGN_DIALOG
|
BIRTHSIGN_DIALOG
|
||||||
};
|
};
|
||||||
typedef std::vector<int> SkillList;
|
|
||||||
|
|
||||||
ReviewDialog();
|
ReviewDialog();
|
||||||
|
|
||||||
|
@ -41,8 +40,8 @@ namespace MWGui
|
||||||
|
|
||||||
void setAttribute(ESM::Attribute::AttributeID attributeId, const MWMechanics::AttributeValue& value);
|
void setAttribute(ESM::Attribute::AttributeID attributeId, const MWMechanics::AttributeValue& value);
|
||||||
|
|
||||||
void configureSkills(const SkillList& major, const SkillList& minor);
|
void configureSkills(const std::vector<ESM::RefId>& major, const std::vector<ESM::RefId>& minor);
|
||||||
void setSkillValue(ESM::Skill::SkillEnum skillId, const MWMechanics::SkillValue& value);
|
void setSkillValue(ESM::RefId id, const MWMechanics::SkillValue& value);
|
||||||
|
|
||||||
void onOpen() override;
|
void onOpen() override;
|
||||||
|
|
||||||
|
@ -76,8 +75,8 @@ namespace MWGui
|
||||||
void onMouseWheel(MyGUI::Widget* _sender, int _rel);
|
void onMouseWheel(MyGUI::Widget* _sender, int _rel);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void addSkills(const SkillList& skills, const std::string& titleId, const std::string& titleDefault,
|
void addSkills(const std::vector<ESM::RefId>& skills, const std::string& titleId,
|
||||||
MyGUI::IntCoord& coord1, MyGUI::IntCoord& coord2);
|
const std::string& titleDefault, MyGUI::IntCoord& coord1, MyGUI::IntCoord& coord2);
|
||||||
void addSeparator(MyGUI::IntCoord& coord1, MyGUI::IntCoord& coord2);
|
void addSeparator(MyGUI::IntCoord& coord1, MyGUI::IntCoord& coord2);
|
||||||
void addGroup(std::string_view label, MyGUI::IntCoord& coord1, MyGUI::IntCoord& coord2);
|
void addGroup(std::string_view label, MyGUI::IntCoord& coord1, MyGUI::IntCoord& coord2);
|
||||||
MyGUI::TextBox* addValueItem(std::string_view text, const std::string& value, const std::string& state,
|
MyGUI::TextBox* addValueItem(std::string_view text, const std::string& value, const std::string& state,
|
||||||
|
@ -93,9 +92,9 @@ namespace MWGui
|
||||||
|
|
||||||
std::map<int, Widgets::MWAttributePtr> mAttributeWidgets;
|
std::map<int, Widgets::MWAttributePtr> mAttributeWidgets;
|
||||||
|
|
||||||
SkillList mMajorSkills, mMinorSkills, mMiscSkills;
|
std::vector<ESM::RefId> mMajorSkills, mMinorSkills, mMiscSkills;
|
||||||
std::map<int, MWMechanics::SkillValue> mSkillValues;
|
std::map<ESM::RefId, MWMechanics::SkillValue> mSkillValues;
|
||||||
std::map<int, MyGUI::TextBox*> mSkillWidgetMap;
|
std::map<ESM::RefId, MyGUI::TextBox*> mSkillWidgetMap;
|
||||||
ESM::RefId mRaceId, mBirthSignId;
|
ESM::RefId mRaceId, mBirthSignId;
|
||||||
std::string mName;
|
std::string mName;
|
||||||
ESM::Class mKlass;
|
ESM::Class mKlass;
|
||||||
|
|
|
@ -286,9 +286,9 @@ namespace MWGui
|
||||||
exit();
|
exit();
|
||||||
}
|
}
|
||||||
|
|
||||||
void EditEffectDialog::setSkill(int skill)
|
void EditEffectDialog::setSkill(ESM::RefId skill)
|
||||||
{
|
{
|
||||||
mEffect.mSkill = skill;
|
mEffect.mSkill = skill.getIf<ESM::IndexRefId>()->getValue();
|
||||||
eventEffectModified(mEffect);
|
eventEffectModified(mEffect);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -30,7 +30,7 @@ namespace MWGui
|
||||||
|
|
||||||
void setConstantEffect(bool constant);
|
void setConstantEffect(bool constant);
|
||||||
|
|
||||||
void setSkill(int skill);
|
void setSkill(ESM::RefId skill);
|
||||||
void setAttribute(int attribute);
|
void setAttribute(int attribute);
|
||||||
|
|
||||||
void newEffect(const ESM::MagicEffect* effect);
|
void newEffect(const ESM::MagicEffect* effect);
|
||||||
|
|
|
@ -83,7 +83,8 @@ namespace MWGui
|
||||||
|
|
||||||
if (effect->mData.mFlags & ESM::MagicEffect::TargetSkill)
|
if (effect->mData.mFlags & ESM::MagicEffect::TargetSkill)
|
||||||
{
|
{
|
||||||
const ESM::Skill* skill = store->get<ESM::Skill>().find(effectInfo.mKey.mArg);
|
const ESM::Skill* skill
|
||||||
|
= store->get<ESM::Skill>().find(ESM::Skill::indexToRefId(effectInfo.mKey.mArg));
|
||||||
sourcesDescription += " (" + skill->mName + ')';
|
sourcesDescription += " (" + skill->mName + ')';
|
||||||
}
|
}
|
||||||
if (effect->mData.mFlags & ESM::MagicEffect::TargetAttribute)
|
if (effect->mData.mFlags & ESM::MagicEffect::TargetAttribute)
|
||||||
|
|
|
@ -55,7 +55,7 @@ namespace MWGui
|
||||||
{
|
{
|
||||||
const ESM::MagicEffect* magicEffect = store.get<ESM::MagicEffect>().find(effectId);
|
const ESM::MagicEffect* magicEffect = store.get<ESM::MagicEffect>().find(effectId);
|
||||||
const ESM::Attribute* attribute = store.get<ESM::Attribute>().search(effect.mAttribute);
|
const ESM::Attribute* attribute = store.get<ESM::Attribute>().search(effect.mAttribute);
|
||||||
const ESM::Skill* skill = store.get<ESM::Skill>().search(effect.mSkill);
|
const ESM::Skill* skill = store.get<ESM::Skill>().search(ESM::Skill::indexToRefId(effect.mSkill));
|
||||||
|
|
||||||
std::string fullEffectName = MWMechanics::getMagicEffectString(*magicEffect, attribute, skill);
|
std::string fullEffectName = MWMechanics::getMagicEffectString(*magicEffect, attribute, skill);
|
||||||
std::string convert = Utf8Stream::lowerCaseUtf8(fullEffectName);
|
std::string convert = Utf8Stream::lowerCaseUtf8(fullEffectName);
|
||||||
|
|
|
@ -83,13 +83,13 @@ namespace MWGui
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Loop over ESM::Skill::SkillEnum
|
for (const ESM::Skill& skill : MWBase::Environment::get().getESMStore()->get<ESM::Skill>())
|
||||||
for (int i = 0; i < ESM::Skill::Length; ++i)
|
|
||||||
{
|
{
|
||||||
if (stats.getSkill(i) != mWatchedSkills[i] || mWatchedStatsEmpty)
|
const auto& value = stats.getSkill(skill.mId);
|
||||||
|
if (value != mWatchedSkills[skill.mId] || mWatchedStatsEmpty)
|
||||||
{
|
{
|
||||||
mWatchedSkills[i] = stats.getSkill(i);
|
mWatchedSkills[skill.mId] = value;
|
||||||
setValue((ESM::Skill::SkillEnum)i, stats.getSkill(i));
|
setValue(skill.mId, value);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -125,13 +125,13 @@ namespace MWGui
|
||||||
setValue("class", cls->mName);
|
setValue("class", cls->mName);
|
||||||
|
|
||||||
size_t size = cls->mData.mSkills.size();
|
size_t size = cls->mData.mSkills.size();
|
||||||
MWBase::WindowManager::SkillList majorSkills(size);
|
std::vector<ESM::RefId> majorSkills(size);
|
||||||
MWBase::WindowManager::SkillList minorSkills(size);
|
std::vector<ESM::RefId> minorSkills(size);
|
||||||
|
|
||||||
for (size_t i = 0; i < size; ++i)
|
for (size_t i = 0; i < size; ++i)
|
||||||
{
|
{
|
||||||
minorSkills[i] = cls->mData.mSkills[i][0];
|
minorSkills[i] = ESM::Skill::indexToRefId(cls->mData.mSkills[i][0]);
|
||||||
majorSkills[i] = cls->mData.mSkills[i][1];
|
majorSkills[i] = ESM::Skill::indexToRefId(cls->mData.mSkills[i][1]);
|
||||||
}
|
}
|
||||||
|
|
||||||
configureSkills(majorSkills, minorSkills);
|
configureSkills(majorSkills, minorSkills);
|
||||||
|
@ -157,12 +157,10 @@ namespace MWGui
|
||||||
listener->setValue(id, value);
|
listener->setValue(id, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
void StatsWatcher::setValue(ESM::Skill::SkillEnum parSkill, const MWMechanics::SkillValue& value)
|
void StatsWatcher::setValue(ESM::RefId id, const MWMechanics::SkillValue& value)
|
||||||
{
|
{
|
||||||
/// \todo Don't use the skill enum as a parameter type (we will have to drop it anyway, once we
|
|
||||||
/// allow custom skills.
|
|
||||||
for (StatsListener* listener : mListeners)
|
for (StatsListener* listener : mListeners)
|
||||||
listener->setValue(parSkill, value);
|
listener->setValue(id, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
void StatsWatcher::setValue(std::string_view id, const MWMechanics::DynamicStat<float>& value)
|
void StatsWatcher::setValue(std::string_view id, const MWMechanics::DynamicStat<float>& value)
|
||||||
|
@ -183,7 +181,7 @@ namespace MWGui
|
||||||
listener->setValue(id, value);
|
listener->setValue(id, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
void StatsWatcher::configureSkills(const std::vector<int>& major, const std::vector<int>& minor)
|
void StatsWatcher::configureSkills(const std::vector<ESM::RefId>& major, const std::vector<ESM::RefId>& minor)
|
||||||
{
|
{
|
||||||
for (StatsListener* listener : mListeners)
|
for (StatsListener* listener : mListeners)
|
||||||
listener->configureSkills(major, minor);
|
listener->configureSkills(major, minor);
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
#ifndef MWGUI_STATSWATCHER_H
|
#ifndef MWGUI_STATSWATCHER_H
|
||||||
#define MWGUI_STATSWATCHER_H
|
#define MWGUI_STATSWATCHER_H
|
||||||
|
|
||||||
|
#include <map>
|
||||||
#include <set>
|
#include <set>
|
||||||
|
|
||||||
#include <components/esm/attr.hpp>
|
#include <components/esm/attr.hpp>
|
||||||
|
@ -22,8 +23,8 @@ namespace MWGui
|
||||||
virtual void setValue(std::string_view id, const MWMechanics::DynamicStat<float>& value) {}
|
virtual void setValue(std::string_view id, const MWMechanics::DynamicStat<float>& value) {}
|
||||||
virtual void setValue(std::string_view, const std::string& value) {}
|
virtual void setValue(std::string_view, const std::string& value) {}
|
||||||
virtual void setValue(std::string_view, int value) {}
|
virtual void setValue(std::string_view, int value) {}
|
||||||
virtual void setValue(const ESM::Skill::SkillEnum parSkill, const MWMechanics::SkillValue& value) {}
|
virtual void setValue(ESM::RefId id, const MWMechanics::SkillValue& value) {}
|
||||||
virtual void configureSkills(const std::vector<int>& major, const std::vector<int>& minor) {}
|
virtual void configureSkills(const std::vector<ESM::RefId>& major, const std::vector<ESM::RefId>& minor) {}
|
||||||
};
|
};
|
||||||
|
|
||||||
class StatsWatcher
|
class StatsWatcher
|
||||||
|
@ -31,7 +32,7 @@ namespace MWGui
|
||||||
MWWorld::Ptr mWatched;
|
MWWorld::Ptr mWatched;
|
||||||
|
|
||||||
MWMechanics::AttributeValue mWatchedAttributes[ESM::Attribute::Length];
|
MWMechanics::AttributeValue mWatchedAttributes[ESM::Attribute::Length];
|
||||||
MWMechanics::SkillValue mWatchedSkills[ESM::Skill::Length];
|
std::map<ESM::RefId, MWMechanics::SkillValue> mWatchedSkills;
|
||||||
|
|
||||||
MWMechanics::DynamicStat<float> mWatchedHealth;
|
MWMechanics::DynamicStat<float> mWatchedHealth;
|
||||||
MWMechanics::DynamicStat<float> mWatchedMagicka;
|
MWMechanics::DynamicStat<float> mWatchedMagicka;
|
||||||
|
@ -53,8 +54,8 @@ namespace MWGui
|
||||||
void setValue(std::string_view id, const MWMechanics::DynamicStat<float>& value);
|
void setValue(std::string_view id, const MWMechanics::DynamicStat<float>& value);
|
||||||
void setValue(std::string_view id, const std::string& value);
|
void setValue(std::string_view id, const std::string& value);
|
||||||
void setValue(std::string_view id, int value);
|
void setValue(std::string_view id, int value);
|
||||||
void setValue(const ESM::Skill::SkillEnum parSkill, const MWMechanics::SkillValue& value);
|
void setValue(ESM::RefId id, const MWMechanics::SkillValue& value);
|
||||||
void configureSkills(const std::vector<int>& major, const std::vector<int>& minor);
|
void configureSkills(const std::vector<ESM::RefId>& major, const std::vector<ESM::RefId>& minor);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
StatsWatcher();
|
StatsWatcher();
|
||||||
|
|
|
@ -37,17 +37,8 @@ namespace MWGui
|
||||||
: WindowPinnableBase("openmw_stats_window.layout")
|
: WindowPinnableBase("openmw_stats_window.layout")
|
||||||
, NoDrop(drag, mMainWidget)
|
, NoDrop(drag, mMainWidget)
|
||||||
, mSkillView(nullptr)
|
, mSkillView(nullptr)
|
||||||
, mMajorSkills()
|
|
||||||
, mMinorSkills()
|
|
||||||
, mMiscSkills()
|
|
||||||
, mSkillValues()
|
|
||||||
, mSkillWidgetMap()
|
|
||||||
, mFactionWidgetMap()
|
|
||||||
, mFactions()
|
|
||||||
, mBirthSignId()
|
|
||||||
, mReputation(0)
|
, mReputation(0)
|
||||||
, mBounty(0)
|
, mBounty(0)
|
||||||
, mSkillWidgets()
|
|
||||||
, mChanged(true)
|
, mChanged(true)
|
||||||
, mMinFullWidth(mMainWidget->getSize().width)
|
, mMinFullWidth(mMainWidget->getSize().width)
|
||||||
{
|
{
|
||||||
|
@ -67,11 +58,10 @@ namespace MWGui
|
||||||
getWidget(mLeftPane, "LeftPane");
|
getWidget(mLeftPane, "LeftPane");
|
||||||
getWidget(mRightPane, "RightPane");
|
getWidget(mRightPane, "RightPane");
|
||||||
|
|
||||||
for (int i = 0; i < ESM::Skill::Length; ++i)
|
for (const ESM::Skill& skill : store.get<ESM::Skill>())
|
||||||
{
|
{
|
||||||
mSkillValues.insert(std::make_pair(i, MWMechanics::SkillValue()));
|
mSkillValues.emplace(skill.mId, MWMechanics::SkillValue());
|
||||||
mSkillWidgetMap.insert(
|
mSkillWidgetMap.emplace(skill.mId, std::make_pair<MyGUI::TextBox*, MyGUI::TextBox*>(nullptr, nullptr));
|
||||||
std::make_pair(i, std::make_pair((MyGUI::TextBox*)nullptr, (MyGUI::TextBox*)nullptr)));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
MyGUI::Window* t = mMainWidget->castType<MyGUI::Window>();
|
MyGUI::Window* t = mMainWidget->castType<MyGUI::Window>();
|
||||||
|
@ -237,7 +227,7 @@ namespace MWGui
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void setSkillProgress(MyGUI::Widget* w, float progress, int skillId)
|
void setSkillProgress(MyGUI::Widget* w, float progress, ESM::RefId skillId)
|
||||||
{
|
{
|
||||||
MWWorld::Ptr player = MWMechanics::getPlayer();
|
MWWorld::Ptr player = MWMechanics::getPlayer();
|
||||||
const MWWorld::ESMStore& esmStore = *MWBase::Environment::get().getESMStore();
|
const MWWorld::ESMStore& esmStore = *MWBase::Environment::get().getESMStore();
|
||||||
|
@ -255,10 +245,10 @@ namespace MWGui
|
||||||
w->setUserString("RangePosition_SkillProgress", MyGUI::utility::toString(progressPercent));
|
w->setUserString("RangePosition_SkillProgress", MyGUI::utility::toString(progressPercent));
|
||||||
}
|
}
|
||||||
|
|
||||||
void StatsWindow::setValue(const ESM::Skill::SkillEnum parSkill, const MWMechanics::SkillValue& value)
|
void StatsWindow::setValue(ESM::RefId id, const MWMechanics::SkillValue& value)
|
||||||
{
|
{
|
||||||
mSkillValues[parSkill] = value;
|
mSkillValues[id] = value;
|
||||||
std::pair<MyGUI::TextBox*, MyGUI::TextBox*> widgets = mSkillWidgetMap[(int)parSkill];
|
std::pair<MyGUI::TextBox*, MyGUI::TextBox*> widgets = mSkillWidgetMap[id];
|
||||||
MyGUI::TextBox* valueWidget = widgets.second;
|
MyGUI::TextBox* valueWidget = widgets.second;
|
||||||
MyGUI::TextBox* nameWidget = widgets.first;
|
MyGUI::TextBox* nameWidget = widgets.first;
|
||||||
if (valueWidget && nameWidget)
|
if (valueWidget && nameWidget)
|
||||||
|
@ -296,8 +286,8 @@ namespace MWGui
|
||||||
valueWidget->setUserString("Visible_SkillProgressVBox", "true");
|
valueWidget->setUserString("Visible_SkillProgressVBox", "true");
|
||||||
valueWidget->setUserString("UserData^Hidden_SkillProgressVBox", "false");
|
valueWidget->setUserString("UserData^Hidden_SkillProgressVBox", "false");
|
||||||
|
|
||||||
setSkillProgress(nameWidget, value.getProgress(), parSkill);
|
setSkillProgress(nameWidget, value.getProgress(), id);
|
||||||
setSkillProgress(valueWidget, value.getProgress(), parSkill);
|
setSkillProgress(valueWidget, value.getProgress(), id);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -314,21 +304,21 @@ namespace MWGui
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void StatsWindow::configureSkills(const std::vector<int>& major, const std::vector<int>& minor)
|
void StatsWindow::configureSkills(const std::vector<ESM::RefId>& major, const std::vector<ESM::RefId>& minor)
|
||||||
{
|
{
|
||||||
mMajorSkills = major;
|
mMajorSkills = major;
|
||||||
mMinorSkills = minor;
|
mMinorSkills = minor;
|
||||||
|
|
||||||
// Update misc skills with the remaining skills not in major or minor
|
// Update misc skills with the remaining skills not in major or minor
|
||||||
std::set<int> skillSet;
|
std::set<ESM::RefId> skillSet;
|
||||||
std::copy(major.begin(), major.end(), std::inserter(skillSet, skillSet.begin()));
|
std::copy(major.begin(), major.end(), std::inserter(skillSet, skillSet.begin()));
|
||||||
std::copy(minor.begin(), minor.end(), std::inserter(skillSet, skillSet.begin()));
|
std::copy(minor.begin(), minor.end(), std::inserter(skillSet, skillSet.begin()));
|
||||||
mMiscSkills.clear();
|
mMiscSkills.clear();
|
||||||
const auto& store = MWBase::Environment::get().getWorld()->getStore().get<ESM::Skill>();
|
const auto& store = MWBase::Environment::get().getWorld()->getStore().get<ESM::Skill>();
|
||||||
for (const auto& skill : store)
|
for (const auto& skill : store)
|
||||||
{
|
{
|
||||||
if (!skillSet.contains(skill.second.mIndex))
|
if (!skillSet.contains(skill.mId))
|
||||||
mMiscSkills.push_back(skill.second.mIndex);
|
mMiscSkills.push_back(skill.mId);
|
||||||
}
|
}
|
||||||
|
|
||||||
updateSkillArea();
|
updateSkillArea();
|
||||||
|
@ -492,8 +482,8 @@ namespace MWGui
|
||||||
return skillNameWidget;
|
return skillNameWidget;
|
||||||
}
|
}
|
||||||
|
|
||||||
void StatsWindow::addSkills(const SkillList& skills, const std::string& titleId, const std::string& titleDefault,
|
void StatsWindow::addSkills(const std::vector<ESM::RefId>& skills, const std::string& titleId,
|
||||||
MyGUI::IntCoord& coord1, MyGUI::IntCoord& coord2)
|
const std::string& titleDefault, MyGUI::IntCoord& coord1, MyGUI::IntCoord& coord2)
|
||||||
{
|
{
|
||||||
// Add a line separator if there are items above
|
// Add a line separator if there are items above
|
||||||
if (!mSkillWidgets.empty())
|
if (!mSkillWidgets.empty())
|
||||||
|
@ -504,19 +494,18 @@ namespace MWGui
|
||||||
addGroup(
|
addGroup(
|
||||||
MWBase::Environment::get().getWindowManager()->getGameSettingString(titleId, titleDefault), coord1, coord2);
|
MWBase::Environment::get().getWindowManager()->getGameSettingString(titleId, titleDefault), coord1, coord2);
|
||||||
|
|
||||||
for (const int skillId : skills)
|
const MWWorld::ESMStore& esmStore = *MWBase::Environment::get().getESMStore();
|
||||||
|
for (const ESM::RefId& skillId : skills)
|
||||||
{
|
{
|
||||||
if (skillId < 0 || skillId >= ESM::Skill::Length) // Skip unknown skill indexes
|
const ESM::Skill* skill = esmStore.get<ESM::Skill>().search(skillId);
|
||||||
|
if (!skill) // Skip unknown skills
|
||||||
continue;
|
continue;
|
||||||
const MWWorld::ESMStore& esmStore = *MWBase::Environment::get().getESMStore();
|
|
||||||
|
|
||||||
const ESM::Skill* skill = esmStore.get<ESM::Skill>().find(skillId);
|
|
||||||
|
|
||||||
const ESM::Attribute* attr = esmStore.get<ESM::Attribute>().find(skill->mData.mAttribute);
|
const ESM::Attribute* attr = esmStore.get<ESM::Attribute>().find(skill->mData.mAttribute);
|
||||||
|
|
||||||
std::pair<MyGUI::TextBox*, MyGUI::TextBox*> widgets
|
std::pair<MyGUI::TextBox*, MyGUI::TextBox*> widgets
|
||||||
= addValueItem(skill->mName, {}, "normal", coord1, coord2);
|
= addValueItem(skill->mName, {}, "normal", coord1, coord2);
|
||||||
mSkillWidgetMap[skillId] = widgets;
|
mSkillWidgetMap[skill->mId] = widgets;
|
||||||
|
|
||||||
for (int i = 0; i < 2; ++i)
|
for (int i = 0; i < 2; ++i)
|
||||||
{
|
{
|
||||||
|
@ -532,7 +521,7 @@ namespace MWGui
|
||||||
mSkillWidgets[mSkillWidgets.size() - 1 - i]->setUserString("Range_SkillProgress", "100");
|
mSkillWidgets[mSkillWidgets.size() - 1 - i]->setUserString("Range_SkillProgress", "100");
|
||||||
}
|
}
|
||||||
|
|
||||||
setValue(static_cast<ESM::Skill::SkillEnum>(skillId), mSkillValues.find(skillId)->second);
|
setValue(skill->mId, mSkillValues.find(skill->mId)->second);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -640,13 +629,13 @@ namespace MWGui
|
||||||
bool firstSkill = true;
|
bool firstSkill = true;
|
||||||
for (int id : faction->mData.mSkills)
|
for (int id : faction->mData.mSkills)
|
||||||
{
|
{
|
||||||
if (id != -1)
|
const ESM::Skill* skill = store.get<ESM::Skill>().search(ESM::Skill::indexToRefId(id));
|
||||||
|
if (skill)
|
||||||
{
|
{
|
||||||
if (!firstSkill)
|
if (!firstSkill)
|
||||||
text += ", ";
|
text += ", ";
|
||||||
|
|
||||||
firstSkill = false;
|
firstSkill = false;
|
||||||
const ESM::Skill* skill = store.get<ESM::Skill>().find(id);
|
|
||||||
text += MyGUI::TextIterator::toTagsString(skill->mName);
|
text += MyGUI::TextIterator::toTagsString(skill->mName);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -12,8 +12,6 @@ namespace MWGui
|
||||||
public:
|
public:
|
||||||
typedef std::map<ESM::RefId, int> FactionList;
|
typedef std::map<ESM::RefId, int> FactionList;
|
||||||
|
|
||||||
typedef std::vector<int> SkillList;
|
|
||||||
|
|
||||||
StatsWindow(DragAndDrop* drag);
|
StatsWindow(DragAndDrop* drag);
|
||||||
|
|
||||||
/// automatically updates all the data in the stats window, but only if it has changed.
|
/// automatically updates all the data in the stats window, but only if it has changed.
|
||||||
|
@ -27,8 +25,8 @@ namespace MWGui
|
||||||
void setValue(std::string_view id, const MWMechanics::DynamicStat<float>& value) override;
|
void setValue(std::string_view id, const MWMechanics::DynamicStat<float>& value) override;
|
||||||
void setValue(std::string_view id, const std::string& value) override;
|
void setValue(std::string_view id, const std::string& value) override;
|
||||||
void setValue(std::string_view id, int value) override;
|
void setValue(std::string_view id, int value) override;
|
||||||
void setValue(const ESM::Skill::SkillEnum parSkill, const MWMechanics::SkillValue& value) override;
|
void setValue(ESM::RefId id, const MWMechanics::SkillValue& value) override;
|
||||||
void configureSkills(const SkillList& major, const SkillList& minor) override;
|
void configureSkills(const std::vector<ESM::RefId>& major, const std::vector<ESM::RefId>& minor) override;
|
||||||
|
|
||||||
void setReputation(int reputation)
|
void setReputation(int reputation)
|
||||||
{
|
{
|
||||||
|
@ -47,8 +45,8 @@ namespace MWGui
|
||||||
void onOpen() override { onWindowResize(mMainWidget->castType<MyGUI::Window>()); }
|
void onOpen() override { onWindowResize(mMainWidget->castType<MyGUI::Window>()); }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void addSkills(const SkillList& skills, const std::string& titleId, const std::string& titleDefault,
|
void addSkills(const std::vector<ESM::RefId>& skills, const std::string& titleId,
|
||||||
MyGUI::IntCoord& coord1, MyGUI::IntCoord& coord2);
|
const std::string& titleDefault, MyGUI::IntCoord& coord1, MyGUI::IntCoord& coord2);
|
||||||
void addSeparator(MyGUI::IntCoord& coord1, MyGUI::IntCoord& coord2);
|
void addSeparator(MyGUI::IntCoord& coord1, MyGUI::IntCoord& coord2);
|
||||||
void addGroup(std::string_view label, MyGUI::IntCoord& coord1, MyGUI::IntCoord& coord2);
|
void addGroup(std::string_view label, MyGUI::IntCoord& coord1, MyGUI::IntCoord& coord2);
|
||||||
std::pair<MyGUI::TextBox*, MyGUI::TextBox*> addValueItem(std::string_view text, const std::string& value,
|
std::pair<MyGUI::TextBox*, MyGUI::TextBox*> addValueItem(std::string_view text, const std::string& value,
|
||||||
|
@ -67,9 +65,9 @@ namespace MWGui
|
||||||
|
|
||||||
MyGUI::ScrollView* mSkillView;
|
MyGUI::ScrollView* mSkillView;
|
||||||
|
|
||||||
SkillList mMajorSkills, mMinorSkills, mMiscSkills;
|
std::vector<ESM::RefId> mMajorSkills, mMinorSkills, mMiscSkills;
|
||||||
std::map<int, MWMechanics::SkillValue> mSkillValues;
|
std::map<ESM::RefId, MWMechanics::SkillValue> mSkillValues;
|
||||||
std::map<int, std::pair<MyGUI::TextBox*, MyGUI::TextBox*>> mSkillWidgetMap;
|
std::map<ESM::RefId, std::pair<MyGUI::TextBox*, MyGUI::TextBox*>> mSkillWidgetMap;
|
||||||
std::map<std::string, MyGUI::Widget*> mFactionWidgetMap;
|
std::map<std::string, MyGUI::Widget*> mFactionWidgetMap;
|
||||||
FactionList mFactions; ///< Stores a list of factions and the current rank
|
FactionList mFactions; ///< Stores a list of factions and the current rank
|
||||||
ESM::RefId mBirthSignId;
|
ESM::RefId mBirthSignId;
|
||||||
|
|
|
@ -805,9 +805,9 @@ namespace MWGui
|
||||||
mFocusToolTipY = min_y;
|
mFocusToolTipY = min_y;
|
||||||
}
|
}
|
||||||
|
|
||||||
void ToolTips::createSkillToolTip(MyGUI::Widget* widget, int skillId)
|
void ToolTips::createSkillToolTip(MyGUI::Widget* widget, ESM::RefId skillId)
|
||||||
{
|
{
|
||||||
if (skillId == -1)
|
if (skillId.empty())
|
||||||
return;
|
return;
|
||||||
|
|
||||||
const MWWorld::ESMStore& store = *MWBase::Environment::get().getESMStore();
|
const MWWorld::ESMStore& store = *MWBase::Environment::get().getESMStore();
|
||||||
|
@ -846,7 +846,7 @@ namespace MWGui
|
||||||
const MWWorld::Store<ESM::Skill>& skills = MWBase::Environment::get().getESMStore()->get<ESM::Skill>();
|
const MWWorld::Store<ESM::Skill>& skills = MWBase::Environment::get().getESMStore()->get<ESM::Skill>();
|
||||||
|
|
||||||
bool isFirst = true;
|
bool isFirst = true;
|
||||||
for (const auto& [_, skill] : skills)
|
for (const auto& skill : skills)
|
||||||
{
|
{
|
||||||
if (skill.mData.mSpecialization == specId)
|
if (skill.mData.mSpecialization == specId)
|
||||||
{
|
{
|
||||||
|
|
|
@ -93,7 +93,7 @@ namespace MWGui
|
||||||
|
|
||||||
// these do not create an actual tooltip, but they fill in the data that is required so the tooltip
|
// these do not create an actual tooltip, but they fill in the data that is required so the tooltip
|
||||||
// system knows what to show in case this widget is hovered
|
// system knows what to show in case this widget is hovered
|
||||||
static void createSkillToolTip(MyGUI::Widget* widget, int skillId);
|
static void createSkillToolTip(MyGUI::Widget* widget, ESM::RefId skillId);
|
||||||
static void createAttributeToolTip(MyGUI::Widget* widget, int attributeId);
|
static void createAttributeToolTip(MyGUI::Widget* widget, int attributeId);
|
||||||
static void createSpecializationToolTip(MyGUI::Widget* widget, const std::string& name, int specId);
|
static void createSpecializationToolTip(MyGUI::Widget* widget, const std::string& name, int specId);
|
||||||
static void createBirthsignToolTip(MyGUI::Widget* widget, const ESM::RefId& birthsignId);
|
static void createBirthsignToolTip(MyGUI::Widget* widget, const ESM::RefId& birthsignId);
|
||||||
|
|
|
@ -21,24 +21,6 @@
|
||||||
|
|
||||||
#include "tooltips.hpp"
|
#include "tooltips.hpp"
|
||||||
|
|
||||||
namespace
|
|
||||||
{
|
|
||||||
// Sorts a container descending by skill value. If skill value is equal, sorts ascending by skill ID.
|
|
||||||
// pair <skill ID, skill value>
|
|
||||||
bool sortSkills(const std::pair<int, int>& left, const std::pair<int, int>& right)
|
|
||||||
{
|
|
||||||
if (left == right)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
if (left.second > right.second)
|
|
||||||
return true;
|
|
||||||
else if (left.second < right.second)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
return left.first < right.first;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
namespace MWGui
|
namespace MWGui
|
||||||
{
|
{
|
||||||
|
|
||||||
|
@ -80,34 +62,37 @@ namespace MWGui
|
||||||
|
|
||||||
mPlayerGold->setCaptionWithReplacing("#{sGold}: " + MyGUI::utility::toString(playerGold));
|
mPlayerGold->setCaptionWithReplacing("#{sGold}: " + MyGUI::utility::toString(playerGold));
|
||||||
|
|
||||||
|
const auto& store = MWBase::Environment::get().getESMStore();
|
||||||
|
const MWWorld::Store<ESM::GameSetting>& gmst = store->get<ESM::GameSetting>();
|
||||||
|
const MWWorld::Store<ESM::Skill>& skillStore = store->get<ESM::Skill>();
|
||||||
|
|
||||||
// NPC can train you in his best 3 skills
|
// NPC can train you in his best 3 skills
|
||||||
std::vector<std::pair<int, float>> skills;
|
std::vector<std::pair<const ESM::Skill*, float>> skills;
|
||||||
|
|
||||||
MWMechanics::NpcStats const& actorStats(actor.getClass().getNpcStats(actor));
|
MWMechanics::NpcStats const& actorStats(actor.getClass().getNpcStats(actor));
|
||||||
for (int i = 0; i < ESM::Skill::Length; ++i)
|
for (const ESM::Skill& skill : skillStore)
|
||||||
{
|
{
|
||||||
float value = getSkillForTraining(actorStats, i);
|
float value = getSkillForTraining(actorStats, skill.mId);
|
||||||
|
|
||||||
skills.emplace_back(i, value);
|
skills.emplace_back(&skill, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
std::sort(skills.begin(), skills.end(), sortSkills);
|
std::sort(skills.begin(), skills.end(), [](const auto& left, const auto& right) {
|
||||||
|
return std::tie(right.second, left.first->mId) < std::tie(left.second, right.first->mId);
|
||||||
|
});
|
||||||
|
|
||||||
MyGUI::EnumeratorWidgetPtr widgets = mTrainingOptions->getEnumerator();
|
MyGUI::EnumeratorWidgetPtr widgets = mTrainingOptions->getEnumerator();
|
||||||
MyGUI::Gui::getInstance().destroyWidgets(widgets);
|
MyGUI::Gui::getInstance().destroyWidgets(widgets);
|
||||||
|
|
||||||
MWMechanics::NpcStats& pcStats = player.getClass().getNpcStats(player);
|
MWMechanics::NpcStats& pcStats = player.getClass().getNpcStats(player);
|
||||||
|
|
||||||
const auto& store = MWBase::Environment::get().getESMStore();
|
|
||||||
const MWWorld::Store<ESM::GameSetting>& gmst = store->get<ESM::GameSetting>();
|
|
||||||
const MWWorld::Store<ESM::Skill>& skillStore = store->get<ESM::Skill>();
|
|
||||||
|
|
||||||
const int lineHeight = MWBase::Environment::get().getWindowManager()->getFontHeight() + 2;
|
const int lineHeight = MWBase::Environment::get().getWindowManager()->getFontHeight() + 2;
|
||||||
|
|
||||||
for (int i = 0; i < 3; ++i)
|
for (int i = 0; i < 3; ++i)
|
||||||
{
|
{
|
||||||
|
const ESM::Skill* skill = skills[i].first;
|
||||||
int price = static_cast<int>(
|
int price = static_cast<int>(
|
||||||
pcStats.getSkill(skills[i].first).getBase() * gmst.find("iTrainingMod")->mValue.getInteger());
|
pcStats.getSkill(skill->mId).getBase() * gmst.find("iTrainingMod")->mValue.getInteger());
|
||||||
price = std::max(1, price);
|
price = std::max(1, price);
|
||||||
price = MWBase::Environment::get().getMechanicsManager()->getBarterOffer(mPtr, price, true);
|
price = MWBase::Environment::get().getMechanicsManager()->getBarterOffer(mPtr, price, true);
|
||||||
|
|
||||||
|
@ -120,13 +105,12 @@ namespace MWGui
|
||||||
button->setUserData(skills[i].first);
|
button->setUserData(skills[i].first);
|
||||||
button->eventMouseButtonClick += MyGUI::newDelegate(this, &TrainingWindow::onTrainingSelected);
|
button->eventMouseButtonClick += MyGUI::newDelegate(this, &TrainingWindow::onTrainingSelected);
|
||||||
|
|
||||||
const ESM::Skill* skill = skillStore.find(skills[i].first);
|
|
||||||
button->setCaptionWithReplacing(
|
button->setCaptionWithReplacing(
|
||||||
MyGUI::TextIterator::toTagsString(skill->mName) + " - " + MyGUI::utility::toString(price));
|
MyGUI::TextIterator::toTagsString(skill->mName) + " - " + MyGUI::utility::toString(price));
|
||||||
|
|
||||||
button->setSize(button->getTextSize().width + 12, button->getSize().height);
|
button->setSize(button->getTextSize().width + 12, button->getSize().height);
|
||||||
|
|
||||||
ToolTips::createSkillToolTip(button, skills[i].first);
|
ToolTips::createSkillToolTip(button, skill->mId);
|
||||||
}
|
}
|
||||||
|
|
||||||
center();
|
center();
|
||||||
|
@ -144,29 +128,29 @@ namespace MWGui
|
||||||
|
|
||||||
void TrainingWindow::onTrainingSelected(MyGUI::Widget* sender)
|
void TrainingWindow::onTrainingSelected(MyGUI::Widget* sender)
|
||||||
{
|
{
|
||||||
int skillId = *sender->getUserData<int>();
|
const ESM::Skill* skill = *sender->getUserData<const ESM::Skill*>();
|
||||||
|
|
||||||
MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayerPtr();
|
MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayerPtr();
|
||||||
MWMechanics::NpcStats& pcStats = player.getClass().getNpcStats(player);
|
MWMechanics::NpcStats& pcStats = player.getClass().getNpcStats(player);
|
||||||
|
|
||||||
const MWWorld::ESMStore& store = *MWBase::Environment::get().getESMStore();
|
const MWWorld::ESMStore& store = *MWBase::Environment::get().getESMStore();
|
||||||
|
|
||||||
int price = pcStats.getSkill(skillId).getBase()
|
int price = pcStats.getSkill(skill->mId).getBase()
|
||||||
* store.get<ESM::GameSetting>().find("iTrainingMod")->mValue.getInteger();
|
* store.get<ESM::GameSetting>().find("iTrainingMod")->mValue.getInteger();
|
||||||
price = MWBase::Environment::get().getMechanicsManager()->getBarterOffer(mPtr, price, true);
|
price = MWBase::Environment::get().getMechanicsManager()->getBarterOffer(mPtr, price, true);
|
||||||
|
|
||||||
if (price > player.getClass().getContainerStore(player).count(MWWorld::ContainerStore::sGoldId))
|
if (price > player.getClass().getContainerStore(player).count(MWWorld::ContainerStore::sGoldId))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (getSkillForTraining(mPtr.getClass().getNpcStats(mPtr), skillId) <= pcStats.getSkill(skillId).getBase())
|
if (getSkillForTraining(mPtr.getClass().getNpcStats(mPtr), skill->mId)
|
||||||
|
<= pcStats.getSkill(skill->mId).getBase())
|
||||||
{
|
{
|
||||||
MWBase::Environment::get().getWindowManager()->messageBox("#{sServiceTrainingWords}");
|
MWBase::Environment::get().getWindowManager()->messageBox("#{sServiceTrainingWords}");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// You can not train a skill above its governing attribute
|
// You can not train a skill above its governing attribute
|
||||||
const ESM::Skill* skill = MWBase::Environment::get().getESMStore()->get<ESM::Skill>().find(skillId);
|
if (pcStats.getSkill(skill->mId).getBase() >= pcStats.getAttribute(skill->mData.mAttribute).getBase())
|
||||||
if (pcStats.getSkill(skillId).getBase() >= pcStats.getAttribute(skill->mData.mAttribute).getBase())
|
|
||||||
{
|
{
|
||||||
MWBase::Environment::get().getWindowManager()->messageBox("#{sNotifyMessage17}");
|
MWBase::Environment::get().getWindowManager()->messageBox("#{sNotifyMessage17}");
|
||||||
return;
|
return;
|
||||||
|
@ -176,7 +160,7 @@ namespace MWGui
|
||||||
MWWorld::LiveCellRef<ESM::NPC>* playerRef = player.get<ESM::NPC>();
|
MWWorld::LiveCellRef<ESM::NPC>* playerRef = player.get<ESM::NPC>();
|
||||||
|
|
||||||
const ESM::Class* class_ = store.get<ESM::Class>().find(playerRef->mBase->mClass);
|
const ESM::Class* class_ = store.get<ESM::Class>().find(playerRef->mBase->mClass);
|
||||||
pcStats.increaseSkill(skillId, *class_, true);
|
pcStats.increaseSkill(skill->mId, *class_, true);
|
||||||
|
|
||||||
// remove gold
|
// remove gold
|
||||||
player.getClass().getContainerStore(player).remove(MWWorld::ContainerStore::sGoldId, price);
|
player.getClass().getContainerStore(player).remove(MWWorld::ContainerStore::sGoldId, price);
|
||||||
|
@ -212,11 +196,11 @@ namespace MWGui
|
||||||
MWBase::Environment::get().getWindowManager()->exitCurrentGuiMode();
|
MWBase::Environment::get().getWindowManager()->exitCurrentGuiMode();
|
||||||
}
|
}
|
||||||
|
|
||||||
float TrainingWindow::getSkillForTraining(const MWMechanics::NpcStats& stats, int skillId) const
|
float TrainingWindow::getSkillForTraining(const MWMechanics::NpcStats& stats, ESM::RefId id) const
|
||||||
{
|
{
|
||||||
if (mTrainingSkillBasedOnBaseSkill)
|
if (mTrainingSkillBasedOnBaseSkill)
|
||||||
return stats.getSkill(skillId).getBase();
|
return stats.getSkill(id).getBase();
|
||||||
return stats.getSkill(skillId).getModified();
|
return stats.getSkill(id).getModified();
|
||||||
}
|
}
|
||||||
|
|
||||||
void TrainingWindow::onFrame(float dt)
|
void TrainingWindow::onFrame(float dt)
|
||||||
|
|
|
@ -42,7 +42,7 @@ namespace MWGui
|
||||||
|
|
||||||
// Retrieve the base skill value if the setting 'training skills based on base skill' is set;
|
// Retrieve the base skill value if the setting 'training skills based on base skill' is set;
|
||||||
// otherwise returns the modified skill
|
// otherwise returns the modified skill
|
||||||
float getSkillForTraining(const MWMechanics::NpcStats& stats, int skillId) const;
|
float getSkillForTraining(const MWMechanics::NpcStats& stats, ESM::RefId id) const;
|
||||||
|
|
||||||
MyGUI::Widget* mTrainingOptions;
|
MyGUI::Widget* mTrainingOptions;
|
||||||
MyGUI::Button* mCancelButton;
|
MyGUI::Button* mCancelButton;
|
||||||
|
|
|
@ -28,28 +28,17 @@ namespace MWGui::Widgets
|
||||||
/* MWSkill */
|
/* MWSkill */
|
||||||
|
|
||||||
MWSkill::MWSkill()
|
MWSkill::MWSkill()
|
||||||
: mSkillId(ESM::Skill::Length)
|
: mSkillNameWidget(nullptr)
|
||||||
, mSkillNameWidget(nullptr)
|
|
||||||
, mSkillValueWidget(nullptr)
|
, mSkillValueWidget(nullptr)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
void MWSkill::setSkillId(ESM::Skill::SkillEnum skill)
|
void MWSkill::setSkillId(ESM::RefId skill)
|
||||||
{
|
{
|
||||||
mSkillId = skill;
|
mSkillId = skill;
|
||||||
updateWidgets();
|
updateWidgets();
|
||||||
}
|
}
|
||||||
|
|
||||||
void MWSkill::setSkillNumber(int skill)
|
|
||||||
{
|
|
||||||
if (skill < 0)
|
|
||||||
setSkillId(ESM::Skill::Length);
|
|
||||||
else if (skill < ESM::Skill::Length)
|
|
||||||
setSkillId(static_cast<ESM::Skill::SkillEnum>(skill));
|
|
||||||
else
|
|
||||||
throw std::runtime_error("Skill number out of range");
|
|
||||||
}
|
|
||||||
|
|
||||||
void MWSkill::setSkillValue(const SkillValue& value)
|
void MWSkill::setSkillValue(const SkillValue& value)
|
||||||
{
|
{
|
||||||
mValue = value;
|
mValue = value;
|
||||||
|
@ -374,7 +363,7 @@ namespace MWGui::Widgets
|
||||||
|
|
||||||
const ESM::MagicEffect* magicEffect = store.get<ESM::MagicEffect>().search(mEffectParams.mEffectID);
|
const ESM::MagicEffect* magicEffect = store.get<ESM::MagicEffect>().search(mEffectParams.mEffectID);
|
||||||
const ESM::Attribute* attribute = store.get<ESM::Attribute>().search(mEffectParams.mAttribute);
|
const ESM::Attribute* attribute = store.get<ESM::Attribute>().search(mEffectParams.mAttribute);
|
||||||
const ESM::Skill* skill = store.get<ESM::Skill>().search(mEffectParams.mSkill);
|
const ESM::Skill* skill = store.get<ESM::Skill>().search(ESM::Skill::indexToRefId(mEffectParams.mSkill));
|
||||||
|
|
||||||
assert(magicEffect);
|
assert(magicEffect);
|
||||||
|
|
||||||
|
|
|
@ -100,11 +100,10 @@ namespace MWGui
|
||||||
|
|
||||||
typedef MWMechanics::Stat<float> SkillValue;
|
typedef MWMechanics::Stat<float> SkillValue;
|
||||||
|
|
||||||
void setSkillId(ESM::Skill::SkillEnum skillId);
|
void setSkillId(ESM::RefId skillId);
|
||||||
void setSkillNumber(int skillId);
|
|
||||||
void setSkillValue(const SkillValue& value);
|
void setSkillValue(const SkillValue& value);
|
||||||
|
|
||||||
ESM::Skill::SkillEnum getSkillId() const { return mSkillId; }
|
ESM::RefId getSkillId() const { return mSkillId; }
|
||||||
const SkillValue& getSkillValue() const { return mValue; }
|
const SkillValue& getSkillValue() const { return mValue; }
|
||||||
|
|
||||||
// Events
|
// Events
|
||||||
|
@ -125,7 +124,7 @@ namespace MWGui
|
||||||
private:
|
private:
|
||||||
void updateWidgets();
|
void updateWidgets();
|
||||||
|
|
||||||
ESM::Skill::SkillEnum mSkillId;
|
ESM::RefId mSkillId;
|
||||||
SkillValue mValue;
|
SkillValue mValue;
|
||||||
MyGUI::TextBox* mSkillNameWidget;
|
MyGUI::TextBox* mSkillNameWidget;
|
||||||
MyGUI::TextBox* mSkillValueWidget;
|
MyGUI::TextBox* mSkillValueWidget;
|
||||||
|
|
|
@ -4,6 +4,7 @@
|
||||||
#include <memory>
|
#include <memory>
|
||||||
#include <set>
|
#include <set>
|
||||||
#include <string>
|
#include <string>
|
||||||
|
#include <utility>
|
||||||
|
|
||||||
#include <components/lua/luastate.hpp>
|
#include <components/lua/luastate.hpp>
|
||||||
#include <components/lua/scriptscontainer.hpp>
|
#include <components/lua/scriptscontainer.hpp>
|
||||||
|
@ -21,11 +22,12 @@ namespace MWLua
|
||||||
class CachedStat
|
class CachedStat
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
using Setter = void (*)(int, std::string_view, const MWWorld::Ptr&, const sol::object&);
|
using Index = std::variant<int, ESM::RefId>;
|
||||||
|
using Setter = void (*)(const Index&, std::string_view, const MWWorld::Ptr&, const sol::object&);
|
||||||
|
|
||||||
CachedStat(Setter setter, int index, std::string_view prop)
|
CachedStat(Setter setter, Index index, std::string_view prop)
|
||||||
: mSetter(setter)
|
: mSetter(setter)
|
||||||
, mIndex(index)
|
, mIndex(std::move(index))
|
||||||
, mProp(std::move(prop))
|
, mProp(std::move(prop))
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
@ -42,7 +44,7 @@ namespace MWLua
|
||||||
|
|
||||||
private:
|
private:
|
||||||
Setter mSetter; // Function that updates a stat's property
|
Setter mSetter; // Function that updates a stat's property
|
||||||
int mIndex; // Optional index to disambiguate the stat
|
Index mIndex; // Optional index to disambiguate the stat
|
||||||
std::string_view mProp; // Name of the stat's property
|
std::string_view mProp; // Name of the stat's property
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -24,9 +24,10 @@ namespace
|
||||||
{
|
{
|
||||||
using SelfObject = MWLua::SelfObject;
|
using SelfObject = MWLua::SelfObject;
|
||||||
using ObjectVariant = MWLua::ObjectVariant;
|
using ObjectVariant = MWLua::ObjectVariant;
|
||||||
|
using Index = const SelfObject::CachedStat::Index&;
|
||||||
|
|
||||||
template <class T>
|
template <class T>
|
||||||
auto addIndexedAccessor(int index)
|
auto addIndexedAccessor(Index index)
|
||||||
{
|
{
|
||||||
return [index](const sol::object& o) { return T::create(ObjectVariant(o), index); };
|
return [index](const sol::object& o) { return T::create(ObjectVariant(o), index); };
|
||||||
}
|
}
|
||||||
|
@ -40,7 +41,7 @@ namespace
|
||||||
|
|
||||||
template <class G>
|
template <class G>
|
||||||
sol::object getValue(const MWLua::Context& context, const ObjectVariant& obj, SelfObject::CachedStat::Setter setter,
|
sol::object getValue(const MWLua::Context& context, const ObjectVariant& obj, SelfObject::CachedStat::Setter setter,
|
||||||
int index, std::string_view prop, G getter)
|
Index index, std::string_view prop, G getter)
|
||||||
{
|
{
|
||||||
if (obj.isSelfObject())
|
if (obj.isSelfObject())
|
||||||
{
|
{
|
||||||
|
@ -99,14 +100,14 @@ namespace MWLua
|
||||||
return sol::make_object(context.mLua->sol(), ptr.getClass().getNpcStats(ptr).getLevelProgress());
|
return sol::make_object(context.mLua->sol(), ptr.getClass().getNpcStats(ptr).getLevelProgress());
|
||||||
}
|
}
|
||||||
|
|
||||||
static std::optional<LevelStat> create(ObjectVariant object, int index)
|
static std::optional<LevelStat> create(ObjectVariant object, Index)
|
||||||
{
|
{
|
||||||
if (!object.ptr().getClass().isActor())
|
if (!object.ptr().getClass().isActor())
|
||||||
return {};
|
return {};
|
||||||
return LevelStat{ std::move(object) };
|
return LevelStat{ std::move(object) };
|
||||||
}
|
}
|
||||||
|
|
||||||
static void setValue(int, std::string_view prop, const MWWorld::Ptr& ptr, const sol::object& value)
|
static void setValue(Index, std::string_view prop, const MWWorld::Ptr& ptr, const sol::object& value)
|
||||||
{
|
{
|
||||||
auto& stats = ptr.getClass().getCreatureStats(ptr);
|
auto& stats = ptr.getClass().getCreatureStats(ptr);
|
||||||
if (prop == "current")
|
if (prop == "current")
|
||||||
|
@ -135,10 +136,11 @@ namespace MWLua
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
static std::optional<DynamicStat> create(ObjectVariant object, int index)
|
static std::optional<DynamicStat> create(ObjectVariant object, Index i)
|
||||||
{
|
{
|
||||||
if (!object.ptr().getClass().isActor())
|
if (!object.ptr().getClass().isActor())
|
||||||
return {};
|
return {};
|
||||||
|
int index = std::get<int>(i);
|
||||||
return DynamicStat{ std::move(object), index };
|
return DynamicStat{ std::move(object), index };
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -149,8 +151,9 @@ namespace MWLua
|
||||||
obj->mStatsCache[SelfObject::CachedStat{ &DynamicStat::setValue, mIndex, prop }] = value;
|
obj->mStatsCache[SelfObject::CachedStat{ &DynamicStat::setValue, mIndex, prop }] = value;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void setValue(int index, std::string_view prop, const MWWorld::Ptr& ptr, const sol::object& value)
|
static void setValue(Index i, std::string_view prop, const MWWorld::Ptr& ptr, const sol::object& value)
|
||||||
{
|
{
|
||||||
|
int index = std::get<int>(i);
|
||||||
auto& stats = ptr.getClass().getCreatureStats(ptr);
|
auto& stats = ptr.getClass().getCreatureStats(ptr);
|
||||||
auto stat = stats.getDynamic(index);
|
auto stat = stats.getDynamic(index);
|
||||||
float floatValue = LuaUtil::cast<float>(value);
|
float floatValue = LuaUtil::cast<float>(value);
|
||||||
|
@ -193,10 +196,11 @@ namespace MWLua
|
||||||
return std::max(0.f, base - damage + modifier); // Should match AttributeValue::getModified
|
return std::max(0.f, base - damage + modifier); // Should match AttributeValue::getModified
|
||||||
}
|
}
|
||||||
|
|
||||||
static std::optional<AttributeStat> create(ObjectVariant object, int index)
|
static std::optional<AttributeStat> create(ObjectVariant object, Index i)
|
||||||
{
|
{
|
||||||
if (!object.ptr().getClass().isActor())
|
if (!object.ptr().getClass().isActor())
|
||||||
return {};
|
return {};
|
||||||
|
int index = std::get<int>(i);
|
||||||
return AttributeStat{ std::move(object), index };
|
return AttributeStat{ std::move(object), index };
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -207,8 +211,9 @@ namespace MWLua
|
||||||
obj->mStatsCache[SelfObject::CachedStat{ &AttributeStat::setValue, mIndex, prop }] = value;
|
obj->mStatsCache[SelfObject::CachedStat{ &AttributeStat::setValue, mIndex, prop }] = value;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void setValue(int index, std::string_view prop, const MWWorld::Ptr& ptr, const sol::object& value)
|
static void setValue(Index i, std::string_view prop, const MWWorld::Ptr& ptr, const sol::object& value)
|
||||||
{
|
{
|
||||||
|
int index = std::get<int>(i);
|
||||||
auto& stats = ptr.getClass().getCreatureStats(ptr);
|
auto& stats = ptr.getClass().getCreatureStats(ptr);
|
||||||
auto stat = stats.getAttribute(index);
|
auto stat = stats.getAttribute(index);
|
||||||
float floatValue = LuaUtil::cast<float>(value);
|
float floatValue = LuaUtil::cast<float>(value);
|
||||||
|
@ -228,37 +233,36 @@ namespace MWLua
|
||||||
class SkillStat
|
class SkillStat
|
||||||
{
|
{
|
||||||
ObjectVariant mObject;
|
ObjectVariant mObject;
|
||||||
int mIndex;
|
ESM::RefId mId;
|
||||||
|
|
||||||
SkillStat(ObjectVariant object, int index)
|
SkillStat(ObjectVariant object, ESM::RefId id)
|
||||||
: mObject(std::move(object))
|
: mObject(std::move(object))
|
||||||
, mIndex(index)
|
, mId(id)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
static float getProgress(const MWWorld::Ptr& ptr, int index, const MWMechanics::SkillValue& stat)
|
static float getProgress(const MWWorld::Ptr& ptr, ESM::RefId id, const MWMechanics::SkillValue& stat)
|
||||||
{
|
{
|
||||||
float progress = stat.getProgress();
|
float progress = stat.getProgress();
|
||||||
if (progress != 0.f)
|
if (progress != 0.f)
|
||||||
progress /= getMaxProgress(ptr, index, stat);
|
progress /= getMaxProgress(ptr, id, stat);
|
||||||
return progress;
|
return progress;
|
||||||
}
|
}
|
||||||
|
|
||||||
static float getMaxProgress(const MWWorld::Ptr& ptr, int index, const MWMechanics::SkillValue& stat)
|
static float getMaxProgress(const MWWorld::Ptr& ptr, ESM::RefId id, const MWMechanics::SkillValue& stat)
|
||||||
{
|
{
|
||||||
const auto& store = *MWBase::Environment::get().getESMStore();
|
const auto& store = *MWBase::Environment::get().getESMStore();
|
||||||
const auto cl = store.get<ESM::Class>().find(ptr.get<ESM::NPC>()->mBase->mClass);
|
const auto cl = store.get<ESM::Class>().find(ptr.get<ESM::NPC>()->mBase->mClass);
|
||||||
return ptr.getClass().getNpcStats(ptr).getSkillProgressRequirement(index, *cl);
|
return ptr.getClass().getNpcStats(ptr).getSkillProgressRequirement(id, *cl);
|
||||||
}
|
}
|
||||||
|
|
||||||
public:
|
public:
|
||||||
template <class G>
|
template <class G>
|
||||||
sol::object get(const Context& context, std::string_view prop, G getter) const
|
sol::object get(const Context& context, std::string_view prop, G getter) const
|
||||||
{
|
{
|
||||||
return getValue(
|
return getValue(context, mObject, &SkillStat::setValue, mId, prop, [this, getter](const MWWorld::Ptr& ptr) {
|
||||||
context, mObject, &SkillStat::setValue, mIndex, prop, [this, getter](const MWWorld::Ptr& ptr) {
|
return (ptr.getClass().getNpcStats(ptr).getSkill(mId).*getter)();
|
||||||
return (ptr.getClass().getNpcStats(ptr).getSkill(mIndex).*getter)();
|
});
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
float getModified(const Context& context) const
|
float getModified(const Context& context) const
|
||||||
|
@ -271,30 +275,31 @@ namespace MWLua
|
||||||
|
|
||||||
sol::object getProgress(const Context& context) const
|
sol::object getProgress(const Context& context) const
|
||||||
{
|
{
|
||||||
return getValue(
|
return getValue(context, mObject, &SkillStat::setValue, mId, "progress", [this](const MWWorld::Ptr& ptr) {
|
||||||
context, mObject, &SkillStat::setValue, mIndex, "progress", [this](const MWWorld::Ptr& ptr) {
|
return getProgress(ptr, mId, ptr.getClass().getNpcStats(ptr).getSkill(mId));
|
||||||
return getProgress(ptr, mIndex, ptr.getClass().getNpcStats(ptr).getSkill(mIndex));
|
});
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static std::optional<SkillStat> create(ObjectVariant object, int index)
|
static std::optional<SkillStat> create(ObjectVariant object, Index index)
|
||||||
{
|
{
|
||||||
if (!object.ptr().getClass().isNpc())
|
if (!object.ptr().getClass().isNpc())
|
||||||
return {};
|
return {};
|
||||||
return SkillStat{ std::move(object), index };
|
ESM::RefId id = std::get<ESM::RefId>(index);
|
||||||
|
return SkillStat{ std::move(object), id };
|
||||||
}
|
}
|
||||||
|
|
||||||
void cache(const Context& context, std::string_view prop, const sol::object& value) const
|
void cache(const Context& context, std::string_view prop, const sol::object& value) const
|
||||||
{
|
{
|
||||||
SelfObject* obj = mObject.asSelfObject();
|
SelfObject* obj = mObject.asSelfObject();
|
||||||
addStatUpdateAction(context.mLuaManager, *obj);
|
addStatUpdateAction(context.mLuaManager, *obj);
|
||||||
obj->mStatsCache[SelfObject::CachedStat{ &SkillStat::setValue, mIndex, prop }] = value;
|
obj->mStatsCache[SelfObject::CachedStat{ &SkillStat::setValue, mId, prop }] = value;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void setValue(int index, std::string_view prop, const MWWorld::Ptr& ptr, const sol::object& value)
|
static void setValue(Index index, std::string_view prop, const MWWorld::Ptr& ptr, const sol::object& value)
|
||||||
{
|
{
|
||||||
|
ESM::RefId id = std::get<ESM::RefId>(index);
|
||||||
auto& stats = ptr.getClass().getNpcStats(ptr);
|
auto& stats = ptr.getClass().getNpcStats(ptr);
|
||||||
auto stat = stats.getSkill(index);
|
auto stat = stats.getSkill(id);
|
||||||
float floatValue = LuaUtil::cast<float>(value);
|
float floatValue = LuaUtil::cast<float>(value);
|
||||||
if (prop == "base")
|
if (prop == "base")
|
||||||
stat.setBase(floatValue);
|
stat.setBase(floatValue);
|
||||||
|
@ -306,8 +311,8 @@ namespace MWLua
|
||||||
else if (prop == "modifier")
|
else if (prop == "modifier")
|
||||||
stat.setModifier(floatValue);
|
stat.setModifier(floatValue);
|
||||||
else if (prop == "progress")
|
else if (prop == "progress")
|
||||||
stat.setProgress(floatValue * getMaxProgress(ptr, index, stat));
|
stat.setProgress(floatValue * getMaxProgress(ptr, id, stat));
|
||||||
stats.setSkill(index, stat);
|
stats.setSkill(id, stat);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@ -385,7 +390,8 @@ namespace MWLua
|
||||||
[context](const SkillStat& stat, const sol::object& value) { stat.cache(context, "progress", value); });
|
[context](const SkillStat& stat, const sol::object& value) { stat.cache(context, "progress", value); });
|
||||||
sol::table skills(context.mLua->sol(), sol::create);
|
sol::table skills(context.mLua->sol(), sol::create);
|
||||||
npcStats["skills"] = LuaUtil::makeReadOnly(skills);
|
npcStats["skills"] = LuaUtil::makeReadOnly(skills);
|
||||||
for (int id = ESM::Skill::Block; id < ESM::Skill::Length; ++id)
|
for (const ESM::Skill& skill : MWBase::Environment::get().getESMStore()->get<ESM::Skill>())
|
||||||
skills[Misc::StringUtils::lowerCase(ESM::Skill::sSkillNames[id])] = addIndexedAccessor<SkillStat>(id);
|
skills[Misc::StringUtils::lowerCase(ESM::Skill::sSkillNames[skill.mIndex])]
|
||||||
|
= addIndexedAccessor<SkillStat>(skill.mId);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -67,7 +67,7 @@ namespace MWLua
|
||||||
sol::table skill(context.mLua->sol(), sol::create);
|
sol::table skill(context.mLua->sol(), sol::create);
|
||||||
book["SKILL"] = LuaUtil::makeStrictReadOnly(skill);
|
book["SKILL"] = LuaUtil::makeStrictReadOnly(skill);
|
||||||
book["createRecordDraft"] = tableToBook;
|
book["createRecordDraft"] = tableToBook;
|
||||||
for (int id = ESM::Skill::Block; id < ESM::Skill::Length; ++id)
|
for (int id = 0; id < ESM::Skill::Length; ++id)
|
||||||
{
|
{
|
||||||
std::string skillName = Misc::StringUtils::lowerCase(ESM::Skill::sSkillNames[id]);
|
std::string skillName = Misc::StringUtils::lowerCase(ESM::Skill::sSkillNames[id]);
|
||||||
skill[skillName] = skillName;
|
skill[skillName] = skillName;
|
||||||
|
|
|
@ -576,7 +576,7 @@ std::vector<std::string> MWMechanics::Alchemy::effectsDescription(const MWWorld:
|
||||||
if (effectID != -1)
|
if (effectID != -1)
|
||||||
{
|
{
|
||||||
const ESM::Attribute* attribute = store->get<ESM::Attribute>().search(data.mAttributes[i]);
|
const ESM::Attribute* attribute = store->get<ESM::Attribute>().search(data.mAttributes[i]);
|
||||||
const ESM::Skill* skill = store->get<ESM::Skill>().search(data.mAttributes[i]);
|
const ESM::Skill* skill = store->get<ESM::Skill>().search(ESM::Skill::indexToRefId(data.mSkills[i]));
|
||||||
std::string effect = getMagicEffectString(*mgef.find(effectID), attribute, skill);
|
std::string effect = getMagicEffectString(*mgef.find(effectID), attribute, skill);
|
||||||
|
|
||||||
effects.push_back(effect);
|
effects.push_back(effect);
|
||||||
|
|
|
@ -27,7 +27,8 @@ namespace MWMechanics
|
||||||
ESM::RefId mWeakestSpell;
|
ESM::RefId mWeakestSpell;
|
||||||
};
|
};
|
||||||
|
|
||||||
std::vector<ESM::RefId> autoCalcNpcSpells(const int* actorSkills, const int* actorAttributes, const ESM::Race* race)
|
std::vector<ESM::RefId> autoCalcNpcSpells(
|
||||||
|
const std::map<ESM::RefId, SkillValue>& actorSkills, const int* actorAttributes, const ESM::Race* race)
|
||||||
{
|
{
|
||||||
const MWWorld::Store<ESM::GameSetting>& gmst
|
const MWWorld::Store<ESM::GameSetting>& gmst
|
||||||
= MWBase::Environment::get().getESMStore()->get<ESM::GameSetting>();
|
= MWBase::Environment::get().getESMStore()->get<ESM::GameSetting>();
|
||||||
|
@ -148,7 +149,7 @@ namespace MWMechanics
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector<ESM::RefId> autoCalcPlayerSpells(
|
std::vector<ESM::RefId> autoCalcPlayerSpells(
|
||||||
const int* actorSkills, const int* actorAttributes, const ESM::Race* race)
|
const std::map<ESM::RefId, SkillValue>& actorSkills, const int* actorAttributes, const ESM::Race* race)
|
||||||
{
|
{
|
||||||
const MWWorld::ESMStore& esmStore = *MWBase::Environment::get().getESMStore();
|
const MWWorld::ESMStore& esmStore = *MWBase::Environment::get().getESMStore();
|
||||||
|
|
||||||
|
@ -226,7 +227,8 @@ namespace MWMechanics
|
||||||
return selectedSpells;
|
return selectedSpells;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool attrSkillCheck(const ESM::Spell* spell, const int* actorSkills, const int* actorAttributes)
|
bool attrSkillCheck(
|
||||||
|
const ESM::Spell* spell, const std::map<ESM::RefId, SkillValue>& actorSkills, const int* actorAttributes)
|
||||||
{
|
{
|
||||||
for (const auto& spellEffect : spell->mEffects.mList)
|
for (const auto& spellEffect : spell->mEffects.mList)
|
||||||
{
|
{
|
||||||
|
@ -240,8 +242,9 @@ namespace MWMechanics
|
||||||
|
|
||||||
if ((magicEffect->mData.mFlags & ESM::MagicEffect::TargetSkill))
|
if ((magicEffect->mData.mFlags & ESM::MagicEffect::TargetSkill))
|
||||||
{
|
{
|
||||||
assert(spellEffect.mSkill >= 0 && spellEffect.mSkill < ESM::Skill::Length);
|
ESM::RefId skill = ESM::Skill::indexToRefId(spellEffect.mSkill);
|
||||||
if (actorSkills[spellEffect.mSkill] < iAutoSpellAttSkillMin)
|
auto found = actorSkills.find(skill);
|
||||||
|
if (found == actorSkills.end() || found->second.getBase() < iAutoSpellAttSkillMin)
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -256,7 +259,8 @@ namespace MWMechanics
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void calcWeakestSchool(const ESM::Spell* spell, const int* actorSkills, int& effectiveSchool, float& skillTerm)
|
void calcWeakestSchool(const ESM::Spell* spell, const std::map<ESM::RefId, SkillValue>& actorSkills,
|
||||||
|
int& effectiveSchool, float& skillTerm)
|
||||||
{
|
{
|
||||||
// Morrowind for some reason uses a formula slightly different from magicka cost calculation
|
// Morrowind for some reason uses a formula slightly different from magicka cost calculation
|
||||||
float minChance = std::numeric_limits<float>::max();
|
float minChance = std::numeric_limits<float>::max();
|
||||||
|
@ -294,7 +298,11 @@ namespace MWMechanics
|
||||||
if (effect.mRange == ESM::RT_Target)
|
if (effect.mRange == ESM::RT_Target)
|
||||||
x *= 1.5f;
|
x *= 1.5f;
|
||||||
|
|
||||||
float s = 2.f * actorSkills[spellSchoolToSkill(magicEffect->mData.mSchool)];
|
float s = 0.f;
|
||||||
|
ESM::RefId skill = spellSchoolToSkill(magicEffect->mData.mSchool);
|
||||||
|
auto found = actorSkills.find(skill);
|
||||||
|
if (found != actorSkills.end())
|
||||||
|
s = 2.f * found->second.getBase();
|
||||||
if (s - x < minChance)
|
if (s - x < minChance)
|
||||||
{
|
{
|
||||||
minChance = s - x;
|
minChance = s - x;
|
||||||
|
@ -304,8 +312,8 @@ namespace MWMechanics
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
float calcAutoCastChance(
|
float calcAutoCastChance(const ESM::Spell* spell, const std::map<ESM::RefId, SkillValue>& actorSkills,
|
||||||
const ESM::Spell* spell, const int* actorSkills, const int* actorAttributes, int effectiveSchool)
|
const int* actorAttributes, int effectiveSchool)
|
||||||
{
|
{
|
||||||
if (spell->mData.mType != ESM::Spell::ST_Spell)
|
if (spell->mData.mType != ESM::Spell::ST_Spell)
|
||||||
return 100.f;
|
return 100.f;
|
||||||
|
@ -315,7 +323,12 @@ namespace MWMechanics
|
||||||
|
|
||||||
float skillTerm = 0;
|
float skillTerm = 0;
|
||||||
if (effectiveSchool != -1)
|
if (effectiveSchool != -1)
|
||||||
skillTerm = 2.f * actorSkills[spellSchoolToSkill(effectiveSchool)];
|
{
|
||||||
|
ESM::RefId skill = spellSchoolToSkill(effectiveSchool);
|
||||||
|
auto found = actorSkills.find(skill);
|
||||||
|
if (found != actorSkills.end())
|
||||||
|
skillTerm = 2.f * found->second.getBase();
|
||||||
|
}
|
||||||
else
|
else
|
||||||
calcWeakestSchool(
|
calcWeakestSchool(
|
||||||
spell, actorSkills, effectiveSchool, skillTerm); // Note effectiveSchool is unused after this
|
spell, actorSkills, effectiveSchool, skillTerm); // Note effectiveSchool is unused after this
|
||||||
|
|
|
@ -1,9 +1,12 @@
|
||||||
#ifndef OPENMW_AUTOCALCSPELL_H
|
#ifndef OPENMW_AUTOCALCSPELL_H
|
||||||
#define OPENMW_AUTOCALCSPELL_H
|
#define OPENMW_AUTOCALCSPELL_H
|
||||||
|
|
||||||
|
#include "creaturestats.hpp"
|
||||||
#include <components/esm/refid.hpp>
|
#include <components/esm/refid.hpp>
|
||||||
|
#include <map>
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
namespace ESM
|
namespace ESM
|
||||||
{
|
{
|
||||||
struct Spell;
|
struct Spell;
|
||||||
|
@ -17,19 +20,21 @@ namespace MWMechanics
|
||||||
/// @note We might want to move this code to a component later, so the editor can use it for preview purposes
|
/// @note We might want to move this code to a component later, so the editor can use it for preview purposes
|
||||||
|
|
||||||
std::vector<ESM::RefId> autoCalcNpcSpells(
|
std::vector<ESM::RefId> autoCalcNpcSpells(
|
||||||
const int* actorSkills, const int* actorAttributes, const ESM::Race* race);
|
const std::map<ESM::RefId, SkillValue>& actorSkills, const int* actorAttributes, const ESM::Race* race);
|
||||||
|
|
||||||
std::vector<ESM::RefId> autoCalcPlayerSpells(
|
std::vector<ESM::RefId> autoCalcPlayerSpells(
|
||||||
const int* actorSkills, const int* actorAttributes, const ESM::Race* race);
|
const std::map<ESM::RefId, SkillValue>& actorSkills, const int* actorAttributes, const ESM::Race* race);
|
||||||
|
|
||||||
// Helpers
|
// Helpers
|
||||||
|
|
||||||
bool attrSkillCheck(const ESM::Spell* spell, const int* actorSkills, const int* actorAttributes);
|
bool attrSkillCheck(
|
||||||
|
const ESM::Spell* spell, const std::map<ESM::RefId, SkillValue>& actorSkills, const int* actorAttributes);
|
||||||
|
|
||||||
void calcWeakestSchool(const ESM::Spell* spell, const int* actorSkills, int& effectiveSchool, float& skillTerm);
|
void calcWeakestSchool(const ESM::Spell* spell, const std::map<ESM::RefId, SkillValue>& actorSkills,
|
||||||
|
int& effectiveSchool, float& skillTerm);
|
||||||
|
|
||||||
float calcAutoCastChance(
|
float calcAutoCastChance(const ESM::Spell* spell, const std::map<ESM::RefId, SkillValue>& actorSkills,
|
||||||
const ESM::Spell* spell, const int* actorSkills, const int* actorAttributes, int effectiveSchool);
|
const int* actorAttributes, int effectiveSchool);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -217,7 +217,7 @@ namespace MWMechanics
|
||||||
|
|
||||||
bool validVictim = !victim.isEmpty() && victim.getClass().isActor();
|
bool validVictim = !victim.isEmpty() && victim.getClass().isActor();
|
||||||
|
|
||||||
int weaponSkill = ESM::Skill::Marksman;
|
ESM::RefId weaponSkill = ESM::Skill::Marksman;
|
||||||
if (!weapon.isEmpty())
|
if (!weapon.isEmpty())
|
||||||
weaponSkill = weapon.getClass().getEquipmentSkill(weapon);
|
weaponSkill = weapon.getClass().getEquipmentSkill(weapon);
|
||||||
|
|
||||||
|
|
|
@ -53,8 +53,8 @@ namespace MWMechanics
|
||||||
{
|
{
|
||||||
const auto& store = MWBase::Environment::get().getESMStore();
|
const auto& store = MWBase::Environment::get().getESMStore();
|
||||||
const ESM::MagicEffect* magicEffect = store->get<ESM::MagicEffect>().search(mId);
|
const ESM::MagicEffect* magicEffect = store->get<ESM::MagicEffect>().search(mId);
|
||||||
return getMagicEffectString(
|
return getMagicEffectString(*magicEffect, store->get<ESM::Attribute>().search(mArg),
|
||||||
*magicEffect, store->get<ESM::Attribute>().search(mArg), store->get<ESM::Skill>().search(mArg));
|
store->get<ESM::Skill>().search(ESM::Skill::indexToRefId(mArg)));
|
||||||
}
|
}
|
||||||
|
|
||||||
bool operator<(const EffectKey& left, const EffectKey& right)
|
bool operator<(const EffectKey& left, const EffectKey& right)
|
||||||
|
|
|
@ -129,7 +129,7 @@ namespace MWMechanics
|
||||||
creatureStats.getActiveSpells().clear(ptr);
|
creatureStats.getActiveSpells().clear(ptr);
|
||||||
|
|
||||||
for (size_t i = 0; i < player->mNpdt.mSkills.size(); ++i)
|
for (size_t i = 0; i < player->mNpdt.mSkills.size(); ++i)
|
||||||
npcStats.getSkill(i).setBase(player->mNpdt.mSkills[i]);
|
npcStats.getSkill(ESM::Skill::indexToRefId(i)).setBase(player->mNpdt.mSkills[i]);
|
||||||
|
|
||||||
creatureStats.setAttribute(ESM::Attribute::Strength, player->mNpdt.mStrength);
|
creatureStats.setAttribute(ESM::Attribute::Strength, player->mNpdt.mStrength);
|
||||||
creatureStats.setAttribute(ESM::Attribute::Intelligence, player->mNpdt.mIntelligence);
|
creatureStats.setAttribute(ESM::Attribute::Intelligence, player->mNpdt.mIntelligence);
|
||||||
|
@ -155,16 +155,16 @@ namespace MWMechanics
|
||||||
creatureStats.setAttribute(i, male ? attribute.mMale : attribute.mFemale);
|
creatureStats.setAttribute(i, male ? attribute.mMale : attribute.mFemale);
|
||||||
}
|
}
|
||||||
|
|
||||||
for (int i = 0; i < 27; ++i)
|
for (const ESM::Skill& skill : esmStore.get<ESM::Skill>())
|
||||||
{
|
{
|
||||||
int bonus = 0;
|
int bonus = 0;
|
||||||
|
|
||||||
auto bonusIt = std::find_if(race->mData.mBonus.begin(), race->mData.mBonus.end(),
|
auto bonusIt = std::find_if(race->mData.mBonus.begin(), race->mData.mBonus.end(),
|
||||||
[i](const auto& bonus) { return bonus.mSkill == i; });
|
[&](const auto& bonus) { return bonus.mSkill == skill.mIndex; });
|
||||||
if (bonusIt != race->mData.mBonus.end())
|
if (bonusIt != race->mData.mBonus.end())
|
||||||
bonus = bonusIt->mBonus;
|
bonus = bonusIt->mBonus;
|
||||||
|
|
||||||
npcStats.getSkill(i).setBase(5 + bonus);
|
npcStats.getSkill(skill.mId).setBase(5 + bonus);
|
||||||
}
|
}
|
||||||
|
|
||||||
for (const ESM::RefId& power : race->mPowers.mList)
|
for (const ESM::RefId& power : race->mPowers.mList)
|
||||||
|
@ -205,29 +205,16 @@ namespace MWMechanics
|
||||||
|
|
||||||
for (const auto& skills : class_->mData.mSkills)
|
for (const auto& skills : class_->mData.mSkills)
|
||||||
{
|
{
|
||||||
int index = skills[i];
|
ESM::RefId id = ESM::Skill::indexToRefId(skills[i]);
|
||||||
|
if (!id.empty())
|
||||||
if (index >= 0 && index < ESM::Skill::Length)
|
npcStats.getSkill(id).setBase(npcStats.getSkill(id).getBase() + bonus);
|
||||||
{
|
|
||||||
npcStats.getSkill(index).setBase(npcStats.getSkill(index).getBase() + bonus);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const MWWorld::Store<ESM::Skill>& skills = esmStore.get<ESM::Skill>();
|
for (const ESM::Skill& skill : esmStore.get<ESM::Skill>())
|
||||||
|
|
||||||
MWWorld::Store<ESM::Skill>::iterator iter = skills.begin();
|
|
||||||
for (; iter != skills.end(); ++iter)
|
|
||||||
{
|
{
|
||||||
if (iter->second.mData.mSpecialization == class_->mData.mSpecialization)
|
if (skill.mData.mSpecialization == class_->mData.mSpecialization)
|
||||||
{
|
npcStats.getSkill(skill.mId).setBase(npcStats.getSkill(skill.mId).getBase() + 5);
|
||||||
int index = iter->first;
|
|
||||||
|
|
||||||
if (index >= 0 && index < 27)
|
|
||||||
{
|
|
||||||
npcStats.getSkill(index).setBase(npcStats.getSkill(index).getBase() + 5);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -236,16 +223,12 @@ namespace MWMechanics
|
||||||
if (mRaceSelected)
|
if (mRaceSelected)
|
||||||
race = esmStore.get<ESM::Race>().find(player->mRace);
|
race = esmStore.get<ESM::Race>().find(player->mRace);
|
||||||
|
|
||||||
int skills[ESM::Skill::Length];
|
|
||||||
for (int i = 0; i < ESM::Skill::Length; ++i)
|
|
||||||
skills[i] = npcStats.getSkill(i).getBase();
|
|
||||||
|
|
||||||
int attributes[ESM::Attribute::Length];
|
int attributes[ESM::Attribute::Length];
|
||||||
for (int i = 0; i < ESM::Attribute::Length; ++i)
|
for (int i = 0; i < ESM::Attribute::Length; ++i)
|
||||||
attributes[i] = npcStats.getAttribute(i).getBase();
|
attributes[i] = npcStats.getAttribute(i).getBase();
|
||||||
npcStats.updateHealth();
|
npcStats.updateHealth();
|
||||||
|
|
||||||
std::vector<ESM::RefId> selectedSpells = autoCalcPlayerSpells(skills, attributes, race);
|
std::vector<ESM::RefId> selectedSpells = autoCalcPlayerSpells(npcStats.getSkills(), attributes, race);
|
||||||
|
|
||||||
for (const ESM::RefId& spell : selectedSpells)
|
for (const ESM::RefId& spell : selectedSpells)
|
||||||
creatureStats.getSpells().add(spell);
|
creatureStats.getSpells().add(spell);
|
||||||
|
@ -1921,7 +1904,7 @@ namespace MWMechanics
|
||||||
const ESM::Skill* acrobatics
|
const ESM::Skill* acrobatics
|
||||||
= MWBase::Environment::get().getESMStore()->get<ESM::Skill>().find(ESM::Skill::Acrobatics);
|
= MWBase::Environment::get().getESMStore()->get<ESM::Skill>().find(ESM::Skill::Acrobatics);
|
||||||
MWMechanics::NpcStats& stats = actor.getClass().getNpcStats(actor);
|
MWMechanics::NpcStats& stats = actor.getClass().getNpcStats(actor);
|
||||||
auto& skill = stats.getSkill(acrobatics->mIndex);
|
auto& skill = stats.getSkill(acrobatics->mId);
|
||||||
skill.setModifier(acrobatics->mWerewolfValue - skill.getModified());
|
skill.setModifier(acrobatics->mWerewolfValue - skill.getModified());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -30,6 +30,8 @@ MWMechanics::NpcStats::NpcStats()
|
||||||
{
|
{
|
||||||
mSkillIncreases.resize(ESM::Attribute::Length, 0);
|
mSkillIncreases.resize(ESM::Attribute::Length, 0);
|
||||||
mSpecIncreases.resize(3, 0);
|
mSpecIncreases.resize(3, 0);
|
||||||
|
for (const ESM::Skill& skill : MWBase::Environment::get().getESMStore()->get<ESM::Skill>())
|
||||||
|
mSkills.emplace(skill.mId, SkillValue{});
|
||||||
}
|
}
|
||||||
|
|
||||||
int MWMechanics::NpcStats::getBaseDisposition() const
|
int MWMechanics::NpcStats::getBaseDisposition() const
|
||||||
|
@ -42,28 +44,28 @@ void MWMechanics::NpcStats::setBaseDisposition(int disposition)
|
||||||
mDisposition = disposition;
|
mDisposition = disposition;
|
||||||
}
|
}
|
||||||
|
|
||||||
const MWMechanics::SkillValue& MWMechanics::NpcStats::getSkill(int index) const
|
const MWMechanics::SkillValue& MWMechanics::NpcStats::getSkill(ESM::RefId id) const
|
||||||
{
|
{
|
||||||
if (index < 0 || index >= ESM::Skill::Length)
|
auto it = mSkills.find(id);
|
||||||
throw std::runtime_error("skill index out of range");
|
if (it == mSkills.end())
|
||||||
|
throw std::runtime_error("skill not found");
|
||||||
return mSkill[index];
|
return it->second;
|
||||||
}
|
}
|
||||||
|
|
||||||
MWMechanics::SkillValue& MWMechanics::NpcStats::getSkill(int index)
|
MWMechanics::SkillValue& MWMechanics::NpcStats::getSkill(ESM::RefId id)
|
||||||
{
|
{
|
||||||
if (index < 0 || index >= ESM::Skill::Length)
|
auto it = mSkills.find(id);
|
||||||
throw std::runtime_error("skill index out of range");
|
if (it == mSkills.end())
|
||||||
|
throw std::runtime_error("skill not found");
|
||||||
return mSkill[index];
|
return it->second;
|
||||||
}
|
}
|
||||||
|
|
||||||
void MWMechanics::NpcStats::setSkill(int index, const MWMechanics::SkillValue& value)
|
void MWMechanics::NpcStats::setSkill(ESM::RefId id, const MWMechanics::SkillValue& value)
|
||||||
{
|
{
|
||||||
if (index < 0 || index >= ESM::Skill::Length)
|
auto it = mSkills.find(id);
|
||||||
throw std::runtime_error("skill index out of range");
|
if (it == mSkills.end())
|
||||||
|
throw std::runtime_error("skill not found");
|
||||||
mSkill[index] = value;
|
it->second = value;
|
||||||
}
|
}
|
||||||
|
|
||||||
const std::map<ESM::RefId, int>& MWMechanics::NpcStats::getFactionRanks() const
|
const std::map<ESM::RefId, int>& MWMechanics::NpcStats::getFactionRanks() const
|
||||||
|
@ -154,22 +156,23 @@ void MWMechanics::NpcStats::setFactionReputation(const ESM::RefId& faction, int
|
||||||
mFactionReputation[faction] = value;
|
mFactionReputation[faction] = value;
|
||||||
}
|
}
|
||||||
|
|
||||||
float MWMechanics::NpcStats::getSkillProgressRequirement(int skillIndex, const ESM::Class& class_) const
|
float MWMechanics::NpcStats::getSkillProgressRequirement(ESM::RefId id, const ESM::Class& class_) const
|
||||||
{
|
{
|
||||||
float progressRequirement = static_cast<float>(1 + getSkill(skillIndex).getBase());
|
float progressRequirement = 1.f + getSkill(id).getBase();
|
||||||
|
|
||||||
const MWWorld::Store<ESM::GameSetting>& gmst = MWBase::Environment::get().getESMStore()->get<ESM::GameSetting>();
|
const MWWorld::Store<ESM::GameSetting>& gmst = MWBase::Environment::get().getESMStore()->get<ESM::GameSetting>();
|
||||||
|
const ESM::Skill* skill = MWBase::Environment::get().getESMStore()->get<ESM::Skill>().find(id);
|
||||||
|
|
||||||
float typeFactor = gmst.find("fMiscSkillBonus")->mValue.getFloat();
|
float typeFactor = gmst.find("fMiscSkillBonus")->mValue.getFloat();
|
||||||
|
|
||||||
for (const auto& skills : class_.mData.mSkills)
|
for (const auto& skills : class_.mData.mSkills)
|
||||||
{
|
{
|
||||||
if (skills[0] == skillIndex)
|
if (skills[0] == skill->mIndex)
|
||||||
{
|
{
|
||||||
typeFactor = gmst.find("fMinorSkillBonus")->mValue.getFloat();
|
typeFactor = gmst.find("fMinorSkillBonus")->mValue.getFloat();
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
else if (skills[1] == skillIndex)
|
else if (skills[1] == skill->mIndex)
|
||||||
{
|
{
|
||||||
typeFactor = gmst.find("fMajorSkillBonus")->mValue.getFloat();
|
typeFactor = gmst.find("fMajorSkillBonus")->mValue.getFloat();
|
||||||
break;
|
break;
|
||||||
|
@ -183,7 +186,6 @@ float MWMechanics::NpcStats::getSkillProgressRequirement(int skillIndex, const E
|
||||||
|
|
||||||
float specialisationFactor = 1;
|
float specialisationFactor = 1;
|
||||||
|
|
||||||
const ESM::Skill* skill = MWBase::Environment::get().getESMStore()->get<ESM::Skill>().find(skillIndex);
|
|
||||||
if (skill->mData.mSpecialization == class_.mData.mSpecialization)
|
if (skill->mData.mSpecialization == class_.mData.mSpecialization)
|
||||||
{
|
{
|
||||||
specialisationFactor = gmst.find("fSpecialSkillBonus")->mValue.getFloat();
|
specialisationFactor = gmst.find("fSpecialSkillBonus")->mValue.getFloat();
|
||||||
|
@ -196,9 +198,9 @@ float MWMechanics::NpcStats::getSkillProgressRequirement(int skillIndex, const E
|
||||||
return progressRequirement;
|
return progressRequirement;
|
||||||
}
|
}
|
||||||
|
|
||||||
void MWMechanics::NpcStats::useSkill(int skillIndex, const ESM::Class& class_, int usageType, float extraFactor)
|
void MWMechanics::NpcStats::useSkill(ESM::RefId id, const ESM::Class& class_, int usageType, float extraFactor)
|
||||||
{
|
{
|
||||||
const ESM::Skill* skill = MWBase::Environment::get().getESMStore()->get<ESM::Skill>().find(skillIndex);
|
const ESM::Skill* skill = MWBase::Environment::get().getESMStore()->get<ESM::Skill>().find(id);
|
||||||
float skillGain = 1;
|
float skillGain = 1;
|
||||||
if (usageType >= 4)
|
if (usageType >= 4)
|
||||||
throw std::runtime_error("skill usage type out of range");
|
throw std::runtime_error("skill usage type out of range");
|
||||||
|
@ -210,21 +212,21 @@ void MWMechanics::NpcStats::useSkill(int skillIndex, const ESM::Class& class_, i
|
||||||
}
|
}
|
||||||
skillGain *= extraFactor;
|
skillGain *= extraFactor;
|
||||||
|
|
||||||
MWMechanics::SkillValue& value = getSkill(skillIndex);
|
MWMechanics::SkillValue& value = getSkill(skill->mId);
|
||||||
|
|
||||||
value.setProgress(value.getProgress() + skillGain);
|
value.setProgress(value.getProgress() + skillGain);
|
||||||
|
|
||||||
if (int(value.getProgress()) >= int(getSkillProgressRequirement(skillIndex, class_)))
|
if (int(value.getProgress()) >= int(getSkillProgressRequirement(skill->mId, class_)))
|
||||||
{
|
{
|
||||||
// skill levelled up
|
// skill levelled up
|
||||||
increaseSkill(skillIndex, class_, false);
|
increaseSkill(skill->mId, class_, false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void MWMechanics::NpcStats::increaseSkill(
|
void MWMechanics::NpcStats::increaseSkill(ESM::RefId id, const ESM::Class& class_, bool preserveProgress, bool readBook)
|
||||||
int skillIndex, const ESM::Class& class_, bool preserveProgress, bool readBook)
|
|
||||||
{
|
{
|
||||||
float base = getSkill(skillIndex).getBase();
|
const ESM::Skill* skill = MWBase::Environment::get().getESMStore()->get<ESM::Skill>().find(id);
|
||||||
|
float base = getSkill(skill->mId).getBase();
|
||||||
|
|
||||||
if (base >= 100.f)
|
if (base >= 100.f)
|
||||||
return;
|
return;
|
||||||
|
@ -237,13 +239,13 @@ void MWMechanics::NpcStats::increaseSkill(
|
||||||
int increase = gmst.find("iLevelupMiscMultAttriubte")->mValue.getInteger(); // Note: GMST has a typo
|
int increase = gmst.find("iLevelupMiscMultAttriubte")->mValue.getInteger(); // Note: GMST has a typo
|
||||||
for (const auto& skills : class_.mData.mSkills)
|
for (const auto& skills : class_.mData.mSkills)
|
||||||
{
|
{
|
||||||
if (skills[0] == skillIndex)
|
if (skills[0] == skill->mIndex)
|
||||||
{
|
{
|
||||||
mLevelProgress += gmst.find("iLevelUpMinorMult")->mValue.getInteger();
|
mLevelProgress += gmst.find("iLevelUpMinorMult")->mValue.getInteger();
|
||||||
increase = gmst.find("iLevelUpMinorMultAttribute")->mValue.getInteger();
|
increase = gmst.find("iLevelUpMinorMultAttribute")->mValue.getInteger();
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
else if (skills[1] == skillIndex)
|
else if (skills[1] == skill->mIndex)
|
||||||
{
|
{
|
||||||
mLevelProgress += gmst.find("iLevelUpMajorMult")->mValue.getInteger();
|
mLevelProgress += gmst.find("iLevelUpMajorMult")->mValue.getInteger();
|
||||||
increase = gmst.find("iLevelUpMajorMultAttribute")->mValue.getInteger();
|
increase = gmst.find("iLevelUpMajorMultAttribute")->mValue.getInteger();
|
||||||
|
@ -251,7 +253,6 @@ void MWMechanics::NpcStats::increaseSkill(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const ESM::Skill* skill = MWBase::Environment::get().getESMStore()->get<ESM::Skill>().find(skillIndex);
|
|
||||||
mSkillIncreases[skill->mData.mAttribute] += increase;
|
mSkillIncreases[skill->mData.mAttribute] += increase;
|
||||||
|
|
||||||
mSpecIncreases[skill->mData.mSpecialization] += gmst.find("iLevelupSpecialization")->mValue.getInteger();
|
mSpecIncreases[skill->mData.mSpecialization] += gmst.find("iLevelupSpecialization")->mValue.getInteger();
|
||||||
|
@ -275,9 +276,9 @@ void MWMechanics::NpcStats::increaseSkill(
|
||||||
MWBase::Environment::get().getWindowManager()->messageBox("#{sLevelUpMsg}", MWGui::ShowInDialogueMode_Never);
|
MWBase::Environment::get().getWindowManager()->messageBox("#{sLevelUpMsg}", MWGui::ShowInDialogueMode_Never);
|
||||||
}
|
}
|
||||||
|
|
||||||
getSkill(skillIndex).setBase(base);
|
getSkill(skill->mId).setBase(base);
|
||||||
if (!preserveProgress)
|
if (!preserveProgress)
|
||||||
getSkill(skillIndex).setProgress(0);
|
getSkill(skill->mId).setProgress(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
int MWMechanics::NpcStats::getLevelProgress() const
|
int MWMechanics::NpcStats::getLevelProgress() const
|
||||||
|
@ -388,9 +389,10 @@ bool MWMechanics::NpcStats::hasSkillsForRank(const ESM::RefId& factionId, int ra
|
||||||
|
|
||||||
std::vector<int> skills;
|
std::vector<int> skills;
|
||||||
|
|
||||||
for (int id : faction.mData.mSkills)
|
for (int index : faction.mData.mSkills)
|
||||||
{
|
{
|
||||||
if (id != -1)
|
ESM::RefId id = ESM::Skill::indexToRefId(index);
|
||||||
|
if (!id.empty())
|
||||||
skills.push_back(static_cast<int>(getSkill(id).getBase()));
|
skills.push_back(static_cast<int>(getSkill(id).getBase()));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -470,8 +472,12 @@ void MWMechanics::NpcStats::writeState(ESM::NpcStats& state) const
|
||||||
|
|
||||||
state.mDisposition = mDisposition;
|
state.mDisposition = mDisposition;
|
||||||
|
|
||||||
for (size_t i = 0; i < state.mSkills.size(); ++i)
|
for (const auto& [id, value] : mSkills)
|
||||||
mSkill[i].writeState(state.mSkills[i]);
|
{
|
||||||
|
// TODO extend format
|
||||||
|
auto index = id.getIf<ESM::IndexRefId>()->getValue();
|
||||||
|
value.writeState(state.mSkills[index]);
|
||||||
|
}
|
||||||
|
|
||||||
state.mIsWerewolf = mIsWerewolf;
|
state.mIsWerewolf = mIsWerewolf;
|
||||||
|
|
||||||
|
@ -524,7 +530,11 @@ void MWMechanics::NpcStats::readState(const ESM::NpcStats& state)
|
||||||
mDisposition = state.mDisposition;
|
mDisposition = state.mDisposition;
|
||||||
|
|
||||||
for (size_t i = 0; i < state.mSkills.size(); ++i)
|
for (size_t i = 0; i < state.mSkills.size(); ++i)
|
||||||
mSkill[i].readState(state.mSkills[i]);
|
{
|
||||||
|
// TODO extend format
|
||||||
|
ESM::RefId id = ESM::Skill::indexToRefId(i);
|
||||||
|
mSkills[id].readState(state.mSkills[i]);
|
||||||
|
}
|
||||||
|
|
||||||
mIsWerewolf = state.mIsWerewolf;
|
mIsWerewolf = state.mIsWerewolf;
|
||||||
|
|
||||||
|
|
|
@ -3,6 +3,7 @@
|
||||||
|
|
||||||
#include "creaturestats.hpp"
|
#include "creaturestats.hpp"
|
||||||
#include <components/esm/refid.hpp>
|
#include <components/esm/refid.hpp>
|
||||||
|
#include <components/esm3/loadskil.hpp>
|
||||||
#include <map>
|
#include <map>
|
||||||
#include <set>
|
#include <set>
|
||||||
#include <string>
|
#include <string>
|
||||||
|
@ -21,7 +22,7 @@ namespace MWMechanics
|
||||||
class NpcStats : public CreatureStats
|
class NpcStats : public CreatureStats
|
||||||
{
|
{
|
||||||
int mDisposition;
|
int mDisposition;
|
||||||
SkillValue mSkill[ESM::Skill::Length]; // SkillValue.mProgress used by the player only
|
std::map<ESM::RefId, SkillValue> mSkills; // SkillValue.mProgress used by the player only
|
||||||
|
|
||||||
int mReputation;
|
int mReputation;
|
||||||
int mCrimeId;
|
int mCrimeId;
|
||||||
|
@ -58,9 +59,9 @@ namespace MWMechanics
|
||||||
int getCrimeId() const;
|
int getCrimeId() const;
|
||||||
void setCrimeId(int id);
|
void setCrimeId(int id);
|
||||||
|
|
||||||
const SkillValue& getSkill(int index) const;
|
const SkillValue& getSkill(ESM::RefId id) const;
|
||||||
SkillValue& getSkill(int index);
|
SkillValue& getSkill(ESM::RefId id);
|
||||||
void setSkill(int index, const SkillValue& value);
|
void setSkill(ESM::RefId id, const SkillValue& value);
|
||||||
|
|
||||||
int getFactionRank(const ESM::RefId& faction) const;
|
int getFactionRank(const ESM::RefId& faction) const;
|
||||||
const std::map<ESM::RefId, int>& getFactionRanks() const;
|
const std::map<ESM::RefId, int>& getFactionRanks() const;
|
||||||
|
@ -79,12 +80,12 @@ namespace MWMechanics
|
||||||
|
|
||||||
bool isInFaction(const ESM::RefId& faction) const;
|
bool isInFaction(const ESM::RefId& faction) const;
|
||||||
|
|
||||||
float getSkillProgressRequirement(int skillIndex, const ESM::Class& class_) const;
|
float getSkillProgressRequirement(ESM::RefId id, const ESM::Class& class_) const;
|
||||||
|
|
||||||
void useSkill(int skillIndex, const ESM::Class& class_, int usageType = -1, float extraFactor = 1.f);
|
void useSkill(ESM::RefId id, const ESM::Class& class_, int usageType = -1, float extraFactor = 1.f);
|
||||||
///< Increase skill by usage.
|
///< Increase skill by usage.
|
||||||
|
|
||||||
void increaseSkill(int skillIndex, const ESM::Class& class_, bool preserveProgress, bool readBook = false);
|
void increaseSkill(ESM::RefId id, const ESM::Class& class_, bool preserveProgress, bool readBook = false);
|
||||||
|
|
||||||
int getLevelProgress() const;
|
int getLevelProgress() const;
|
||||||
|
|
||||||
|
@ -133,6 +134,8 @@ namespace MWMechanics
|
||||||
|
|
||||||
void readState(const ESM::CreatureStats& state);
|
void readState(const ESM::CreatureStats& state);
|
||||||
void readState(const ESM::NpcStats& state);
|
void readState(const ESM::NpcStats& state);
|
||||||
|
|
||||||
|
const std::map<ESM::RefId, SkillValue>& getSkills() const { return mSkills; }
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -105,7 +105,7 @@ namespace
|
||||||
void damageSkill(const MWWorld::Ptr& target, const ESM::ActiveEffect& effect, float magnitude)
|
void damageSkill(const MWWorld::Ptr& target, const ESM::ActiveEffect& effect, float magnitude)
|
||||||
{
|
{
|
||||||
auto& npcStats = target.getClass().getNpcStats(target);
|
auto& npcStats = target.getClass().getNpcStats(target);
|
||||||
auto& skill = npcStats.getSkill(effect.mArg);
|
auto& skill = npcStats.getSkill(ESM::Skill::indexToRefId(effect.mArg));
|
||||||
if (effect.mEffectId == ESM::MagicEffect::DamageSkill)
|
if (effect.mEffectId == ESM::MagicEffect::DamageSkill)
|
||||||
magnitude = std::min(skill.getModified(), magnitude);
|
magnitude = std::min(skill.getModified(), magnitude);
|
||||||
skill.damage(magnitude);
|
skill.damage(magnitude);
|
||||||
|
@ -114,14 +114,14 @@ namespace
|
||||||
void restoreSkill(const MWWorld::Ptr& target, const ESM::ActiveEffect& effect, float magnitude)
|
void restoreSkill(const MWWorld::Ptr& target, const ESM::ActiveEffect& effect, float magnitude)
|
||||||
{
|
{
|
||||||
auto& npcStats = target.getClass().getNpcStats(target);
|
auto& npcStats = target.getClass().getNpcStats(target);
|
||||||
auto& skill = npcStats.getSkill(effect.mArg);
|
auto& skill = npcStats.getSkill(ESM::Skill::indexToRefId(effect.mArg));
|
||||||
skill.restore(magnitude);
|
skill.restore(magnitude);
|
||||||
}
|
}
|
||||||
|
|
||||||
void fortifySkill(const MWWorld::Ptr& target, const ESM::ActiveEffect& effect, float magnitude)
|
void fortifySkill(const MWWorld::Ptr& target, const ESM::ActiveEffect& effect, float magnitude)
|
||||||
{
|
{
|
||||||
auto& npcStats = target.getClass().getNpcStats(target);
|
auto& npcStats = target.getClass().getNpcStats(target);
|
||||||
auto& skill = npcStats.getSkill(effect.mArg);
|
auto& skill = npcStats.getSkill(ESM::Skill::indexToRefId(effect.mArg));
|
||||||
skill.setModifier(skill.getModifier() + magnitude);
|
skill.setModifier(skill.getModifier() + magnitude);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -668,7 +668,7 @@ namespace MWMechanics
|
||||||
if (spellParams.getType() == ESM::ActiveSpells::Type_Ability)
|
if (spellParams.getType() == ESM::ActiveSpells::Type_Ability)
|
||||||
{
|
{
|
||||||
auto& npcStats = target.getClass().getNpcStats(target);
|
auto& npcStats = target.getClass().getNpcStats(target);
|
||||||
SkillValue& skill = npcStats.getSkill(effect.mArg);
|
SkillValue& skill = npcStats.getSkill(ESM::Skill::indexToRefId(effect.mArg));
|
||||||
// Damage Skill abilities reduce base skill :todd:
|
// Damage Skill abilities reduce base skill :todd:
|
||||||
skill.setBase(std::max(skill.getBase() - effect.mMagnitude, 0.f));
|
skill.setBase(std::max(skill.getBase() - effect.mMagnitude, 0.f));
|
||||||
}
|
}
|
||||||
|
@ -760,7 +760,7 @@ namespace MWMechanics
|
||||||
{
|
{
|
||||||
// Abilities affect base stats, but not for drain
|
// Abilities affect base stats, but not for drain
|
||||||
auto& npcStats = target.getClass().getNpcStats(target);
|
auto& npcStats = target.getClass().getNpcStats(target);
|
||||||
auto& skill = npcStats.getSkill(effect.mArg);
|
auto& skill = npcStats.getSkill(ESM::Skill::indexToRefId(effect.mArg));
|
||||||
skill.setBase(skill.getBase() + effect.mMagnitude);
|
skill.setBase(skill.getBase() + effect.mMagnitude);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
@ -1218,7 +1218,7 @@ namespace MWMechanics
|
||||||
if (spellParams.getType() == ESM::ActiveSpells::Type_Ability)
|
if (spellParams.getType() == ESM::ActiveSpells::Type_Ability)
|
||||||
{
|
{
|
||||||
auto& npcStats = target.getClass().getNpcStats(target);
|
auto& npcStats = target.getClass().getNpcStats(target);
|
||||||
auto& skill = npcStats.getSkill(effect.mArg);
|
auto& skill = npcStats.getSkill(ESM::Skill::indexToRefId(effect.mArg));
|
||||||
skill.setBase(skill.getBase() - effect.mMagnitude);
|
skill.setBase(skill.getBase() - effect.mMagnitude);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
|
|
@ -565,7 +565,7 @@ namespace MWMechanics
|
||||||
case ESM::MagicEffect::DrainSkill:
|
case ESM::MagicEffect::DrainSkill:
|
||||||
if (enemy.isEmpty() || !enemy.getClass().isNpc())
|
if (enemy.isEmpty() || !enemy.getClass().isNpc())
|
||||||
return 0.f;
|
return 0.f;
|
||||||
if (enemy.getClass().getSkill(enemy, effect.mSkill) <= 0)
|
if (enemy.getClass().getSkill(enemy, ESM::Skill::indexToRefId(effect.mSkill)) <= 0)
|
||||||
return 0.f;
|
return 0.f;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
@ -600,7 +600,7 @@ namespace MWMechanics
|
||||||
&& (e != ESM::MagicEffect::BoundLongbow || effect.mEffectID == e
|
&& (e != ESM::MagicEffect::BoundLongbow || effect.mEffectID == e
|
||||||
|| rateAmmo(actor, enemy, getWeaponType(ESM::Weapon::MarksmanBow)->mAmmoType) <= 0.f))
|
|| rateAmmo(actor, enemy, getWeaponType(ESM::Weapon::MarksmanBow)->mAmmoType) <= 0.f))
|
||||||
return 0.f;
|
return 0.f;
|
||||||
ESM::Skill::SkillEnum skill = ESM::Skill::ShortBlade;
|
ESM::RefId skill = ESM::Skill::ShortBlade;
|
||||||
if (effect.mEffectID == ESM::MagicEffect::BoundLongsword)
|
if (effect.mEffectID == ESM::MagicEffect::BoundLongsword)
|
||||||
skill = ESM::Skill::LongBlade;
|
skill = ESM::Skill::LongBlade;
|
||||||
else if (effect.mEffectID == ESM::MagicEffect::BoundMace)
|
else if (effect.mEffectID == ESM::MagicEffect::BoundMace)
|
||||||
|
|
|
@ -15,9 +15,9 @@
|
||||||
|
|
||||||
namespace MWMechanics
|
namespace MWMechanics
|
||||||
{
|
{
|
||||||
ESM::Skill::SkillEnum spellSchoolToSkill(int school)
|
ESM::RefId spellSchoolToSkill(int school)
|
||||||
{
|
{
|
||||||
static const std::array<ESM::Skill::SkillEnum, 6> schoolSkillArray{
|
static const std::array<ESM::RefId, 6> schoolSkillArray{
|
||||||
ESM::Skill::Alteration,
|
ESM::Skill::Alteration,
|
||||||
ESM::Skill::Conjuration,
|
ESM::Skill::Conjuration,
|
||||||
ESM::Skill::Destruction,
|
ESM::Skill::Destruction,
|
||||||
|
|
|
@ -17,7 +17,7 @@ namespace MWWorld
|
||||||
|
|
||||||
namespace MWMechanics
|
namespace MWMechanics
|
||||||
{
|
{
|
||||||
ESM::Skill::SkillEnum spellSchoolToSkill(int school);
|
ESM::RefId spellSchoolToSkill(int school);
|
||||||
|
|
||||||
enum class EffectCostMethod
|
enum class EffectCostMethod
|
||||||
{
|
{
|
||||||
|
|
|
@ -120,8 +120,8 @@ namespace MWMechanics
|
||||||
int value = 50.f;
|
int value = 50.f;
|
||||||
if (actor.getClass().isNpc())
|
if (actor.getClass().isNpc())
|
||||||
{
|
{
|
||||||
int skill = item.getClass().getEquipmentSkill(item);
|
ESM::RefId skill = item.getClass().getEquipmentSkill(item);
|
||||||
if (skill != -1)
|
if (!skill.empty())
|
||||||
value = actor.getClass().getSkill(actor, skill);
|
value = actor.getClass().getSkill(actor, skill);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
|
|
@ -392,7 +392,7 @@ namespace MWScript
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
int skill = it->getClass().getEquipmentSkill(*it);
|
ESM::RefId skill = it->getClass().getEquipmentSkill(*it);
|
||||||
if (skill == ESM::Skill::HeavyArmor)
|
if (skill == ESM::Skill::HeavyArmor)
|
||||||
runtime.push(2);
|
runtime.push(2);
|
||||||
else if (skill == ESM::Skill::MediumArmor)
|
else if (skill == ESM::Skill::MediumArmor)
|
||||||
|
|
|
@ -345,11 +345,11 @@ namespace MWScript
|
||||||
template <class R>
|
template <class R>
|
||||||
class OpGetSkill : public Interpreter::Opcode0
|
class OpGetSkill : public Interpreter::Opcode0
|
||||||
{
|
{
|
||||||
int mIndex;
|
ESM::RefId mId;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
OpGetSkill(int index)
|
OpGetSkill(ESM::RefId id)
|
||||||
: mIndex(index)
|
: mId(id)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -357,7 +357,7 @@ namespace MWScript
|
||||||
{
|
{
|
||||||
MWWorld::Ptr ptr = R()(runtime);
|
MWWorld::Ptr ptr = R()(runtime);
|
||||||
|
|
||||||
Interpreter::Type_Float value = ptr.getClass().getSkill(ptr, mIndex);
|
Interpreter::Type_Float value = ptr.getClass().getSkill(ptr, mId);
|
||||||
|
|
||||||
runtime.push(value);
|
runtime.push(value);
|
||||||
}
|
}
|
||||||
|
@ -366,11 +366,11 @@ namespace MWScript
|
||||||
template <class R>
|
template <class R>
|
||||||
class OpSetSkill : public Interpreter::Opcode0
|
class OpSetSkill : public Interpreter::Opcode0
|
||||||
{
|
{
|
||||||
int mIndex;
|
ESM::RefId mId;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
OpSetSkill(int index)
|
OpSetSkill(ESM::RefId id)
|
||||||
: mIndex(index)
|
: mId(id)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -383,18 +383,18 @@ namespace MWScript
|
||||||
|
|
||||||
MWMechanics::NpcStats& stats = ptr.getClass().getNpcStats(ptr);
|
MWMechanics::NpcStats& stats = ptr.getClass().getNpcStats(ptr);
|
||||||
|
|
||||||
stats.getSkill(mIndex).setBase(value, true);
|
stats.getSkill(mId).setBase(value, true);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
template <class R>
|
template <class R>
|
||||||
class OpModSkill : public Interpreter::Opcode0
|
class OpModSkill : public Interpreter::Opcode0
|
||||||
{
|
{
|
||||||
int mIndex;
|
ESM::RefId mId;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
OpModSkill(int index)
|
OpModSkill(ESM::RefId id)
|
||||||
: mIndex(index)
|
: mId(id)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -405,7 +405,7 @@ namespace MWScript
|
||||||
Interpreter::Type_Float value = runtime[0].mFloat;
|
Interpreter::Type_Float value = runtime[0].mFloat;
|
||||||
runtime.pop();
|
runtime.pop();
|
||||||
|
|
||||||
MWMechanics::SkillValue& skill = ptr.getClass().getNpcStats(ptr).getSkill(mIndex);
|
MWMechanics::SkillValue& skill = ptr.getClass().getNpcStats(ptr).getSkill(mId);
|
||||||
modStat(skill, value);
|
modStat(skill, value);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -1364,14 +1364,15 @@ namespace MWScript
|
||||||
|
|
||||||
for (int i = 0; i < Compiler::Stats::numberOfSkills; ++i)
|
for (int i = 0; i < Compiler::Stats::numberOfSkills; ++i)
|
||||||
{
|
{
|
||||||
interpreter.installSegment5<OpGetSkill<ImplicitRef>>(Compiler::Stats::opcodeGetSkill + i, i);
|
ESM::RefId id = ESM::Skill::indexToRefId(i);
|
||||||
interpreter.installSegment5<OpGetSkill<ExplicitRef>>(Compiler::Stats::opcodeGetSkillExplicit + i, i);
|
interpreter.installSegment5<OpGetSkill<ImplicitRef>>(Compiler::Stats::opcodeGetSkill + i, id);
|
||||||
|
interpreter.installSegment5<OpGetSkill<ExplicitRef>>(Compiler::Stats::opcodeGetSkillExplicit + i, id);
|
||||||
|
|
||||||
interpreter.installSegment5<OpSetSkill<ImplicitRef>>(Compiler::Stats::opcodeSetSkill + i, i);
|
interpreter.installSegment5<OpSetSkill<ImplicitRef>>(Compiler::Stats::opcodeSetSkill + i, id);
|
||||||
interpreter.installSegment5<OpSetSkill<ExplicitRef>>(Compiler::Stats::opcodeSetSkillExplicit + i, i);
|
interpreter.installSegment5<OpSetSkill<ExplicitRef>>(Compiler::Stats::opcodeSetSkillExplicit + i, id);
|
||||||
|
|
||||||
interpreter.installSegment5<OpModSkill<ImplicitRef>>(Compiler::Stats::opcodeModSkill + i, i);
|
interpreter.installSegment5<OpModSkill<ImplicitRef>>(Compiler::Stats::opcodeModSkill + i, id);
|
||||||
interpreter.installSegment5<OpModSkill<ExplicitRef>>(Compiler::Stats::opcodeModSkillExplicit + i, i);
|
interpreter.installSegment5<OpModSkill<ExplicitRef>>(Compiler::Stats::opcodeModSkillExplicit + i, id);
|
||||||
}
|
}
|
||||||
|
|
||||||
interpreter.installSegment5<OpGetPCCrimeLevel>(Compiler::Stats::opcodeGetPCCrimeLevel);
|
interpreter.installSegment5<OpGetPCCrimeLevel>(Compiler::Stats::opcodeGetPCCrimeLevel);
|
||||||
|
|
|
@ -16,19 +16,4 @@ namespace MWWorld
|
||||||
{
|
{
|
||||||
actor.getClass().consume(getTarget(), actor);
|
actor.getClass().consume(getTarget(), actor);
|
||||||
}
|
}
|
||||||
|
|
||||||
ActionApplyWithSkill::ActionApplyWithSkill(const Ptr& object, const ESM::RefId& id, int skillIndex, int usageType)
|
|
||||||
: Action(false, object)
|
|
||||||
, mId(id)
|
|
||||||
, mSkillIndex(skillIndex)
|
|
||||||
, mUsageType(usageType)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
void ActionApplyWithSkill::executeImp(const Ptr& actor)
|
|
||||||
{
|
|
||||||
bool consumed = actor.getClass().consume(getTarget(), actor);
|
|
||||||
if (consumed && mUsageType != -1 && actor == MWMechanics::getPlayer())
|
|
||||||
actor.getClass().skillUsageSucceeded(actor, mSkillIndex, mUsageType);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -16,18 +16,6 @@ namespace MWWorld
|
||||||
public:
|
public:
|
||||||
ActionApply(const Ptr& object, const ESM::RefId& id);
|
ActionApply(const Ptr& object, const ESM::RefId& id);
|
||||||
};
|
};
|
||||||
|
|
||||||
class ActionApplyWithSkill : public Action
|
|
||||||
{
|
|
||||||
ESM::RefId mId;
|
|
||||||
int mSkillIndex;
|
|
||||||
int mUsageType;
|
|
||||||
|
|
||||||
void executeImp(const Ptr& actor) override;
|
|
||||||
|
|
||||||
public:
|
|
||||||
ActionApplyWithSkill(const Ptr& object, const ESM::RefId& id, int skillIndex, int usageType);
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -2,6 +2,7 @@
|
||||||
|
|
||||||
#include <components/esm3/loadbook.hpp>
|
#include <components/esm3/loadbook.hpp>
|
||||||
#include <components/esm3/loadclas.hpp>
|
#include <components/esm3/loadclas.hpp>
|
||||||
|
#include <components/esm3/loadskil.hpp>
|
||||||
|
|
||||||
#include "../mwbase/environment.hpp"
|
#include "../mwbase/environment.hpp"
|
||||||
#include "../mwbase/windowmanager.hpp"
|
#include "../mwbase/windowmanager.hpp"
|
||||||
|
@ -46,15 +47,15 @@ namespace MWWorld
|
||||||
MWMechanics::NpcStats& npcStats = actor.getClass().getNpcStats(actor);
|
MWMechanics::NpcStats& npcStats = actor.getClass().getNpcStats(actor);
|
||||||
|
|
||||||
// Skill gain from books
|
// Skill gain from books
|
||||||
if (ref->mBase->mData.mSkillId >= 0 && ref->mBase->mData.mSkillId < ESM::Skill::Length
|
ESM::RefId skill = ESM::Skill::indexToRefId(ref->mBase->mData.mSkillId);
|
||||||
&& !npcStats.hasBeenUsed(ref->mBase->mId))
|
if (!skill.empty() && !npcStats.hasBeenUsed(ref->mBase->mId))
|
||||||
{
|
{
|
||||||
MWWorld::LiveCellRef<ESM::NPC>* playerRef = actor.get<ESM::NPC>();
|
MWWorld::LiveCellRef<ESM::NPC>* playerRef = actor.get<ESM::NPC>();
|
||||||
|
|
||||||
const ESM::Class* class_
|
const ESM::Class* class_
|
||||||
= MWBase::Environment::get().getESMStore()->get<ESM::Class>().find(playerRef->mBase->mClass);
|
= MWBase::Environment::get().getESMStore()->get<ESM::Class>().find(playerRef->mBase->mClass);
|
||||||
|
|
||||||
npcStats.increaseSkill(ref->mBase->mData.mSkillId, *class_, true, true);
|
npcStats.increaseSkill(skill, *class_, true, true);
|
||||||
|
|
||||||
npcStats.flagAsUsed(ref->mBase->mId);
|
npcStats.flagAsUsed(ref->mBase->mId);
|
||||||
}
|
}
|
||||||
|
|
|
@ -52,7 +52,7 @@ namespace MWWorld
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Class::skillUsageSucceeded(const MWWorld::Ptr& ptr, int skill, int usageType, float extraFactor) const
|
void Class::skillUsageSucceeded(const MWWorld::Ptr& ptr, ESM::RefId skill, int usageType, float extraFactor) const
|
||||||
{
|
{
|
||||||
throw std::runtime_error("class does not represent an actor");
|
throw std::runtime_error("class does not represent an actor");
|
||||||
}
|
}
|
||||||
|
@ -209,9 +209,9 @@ namespace MWWorld
|
||||||
return std::make_pair(std::vector<int>(), false);
|
return std::make_pair(std::vector<int>(), false);
|
||||||
}
|
}
|
||||||
|
|
||||||
int Class::getEquipmentSkill(const ConstPtr& ptr) const
|
ESM::RefId Class::getEquipmentSkill(const ConstPtr& ptr) const
|
||||||
{
|
{
|
||||||
return -1;
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
int Class::getValue(const ConstPtr& ptr) const
|
int Class::getValue(const ConstPtr& ptr) const
|
||||||
|
@ -438,7 +438,7 @@ namespace MWWorld
|
||||||
return canSwim(ptr) || canWalk(ptr) || canFly(ptr);
|
return canSwim(ptr) || canWalk(ptr) || canFly(ptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
float Class::getSkill(const MWWorld::Ptr& ptr, int skill) const
|
float Class::getSkill(const MWWorld::Ptr& ptr, ESM::RefId id) const
|
||||||
{
|
{
|
||||||
throw std::runtime_error("class does not support skills");
|
throw std::runtime_error("class does not support skills");
|
||||||
}
|
}
|
||||||
|
|
|
@ -14,6 +14,7 @@
|
||||||
|
|
||||||
#include "../mwmechanics/aisetting.hpp"
|
#include "../mwmechanics/aisetting.hpp"
|
||||||
#include <components/esm/refid.hpp>
|
#include <components/esm/refid.hpp>
|
||||||
|
#include <components/esm3/loadskil.hpp>
|
||||||
|
|
||||||
namespace ESM
|
namespace ESM
|
||||||
{
|
{
|
||||||
|
@ -208,10 +209,9 @@ namespace MWWorld
|
||||||
///
|
///
|
||||||
/// Default implementation: return (empty vector, false).
|
/// Default implementation: return (empty vector, false).
|
||||||
|
|
||||||
virtual int getEquipmentSkill(const ConstPtr& ptr) const;
|
virtual ESM::RefId getEquipmentSkill(const ConstPtr& ptr) const;
|
||||||
/// Return the index of the skill this item corresponds to when equipped or -1, if there is
|
/// Return the index of the skill this item corresponds to when equipped.
|
||||||
/// no such skill.
|
/// (default implementation: return empty ref id)
|
||||||
/// (default implementation: return -1)
|
|
||||||
|
|
||||||
virtual int getValue(const ConstPtr& ptr) const;
|
virtual int getValue(const ConstPtr& ptr) const;
|
||||||
///< Return trade value of the object. Throws an exception, if the object can't be traded.
|
///< Return trade value of the object. Throws an exception, if the object can't be traded.
|
||||||
|
@ -234,7 +234,7 @@ namespace MWWorld
|
||||||
///< Consume an item, e. g. a potion.
|
///< Consume an item, e. g. a potion.
|
||||||
|
|
||||||
virtual void skillUsageSucceeded(
|
virtual void skillUsageSucceeded(
|
||||||
const MWWorld::Ptr& ptr, int skill, int usageType, float extraFactor = 1.f) const;
|
const MWWorld::Ptr& ptr, ESM::RefId skill, int usageType, float extraFactor = 1.f) const;
|
||||||
///< Inform actor \a ptr that a skill use has succeeded.
|
///< Inform actor \a ptr that a skill use has succeeded.
|
||||||
///
|
///
|
||||||
/// (default implementations: throws an exception)
|
/// (default implementations: throws an exception)
|
||||||
|
@ -340,7 +340,7 @@ namespace MWWorld
|
||||||
bool isPureLandCreature(const MWWorld::Ptr& ptr) const;
|
bool isPureLandCreature(const MWWorld::Ptr& ptr) const;
|
||||||
bool isMobile(const MWWorld::Ptr& ptr) const;
|
bool isMobile(const MWWorld::Ptr& ptr) const;
|
||||||
|
|
||||||
virtual float getSkill(const MWWorld::Ptr& ptr, int skill) const;
|
virtual float getSkill(const MWWorld::Ptr& ptr, ESM::RefId id) const;
|
||||||
|
|
||||||
virtual void readAdditionalState(const MWWorld::Ptr& ptr, const ESM::ObjectState& state) const;
|
virtual void readAdditionalState(const MWWorld::Ptr& ptr, const ESM::ObjectState& state) const;
|
||||||
///< Read additional state from \a state into \a ptr.
|
///< Read additional state from \a state into \a ptr.
|
||||||
|
|
|
@ -236,7 +236,7 @@ void MWWorld::InventoryStore::autoEquipWeapon(TSlots& slots_)
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
static const ESM::Skill::SkillEnum weaponSkills[] = {
|
static const ESM::RefId weaponSkills[] = {
|
||||||
ESM::Skill::LongBlade,
|
ESM::Skill::LongBlade,
|
||||||
ESM::Skill::Axe,
|
ESM::Skill::Axe,
|
||||||
ESM::Skill::Spear,
|
ESM::Skill::Spear,
|
||||||
|
@ -285,7 +285,7 @@ void MWWorld::InventoryStore::autoEquipWeapon(TSlots& slots_)
|
||||||
|
|
||||||
for (int j = 0; j < static_cast<int>(weaponSkillsLength); ++j)
|
for (int j = 0; j < static_cast<int>(weaponSkillsLength); ++j)
|
||||||
{
|
{
|
||||||
float skillValue = mActor.getClass().getSkill(mActor, static_cast<int>(weaponSkills[j]));
|
float skillValue = mActor.getClass().getSkill(mActor, weaponSkills[j]);
|
||||||
if (skillValue > max && !weaponSkillVisited[j])
|
if (skillValue > max && !weaponSkillVisited[j])
|
||||||
{
|
{
|
||||||
max = skillValue;
|
max = skillValue;
|
||||||
|
|
|
@ -221,7 +221,7 @@ namespace MWWorld
|
||||||
creatureStats.mAiSettings[i].mMod = 0.f;
|
creatureStats.mAiSettings[i].mMod = 0.f;
|
||||||
if (npcStats)
|
if (npcStats)
|
||||||
{
|
{
|
||||||
for (std::size_t i = 0; i < ESM::Skill::Length; ++i)
|
for (std::size_t i = 0; i < npcStats->mSkills.size(); ++i)
|
||||||
npcStats->mSkills[i].mMod = 0.f;
|
npcStats->mSkills[i].mMod = 0.f;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -59,23 +59,23 @@ namespace MWWorld
|
||||||
{
|
{
|
||||||
MWMechanics::NpcStats& stats = getPlayer().getClass().getNpcStats(getPlayer());
|
MWMechanics::NpcStats& stats = getPlayer().getClass().getNpcStats(getPlayer());
|
||||||
|
|
||||||
for (int i = 0; i < ESM::Skill::Length; ++i)
|
for (size_t i = 0; i < mSaveSkills.size(); ++i)
|
||||||
mSaveSkills[i] = stats.getSkill(i).getModified();
|
mSaveSkills[i] = stats.getSkill(ESM::Skill::indexToRefId(i)).getModified();
|
||||||
for (int i = 0; i < ESM::Attribute::Length; ++i)
|
for (int i = 0; i < ESM::Attribute::Length; ++i)
|
||||||
mSaveAttributes[i] = stats.getAttribute(i).getModified();
|
mSaveAttributes[i] = stats.getAttribute(i).getModified();
|
||||||
}
|
}
|
||||||
|
|
||||||
void Player::restoreStats()
|
void Player::restoreStats()
|
||||||
{
|
{
|
||||||
const MWWorld::Store<ESM::GameSetting>& gmst
|
const auto& store = MWBase::Environment::get().getESMStore();
|
||||||
= MWBase::Environment::get().getESMStore()->get<ESM::GameSetting>();
|
const MWWorld::Store<ESM::GameSetting>& gmst = store->get<ESM::GameSetting>();
|
||||||
MWMechanics::CreatureStats& creatureStats = getPlayer().getClass().getCreatureStats(getPlayer());
|
MWMechanics::CreatureStats& creatureStats = getPlayer().getClass().getCreatureStats(getPlayer());
|
||||||
MWMechanics::NpcStats& npcStats = getPlayer().getClass().getNpcStats(getPlayer());
|
MWMechanics::NpcStats& npcStats = getPlayer().getClass().getNpcStats(getPlayer());
|
||||||
MWMechanics::DynamicStat<float> health = creatureStats.getDynamic(0);
|
MWMechanics::DynamicStat<float> health = creatureStats.getDynamic(0);
|
||||||
creatureStats.setHealth(health.getBase() / gmst.find("fWereWolfHealth")->mValue.getFloat());
|
creatureStats.setHealth(health.getBase() / gmst.find("fWereWolfHealth")->mValue.getFloat());
|
||||||
for (int i = 0; i < ESM::Skill::Length; ++i)
|
for (size_t i = 0; i < mSaveSkills.size(); ++i)
|
||||||
{
|
{
|
||||||
auto& skill = npcStats.getSkill(i);
|
auto& skill = npcStats.getSkill(ESM::Skill::indexToRefId(i));
|
||||||
skill.restore(skill.getDamage());
|
skill.restore(skill.getDamage());
|
||||||
skill.setModifier(mSaveSkills[i] - skill.getBase());
|
skill.setModifier(mSaveSkills[i] - skill.getBase());
|
||||||
}
|
}
|
||||||
|
@ -103,13 +103,13 @@ namespace MWWorld
|
||||||
npcStats.setAttribute(attribute.mId, value);
|
npcStats.setAttribute(attribute.mId, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
for (const auto& [_, skill] : store->get<ESM::Skill>())
|
for (const auto& skill : store->get<ESM::Skill>())
|
||||||
{
|
{
|
||||||
// Acrobatics is set separately for some reason.
|
// Acrobatics is set separately for some reason.
|
||||||
if (skill.mIndex == ESM::Skill::Acrobatics)
|
if (skill.mId == ESM::Skill::Acrobatics)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
MWMechanics::SkillValue& value = npcStats.getSkill(skill.mIndex);
|
MWMechanics::SkillValue& value = npcStats.getSkill(skill.mId);
|
||||||
value.setModifier(skill.mWerewolfValue - value.getModified());
|
value.setModifier(skill.mWerewolfValue - value.getModified());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -251,10 +251,7 @@ namespace MWWorld
|
||||||
mPreviousItems.clear();
|
mPreviousItems.clear();
|
||||||
mLastKnownExteriorPosition = osg::Vec3f(0, 0, 0);
|
mLastKnownExteriorPosition = osg::Vec3f(0, 0, 0);
|
||||||
|
|
||||||
for (int i = 0; i < ESM::Skill::Length; ++i)
|
mSaveSkills.fill(0.f);
|
||||||
{
|
|
||||||
mSaveSkills[i] = 0.f;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (int i = 0; i < ESM::Attribute::Length; ++i)
|
for (int i = 0; i < ESM::Attribute::Length; ++i)
|
||||||
{
|
{
|
||||||
|
@ -296,7 +293,7 @@ namespace MWWorld
|
||||||
|
|
||||||
for (int i = 0; i < ESM::Attribute::Length; ++i)
|
for (int i = 0; i < ESM::Attribute::Length; ++i)
|
||||||
player.mSaveAttributes[i] = mSaveAttributes[i];
|
player.mSaveAttributes[i] = mSaveAttributes[i];
|
||||||
for (int i = 0; i < ESM::Skill::Length; ++i)
|
for (size_t i = 0; i < mSaveSkills.size(); ++i)
|
||||||
player.mSaveSkills[i] = mSaveSkills[i];
|
player.mSaveSkills[i] = mSaveSkills[i];
|
||||||
|
|
||||||
player.mPreviousItems = mPreviousItems;
|
player.mPreviousItems = mPreviousItems;
|
||||||
|
@ -334,7 +331,7 @@ namespace MWWorld
|
||||||
|
|
||||||
for (int i = 0; i < ESM::Attribute::Length; ++i)
|
for (int i = 0; i < ESM::Attribute::Length; ++i)
|
||||||
mSaveAttributes[i] = player.mSaveAttributes[i];
|
mSaveAttributes[i] = player.mSaveAttributes[i];
|
||||||
for (int i = 0; i < ESM::Skill::Length; ++i)
|
for (size_t i = 0; i < mSaveSkills.size(); ++i)
|
||||||
mSaveSkills[i] = player.mSaveSkills[i];
|
mSaveSkills[i] = player.mSaveSkills[i];
|
||||||
|
|
||||||
if (player.mObject.mNpcStats.mIsWerewolf)
|
if (player.mObject.mNpcStats.mIsWerewolf)
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
#ifndef GAME_MWWORLD_PLAYER_H
|
#ifndef GAME_MWWORLD_PLAYER_H
|
||||||
#define GAME_MWWORLD_PLAYER_H
|
#define GAME_MWWORLD_PLAYER_H
|
||||||
|
|
||||||
|
#include <array>
|
||||||
#include <map>
|
#include <map>
|
||||||
|
|
||||||
#include "../mwworld/livecellref.hpp"
|
#include "../mwworld/livecellref.hpp"
|
||||||
|
@ -50,7 +51,7 @@ namespace MWWorld
|
||||||
PreviousItems mPreviousItems;
|
PreviousItems mPreviousItems;
|
||||||
|
|
||||||
// Saved stats prior to becoming a werewolf
|
// Saved stats prior to becoming a werewolf
|
||||||
float mSaveSkills[ESM::Skill::Length];
|
std::array<float, ESM::Skill::Length> mSaveSkills;
|
||||||
float mSaveAttributes[ESM::Attribute::Length];
|
float mSaveAttributes[ESM::Attribute::Length];
|
||||||
|
|
||||||
bool mJumping;
|
bool mJumping;
|
||||||
|
|
|
@ -114,7 +114,6 @@ namespace MWWorld
|
||||||
|
|
||||||
// Need to instantiate these before they're used
|
// Need to instantiate these before they're used
|
||||||
template class IndexedStore<ESM::MagicEffect>;
|
template class IndexedStore<ESM::MagicEffect>;
|
||||||
template class IndexedStore<ESM::Skill>;
|
|
||||||
|
|
||||||
template <class T, class Id>
|
template <class T, class Id>
|
||||||
TypedDynamicStore<T, Id>::TypedDynamicStore()
|
TypedDynamicStore<T, Id>::TypedDynamicStore()
|
||||||
|
@ -170,11 +169,19 @@ namespace MWWorld
|
||||||
{
|
{
|
||||||
if constexpr (std::is_same_v<Id, ESM::RefId>)
|
if constexpr (std::is_same_v<Id, ESM::RefId>)
|
||||||
{
|
{
|
||||||
std::vector<const T*> results;
|
if (prefix.empty())
|
||||||
std::copy_if(mShared.begin(), mShared.end(), std::back_inserter(results),
|
{
|
||||||
[prefix](const T* item) { return item->mId.startsWith(prefix); });
|
if (!mShared.empty())
|
||||||
if (!results.empty())
|
return mShared[Misc::Rng::rollDice(mShared.size(), prng)];
|
||||||
return results[Misc::Rng::rollDice(results.size(), prng)];
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
std::vector<const T*> results;
|
||||||
|
std::copy_if(mShared.begin(), mShared.end(), std::back_inserter(results),
|
||||||
|
[prefix](const T* item) { return item->mId.startsWith(prefix); });
|
||||||
|
if (!results.empty())
|
||||||
|
return results[Misc::Rng::rollDice(results.size(), prng)];
|
||||||
|
}
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
@ -916,8 +923,6 @@ namespace MWWorld
|
||||||
// Skill
|
// Skill
|
||||||
//=========================================================================
|
//=========================================================================
|
||||||
|
|
||||||
Store<ESM::Skill>::Store() {}
|
|
||||||
|
|
||||||
void Store<ESM::Skill>::setUp(const MWWorld::Store<ESM::GameSetting>& settings)
|
void Store<ESM::Skill>::setUp(const MWWorld::Store<ESM::GameSetting>& settings)
|
||||||
{
|
{
|
||||||
constexpr std::string_view skillValues[ESM::Skill::Length][3] = {
|
constexpr std::string_view skillValues[ESM::Skill::Length][3] = {
|
||||||
|
@ -950,15 +955,13 @@ namespace MWWorld
|
||||||
{ "sSkillSpeechcraft", "icons\\k\\stealth_speechcraft.dds", "fWerewolfSpeechcraft" },
|
{ "sSkillSpeechcraft", "icons\\k\\stealth_speechcraft.dds", "fWerewolfSpeechcraft" },
|
||||||
{ "sSkillHandtohand", "icons\\k\\stealth_handtohand.dds", "fWerewolfHandtohand" },
|
{ "sSkillHandtohand", "icons\\k\\stealth_handtohand.dds", "fWerewolfHandtohand" },
|
||||||
};
|
};
|
||||||
for (int i = 0; i < ESM::Skill::Length; ++i)
|
for (ESM::Skill* skill : mShared)
|
||||||
{
|
{
|
||||||
auto found = mStatic.find(i);
|
if (skill->mIndex >= 0)
|
||||||
if (found != mStatic.end())
|
|
||||||
{
|
{
|
||||||
ESM::Skill& skill = found->second;
|
skill->mName = getGMSTString(settings, skillValues[skill->mIndex][0]);
|
||||||
skill.mName = getGMSTString(settings, skillValues[i][0]);
|
skill->mIcon = skillValues[skill->mIndex][1];
|
||||||
skill.mIcon = skillValues[i][1];
|
skill->mWerewolfValue = getGMSTFloat(settings, skillValues[skill->mIndex][2]);
|
||||||
skill.mWerewolfValue = getGMSTFloat(settings, skillValues[i][2]);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1363,7 +1366,7 @@ template class MWWorld::TypedDynamicStore<ESM::Race>;
|
||||||
template class MWWorld::TypedDynamicStore<ESM::Region>;
|
template class MWWorld::TypedDynamicStore<ESM::Region>;
|
||||||
template class MWWorld::TypedDynamicStore<ESM::Repair>;
|
template class MWWorld::TypedDynamicStore<ESM::Repair>;
|
||||||
template class MWWorld::TypedDynamicStore<ESM::Script>;
|
template class MWWorld::TypedDynamicStore<ESM::Script>;
|
||||||
// template class MWWorld::Store<ESM::Skill>;
|
template class MWWorld::TypedDynamicStore<ESM::Skill>;
|
||||||
template class MWWorld::TypedDynamicStore<ESM::Sound>;
|
template class MWWorld::TypedDynamicStore<ESM::Sound>;
|
||||||
template class MWWorld::TypedDynamicStore<ESM::SoundGenerator>;
|
template class MWWorld::TypedDynamicStore<ESM::SoundGenerator>;
|
||||||
template class MWWorld::TypedDynamicStore<ESM::Spell>;
|
template class MWWorld::TypedDynamicStore<ESM::Spell>;
|
||||||
|
|
|
@ -17,6 +17,7 @@
|
||||||
#include <components/esm3/loadgmst.hpp>
|
#include <components/esm3/loadgmst.hpp>
|
||||||
#include <components/esm3/loadland.hpp>
|
#include <components/esm3/loadland.hpp>
|
||||||
#include <components/esm3/loadpgrd.hpp>
|
#include <components/esm3/loadpgrd.hpp>
|
||||||
|
#include <components/esm3/loadskil.hpp>
|
||||||
#include <components/esm4/loadcell.hpp>
|
#include <components/esm4/loadcell.hpp>
|
||||||
#include <components/esm4/loadland.hpp>
|
#include <components/esm4/loadland.hpp>
|
||||||
#include <components/esm4/loadrefr.hpp>
|
#include <components/esm4/loadrefr.hpp>
|
||||||
|
@ -30,7 +31,6 @@ namespace ESM
|
||||||
struct Attribute;
|
struct Attribute;
|
||||||
struct LandTexture;
|
struct LandTexture;
|
||||||
struct MagicEffect;
|
struct MagicEffect;
|
||||||
struct Skill;
|
|
||||||
struct WeaponType;
|
struct WeaponType;
|
||||||
class ESMReader;
|
class ESMReader;
|
||||||
class ESMWriter;
|
class ESMWriter;
|
||||||
|
@ -478,10 +478,12 @@ namespace MWWorld
|
||||||
};
|
};
|
||||||
|
|
||||||
template <>
|
template <>
|
||||||
class Store<ESM::Skill> : public IndexedStore<ESM::Skill>
|
class Store<ESM::Skill> : public TypedDynamicStore<ESM::Skill>
|
||||||
{
|
{
|
||||||
|
using TypedDynamicStore<ESM::Skill>::setUp;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
Store();
|
Store() = default;
|
||||||
|
|
||||||
void setUp(const MWWorld::Store<ESM::GameSetting>& settings);
|
void setUp(const MWWorld::Store<ESM::GameSetting>& settings);
|
||||||
};
|
};
|
||||||
|
|
|
@ -496,7 +496,7 @@ namespace
|
||||||
const RecordType* result = nullptr;
|
const RecordType* result = nullptr;
|
||||||
if constexpr (std::is_same_v<RecordType, ESM::LandTexture>)
|
if constexpr (std::is_same_v<RecordType, ESM::LandTexture>)
|
||||||
result = esmStore.get<RecordType>().search(index, 0);
|
result = esmStore.get<RecordType>().search(index, 0);
|
||||||
else if constexpr (ESM::hasIndex<RecordType>)
|
else if constexpr (ESM::hasIndex<RecordType> && !std::is_same_v<RecordType, ESM::Skill>)
|
||||||
result = esmStore.get<RecordType>().search(index);
|
result = esmStore.get<RecordType>().search(index);
|
||||||
else
|
else
|
||||||
result = esmStore.get<RecordType>().search(refId);
|
result = esmStore.get<RecordType>().search(refId);
|
||||||
|
|
|
@ -37,11 +37,11 @@ namespace ESM
|
||||||
"Handtohand",
|
"Handtohand",
|
||||||
};
|
};
|
||||||
|
|
||||||
Skill::SkillEnum Skill::stringToSkillId(std::string_view skill)
|
int Skill::stringToSkillId(std::string_view skill)
|
||||||
{
|
{
|
||||||
for (int id = 0; id < Skill::Length; ++id)
|
for (int id = 0; id < Skill::Length; ++id)
|
||||||
if (Misc::StringUtils::ciEqual(sSkillNames[id], skill))
|
if (Misc::StringUtils::ciEqual(sSkillNames[id], skill))
|
||||||
return Skill::SkillEnum(id);
|
return id;
|
||||||
|
|
||||||
throw std::logic_error("No such skill: " + std::string(skill));
|
throw std::logic_error("No such skill: " + std::string(skill));
|
||||||
}
|
}
|
||||||
|
@ -75,6 +75,8 @@ namespace ESM
|
||||||
}
|
}
|
||||||
if (!hasIndex)
|
if (!hasIndex)
|
||||||
esm.fail("Missing INDX");
|
esm.fail("Missing INDX");
|
||||||
|
else if (mIndex < 0 || mIndex >= Length)
|
||||||
|
esm.fail("Invalid INDX");
|
||||||
if (!hasData)
|
if (!hasData)
|
||||||
esm.fail("Missing SKDT");
|
esm.fail("Missing SKDT");
|
||||||
|
|
||||||
|
@ -101,7 +103,7 @@ namespace ESM
|
||||||
|
|
||||||
RefId Skill::indexToRefId(int index)
|
RefId Skill::indexToRefId(int index)
|
||||||
{
|
{
|
||||||
if (index == -1)
|
if (index < 0 || index >= Length)
|
||||||
return RefId();
|
return RefId();
|
||||||
return RefId::index(sRecordId, static_cast<std::uint32_t>(index));
|
return RefId::index(sRecordId, static_cast<std::uint32_t>(index));
|
||||||
}
|
}
|
||||||
|
|
|
@ -41,47 +41,44 @@ namespace ESM
|
||||||
// Skill index. Skils don't have an id ("NAME") like most records,
|
// Skill index. Skils don't have an id ("NAME") like most records,
|
||||||
// they only have a numerical index that matches one of the
|
// they only have a numerical index that matches one of the
|
||||||
// hard-coded skills in the game.
|
// hard-coded skills in the game.
|
||||||
int mIndex;
|
int mIndex{ -1 };
|
||||||
|
|
||||||
std::string mDescription;
|
std::string mDescription;
|
||||||
std::string mName;
|
std::string mName;
|
||||||
std::string mIcon;
|
std::string mIcon;
|
||||||
float mWerewolfValue{};
|
float mWerewolfValue{};
|
||||||
|
|
||||||
enum SkillEnum
|
static constexpr IndexRefId Block{ sRecordId, 0 };
|
||||||
{
|
static constexpr IndexRefId Armorer{ sRecordId, 1 };
|
||||||
Block = 0,
|
static constexpr IndexRefId MediumArmor{ sRecordId, 2 };
|
||||||
Armorer = 1,
|
static constexpr IndexRefId HeavyArmor{ sRecordId, 3 };
|
||||||
MediumArmor = 2,
|
static constexpr IndexRefId BluntWeapon{ sRecordId, 4 };
|
||||||
HeavyArmor = 3,
|
static constexpr IndexRefId LongBlade{ sRecordId, 5 };
|
||||||
BluntWeapon = 4,
|
static constexpr IndexRefId Axe{ sRecordId, 6 };
|
||||||
LongBlade = 5,
|
static constexpr IndexRefId Spear{ sRecordId, 7 };
|
||||||
Axe = 6,
|
static constexpr IndexRefId Athletics{ sRecordId, 8 };
|
||||||
Spear = 7,
|
static constexpr IndexRefId Enchant{ sRecordId, 9 };
|
||||||
Athletics = 8,
|
static constexpr IndexRefId Destruction{ sRecordId, 10 };
|
||||||
Enchant = 9,
|
static constexpr IndexRefId Alteration{ sRecordId, 11 };
|
||||||
Destruction = 10,
|
static constexpr IndexRefId Illusion{ sRecordId, 12 };
|
||||||
Alteration = 11,
|
static constexpr IndexRefId Conjuration{ sRecordId, 13 };
|
||||||
Illusion = 12,
|
static constexpr IndexRefId Mysticism{ sRecordId, 14 };
|
||||||
Conjuration = 13,
|
static constexpr IndexRefId Restoration{ sRecordId, 15 };
|
||||||
Mysticism = 14,
|
static constexpr IndexRefId Alchemy{ sRecordId, 16 };
|
||||||
Restoration = 15,
|
static constexpr IndexRefId Unarmored{ sRecordId, 17 };
|
||||||
Alchemy = 16,
|
static constexpr IndexRefId Security{ sRecordId, 18 };
|
||||||
Unarmored = 17,
|
static constexpr IndexRefId Sneak{ sRecordId, 19 };
|
||||||
Security = 18,
|
static constexpr IndexRefId Acrobatics{ sRecordId, 20 };
|
||||||
Sneak = 19,
|
static constexpr IndexRefId LightArmor{ sRecordId, 21 };
|
||||||
Acrobatics = 20,
|
static constexpr IndexRefId ShortBlade{ sRecordId, 22 };
|
||||||
LightArmor = 21,
|
static constexpr IndexRefId Marksman{ sRecordId, 23 };
|
||||||
ShortBlade = 22,
|
static constexpr IndexRefId Mercantile{ sRecordId, 24 };
|
||||||
Marksman = 23,
|
static constexpr IndexRefId Speechcraft{ sRecordId, 25 };
|
||||||
Mercantile = 24,
|
static constexpr IndexRefId HandToHand{ sRecordId, 26 };
|
||||||
Speechcraft = 25,
|
static constexpr int Length = 27;
|
||||||
HandToHand = 26,
|
|
||||||
Length
|
|
||||||
};
|
|
||||||
static const std::string sSkillNames[Length];
|
static const std::string sSkillNames[Length];
|
||||||
|
|
||||||
static SkillEnum stringToSkillId(std::string_view skill);
|
static int stringToSkillId(std::string_view skill);
|
||||||
|
|
||||||
void load(ESMReader& esm, bool& isDeleted);
|
void load(ESMReader& esm, bool& isDeleted);
|
||||||
void save(ESMWriter& esm, bool isDeleted = false) const;
|
void save(ESMWriter& esm, bool isDeleted = false) const;
|
||||||
|
|
|
@ -109,13 +109,13 @@ namespace ESM
|
||||||
ESM::RefId mSoundIdUp;
|
ESM::RefId mSoundIdUp;
|
||||||
std::string mAttachBone;
|
std::string mAttachBone;
|
||||||
std::string mSheathingBone;
|
std::string mSheathingBone;
|
||||||
Skill::SkillEnum mSkill;
|
ESM::RefId mSkill;
|
||||||
Class mWeaponClass;
|
Class mWeaponClass;
|
||||||
int mAmmoType;
|
int mAmmoType;
|
||||||
int mFlags;
|
int mFlags;
|
||||||
|
|
||||||
WeaponType(std::string shortGroup, std::string longGroup, const std::string& soundId, std::string attachBone,
|
WeaponType(std::string shortGroup, std::string longGroup, const std::string& soundId, std::string attachBone,
|
||||||
std::string sheathingBone, Skill::SkillEnum skill, Class weaponClass, int ammoType, int flags)
|
std::string sheathingBone, ESM::RefId skill, Class weaponClass, int ammoType, int flags)
|
||||||
: mShortGroup(std::move(shortGroup))
|
: mShortGroup(std::move(shortGroup))
|
||||||
, mLongGroup(std::move(longGroup))
|
, mLongGroup(std::move(longGroup))
|
||||||
, mSoundIdDown(ESM::RefId::stringRefId(soundId + " Down"))
|
, mSoundIdDown(ESM::RefId::stringRefId(soundId + " Down"))
|
||||||
|
|
|
@ -73,7 +73,8 @@ namespace ESM
|
||||||
mSaveSkills[i] = skill.mBase + skill.mMod - skill.mDamage;
|
mSaveSkills[i] = skill.mBase + skill.mMod - skill.mDamage;
|
||||||
if (mObject.mNpcStats.mIsWerewolf)
|
if (mObject.mNpcStats.mIsWerewolf)
|
||||||
{
|
{
|
||||||
if (i == Skill::Acrobatics)
|
constexpr int Acrobatics = 20;
|
||||||
|
if (i == Acrobatics)
|
||||||
mSetWerewolfAcrobatics = mObject.mNpcStats.mSkills[i].mBase != skill.mBase;
|
mSetWerewolfAcrobatics = mObject.mNpcStats.mSkills[i].mBase != skill.mBase;
|
||||||
mObject.mNpcStats.mSkills[i] = skill;
|
mObject.mNpcStats.mSkills[i] = skill;
|
||||||
}
|
}
|
||||||
|
|
|
@ -14,45 +14,27 @@
|
||||||
<Property key="Caption" value="#{sSpecializationCombat}"/>
|
<Property key="Caption" value="#{sSpecializationCombat}"/>
|
||||||
<Property key="TextAlign" value="Left Top"/>
|
<Property key="TextAlign" value="Left Top"/>
|
||||||
</Widget>
|
</Widget>
|
||||||
<Widget type="MWSkill" skin="MW_StatNameButton" position="0 50 154 18" name="CombatSkill0" align="Left Top"/>
|
<Widget type="ScrollView" skin="MW_ScrollView" position="0 50 154 168" name="CombatSkills" align="Left Top">
|
||||||
<Widget type="MWSkill" skin="MW_StatNameButton" position="0 68 154 18" name="CombatSkill1" align="Left Top"/>
|
<Property key="CanvasAlign" value="Left"/>
|
||||||
<Widget type="MWSkill" skin="MW_StatNameButton" position="0 86 154 18" name="CombatSkill2" align="Left Top"/>
|
</Widget>
|
||||||
<Widget type="MWSkill" skin="MW_StatNameButton" position="0 104 154 18" name="CombatSkill3" align="Left Top"/>
|
|
||||||
<Widget type="MWSkill" skin="MW_StatNameButton" position="0 122 154 18" name="CombatSkill4" align="Left Top"/>
|
|
||||||
<Widget type="MWSkill" skin="MW_StatNameButton" position="0 140 154 18" name="CombatSkill5" align="Left Top"/>
|
|
||||||
<Widget type="MWSkill" skin="MW_StatNameButton" position="0 158 154 18" name="CombatSkill6" align="Left Top"/>
|
|
||||||
<Widget type="MWSkill" skin="MW_StatNameButton" position="0 176 154 18" name="CombatSkill7" align="Left Top"/>
|
|
||||||
<Widget type="MWSkill" skin="MW_StatNameButton" position="0 194 154 18" name="CombatSkill8" align="Left Top"/>
|
|
||||||
|
|
||||||
<!-- Magic list -->
|
<!-- Magic list -->
|
||||||
<Widget type="TextBox" skin="HeaderText" position="158 32 154 18" name="MagicLabelT" align="Left Top">
|
<Widget type="TextBox" skin="HeaderText" position="158 32 154 18" name="MagicLabelT" align="Left Top">
|
||||||
<Property key="Caption" value="#{sSpecializationMagic}"/>
|
<Property key="Caption" value="#{sSpecializationMagic}"/>
|
||||||
<Property key="TextAlign" value="Left Top"/>
|
<Property key="TextAlign" value="Left Top"/>
|
||||||
</Widget>
|
</Widget>
|
||||||
<Widget type="MWSkill" skin="MW_StatNameButton" position="158 50 154 18" name="MagicSkill0" align="Left Top"/>
|
<Widget type="ScrollView" skin="MW_ScrollView" position="158 50 154 168" name="MagicSkills" align="Left Top">
|
||||||
<Widget type="MWSkill" skin="MW_StatNameButton" position="158 68 154 18" name="MagicSkill1" align="Left Top"/>
|
<Property key="CanvasAlign" value="Left"/>
|
||||||
<Widget type="MWSkill" skin="MW_StatNameButton" position="158 86 154 18" name="MagicSkill2" align="Left Top"/>
|
</Widget>
|
||||||
<Widget type="MWSkill" skin="MW_StatNameButton" position="158 104 154 18" name="MagicSkill3" align="Left Top"/>
|
|
||||||
<Widget type="MWSkill" skin="MW_StatNameButton" position="158 122 154 18" name="MagicSkill4" align="Left Top"/>
|
|
||||||
<Widget type="MWSkill" skin="MW_StatNameButton" position="158 140 154 18" name="MagicSkill5" align="Left Top"/>
|
|
||||||
<Widget type="MWSkill" skin="MW_StatNameButton" position="158 158 154 18" name="MagicSkill6" align="Left Top"/>
|
|
||||||
<Widget type="MWSkill" skin="MW_StatNameButton" position="158 176 154 18" name="MagicSkill7" align="Left Top"/>
|
|
||||||
<Widget type="MWSkill" skin="MW_StatNameButton" position="158 194 154 18" name="MagicSkill8" align="Left Top"/>
|
|
||||||
|
|
||||||
<!-- Stealth list -->
|
<!-- Stealth list -->
|
||||||
<Widget type="TextBox" skin="HeaderText" position="316 32 131 18" name="StealthLabelT" align="Left Top">
|
<Widget type="TextBox" skin="HeaderText" position="316 32 131 18" name="StealthLabelT" align="Left Top">
|
||||||
<Property key="Caption" value="#{sSpecializationStealth}"/>
|
<Property key="Caption" value="#{sSpecializationStealth}"/>
|
||||||
<Property key="TextAlign" value="Left Top"/>
|
<Property key="TextAlign" value="Left Top"/>
|
||||||
</Widget>
|
</Widget>
|
||||||
<Widget type="MWSkill" skin="MW_StatNameButton" position="316 50 154 18" name="StealthSkill0" align="Left Top"/>
|
<Widget type="ScrollView" skin="MW_ScrollView" position="316 50 154 168" name="StealthSkills" align="Left Top">
|
||||||
<Widget type="MWSkill" skin="MW_StatNameButton" position="316 68 154 18" name="StealthSkill1" align="Left Top"/>
|
<Property key="CanvasAlign" value="Left"/>
|
||||||
<Widget type="MWSkill" skin="MW_StatNameButton" position="316 86 154 18" name="StealthSkill2" align="Left Top"/>
|
</Widget>
|
||||||
<Widget type="MWSkill" skin="MW_StatNameButton" position="316 104 154 18" name="StealthSkill3" align="Left Top"/>
|
|
||||||
<Widget type="MWSkill" skin="MW_StatNameButton" position="316 122 154 18" name="StealthSkill4" align="Left Top"/>
|
|
||||||
<Widget type="MWSkill" skin="MW_StatNameButton" position="316 140 154 18" name="StealthSkill5" align="Left Top"/>
|
|
||||||
<Widget type="MWSkill" skin="MW_StatNameButton" position="316 158 154 18" name="StealthSkill6" align="Left Top"/>
|
|
||||||
<Widget type="MWSkill" skin="MW_StatNameButton" position="316 176 154 18" name="StealthSkill7" align="Left Top"/>
|
|
||||||
<Widget type="MWSkill" skin="MW_StatNameButton" position="316 194 154 18" name="StealthSkill8" align="Left Top"/>
|
|
||||||
|
|
||||||
<!-- Dialog buttons -->
|
<!-- Dialog buttons -->
|
||||||
<Widget type="HBox" position="0 218 457 28">
|
<Widget type="HBox" position="0 218 457 28">
|
||||||
|
|
Loading…
Reference in a new issue