1
0
mirror of https://gitlab.com/OpenMW/openmw.git synced 2025-01-29 00:32:49 +00:00

Ignoring revisions in .git-blame-ignore-revs. Click here to bypass and see the normal blame view.

1578 lines
66 KiB
C++
Raw Normal View History

2019-08-06 21:30:21 +02:00
#include "npc.hpp"
2010-08-03 13:03:08 +02:00
#include <MyGUI_TextIterator.h>
#include <memory>
#include <components/misc/constants.hpp>
#include <components/misc/resourcehelpers.hpp>
2015-04-22 17:58:55 +02:00
#include <components/misc/rng.hpp>
2018-08-14 23:05:43 +04:00
#include <components/debug/debuglog.hpp>
2022-09-08 21:08:59 +02:00
#include <components/esm3/loadbody.hpp>
#include <components/esm3/loadclas.hpp>
#include <components/esm3/loadmgef.hpp>
#include <components/esm3/loadnpc.hpp>
#include <components/esm3/loadrace.hpp>
#include <components/esm3/loadsoun.hpp>
2022-09-08 21:08:59 +02:00
#include <components/esm3/npcstate.hpp>
#include <components/settings/settings.hpp>
2010-08-03 13:03:08 +02:00
#include "../mwbase/dialoguemanager.hpp"
#include "../mwbase/environment.hpp"
#include "../mwbase/luamanager.hpp"
#include "../mwbase/mechanicsmanager.hpp"
#include "../mwbase/soundmanager.hpp"
#include "../mwbase/windowmanager.hpp"
#include "../mwbase/world.hpp"
2015-08-21 21:12:39 +12:00
#include "../mwmechanics/actorutil.hpp"
#include "../mwmechanics/aisetting.hpp"
#include "../mwmechanics/autocalcspell.hpp"
#include "../mwmechanics/combat.hpp"
#include "../mwmechanics/creaturecustomdataresetter.hpp"
2010-08-03 13:32:37 +02:00
#include "../mwmechanics/creaturestats.hpp"
#include "../mwmechanics/difficultyscaling.hpp"
#include "../mwmechanics/disease.hpp"
#include "../mwmechanics/inventory.hpp"
#include "../mwmechanics/movement.hpp"
#include "../mwmechanics/npcstats.hpp"
#include "../mwmechanics/setbaseaisetting.hpp"
#include "../mwmechanics/spellcasting.hpp"
#include "../mwmechanics/weapontype.hpp"
2010-08-03 13:32:37 +02:00
2012-10-28 16:04:33 +01:00
#include "../mwworld/actionopen.hpp"
#include "../mwworld/actiontalk.hpp"
2014-02-23 20:11:05 +01:00
#include "../mwworld/cellstore.hpp"
2012-01-27 15:11:02 +01:00
#include "../mwworld/customdata.hpp"
#include "../mwworld/esmstore.hpp"
2013-08-08 22:34:53 -07:00
#include "../mwworld/failedaction.hpp"
#include "../mwworld/inventorystore.hpp"
2019-08-06 21:30:21 +02:00
#include "../mwworld/localscripts.hpp"
#include "../mwworld/ptr.hpp"
2010-08-03 13:03:08 +02:00
2016-02-09 00:26:22 +01:00
#include "../mwrender/npcanimation.hpp"
#include "../mwrender/objects.hpp"
#include "../mwrender/renderinginterface.hpp"
#include "../mwgui/tooltips.hpp"
#include "../mwgui/ustring.hpp"
2011-01-18 10:45:29 +01:00
namespace
{
int is_even(double d)
{
double int_part;
modf(d / 2.0, &int_part);
return 2.0 * int_part == d;
}
int round_ieee_754(double d)
{
double i = floor(d);
d -= i;
if (d < 0.5)
return static_cast<int>(i);
if (d > 0.5)
return static_cast<int>(i) + 1;
if (is_even(i))
return static_cast<int>(i);
return static_cast<int>(i) + 1;
}
void autoCalculateAttributes(const ESM::NPC* npc, MWMechanics::CreatureStats& creatureStats)
{
// race bonus
2023-04-20 21:07:53 +02:00
const ESM::Race* race = MWBase::Environment::get().getESMStore()->get<ESM::Race>().find(npc->mRace);
bool male = (npc->mFlags & ESM::NPC::Female) == 0;
int level = creatureStats.getLevel();
for (int i = 0; i < ESM::Attribute::Length; ++i)
{
const ESM::Race::MaleFemale& attribute = race->mData.mAttributeValues[i];
creatureStats.setAttribute(i, male ? attribute.mMale : attribute.mFemale);
}
// class bonus
2023-04-20 21:07:53 +02:00
const ESM::Class* class_ = MWBase::Environment::get().getESMStore()->get<ESM::Class>().find(npc->mClass);
for (int i = 0; i < 2; ++i)
{
int attribute = class_->mData.mAttribute[i];
if (attribute >= 0 && attribute < 8)
{
creatureStats.setAttribute(attribute, creatureStats.getAttribute(attribute).getBase() + 10);
}
}
// skill bonus
for (int attribute = 0; attribute < ESM::Attribute::Length; ++attribute)
{
float modifierSum = 0;
for (int j = 0; j < ESM::Skill::Length; ++j)
{
2023-04-20 21:07:53 +02:00
const ESM::Skill* skill = MWBase::Environment::get().getESMStore()->get<ESM::Skill>().find(j);
if (skill->mData.mAttribute != attribute)
continue;
// is this a minor or major skill?
float add = 0.2f;
for (int k = 0; k < 5; ++k)
{
if (class_->mData.mSkills[k][0] == j)
add = 0.5;
}
for (int k = 0; k < 5; ++k)
{
if (class_->mData.mSkills[k][1] == j)
add = 1.0;
}
modifierSum += add;
}
creatureStats.setAttribute(attribute,
std::min(
round_ieee_754(creatureStats.getAttribute(attribute).getBase() + (level - 1) * modifierSum), 100));
}
// initial health
float strength = creatureStats.getAttribute(ESM::Attribute::Strength).getBase();
float endurance = creatureStats.getAttribute(ESM::Attribute::Endurance).getBase();
int multiplier = 3;
if (class_->mData.mSpecialization == ESM::Class::Combat)
multiplier += 2;
else if (class_->mData.mSpecialization == ESM::Class::Stealth)
multiplier += 1;
if (class_->mData.mAttribute[0] == ESM::Attribute::Endurance
|| class_->mData.mAttribute[1] == ESM::Attribute::Endurance)
multiplier += 1;
creatureStats.setHealth(floor(0.5f * (strength + endurance)) + multiplier * (creatureStats.getLevel() - 1));
}
/**
* @brief autoCalculateSkills
*
* Skills are calculated with following formulae ( http://www.uesp.net/wiki/Morrowind:NPCs#Skills ):
*
* Skills: (Level - 1) × (Majority Multiplier + Specialization Multiplier)
*
* The Majority Multiplier is 1.0 for a Major or Minor Skill, or 0.1 for a Miscellaneous Skill.
*
* The Specialization Multiplier is 0.5 for a Skill in the same Specialization as the class,
* zero for other Skills.
*
* and by adding class, race, specialization bonus.
*/
void autoCalculateSkills(
const ESM::NPC* npc, MWMechanics::NpcStats& npcStats, const MWWorld::Ptr& ptr, bool spellsInitialised)
{
2023-04-20 21:07:53 +02:00
const ESM::Class* class_ = MWBase::Environment::get().getESMStore()->get<ESM::Class>().find(npc->mClass);
unsigned int level = npcStats.getLevel();
2023-04-20 21:07:53 +02:00
const ESM::Race* race = MWBase::Environment::get().getESMStore()->get<ESM::Race>().find(npc->mRace);
for (int i = 0; i < 2; ++i)
{
int bonus = (i == 0) ? 10 : 25;
for (int i2 = 0; i2 < 5; ++i2)
{
int index = class_->mData.mSkills[i2][i];
if (index >= 0 && index < ESM::Skill::Length)
{
npcStats.getSkill(index).setBase(npcStats.getSkill(index).getBase() + bonus);
}
}
}
for (int skillIndex = 0; skillIndex < ESM::Skill::Length; ++skillIndex)
{
float majorMultiplier = 0.1f;
float specMultiplier = 0.0f;
int raceBonus = 0;
int specBonus = 0;
for (int raceSkillIndex = 0; raceSkillIndex < 7; ++raceSkillIndex)
{
if (race->mData.mBonus[raceSkillIndex].mSkill == skillIndex)
{
raceBonus = race->mData.mBonus[raceSkillIndex].mBonus;
break;
}
}
for (int k = 0; k < 5; ++k)
{
// is this a minor or major skill?
if ((class_->mData.mSkills[k][0] == skillIndex) || (class_->mData.mSkills[k][1] == skillIndex))
{
majorMultiplier = 1.0f;
break;
}
}
// is this skill in the same Specialization as the class?
2023-04-20 21:07:53 +02:00
const ESM::Skill* skill = MWBase::Environment::get().getESMStore()->get<ESM::Skill>().find(skillIndex);
if (skill->mData.mSpecialization == class_->mData.mSpecialization)
{
specMultiplier = 0.5f;
specBonus = 5;
}
npcStats.getSkill(skillIndex)
.setBase(std::min(round_ieee_754(npcStats.getSkill(skillIndex).getBase() + 5 + raceBonus + specBonus
2014-07-12 14:43:57 +02:00
+ (int(level) - 1) * (majorMultiplier + specMultiplier)),
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];
for (int i = 0; i < ESM::Attribute::Length; ++i)
attributes[i] = npcStats.getAttribute(i).getBase();
if (!spellsInitialised)
{
Initial commit: In ESM structures, replace the string members that are RefIds to other records, to a new strong type The strong type is actually just a string underneath, but this will help in the future to have a distinction so it's easier to search and replace when we use an integer ID Slowly going through all the changes to make, still hundreds of errors a lot of functions/structures use std::string or stringview to designate an ID. So it takes time Continues slowly replacing ids. There are technically more and more compilation errors I have good hope that there is a point where the amount of errors will dramatically go down as all the main functions use the ESM::RefId type Continue moving forward, changes to the stores slowly moving along Starting to see the fruit of those changes. still many many error, but more and more Irun into a situation where a function is sandwiched between two functions that use the RefId type. More replacements. Things are starting to get easier I can see more and more often the issue is that the function is awaiting a RefId, but is given a string there is less need to go down functions and to fix a long list of them. Still moving forward, and for the first time error count is going down! Good pace, not sure about topics though, mId and mName are actually the same thing and are used interchangeably Cells are back to using string for the name, haven't fixed everything yet. Many other changes Under the bar of 400 compilation errors. more good progress <100 compile errors! More progress Game settings store can use string for find, it was a bit absurd how every use of it required to create refId from string some more progress on other fronts Mostly game settings clean one error opened a lot of other errors. Down to 18, but more will prbably appear only link errors left?? Fixed link errors OpenMW compiles, and launches, with some issues, but still!
2022-09-25 13:17:09 +02:00
std::vector<ESM::RefId> spells = MWMechanics::autoCalcNpcSpells(skills, attributes, race);
npcStats.getSpells().addAllToInstance(spells);
}
}
}
namespace MWClass
2010-08-03 13:03:08 +02:00
{
2022-04-04 02:44:53 +02:00
Npc::Npc()
: MWWorld::RegisteredClass<Npc, Actor>(ESM::NPC::sRecordId)
{
}
class NpcCustomData : public MWWorld::TypedCustomData<NpcCustomData>
{
public:
MWMechanics::NpcStats mNpcStats;
MWMechanics::Movement mMovement;
MWWorld::InventoryStore mInventoryStore;
NpcCustomData& asNpcCustomData() override { return *this; }
const NpcCustomData& asNpcCustomData() const override { return *this; }
};
const Npc::GMST& Npc::getGmst()
{
2021-10-24 18:45:04 +04:00
static const GMST staticGmst = [] {
GMST gmst;
const MWWorld::Store<ESM::GameSetting>& store
2023-04-20 21:07:53 +02:00
= MWBase::Environment::get().getESMStore()->get<ESM::GameSetting>();
gmst.fMinWalkSpeed = store.find("fMinWalkSpeed");
gmst.fMaxWalkSpeed = store.find("fMaxWalkSpeed");
gmst.fEncumberedMoveEffect = store.find("fEncumberedMoveEffect");
gmst.fSneakSpeedMultiplier = store.find("fSneakSpeedMultiplier");
gmst.fAthleticsRunBonus = store.find("fAthleticsRunBonus");
gmst.fBaseRunMultiplier = store.find("fBaseRunMultiplier");
gmst.fMinFlySpeed = store.find("fMinFlySpeed");
gmst.fMaxFlySpeed = store.find("fMaxFlySpeed");
gmst.fSwimRunBase = store.find("fSwimRunBase");
gmst.fSwimRunAthleticsMult = store.find("fSwimRunAthleticsMult");
gmst.fJumpEncumbranceBase = store.find("fJumpEncumbranceBase");
gmst.fJumpEncumbranceMultiplier = store.find("fJumpEncumbranceMultiplier");
gmst.fJumpAcrobaticsBase = store.find("fJumpAcrobaticsBase");
gmst.fJumpAcroMultiplier = store.find("fJumpAcroMultiplier");
gmst.fJumpRunMultiplier = store.find("fJumpRunMultiplier");
gmst.fWereWolfRunMult = store.find("fWereWolfRunMult");
gmst.fKnockDownMult = store.find("fKnockDownMult");
gmst.iKnockDownOddsMult = store.find("iKnockDownOddsMult");
gmst.iKnockDownOddsBase = store.find("iKnockDownOddsBase");
gmst.fCombatArmorMinMult = store.find("fCombatArmorMinMult");
2013-02-15 01:27:57 -08:00
return gmst;
}();
2021-10-24 18:45:04 +04:00
return staticGmst;
}
void Npc::ensureCustomData(const MWWorld::Ptr& ptr) const
{
if (!ptr.getRefData().getCustomData())
{
bool recalculate = false;
auto tempData = std::make_unique<NpcCustomData>();
NpcCustomData* data = tempData.get();
MWMechanics::CreatureCustomDataResetter resetter{ ptr };
ptr.getRefData().setCustomData(std::move(tempData));
MWWorld::LiveCellRef<ESM::NPC>* ref = ptr.get<ESM::NPC>();
bool spellsInitialised = data->mNpcStats.getSpells().setSpells(ref->mBase->mId);
// creature stats
int gold = 0;
if (ref->mBase->mNpdtType != ESM::NPC::NPC_WITH_AUTOCALCULATED_STATS)
{
gold = ref->mBase->mNpdt.mGold;
for (unsigned int i = 0; i < ESM::Skill::Length; ++i)
data->mNpcStats.getSkill(i).setBase(ref->mBase->mNpdt.mSkills[i]);
2012-11-05 16:07:59 +04:00
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::Willpower, ref->mBase->mNpdt.mWillpower);
data->mNpcStats.setAttribute(ESM::Attribute::Agility, ref->mBase->mNpdt.mAgility);
data->mNpcStats.setAttribute(ESM::Attribute::Speed, ref->mBase->mNpdt.mSpeed);
data->mNpcStats.setAttribute(ESM::Attribute::Endurance, ref->mBase->mNpdt.mEndurance);
data->mNpcStats.setAttribute(ESM::Attribute::Personality, ref->mBase->mNpdt.mPersonality);
data->mNpcStats.setAttribute(ESM::Attribute::Luck, ref->mBase->mNpdt.mLuck);
data->mNpcStats.setHealth(ref->mBase->mNpdt.mHealth);
data->mNpcStats.setMagicka(ref->mBase->mNpdt.mMana);
data->mNpcStats.setFatigue(ref->mBase->mNpdt.mFatigue);
2013-08-08 23:27:03 -07:00
data->mNpcStats.setLevel(ref->mBase->mNpdt.mLevel);
data->mNpcStats.setBaseDisposition(ref->mBase->mNpdt.mDisposition);
data->mNpcStats.setReputation(ref->mBase->mNpdt.mReputation);
}
else
{
gold = ref->mBase->mNpdt.mGold;
for (int i = 0; i < 3; ++i)
2013-08-08 23:27:03 -07:00
data->mNpcStats.setDynamic(i, 10);
data->mNpcStats.setLevel(ref->mBase->mNpdt.mLevel);
data->mNpcStats.setBaseDisposition(ref->mBase->mNpdt.mDisposition);
data->mNpcStats.setReputation(ref->mBase->mNpdt.mReputation);
2013-08-08 23:27:03 -07:00
autoCalculateAttributes(ref->mBase, data->mNpcStats);
autoCalculateSkills(ref->mBase, data->mNpcStats, ptr, spellsInitialised);
recalculate = true;
}
// Persistent actors with 0 health do not play death animation
if (data->mNpcStats.isDead())
data->mNpcStats.setDeathAnimationFinished(isPersistent(ptr));
// race powers
2023-04-20 21:07:53 +02:00
const ESM::Race* race = MWBase::Environment::get().getESMStore()->get<ESM::Race>().find(ref->mBase->mRace);
data->mNpcStats.getSpells().addAllToInstance(race->mPowers.mList);
2015-01-27 17:32:21 +01:00
if (!ref->mBase->mFaction.empty())
{
static const int iAutoRepFacMod = MWBase::Environment::get()
2023-04-20 21:07:53 +02:00
.getESMStore()
->get<ESM::GameSetting>()
2018-08-29 18:38:12 +03:00
.find("iAutoRepFacMod")
->mValue.getInteger();
static const int iAutoRepLevMod = MWBase::Environment::get()
2023-04-20 21:07:53 +02:00
.getESMStore()
->get<ESM::GameSetting>()
2018-08-29 18:38:12 +03:00
.find("iAutoRepLevMod")
->mValue.getInteger();
2015-01-27 17:32:21 +01:00
int rank = ref->mBase->getFactionRank();
data->mNpcStats.setReputation(
iAutoRepFacMod * (rank + 1) + iAutoRepLevMod * (data->mNpcStats.getLevel() - 1));
}
2013-08-08 23:27:03 -07:00
data->mNpcStats.getAiSequence().fill(ref->mBase->mAiPackage);
data->mNpcStats.setAiSetting(MWMechanics::AiSetting::Hello, ref->mBase->mAiData.mHello);
data->mNpcStats.setAiSetting(MWMechanics::AiSetting::Fight, ref->mBase->mAiData.mFight);
data->mNpcStats.setAiSetting(MWMechanics::AiSetting::Flee, ref->mBase->mAiData.mFlee);
data->mNpcStats.setAiSetting(MWMechanics::AiSetting::Alarm, ref->mBase->mAiData.mAlarm);
// spells
if (!spellsInitialised)
data->mNpcStats.getSpells().addAllToInstance(ref->mBase->mSpells.mList);
data->mNpcStats.setGoldPool(gold);
// store
resetter.mPtr = {};
if (recalculate)
data->mNpcStats.recalculateMagicka();
// inventory
// setting ownership is used to make the NPC auto-equip his initial equipment only, and not bartered items
auto& prng = MWBase::Environment::get().getWorld()->getPrng();
getInventoryStore(ptr).fill(ref->mBase->mInventory, ptr.getCellRef().getRefId(), prng);
getInventoryStore(ptr).autoEquip();
}
}
void Npc::insertObjectRendering(
const MWWorld::Ptr& ptr, const std::string& model, MWRender::RenderingInterface& renderingInterface) const
{
renderingInterface.getObjects().insertNPC(ptr);
2011-11-11 23:01:12 -05:00
}
2010-12-21 21:45:54 -05:00
2015-12-18 16:41:37 +01:00
bool Npc::isPersistent(const MWWorld::ConstPtr& actor) const
2013-05-16 18:50:26 +02:00
{
2015-12-18 16:41:37 +01:00
const MWWorld::LiveCellRef<ESM::NPC>* ref = actor.get<ESM::NPC>();
return (ref->mBase->mRecordFlags & ESM::FLAG_Persistent) != 0;
2013-05-16 18:50:26 +02:00
}
2015-12-18 15:51:05 +01:00
std::string Npc::getModel(const MWWorld::ConstPtr& ptr) const
2012-07-24 20:22:11 +04:00
{
2015-12-18 15:51:05 +01:00
const MWWorld::LiveCellRef<ESM::NPC>* ref = ptr.get<ESM::NPC>();
2021-01-01 22:51:23 +02:00
std::string model = Settings::Manager::getString("baseanim", "Models");
2023-04-20 21:07:53 +02:00
const ESM::Race* race = MWBase::Environment::get().getESMStore()->get<ESM::Race>().find(ref->mBase->mRace);
if (race->mData.mFlags & ESM::Race::Beast)
model = Settings::Manager::getString("baseanimkna", "Models");
2012-07-24 20:22:11 +04:00
return model;
}
void Npc::getModelsToPreload(const MWWorld::Ptr& ptr, std::vector<std::string>& models) const
{
const MWWorld::LiveCellRef<ESM::NPC>* npc = ptr.get<ESM::NPC>();
2023-04-20 21:07:53 +02:00
const ESM::Race* race = MWBase::Environment::get().getESMStore()->get<ESM::Race>().search(npc->mBase->mRace);
if (race && race->mData.mFlags & ESM::Race::Beast)
models.emplace_back(Settings::Manager::getString("baseanimkna", "Models"));
// keep these always loaded just in case
models.emplace_back(Settings::Manager::getString("xargonianswimkna", "Models"));
models.emplace_back(Settings::Manager::getString("xbaseanimfemale", "Models"));
models.emplace_back(Settings::Manager::getString("xbaseanim", "Models"));
const VFS::Manager* const vfs = MWBase::Environment::get().getResourceSystem()->getVFS();
if (!npc->mBase->mModel.empty())
models.push_back(Misc::ResourceHelpers::correctMeshPath(npc->mBase->mModel, vfs));
if (!npc->mBase->mHead.empty())
{
const ESM::BodyPart* head
2023-04-20 21:07:53 +02:00
= MWBase::Environment::get().getESMStore()->get<ESM::BodyPart>().search(npc->mBase->mHead);
if (head)
models.push_back(Misc::ResourceHelpers::correctMeshPath(head->mModel, vfs));
}
if (!npc->mBase->mHair.empty())
{
const ESM::BodyPart* hair
2023-04-20 21:07:53 +02:00
= MWBase::Environment::get().getESMStore()->get<ESM::BodyPart>().search(npc->mBase->mHair);
if (hair)
models.push_back(Misc::ResourceHelpers::correctMeshPath(hair->mModel, vfs));
}
2016-02-09 00:26:22 +01:00
bool female = (npc->mBase->mFlags & ESM::NPC::Female);
// FIXME: use const version of InventoryStore functions once they are available
2016-02-09 00:26:22 +01:00
// preload equipped items
const MWWorld::InventoryStore& invStore = getInventoryStore(ptr);
for (int slot = 0; slot < MWWorld::InventoryStore::Slots; ++slot)
{
MWWorld::ConstContainerStoreIterator equipped = invStore.getSlot(slot);
if (equipped != invStore.end())
{
std::vector<ESM::PartReference> parts;
if (equipped->getType() == ESM::Clothing::sRecordId)
{
const ESM::Clothing* clothes = equipped->get<ESM::Clothing>()->mBase;
parts = clothes->mParts.mParts;
}
else if (equipped->getType() == ESM::Armor::sRecordId)
{
const ESM::Armor* armor = equipped->get<ESM::Armor>()->mBase;
parts = armor->mParts.mParts;
}
else
{
std::string model = equipped->getClass().getModel(*equipped);
if (!model.empty())
models.push_back(model);
}
for (std::vector<ESM::PartReference>::const_iterator it = parts.begin(); it != parts.end(); ++it)
{
const ESM::RefId& partname
= (female && !it->mFemale.empty()) || (!female && it->mMale.empty()) ? it->mFemale : it->mMale;
const ESM::BodyPart* part
2023-04-20 21:07:53 +02:00
= MWBase::Environment::get().getESMStore()->get<ESM::BodyPart>().search(partname);
if (part && !part->mModel.empty())
models.push_back(Misc::ResourceHelpers::correctMeshPath(part->mModel, vfs));
}
}
}
2016-02-09 00:26:22 +01:00
// preload body parts
if (race)
{
const std::vector<const ESM::BodyPart*>& parts
Initial commit: In ESM structures, replace the string members that are RefIds to other records, to a new strong type The strong type is actually just a string underneath, but this will help in the future to have a distinction so it's easier to search and replace when we use an integer ID Slowly going through all the changes to make, still hundreds of errors a lot of functions/structures use std::string or stringview to designate an ID. So it takes time Continues slowly replacing ids. There are technically more and more compilation errors I have good hope that there is a point where the amount of errors will dramatically go down as all the main functions use the ESM::RefId type Continue moving forward, changes to the stores slowly moving along Starting to see the fruit of those changes. still many many error, but more and more Irun into a situation where a function is sandwiched between two functions that use the RefId type. More replacements. Things are starting to get easier I can see more and more often the issue is that the function is awaiting a RefId, but is given a string there is less need to go down functions and to fix a long list of them. Still moving forward, and for the first time error count is going down! Good pace, not sure about topics though, mId and mName are actually the same thing and are used interchangeably Cells are back to using string for the name, haven't fixed everything yet. Many other changes Under the bar of 400 compilation errors. more good progress <100 compile errors! More progress Game settings store can use string for find, it was a bit absurd how every use of it required to create refId from string some more progress on other fronts Mostly game settings clean one error opened a lot of other errors. Down to 18, but more will prbably appear only link errors left?? Fixed link errors OpenMW compiles, and launches, with some issues, but still!
2022-09-25 13:17:09 +02:00
= MWRender::NpcAnimation::getBodyParts(race->mId, female, false, false);
2016-02-09 00:26:22 +01:00
for (std::vector<const ESM::BodyPart*>::const_iterator it = parts.begin(); it != parts.end(); ++it)
{
const ESM::BodyPart* part = *it;
if (part && !part->mModel.empty())
models.push_back(Misc::ResourceHelpers::correctMeshPath(part->mModel, vfs));
2016-02-09 00:26:22 +01:00
}
}
}
2022-08-16 21:15:03 +02:00
std::string_view Npc::getName(const MWWorld::ConstPtr& ptr) const
2010-08-03 17:11:41 +02:00
{
if (ptr.getRefData().getCustomData()
&& ptr.getRefData().getCustomData()->asNpcCustomData().mNpcStats.isWerewolf())
{
const MWWorld::Store<ESM::GameSetting>& store
2023-04-20 21:07:53 +02:00
= MWBase::Environment::get().getESMStore()->get<ESM::GameSetting>();
2018-08-29 18:38:12 +03:00
return store.find("sWerewolfPopup")->mValue.getString();
}
2010-08-03 17:11:41 +02:00
const MWWorld::LiveCellRef<ESM::NPC>* ref = ptr.get<ESM::NPC>();
const std::string& name = ref->mBase->mName;
Initial commit: In ESM structures, replace the string members that are RefIds to other records, to a new strong type The strong type is actually just a string underneath, but this will help in the future to have a distinction so it's easier to search and replace when we use an integer ID Slowly going through all the changes to make, still hundreds of errors a lot of functions/structures use std::string or stringview to designate an ID. So it takes time Continues slowly replacing ids. There are technically more and more compilation errors I have good hope that there is a point where the amount of errors will dramatically go down as all the main functions use the ESM::RefId type Continue moving forward, changes to the stores slowly moving along Starting to see the fruit of those changes. still many many error, but more and more Irun into a situation where a function is sandwiched between two functions that use the RefId type. More replacements. Things are starting to get easier I can see more and more often the issue is that the function is awaiting a RefId, but is given a string there is less need to go down functions and to fix a long list of them. Still moving forward, and for the first time error count is going down! Good pace, not sure about topics though, mId and mName are actually the same thing and are used interchangeably Cells are back to using string for the name, haven't fixed everything yet. Many other changes Under the bar of 400 compilation errors. more good progress <100 compile errors! More progress Game settings store can use string for find, it was a bit absurd how every use of it required to create refId from string some more progress on other fronts Mostly game settings clean one error opened a lot of other errors. Down to 18, but more will prbably appear only link errors left?? Fixed link errors OpenMW compiles, and launches, with some issues, but still!
2022-09-25 13:17:09 +02:00
return !name.empty() ? name : ref->mBase->mId.getRefIdString();
2010-08-03 17:11:41 +02:00
}
MWMechanics::CreatureStats& Npc::getCreatureStats(const MWWorld::Ptr& ptr) const
2010-08-03 13:03:08 +02:00
{
ensureCustomData(ptr);
2010-08-03 13:03:08 +02:00
return ptr.getRefData().getCustomData()->asNpcCustomData().mNpcStats;
2010-08-03 13:03:08 +02:00
}
2010-08-19 12:49:13 +02:00
MWMechanics::NpcStats& Npc::getNpcStats(const MWWorld::Ptr& ptr) const
{
ensureCustomData(ptr);
2010-08-19 12:49:13 +02:00
return ptr.getRefData().getCustomData()->asNpcCustomData().mNpcStats;
2010-08-19 12:49:13 +02:00
}
bool Npc::evaluateHit(const MWWorld::Ptr& ptr, MWWorld::Ptr& victim, osg::Vec3f& hitPosition) const
2013-07-24 02:51:42 -07:00
{
victim = MWWorld::Ptr();
hitPosition = osg::Vec3f();
// Get the weapon used (if hand-to-hand, weapon = inv.end())
MWWorld::InventoryStore& inv = getInventoryStore(ptr);
MWWorld::ContainerStoreIterator weaponslot = inv.getSlot(MWWorld::InventoryStore::Slot_CarriedRight);
MWWorld::Ptr weapon;
if (weaponslot != inv.end() && weaponslot->getType() == ESM::Weapon::sRecordId)
weapon = *weaponslot;
MWBase::World* world = MWBase::Environment::get().getWorld();
const MWWorld::Store<ESM::GameSetting>& store = world->getStore().get<ESM::GameSetting>();
2018-08-29 18:38:12 +03:00
const float fCombatDistance = store.find("fCombatDistance")->mValue.getFloat();
2014-01-20 17:31:08 +01:00
float dist = fCombatDistance
* (!weapon.isEmpty() ? weapon.get<ESM::Weapon>()->mBase->mData.mReach
2018-08-29 18:38:12 +03:00
: store.find("fHandToHandReach")->mValue.getFloat());
2014-01-20 17:31:08 +01:00
// For AI actors, get combat targets to use in the ray cast. Only those targets will return a positive hit
// result.
std::vector<MWWorld::Ptr> targetActors;
if (ptr != MWMechanics::getPlayer())
getCreatureStats(ptr).getAiSequence().getCombatTargets(targetActors);
2014-01-17 17:19:08 +01:00
// TODO: Use second to work out the hit angle
std::pair<MWWorld::Ptr, osg::Vec3f> result = world->getHitContact(ptr, dist, targetActors);
if (result.first.isEmpty()) // Didn't hit anything
return true;
const MWWorld::Class& othercls = result.first.getClass();
if (!othercls.isActor()) // Can't hit non-actors
return true;
MWMechanics::CreatureStats& otherstats = othercls.getCreatureStats(result.first);
if (otherstats.isDead()) // Can't hit dead actors
return true;
// Note that earlier we returned true in spite of an apparent failure to hit anything alive.
// This is because hitting nothing is not a "miss" and should be handled as such character controller-side.
victim = result.first;
hitPosition = result.second;
int weapskill = ESM::Skill::HandToHand;
if (!weapon.isEmpty())
weapskill = weapon.getClass().getEquipmentSkill(weapon);
float hitchance = MWMechanics::getHitChance(ptr, victim, getSkill(ptr, weapskill));
return Misc::Rng::roll0to99(world->getPrng()) < hitchance;
}
void Npc::hit(const MWWorld::Ptr& ptr, float attackStrength, int type, const MWWorld::Ptr& victim,
const osg::Vec3f& hitPosition, bool success) const
{
MWWorld::InventoryStore& inv = getInventoryStore(ptr);
MWWorld::ContainerStoreIterator weaponslot = inv.getSlot(MWWorld::InventoryStore::Slot_CarriedRight);
MWWorld::Ptr weapon;
if (weaponslot != inv.end() && weaponslot->getType() == ESM::Weapon::sRecordId)
weapon = *weaponslot;
MWMechanics::applyFatigueLoss(ptr, weapon, attackStrength);
2013-07-24 02:51:42 -07:00
if (victim.isEmpty()) // Didn't hit anything
return;
const MWWorld::Class& othercls = victim.getClass();
MWMechanics::CreatureStats& otherstats = othercls.getCreatureStats(victim);
if (otherstats.isDead()) // Can't hit dead actors
2013-07-24 02:51:42 -07:00
return;
2015-08-21 21:12:39 +12:00
if (ptr == MWMechanics::getPlayer())
2013-07-30 15:58:24 +02:00
MWBase::Environment::get().getWindowManager()->setEnemy(victim);
2013-07-30 06:17:21 +02:00
if (!success)
{
othercls.onHit(victim, 0.0f, false, weapon, ptr, osg::Vec3f(), false);
MWMechanics::reduceWeaponCondition(0.f, false, weapon, ptr);
return;
}
2013-07-24 02:51:42 -07:00
2013-07-28 06:48:25 -07:00
bool healthdmg;
float damage = 0.0f;
if (!weapon.isEmpty())
2013-07-24 02:51:42 -07:00
{
2018-10-09 10:21:12 +04:00
const unsigned char* attack = nullptr;
2014-01-28 21:07:26 +02:00
if (type == ESM::Weapon::AT_Chop)
attack = weapon.get<ESM::Weapon>()->mBase->mData.mChop;
2014-01-28 21:07:26 +02:00
else if (type == ESM::Weapon::AT_Slash)
attack = weapon.get<ESM::Weapon>()->mBase->mData.mSlash;
2014-01-28 21:07:26 +02:00
else if (type == ESM::Weapon::AT_Thrust)
attack = weapon.get<ESM::Weapon>()->mBase->mData.mThrust;
if (attack)
{
damage = attack[0] + ((attack[1] - attack[0]) * attackStrength);
}
2015-03-12 03:08:58 +01:00
MWMechanics::adjustWeaponDamage(damage, weapon, ptr);
MWMechanics::reduceWeaponCondition(damage, true, weapon, ptr);
MWMechanics::resistNormalWeapon(victim, ptr, weapon, damage);
MWMechanics::applyWerewolfDamageMult(victim, weapon, damage);
2013-07-28 06:48:25 -07:00
healthdmg = true;
}
else
{
MWMechanics::getHandToHandDamage(ptr, victim, damage, healthdmg, attackStrength);
2013-07-24 02:51:42 -07:00
}
MWBase::World* world = MWBase::Environment::get().getWorld();
const MWWorld::Store<ESM::GameSetting>& store = world->getStore().get<ESM::GameSetting>();
2015-08-21 21:12:39 +12:00
if (ptr == MWMechanics::getPlayer())
{
int weapskill = ESM::Skill::HandToHand;
if (!weapon.isEmpty())
weapskill = weapon.getClass().getEquipmentSkill(weapon);
skillUsageSucceeded(ptr, weapskill, 0);
const MWMechanics::AiSequence& seq = victim.getClass().getCreatureStats(victim).getAiSequence();
bool unaware
= !seq.isInCombat() && !MWBase::Environment::get().getMechanicsManager()->awarenessCheck(ptr, victim);
if (unaware)
{
2018-08-29 18:38:12 +03:00
damage *= store.find("fCombatCriticalStrikeMult")->mValue.getFloat();
MWBase::Environment::get().getWindowManager()->messageBox("#{sTargetCriticalStrike}");
MWBase::Environment::get().getSoundManager()->playSound3D(
victim, ESM::RefId::stringRefId("critical damage"), 1.0f, 1.0f);
}
}
if (othercls.getCreatureStats(victim).getKnockedDown())
2018-08-29 18:38:12 +03:00
damage *= store.find("fCombatKODamageMult")->mValue.getFloat();
// Apply "On hit" enchanted weapons
MWMechanics::applyOnStrikeEnchantment(ptr, victim, weapon, hitPosition);
MWMechanics::applyElementalShields(ptr, victim);
if (MWMechanics::blockMeleeAttack(ptr, victim, weapon, damage, attackStrength))
{
damage = 0;
victim.getClass().block(victim);
}
2017-03-25 22:40:11 +04:00
if (victim == MWMechanics::getPlayer() && MWBase::Environment::get().getWorld()->getGodModeState())
damage = 0;
MWMechanics::diseaseContact(victim, ptr);
othercls.onHit(victim, damage, healthdmg, weapon, ptr, hitPosition, true);
2013-07-24 02:51:42 -07:00
}
2016-09-13 00:49:31 +09:00
void Npc::onHit(const MWWorld::Ptr& ptr, float damage, bool ishealth, const MWWorld::Ptr& object,
const MWWorld::Ptr& attacker, const osg::Vec3f& hitPosition, bool successful) const
2013-07-24 02:51:42 -07:00
{
2013-07-28 06:48:25 -07:00
MWBase::SoundManager* sndMgr = MWBase::Environment::get().getSoundManager();
MWMechanics::CreatureStats& stats = getCreatureStats(ptr);
bool wasDead = stats.isDead();
// Note OnPcHitMe is not set for friendly hits.
bool setOnPcHitMe = true;
// NOTE: 'object' and/or 'attacker' may be empty.
if (!attacker.isEmpty() && attacker.getClass().isActor() && !stats.getAiSequence().isInCombat(attacker))
{
stats.setAttacked(true);
setOnPcHitMe = MWBase::Environment::get().getMechanicsManager()->actorAttacked(ptr, attacker);
}
// Attacker and target store each other as hitattemptactor if they have no one stored yet
if (!attacker.isEmpty() && attacker.getClass().isActor())
{
MWMechanics::CreatureStats& statsAttacker = attacker.getClass().getCreatureStats(attacker);
// First handle the attacked actor
2017-02-06 21:32:36 +09:00
if ((stats.getHitAttemptActorId() == -1)
&& (statsAttacker.getAiSequence().isInCombat(ptr) || attacker == MWMechanics::getPlayer()))
2017-02-06 21:32:36 +09:00
stats.setHitAttemptActorId(statsAttacker.getActorId());
// Next handle the attacking actor
2017-02-06 21:32:36 +09:00
if ((statsAttacker.getHitAttemptActorId() == -1)
&& (statsAttacker.getAiSequence().isInCombat(ptr) || attacker == MWMechanics::getPlayer()))
2017-02-06 21:32:36 +09:00
statsAttacker.setHitAttemptActorId(stats.getActorId());
}
if (!object.isEmpty())
stats.setLastHitAttemptObject(object.getCellRef().getRefId());
if (setOnPcHitMe && !attacker.isEmpty() && attacker == MWMechanics::getPlayer())
2015-06-18 15:00:04 +02:00
{
Initial commit: In ESM structures, replace the string members that are RefIds to other records, to a new strong type The strong type is actually just a string underneath, but this will help in the future to have a distinction so it's easier to search and replace when we use an integer ID Slowly going through all the changes to make, still hundreds of errors a lot of functions/structures use std::string or stringview to designate an ID. So it takes time Continues slowly replacing ids. There are technically more and more compilation errors I have good hope that there is a point where the amount of errors will dramatically go down as all the main functions use the ESM::RefId type Continue moving forward, changes to the stores slowly moving along Starting to see the fruit of those changes. still many many error, but more and more Irun into a situation where a function is sandwiched between two functions that use the RefId type. More replacements. Things are starting to get easier I can see more and more often the issue is that the function is awaiting a RefId, but is given a string there is less need to go down functions and to fix a long list of them. Still moving forward, and for the first time error count is going down! Good pace, not sure about topics though, mId and mName are actually the same thing and are used interchangeably Cells are back to using string for the name, haven't fixed everything yet. Many other changes Under the bar of 400 compilation errors. more good progress <100 compile errors! More progress Game settings store can use string for find, it was a bit absurd how every use of it required to create refId from string some more progress on other fronts Mostly game settings clean one error opened a lot of other errors. Down to 18, but more will prbably appear only link errors left?? Fixed link errors OpenMW compiles, and launches, with some issues, but still!
2022-09-25 13:17:09 +02:00
const ESM::RefId& script = getScript(ptr);
2015-06-18 15:00:04 +02:00
/* Set the OnPCHitMe script variable. The script is responsible for clearing it. */
if (!script.empty())
ptr.getRefData().getLocals().setVarByInt(script, "onpchitme", 1);
}
if (!successful)
{
// Missed
if (!attacker.isEmpty() && attacker == MWMechanics::getPlayer())
Initial commit: In ESM structures, replace the string members that are RefIds to other records, to a new strong type The strong type is actually just a string underneath, but this will help in the future to have a distinction so it's easier to search and replace when we use an integer ID Slowly going through all the changes to make, still hundreds of errors a lot of functions/structures use std::string or stringview to designate an ID. So it takes time Continues slowly replacing ids. There are technically more and more compilation errors I have good hope that there is a point where the amount of errors will dramatically go down as all the main functions use the ESM::RefId type Continue moving forward, changes to the stores slowly moving along Starting to see the fruit of those changes. still many many error, but more and more Irun into a situation where a function is sandwiched between two functions that use the RefId type. More replacements. Things are starting to get easier I can see more and more often the issue is that the function is awaiting a RefId, but is given a string there is less need to go down functions and to fix a long list of them. Still moving forward, and for the first time error count is going down! Good pace, not sure about topics though, mId and mName are actually the same thing and are used interchangeably Cells are back to using string for the name, haven't fixed everything yet. Many other changes Under the bar of 400 compilation errors. more good progress <100 compile errors! More progress Game settings store can use string for find, it was a bit absurd how every use of it required to create refId from string some more progress on other fronts Mostly game settings clean one error opened a lot of other errors. Down to 18, but more will prbably appear only link errors left?? Fixed link errors OpenMW compiles, and launches, with some issues, but still!
2022-09-25 13:17:09 +02:00
sndMgr->playSound3D(ptr, ESM::RefId::stringRefId("miss"), 1.0f, 1.0f);
return;
}
2013-07-24 02:51:42 -07:00
if (!object.isEmpty())
stats.setLastHitObject(object.getCellRef().getRefId());
2013-07-26 07:04:36 -07:00
if (damage > 0.0f && !object.isEmpty())
MWMechanics::resistNormalWeapon(ptr, attacker, object, damage);
if (damage < 0.001f)
damage = 0;
2017-03-25 22:40:11 +04:00
bool godmode = ptr == MWMechanics::getPlayer() && MWBase::Environment::get().getWorld()->getGodModeState();
if (godmode)
damage = 0;
if (damage > 0.0f && !attacker.isEmpty())
2013-07-24 02:51:42 -07:00
{
// 'ptr' is losing health. Play a 'hit' voiced dialog entry if not already saying
// something, alert the character controller, scripts, etc.
2023-04-20 21:07:53 +02:00
const MWWorld::ESMStore& store = *MWBase::Environment::get().getESMStore();
const GMST& gmst = getGmst();
int chance = store.get<ESM::GameSetting>().find("iVoiceHitOdds")->mValue.getInteger();
auto& prng = MWBase::Environment::get().getWorld()->getPrng();
if (Misc::Rng::roll0to99(prng) < chance)
Initial commit: In ESM structures, replace the string members that are RefIds to other records, to a new strong type The strong type is actually just a string underneath, but this will help in the future to have a distinction so it's easier to search and replace when we use an integer ID Slowly going through all the changes to make, still hundreds of errors a lot of functions/structures use std::string or stringview to designate an ID. So it takes time Continues slowly replacing ids. There are technically more and more compilation errors I have good hope that there is a point where the amount of errors will dramatically go down as all the main functions use the ESM::RefId type Continue moving forward, changes to the stores slowly moving along Starting to see the fruit of those changes. still many many error, but more and more Irun into a situation where a function is sandwiched between two functions that use the RefId type. More replacements. Things are starting to get easier I can see more and more often the issue is that the function is awaiting a RefId, but is given a string there is less need to go down functions and to fix a long list of them. Still moving forward, and for the first time error count is going down! Good pace, not sure about topics though, mId and mName are actually the same thing and are used interchangeably Cells are back to using string for the name, haven't fixed everything yet. Many other changes Under the bar of 400 compilation errors. more good progress <100 compile errors! More progress Game settings store can use string for find, it was a bit absurd how every use of it required to create refId from string some more progress on other fronts Mostly game settings clean one error opened a lot of other errors. Down to 18, but more will prbably appear only link errors left?? Fixed link errors OpenMW compiles, and launches, with some issues, but still!
2022-09-25 13:17:09 +02:00
MWBase::Environment::get().getDialogueManager()->say(ptr, ESM::RefId::stringRefId("hit"));
// Check for knockdown
2018-08-29 18:38:12 +03:00
float agilityTerm
= stats.getAttribute(ESM::Attribute::Agility).getModified() * gmst.fKnockDownMult->mValue.getFloat();
float knockdownTerm = stats.getAttribute(ESM::Attribute::Agility).getModified()
2018-08-29 18:38:12 +03:00
* gmst.iKnockDownOddsMult->mValue.getInteger() * 0.01f
+ gmst.iKnockDownOddsBase->mValue.getInteger();
if (ishealth && agilityTerm <= damage && knockdownTerm <= Misc::Rng::roll0to99(prng))
stats.setKnockedDown(true);
else
stats.setHitRecovery(true); // Is this supposed to always occur?
if (damage > 0 && ishealth)
{
// Hit percentages:
// cuirass = 30%
// shield, helmet, greaves, boots, pauldrons = 10% each
// guantlets = 5% each
static const int hitslots[20]
= { MWWorld::InventoryStore::Slot_Cuirass, MWWorld::InventoryStore::Slot_Cuirass,
MWWorld::InventoryStore::Slot_Cuirass, MWWorld::InventoryStore::Slot_Cuirass,
MWWorld::InventoryStore::Slot_Cuirass, MWWorld::InventoryStore::Slot_Cuirass,
MWWorld::InventoryStore::Slot_CarriedLeft, MWWorld::InventoryStore::Slot_CarriedLeft,
MWWorld::InventoryStore::Slot_Helmet, MWWorld::InventoryStore::Slot_Helmet,
MWWorld::InventoryStore::Slot_Greaves, MWWorld::InventoryStore::Slot_Greaves,
MWWorld::InventoryStore::Slot_Boots, MWWorld::InventoryStore::Slot_Boots,
MWWorld::InventoryStore::Slot_LeftPauldron, MWWorld::InventoryStore::Slot_LeftPauldron,
MWWorld::InventoryStore::Slot_RightPauldron, MWWorld::InventoryStore::Slot_RightPauldron,
MWWorld::InventoryStore::Slot_LeftGauntlet, MWWorld::InventoryStore::Slot_RightGauntlet };
int hitslot = hitslots[Misc::Rng::rollDice(20, prng)];
float unmitigatedDamage = damage;
float x = damage / (damage + getArmorRating(ptr));
2018-08-29 18:38:12 +03:00
damage *= std::max(gmst.fCombatArmorMinMult->mValue.getFloat(), x);
int damageDiff = static_cast<int>(unmitigatedDamage - damage);
damage = std::max(1.f, damage);
damageDiff = std::max(1, damageDiff);
MWWorld::InventoryStore& inv = getInventoryStore(ptr);
MWWorld::ContainerStoreIterator armorslot = inv.getSlot(hitslot);
MWWorld::Ptr armor = ((armorslot != inv.end()) ? *armorslot : MWWorld::Ptr());
bool hasArmor = !armor.isEmpty() && armor.getType() == ESM::Armor::sRecordId;
// If there's no item in the carried left slot or if it is not a shield redistribute the hit.
if (!hasArmor && hitslot == MWWorld::InventoryStore::Slot_CarriedLeft)
{
if (Misc::Rng::rollDice(2, prng) == 0)
hitslot = MWWorld::InventoryStore::Slot_Cuirass;
else
hitslot = MWWorld::InventoryStore::Slot_LeftPauldron;
armorslot = inv.getSlot(hitslot);
if (armorslot != inv.end())
{
armor = *armorslot;
hasArmor = !armor.isEmpty() && armor.getType() == ESM::Armor::sRecordId;
}
}
if (hasArmor)
{
static const bool creatureDamage
= Settings::Manager::getBool("unarmed creature attacks damage armor", "Game");
if (!object.isEmpty() || attacker.isEmpty() || attacker.getClass().isNpc()
|| creatureDamage) // Unarmed creature attacks don't affect armor condition unless it was
// explicitly requested.
{
int armorhealth = armor.getClass().getItemHealth(armor);
armorhealth -= std::min(damageDiff, armorhealth);
armor.getCellRef().setCharge(armorhealth);
// Armor broken? unequip it
if (armorhealth == 0)
armor = *inv.unequipItem(armor);
}
2015-08-21 21:12:39 +12:00
if (ptr == MWMechanics::getPlayer())
skillUsageSucceeded(ptr, armor.getClass().getEquipmentSkill(armor), 0);
switch (armor.getClass().getEquipmentSkill(armor))
{
case ESM::Skill::LightArmor:
Initial commit: In ESM structures, replace the string members that are RefIds to other records, to a new strong type The strong type is actually just a string underneath, but this will help in the future to have a distinction so it's easier to search and replace when we use an integer ID Slowly going through all the changes to make, still hundreds of errors a lot of functions/structures use std::string or stringview to designate an ID. So it takes time Continues slowly replacing ids. There are technically more and more compilation errors I have good hope that there is a point where the amount of errors will dramatically go down as all the main functions use the ESM::RefId type Continue moving forward, changes to the stores slowly moving along Starting to see the fruit of those changes. still many many error, but more and more Irun into a situation where a function is sandwiched between two functions that use the RefId type. More replacements. Things are starting to get easier I can see more and more often the issue is that the function is awaiting a RefId, but is given a string there is less need to go down functions and to fix a long list of them. Still moving forward, and for the first time error count is going down! Good pace, not sure about topics though, mId and mName are actually the same thing and are used interchangeably Cells are back to using string for the name, haven't fixed everything yet. Many other changes Under the bar of 400 compilation errors. more good progress <100 compile errors! More progress Game settings store can use string for find, it was a bit absurd how every use of it required to create refId from string some more progress on other fronts Mostly game settings clean one error opened a lot of other errors. Down to 18, but more will prbably appear only link errors left?? Fixed link errors OpenMW compiles, and launches, with some issues, but still!
2022-09-25 13:17:09 +02:00
sndMgr->playSound3D(ptr, ESM::RefId::stringRefId("Light Armor Hit"), 1.0f, 1.0f);
break;
case ESM::Skill::MediumArmor:
Initial commit: In ESM structures, replace the string members that are RefIds to other records, to a new strong type The strong type is actually just a string underneath, but this will help in the future to have a distinction so it's easier to search and replace when we use an integer ID Slowly going through all the changes to make, still hundreds of errors a lot of functions/structures use std::string or stringview to designate an ID. So it takes time Continues slowly replacing ids. There are technically more and more compilation errors I have good hope that there is a point where the amount of errors will dramatically go down as all the main functions use the ESM::RefId type Continue moving forward, changes to the stores slowly moving along Starting to see the fruit of those changes. still many many error, but more and more Irun into a situation where a function is sandwiched between two functions that use the RefId type. More replacements. Things are starting to get easier I can see more and more often the issue is that the function is awaiting a RefId, but is given a string there is less need to go down functions and to fix a long list of them. Still moving forward, and for the first time error count is going down! Good pace, not sure about topics though, mId and mName are actually the same thing and are used interchangeably Cells are back to using string for the name, haven't fixed everything yet. Many other changes Under the bar of 400 compilation errors. more good progress <100 compile errors! More progress Game settings store can use string for find, it was a bit absurd how every use of it required to create refId from string some more progress on other fronts Mostly game settings clean one error opened a lot of other errors. Down to 18, but more will prbably appear only link errors left?? Fixed link errors OpenMW compiles, and launches, with some issues, but still!
2022-09-25 13:17:09 +02:00
sndMgr->playSound3D(ptr, ESM::RefId::stringRefId("Medium Armor Hit"), 1.0f, 1.0f);
break;
case ESM::Skill::HeavyArmor:
Initial commit: In ESM structures, replace the string members that are RefIds to other records, to a new strong type The strong type is actually just a string underneath, but this will help in the future to have a distinction so it's easier to search and replace when we use an integer ID Slowly going through all the changes to make, still hundreds of errors a lot of functions/structures use std::string or stringview to designate an ID. So it takes time Continues slowly replacing ids. There are technically more and more compilation errors I have good hope that there is a point where the amount of errors will dramatically go down as all the main functions use the ESM::RefId type Continue moving forward, changes to the stores slowly moving along Starting to see the fruit of those changes. still many many error, but more and more Irun into a situation where a function is sandwiched between two functions that use the RefId type. More replacements. Things are starting to get easier I can see more and more often the issue is that the function is awaiting a RefId, but is given a string there is less need to go down functions and to fix a long list of them. Still moving forward, and for the first time error count is going down! Good pace, not sure about topics though, mId and mName are actually the same thing and are used interchangeably Cells are back to using string for the name, haven't fixed everything yet. Many other changes Under the bar of 400 compilation errors. more good progress <100 compile errors! More progress Game settings store can use string for find, it was a bit absurd how every use of it required to create refId from string some more progress on other fronts Mostly game settings clean one error opened a lot of other errors. Down to 18, but more will prbably appear only link errors left?? Fixed link errors OpenMW compiles, and launches, with some issues, but still!
2022-09-25 13:17:09 +02:00
sndMgr->playSound3D(ptr, ESM::RefId::stringRefId("Heavy Armor Hit"), 1.0f, 1.0f);
break;
}
}
2015-08-21 21:12:39 +12:00
else if (ptr == MWMechanics::getPlayer())
skillUsageSucceeded(ptr, ESM::Skill::Unarmored, 0);
}
2013-07-24 02:51:42 -07:00
}
if (ishealth)
2013-07-28 06:48:25 -07:00
{
2017-03-25 22:40:11 +04:00
if (!attacker.isEmpty() && !godmode)
damage = scaleDamage(damage, attacker, ptr);
if (damage > 0.0f)
{
sndMgr->playSound3D(ptr, ESM::RefId::stringRefId("Health Damage"), 1.0f, 1.0f);
2015-08-21 21:12:39 +12:00
if (ptr == MWMechanics::getPlayer())
MWBase::Environment::get().getWindowManager()->activateHitOverlay();
if (!attacker.isEmpty())
MWBase::Environment::get().getWorld()->spawnBloodEffect(ptr, hitPosition);
}
2015-07-24 20:23:27 +02:00
MWMechanics::DynamicStat<float> health(getCreatureStats(ptr).getHealth());
health.setCurrent(health.getCurrent() - damage);
stats.setHealth(health);
2013-07-28 06:48:25 -07:00
}
else
{
MWMechanics::DynamicStat<float> fatigue(getCreatureStats(ptr).getFatigue());
fatigue.setCurrent(fatigue.getCurrent() - damage, true);
stats.setFatigue(fatigue);
2013-07-28 06:48:25 -07:00
}
if (!wasDead && getCreatureStats(ptr).isDead())
{
// NPC was killed
2014-06-17 16:51:59 +02:00
if (!attacker.isEmpty() && attacker.getClass().isNpc()
&& attacker.getClass().getNpcStats(attacker).isWerewolf())
{
attacker.getClass().getNpcStats(attacker).addWerewolfKill();
}
MWBase::Environment::get().getMechanicsManager()->actorKilled(ptr, attacker);
}
}
std::unique_ptr<MWWorld::Action> Npc::activate(const MWWorld::Ptr& ptr, const MWWorld::Ptr& actor) const
{
// player got activated by another NPC
2015-08-21 21:12:39 +12:00
if (ptr == MWMechanics::getPlayer())
2022-05-29 13:24:48 +02:00
return std::make_unique<MWWorld::ActionTalk>(actor);
// Werewolfs can't activate NPCs
if (actor.getClass().isNpc() && actor.getClass().getNpcStats(actor).isWerewolf())
2013-08-08 22:34:53 -07:00
{
2023-04-20 21:07:53 +02:00
const MWWorld::ESMStore& store = *MWBase::Environment::get().getESMStore();
auto& prng = MWBase::Environment::get().getWorld()->getPrng();
const ESM::Sound* sound = store.get<ESM::Sound>().searchRandom("WolfNPC", prng);
2013-08-11 00:35:19 -07:00
2022-05-29 13:24:48 +02:00
std::unique_ptr<MWWorld::Action> action = std::make_unique<MWWorld::FailedAction>("#{sWerewolfRefusal}");
2013-08-11 00:35:19 -07:00
if (sound)
action->setSound(sound->mId);
2013-08-08 22:34:53 -07:00
return action;
}
const MWMechanics::CreatureStats& stats = getCreatureStats(ptr);
if (stats.isDead())
{
bool canLoot = Settings::Manager::getBool("can loot during death animation", "Game");
// by default user can loot friendly actors during death animation
if (canLoot && !stats.getAiSequence().isInCombat())
2022-05-29 13:24:48 +02:00
return std::make_unique<MWWorld::ActionOpen>(ptr);
// otherwise wait until death animation
if (stats.isDeathAnimationFinished())
2022-05-29 13:24:48 +02:00
return std::make_unique<MWWorld::ActionOpen>(ptr);
}
else if (!stats.getAiSequence().isInCombat())
{
if (stats.getKnockedDown() || MWBase::Environment::get().getMechanicsManager()->isSneaking(actor))
2022-05-29 13:24:48 +02:00
return std::make_unique<MWWorld::ActionOpen>(ptr); // stealing
// Can't talk to werewolves
if (!getNpcStats(ptr).isWerewolf())
2022-05-29 13:24:48 +02:00
return std::make_unique<MWWorld::ActionTalk>(ptr);
}
else // In combat
{
const bool stealingInCombat
= Settings::Manager::getBool("always allow stealing from knocked out actors", "Game");
if (stealingInCombat && stats.getKnockedDown())
2022-05-29 13:24:48 +02:00
return std::make_unique<MWWorld::ActionOpen>(ptr); // stealing
}
2017-08-12 21:18:05 +04:00
// Tribunal and some mod companions oddly enough must use open action as fallback
if (!getScript(ptr).empty() && ptr.getRefData().getLocals().getIntVar(getScript(ptr), "companion"))
2022-05-29 13:24:48 +02:00
return std::make_unique<MWWorld::ActionOpen>(ptr);
2022-05-29 13:24:48 +02:00
return std::make_unique<MWWorld::FailedAction>();
}
MWWorld::ContainerStore& Npc::getContainerStore(const MWWorld::Ptr& ptr) const
2010-08-04 14:37:23 +02:00
{
ensureCustomData(ptr);
auto& store = ptr.getRefData().getCustomData()->asNpcCustomData().mInventoryStore;
store.setActor(ptr);
return store;
}
MWWorld::InventoryStore& Npc::getInventoryStore(const MWWorld::Ptr& ptr) const
{
ensureCustomData(ptr);
auto& store = ptr.getRefData().getCustomData()->asNpcCustomData().mInventoryStore;
store.setActor(ptr);
return store;
2010-08-04 14:37:23 +02:00
}
Initial commit: In ESM structures, replace the string members that are RefIds to other records, to a new strong type The strong type is actually just a string underneath, but this will help in the future to have a distinction so it's easier to search and replace when we use an integer ID Slowly going through all the changes to make, still hundreds of errors a lot of functions/structures use std::string or stringview to designate an ID. So it takes time Continues slowly replacing ids. There are technically more and more compilation errors I have good hope that there is a point where the amount of errors will dramatically go down as all the main functions use the ESM::RefId type Continue moving forward, changes to the stores slowly moving along Starting to see the fruit of those changes. still many many error, but more and more Irun into a situation where a function is sandwiched between two functions that use the RefId type. More replacements. Things are starting to get easier I can see more and more often the issue is that the function is awaiting a RefId, but is given a string there is less need to go down functions and to fix a long list of them. Still moving forward, and for the first time error count is going down! Good pace, not sure about topics though, mId and mName are actually the same thing and are used interchangeably Cells are back to using string for the name, haven't fixed everything yet. Many other changes Under the bar of 400 compilation errors. more good progress <100 compile errors! More progress Game settings store can use string for find, it was a bit absurd how every use of it required to create refId from string some more progress on other fronts Mostly game settings clean one error opened a lot of other errors. Down to 18, but more will prbably appear only link errors left?? Fixed link errors OpenMW compiles, and launches, with some issues, but still!
2022-09-25 13:17:09 +02:00
const ESM::RefId& Npc::getScript(const MWWorld::ConstPtr& ptr) const
{
2015-12-18 00:12:03 +01:00
const MWWorld::LiveCellRef<ESM::NPC>* ref = ptr.get<ESM::NPC>();
2012-11-05 16:07:59 +04:00
return ref->mBase->mScript;
}
float Npc::getMaxSpeed(const MWWorld::Ptr& ptr) const
2011-01-18 10:45:29 +01:00
{
2020-09-01 00:37:37 +02:00
// TODO: This function is called several times per frame for each NPC.
// It would be better to calculate it only once per frame for each NPC and save the result in CreatureStats.
const MWMechanics::NpcStats& stats = getNpcStats(ptr);
bool godmode = ptr == MWMechanics::getPlayer() && MWBase::Environment::get().getWorld()->getGodModeState();
if ((!godmode && stats.isParalyzed()) || stats.getKnockedDown() || stats.isDead())
return 0.f;
2013-02-15 01:27:57 -08:00
const MWBase::World* world = MWBase::Environment::get().getWorld();
const GMST& gmst = getGmst();
const MWMechanics::MagicEffects& mageffects = stats.getMagicEffects();
2013-02-19 02:10:36 -08:00
const float normalizedEncumbrance = getNormalizedEncumbrance(ptr);
2013-02-15 01:27:57 -08:00
2019-02-18 16:21:42 +03:00
bool swimming = world->isSwimming(ptr);
bool sneaking = MWBase::Environment::get().getMechanicsManager()->isSneaking(ptr);
bool running = stats.getStance(MWMechanics::CreatureStats::Stance_Run);
2019-02-18 16:21:42 +03:00
bool inair = !world->isOnGround(ptr) && !swimming && !world->isFlying(ptr);
running = running && (inair || MWBase::Environment::get().getMechanicsManager()->isRunning(ptr));
2013-02-15 01:27:57 -08:00
float moveSpeed;
if (getEncumbrance(ptr) > getCapacity(ptr))
2013-02-15 01:27:57 -08:00
moveSpeed = 0.0f;
else if (mageffects.get(ESM::MagicEffect::Levitate).getMagnitude() > 0 && world->isLevitationEnabled())
2013-02-15 01:27:57 -08:00
{
float flySpeed = 0.01f
* (stats.getAttribute(ESM::Attribute::Speed).getModified()
+ mageffects.get(ESM::MagicEffect::Levitate).getMagnitude());
2018-08-29 18:38:12 +03:00
flySpeed = gmst.fMinFlySpeed->mValue.getFloat()
+ flySpeed * (gmst.fMaxFlySpeed->mValue.getFloat() - gmst.fMinFlySpeed->mValue.getFloat());
flySpeed *= 1.0f - gmst.fEncumberedMoveEffect->mValue.getFloat() * normalizedEncumbrance;
2013-02-15 01:27:57 -08:00
flySpeed = std::max(0.0f, flySpeed);
moveSpeed = flySpeed;
}
2019-02-18 16:21:42 +03:00
else if (swimming)
moveSpeed = getSwimSpeed(ptr);
2019-02-18 16:21:42 +03:00
else if (running && !sneaking)
moveSpeed = getRunSpeed(ptr);
2013-02-15 01:27:57 -08:00
else
moveSpeed = getWalkSpeed(ptr);
2013-02-15 01:27:57 -08:00
if (stats.isWerewolf() && running && stats.getDrawState() == MWMechanics::DrawState::Nothing)
2018-08-29 18:38:12 +03:00
moveSpeed *= gmst.fWereWolfRunMult->mValue.getFloat();
2013-02-15 01:27:57 -08:00
return moveSpeed;
2011-01-18 10:45:29 +01:00
}
float Npc::getJump(const MWWorld::Ptr& ptr) const
{
if (getEncumbrance(ptr) > getCapacity(ptr))
return 0.f;
const MWMechanics::NpcStats& stats = getNpcStats(ptr);
bool godmode = ptr == MWMechanics::getPlayer() && MWBase::Environment::get().getWorld()->getGodModeState();
if ((!godmode && stats.isParalyzed()) || stats.getKnockedDown() || stats.isDead())
return 0.f;
const GMST& gmst = getGmst();
const MWMechanics::MagicEffects& mageffects = stats.getMagicEffects();
2018-08-29 18:38:12 +03:00
const float encumbranceTerm = gmst.fJumpEncumbranceBase->mValue.getFloat()
+ gmst.fJumpEncumbranceMultiplier->mValue.getFloat() * (1.0f - Npc::getNormalizedEncumbrance(ptr));
float a = getSkill(ptr, ESM::Skill::Acrobatics);
float b = 0.0f;
if (a > 50.0f)
{
b = a - 50.0f;
a = 50.0f;
}
2018-08-29 18:38:12 +03:00
float x = gmst.fJumpAcrobaticsBase->mValue.getFloat()
+ std::pow(a / 15.0f, gmst.fJumpAcroMultiplier->mValue.getFloat());
x += 3.0f * b * gmst.fJumpAcroMultiplier->mValue.getFloat();
x += mageffects.get(ESM::MagicEffect::Jump).getMagnitude() * 64;
x *= encumbranceTerm;
if (stats.getStance(MWMechanics::CreatureStats::Stance_Run))
2018-08-29 18:38:12 +03:00
x *= gmst.fJumpRunMultiplier->mValue.getFloat();
x *= stats.getFatigueTerm();
x -= -Constants::GravityConst * Constants::UnitsPerMeter;
2013-08-03 00:07:52 -07:00
x /= 3.0f;
return x;
}
MWMechanics::Movement& Npc::getMovementSettings(const MWWorld::Ptr& ptr) const
{
ensureCustomData(ptr);
return ptr.getRefData().getCustomData()->asNpcCustomData().mMovement;
}
2015-12-18 16:39:35 +01:00
bool Npc::isEssential(const MWWorld::ConstPtr& ptr) const
2012-10-27 13:33:54 +02:00
{
2015-12-18 16:39:35 +01:00
const MWWorld::LiveCellRef<ESM::NPC>* ref = ptr.get<ESM::NPC>();
return (ref->mBase->mFlags & ESM::NPC::Essential) != 0;
2012-10-27 13:33:54 +02:00
}
2015-12-19 16:13:00 +01:00
bool Npc::hasToolTip(const MWWorld::ConstPtr& ptr) const
{
if (!ptr.getRefData().getCustomData() || MWBase::Environment::get().getWindowManager()->isGuiMode())
2015-12-19 16:13:00 +01:00
return true;
const NpcCustomData& customData = ptr.getRefData().getCustomData()->asNpcCustomData();
if (customData.mNpcStats.isDead() && customData.mNpcStats.isDeathAnimationFinished())
return true;
if (!customData.mNpcStats.getAiSequence().isInCombat())
return true;
const bool stealingInCombat
= Settings::Manager::getBool("always allow stealing from knocked out actors", "Game");
if (stealingInCombat && customData.mNpcStats.getKnockedDown())
return true;
return false;
2015-12-19 16:13:00 +01:00
}
2015-12-19 16:29:07 +01:00
MWGui::ToolTipInfo Npc::getToolTipInfo(const MWWorld::ConstPtr& ptr, int count) const
{
const MWWorld::LiveCellRef<ESM::NPC>* ref = ptr.get<ESM::NPC>();
bool fullHelp = MWBase::Environment::get().getWindowManager()->getFullHelp();
MWGui::ToolTipInfo info;
2022-08-16 21:15:03 +02:00
std::string_view name = getName(ptr);
info.caption = MyGUI::TextIterator::toTagsString(MWGui::toUString(name));
if (fullHelp && !ref->mBase->mName.empty() && ptr.getRefData().getCustomData()
&& ptr.getRefData().getCustomData()->asNpcCustomData().mNpcStats.isWerewolf())
{
info.caption += " (";
info.caption += MyGUI::TextIterator::toTagsString(ref->mBase->mName);
info.caption += ")";
}
if (fullHelp)
Initial commit: In ESM structures, replace the string members that are RefIds to other records, to a new strong type The strong type is actually just a string underneath, but this will help in the future to have a distinction so it's easier to search and replace when we use an integer ID Slowly going through all the changes to make, still hundreds of errors a lot of functions/structures use std::string or stringview to designate an ID. So it takes time Continues slowly replacing ids. There are technically more and more compilation errors I have good hope that there is a point where the amount of errors will dramatically go down as all the main functions use the ESM::RefId type Continue moving forward, changes to the stores slowly moving along Starting to see the fruit of those changes. still many many error, but more and more Irun into a situation where a function is sandwiched between two functions that use the RefId type. More replacements. Things are starting to get easier I can see more and more often the issue is that the function is awaiting a RefId, but is given a string there is less need to go down functions and to fix a long list of them. Still moving forward, and for the first time error count is going down! Good pace, not sure about topics though, mId and mName are actually the same thing and are used interchangeably Cells are back to using string for the name, haven't fixed everything yet. Many other changes Under the bar of 400 compilation errors. more good progress <100 compile errors! More progress Game settings store can use string for find, it was a bit absurd how every use of it required to create refId from string some more progress on other fronts Mostly game settings clean one error opened a lot of other errors. Down to 18, but more will prbably appear only link errors left?? Fixed link errors OpenMW compiles, and launches, with some issues, but still!
2022-09-25 13:17:09 +02:00
info.text = MWGui::ToolTips::getMiscString(ref->mBase->mScript.getRefIdString(), "Script");
return info;
}
2012-05-15 21:17:00 +02:00
2012-05-15 22:31:52 +02:00
float Npc::getCapacity(const MWWorld::Ptr& ptr) const
2012-05-15 21:17:00 +02:00
{
const MWMechanics::CreatureStats& stats = getCreatureStats(ptr);
2018-08-29 18:38:12 +03:00
static const float fEncumbranceStrMult = MWBase::Environment::get()
2023-04-20 21:07:53 +02:00
.getESMStore()
->get<ESM::GameSetting>()
2018-08-29 18:38:12 +03:00
.find("fEncumbranceStrMult")
->mValue.getFloat();
return stats.getAttribute(ESM::Attribute::Strength).getModified() * fEncumbranceStrMult;
2012-05-15 21:17:00 +02:00
}
2012-05-15 21:34:00 +02:00
float Npc::getEncumbrance(const MWWorld::Ptr& ptr) const
{
// According to UESP, inventory weight is ignored in werewolf form. Does that include
// feather and burden effects?
return getNpcStats(ptr).isWerewolf() ? 0.0f : Actor::getEncumbrance(ptr);
2012-05-15 21:34:00 +02:00
}
2022-05-12 17:29:12 +02:00
bool Npc::consume(const MWWorld::Ptr& consumable, const MWWorld::Ptr& actor) const
{
2022-05-12 17:29:12 +02:00
MWBase::Environment::get().getWorld()->breakInvisibility(actor);
MWMechanics::CastSpell cast(actor, actor);
Initial commit: In ESM structures, replace the string members that are RefIds to other records, to a new strong type The strong type is actually just a string underneath, but this will help in the future to have a distinction so it's easier to search and replace when we use an integer ID Slowly going through all the changes to make, still hundreds of errors a lot of functions/structures use std::string or stringview to designate an ID. So it takes time Continues slowly replacing ids. There are technically more and more compilation errors I have good hope that there is a point where the amount of errors will dramatically go down as all the main functions use the ESM::RefId type Continue moving forward, changes to the stores slowly moving along Starting to see the fruit of those changes. still many many error, but more and more Irun into a situation where a function is sandwiched between two functions that use the RefId type. More replacements. Things are starting to get easier I can see more and more often the issue is that the function is awaiting a RefId, but is given a string there is less need to go down functions and to fix a long list of them. Still moving forward, and for the first time error count is going down! Good pace, not sure about topics though, mId and mName are actually the same thing and are used interchangeably Cells are back to using string for the name, haven't fixed everything yet. Many other changes Under the bar of 400 compilation errors. more good progress <100 compile errors! More progress Game settings store can use string for find, it was a bit absurd how every use of it required to create refId from string some more progress on other fronts Mostly game settings clean one error opened a lot of other errors. Down to 18, but more will prbably appear only link errors left?? Fixed link errors OpenMW compiles, and launches, with some issues, but still!
2022-09-25 13:17:09 +02:00
const ESM::RefId& recordId = consumable.getCellRef().getRefId();
MWBase::Environment::get().getLuaManager()->itemConsumed(consumable, actor);
actor.getClass().getContainerStore(actor).remove(consumable, 1);
2022-05-12 17:29:12 +02:00
return cast.cast(recordId);
}
void Npc::skillUsageSucceeded(const MWWorld::Ptr& ptr, int skill, int usageType, float extraFactor) const
{
MWMechanics::NpcStats& stats = getNpcStats(ptr);
if (stats.isWerewolf())
return;
MWWorld::LiveCellRef<ESM::NPC>* ref = ptr.get<ESM::NPC>();
2023-04-20 21:07:53 +02:00
const ESM::Class* class_ = MWBase::Environment::get().getESMStore()->get<ESM::Class>().find(ref->mBase->mClass);
stats.useSkill(skill, *class_, usageType, extraFactor);
}
2013-03-17 22:29:12 +01:00
float Npc::getArmorRating(const MWWorld::Ptr& ptr) const
{
const MWWorld::Store<ESM::GameSetting>& store
2023-04-20 21:07:53 +02:00
= MWBase::Environment::get().getESMStore()->get<ESM::GameSetting>();
2013-03-17 22:29:12 +01:00
MWMechanics::NpcStats& stats = getNpcStats(ptr);
const MWWorld::InventoryStore& invStore = getInventoryStore(ptr);
2013-03-17 22:29:12 +01:00
2018-08-29 18:38:12 +03:00
float fUnarmoredBase1 = store.find("fUnarmoredBase1")->mValue.getFloat();
float fUnarmoredBase2 = store.find("fUnarmoredBase2")->mValue.getFloat();
float unarmoredSkill = getSkill(ptr, ESM::Skill::Unarmored);
2013-03-17 22:29:12 +01:00
float ratings[MWWorld::InventoryStore::Slots];
for (int i = 0; i < MWWorld::InventoryStore::Slots; i++)
2013-03-17 22:29:12 +01:00
{
MWWorld::ConstContainerStoreIterator it = invStore.getSlot(i);
if (it == invStore.end() || it->getType() != ESM::Armor::sRecordId)
2013-03-17 22:29:12 +01:00
{
// unarmored
ratings[i] = (fUnarmoredBase1 * unarmoredSkill) * (fUnarmoredBase2 * unarmoredSkill);
2013-03-17 22:29:12 +01:00
}
else
{
ratings[i] = it->getClass().getEffectiveArmorRating(*it, ptr);
// Take in account armor condition
const bool hasHealth = it->getClass().hasItemHealth(*it);
if (hasHealth)
{
ratings[i] *= it->getClass().getItemNormalizedHealth(*it);
}
2013-03-17 22:29:12 +01:00
}
}
float shield = stats.getMagicEffects().get(ESM::MagicEffect::Shield).getMagnitude();
2013-03-17 22:29:12 +01:00
return ratings[MWWorld::InventoryStore::Slot_Cuirass] * 0.3f
2013-03-17 22:29:12 +01:00
+ (ratings[MWWorld::InventoryStore::Slot_CarriedLeft] + ratings[MWWorld::InventoryStore::Slot_Helmet]
+ ratings[MWWorld::InventoryStore::Slot_Greaves] + ratings[MWWorld::InventoryStore::Slot_Boots]
+ ratings[MWWorld::InventoryStore::Slot_LeftPauldron]
+ ratings[MWWorld::InventoryStore::Slot_RightPauldron])
* 0.1f
+ (ratings[MWWorld::InventoryStore::Slot_LeftGauntlet]
+ ratings[MWWorld::InventoryStore::Slot_RightGauntlet])
* 0.05f
2013-03-17 22:29:12 +01:00
+ shield;
}
2015-12-18 16:46:02 +01:00
void Npc::adjustScale(const MWWorld::ConstPtr& ptr, osg::Vec3f& scale, bool rendering) const
2013-03-15 16:44:35 +01:00
{
if (!rendering)
return; // collision meshes are not scaled based on race height
// having the same collision extents for all races makes the environments easier to test
2015-12-18 16:46:02 +01:00
const MWWorld::LiveCellRef<ESM::NPC>* ref = ptr.get<ESM::NPC>();
2013-03-15 16:44:35 +01:00
2023-04-20 21:07:53 +02:00
const ESM::Race* race = MWBase::Environment::get().getESMStore()->get<ESM::Race>().find(ref->mBase->mRace);
2013-03-15 16:44:35 +01:00
// Race weight should not affect 1st-person meshes, otherwise it will change hand proportions and can break
// aiming.
if (ptr == MWMechanics::getPlayer() && ptr.isInCell() && MWBase::Environment::get().getWorld()->isFirstPerson())
{
if (ref->mBase->isMale())
scale *= race->mData.mHeight.mMale;
else
scale *= race->mData.mHeight.mFemale;
return;
}
2013-03-15 16:44:35 +01:00
if (ref->mBase->isMale())
{
scale.x() *= race->mData.mWeight.mMale;
scale.y() *= race->mData.mWeight.mMale;
scale.z() *= race->mData.mHeight.mMale;
}
2013-03-15 16:44:35 +01:00
else
{
scale.x() *= race->mData.mWeight.mFemale;
scale.y() *= race->mData.mWeight.mFemale;
scale.z() *= race->mData.mHeight.mFemale;
}
2013-03-15 16:44:35 +01:00
}
2015-12-18 16:44:35 +01:00
int Npc::getServices(const MWWorld::ConstPtr& actor) const
2013-05-11 18:38:27 +02:00
{
const ESM::NPC* npc = actor.get<ESM::NPC>()->mBase;
if (npc->mFlags & ESM::NPC::Autocalc)
{
2023-04-20 21:07:53 +02:00
const ESM::Class* class_ = MWBase::Environment::get().getESMStore()->get<ESM::Class>().find(npc->mClass);
return class_->mData.mServices;
}
return npc->mAiData.mServices;
2013-05-11 18:38:27 +02:00
}
Initial commit: In ESM structures, replace the string members that are RefIds to other records, to a new strong type The strong type is actually just a string underneath, but this will help in the future to have a distinction so it's easier to search and replace when we use an integer ID Slowly going through all the changes to make, still hundreds of errors a lot of functions/structures use std::string or stringview to designate an ID. So it takes time Continues slowly replacing ids. There are technically more and more compilation errors I have good hope that there is a point where the amount of errors will dramatically go down as all the main functions use the ESM::RefId type Continue moving forward, changes to the stores slowly moving along Starting to see the fruit of those changes. still many many error, but more and more Irun into a situation where a function is sandwiched between two functions that use the RefId type. More replacements. Things are starting to get easier I can see more and more often the issue is that the function is awaiting a RefId, but is given a string there is less need to go down functions and to fix a long list of them. Still moving forward, and for the first time error count is going down! Good pace, not sure about topics though, mId and mName are actually the same thing and are used interchangeably Cells are back to using string for the name, haven't fixed everything yet. Many other changes Under the bar of 400 compilation errors. more good progress <100 compile errors! More progress Game settings store can use string for find, it was a bit absurd how every use of it required to create refId from string some more progress on other fronts Mostly game settings clean one error opened a lot of other errors. Down to 18, but more will prbably appear only link errors left?? Fixed link errors OpenMW compiles, and launches, with some issues, but still!
2022-09-25 13:17:09 +02:00
const ESM::RefId& Npc::getSoundIdFromSndGen(const MWWorld::Ptr& ptr, std::string_view name) const
2013-07-17 23:58:21 -07:00
{
static const ESM::RefId swimLeft = ESM::RefId::stringRefId("Swim Left");
static const ESM::RefId swimRight = ESM::RefId::stringRefId("Swim Right");
static const ESM::RefId footWaterLeft = ESM::RefId::stringRefId("FootWaterLeft");
static const ESM::RefId footWaterRight = ESM::RefId::stringRefId("FootWaterRight");
static const ESM::RefId footBareLeft = ESM::RefId::stringRefId("FootBareLeft");
static const ESM::RefId footBareRight = ESM::RefId::stringRefId("FootBareRight");
static const ESM::RefId footLightLeft = ESM::RefId::stringRefId("footLightLeft");
static const ESM::RefId footLightRight = ESM::RefId::stringRefId("footLightRight");
static const ESM::RefId footMediumRight = ESM::RefId::stringRefId("FootMedRight");
static const ESM::RefId footMediumLeft = ESM::RefId::stringRefId("FootMedLeft");
static const ESM::RefId footHeavyLeft = ESM::RefId::stringRefId("footHeavyLeft");
static const ESM::RefId footHeavyRight = ESM::RefId::stringRefId("footHeavyRight");
if (name == "left" || name == "right")
2013-07-17 23:58:21 -07:00
{
MWBase::World* world = MWBase::Environment::get().getWorld();
if (world->isFlying(ptr))
Initial commit: In ESM structures, replace the string members that are RefIds to other records, to a new strong type The strong type is actually just a string underneath, but this will help in the future to have a distinction so it's easier to search and replace when we use an integer ID Slowly going through all the changes to make, still hundreds of errors a lot of functions/structures use std::string or stringview to designate an ID. So it takes time Continues slowly replacing ids. There are technically more and more compilation errors I have good hope that there is a point where the amount of errors will dramatically go down as all the main functions use the ESM::RefId type Continue moving forward, changes to the stores slowly moving along Starting to see the fruit of those changes. still many many error, but more and more Irun into a situation where a function is sandwiched between two functions that use the RefId type. More replacements. Things are starting to get easier I can see more and more often the issue is that the function is awaiting a RefId, but is given a string there is less need to go down functions and to fix a long list of them. Still moving forward, and for the first time error count is going down! Good pace, not sure about topics though, mId and mName are actually the same thing and are used interchangeably Cells are back to using string for the name, haven't fixed everything yet. Many other changes Under the bar of 400 compilation errors. more good progress <100 compile errors! More progress Game settings store can use string for find, it was a bit absurd how every use of it required to create refId from string some more progress on other fronts Mostly game settings clean one error opened a lot of other errors. Down to 18, but more will prbably appear only link errors left?? Fixed link errors OpenMW compiles, and launches, with some issues, but still!
2022-09-25 13:17:09 +02:00
return ESM::RefId::sEmpty;
2015-06-01 21:41:13 +02:00
osg::Vec3f pos(ptr.getRefData().getPosition().asVec3());
if (world->isSwimming(ptr))
return (name == "left") ? swimLeft : swimRight;
if (world->isUnderwater(ptr.getCell(), pos) || world->isWalkingOnWater(ptr))
return (name == "left") ? footWaterLeft : footWaterRight;
2013-07-17 23:58:21 -07:00
if (world->isOnGround(ptr))
{
if (getNpcStats(ptr).isWerewolf()
&& getCreatureStats(ptr).getStance(MWMechanics::CreatureStats::Stance_Run))
{
int weaponType = ESM::Weapon::None;
MWMechanics::getActiveWeapon(ptr, &weaponType);
if (weaponType == ESM::Weapon::None)
Initial commit: In ESM structures, replace the string members that are RefIds to other records, to a new strong type The strong type is actually just a string underneath, but this will help in the future to have a distinction so it's easier to search and replace when we use an integer ID Slowly going through all the changes to make, still hundreds of errors a lot of functions/structures use std::string or stringview to designate an ID. So it takes time Continues slowly replacing ids. There are technically more and more compilation errors I have good hope that there is a point where the amount of errors will dramatically go down as all the main functions use the ESM::RefId type Continue moving forward, changes to the stores slowly moving along Starting to see the fruit of those changes. still many many error, but more and more Irun into a situation where a function is sandwiched between two functions that use the RefId type. More replacements. Things are starting to get easier I can see more and more often the issue is that the function is awaiting a RefId, but is given a string there is less need to go down functions and to fix a long list of them. Still moving forward, and for the first time error count is going down! Good pace, not sure about topics though, mId and mName are actually the same thing and are used interchangeably Cells are back to using string for the name, haven't fixed everything yet. Many other changes Under the bar of 400 compilation errors. more good progress <100 compile errors! More progress Game settings store can use string for find, it was a bit absurd how every use of it required to create refId from string some more progress on other fronts Mostly game settings clean one error opened a lot of other errors. Down to 18, but more will prbably appear only link errors left?? Fixed link errors OpenMW compiles, and launches, with some issues, but still!
2022-09-25 13:17:09 +02:00
return ESM::RefId::sEmpty;
}
const MWWorld::InventoryStore& inv = Npc::getInventoryStore(ptr);
MWWorld::ConstContainerStoreIterator boots = inv.getSlot(MWWorld::InventoryStore::Slot_Boots);
if (boots == inv.end() || boots->getType() != ESM::Armor::sRecordId)
return (name == "left") ? footBareLeft : footBareRight;
switch (boots->getClass().getEquipmentSkill(*boots))
{
case ESM::Skill::LightArmor:
return (name == "left") ? footLightLeft : footLightRight;
break;
case ESM::Skill::MediumArmor:
return (name == "left") ? footMediumLeft : footMediumRight;
break;
case ESM::Skill::HeavyArmor:
return (name == "left") ? footHeavyLeft : footHeavyRight;
break;
}
}
Initial commit: In ESM structures, replace the string members that are RefIds to other records, to a new strong type The strong type is actually just a string underneath, but this will help in the future to have a distinction so it's easier to search and replace when we use an integer ID Slowly going through all the changes to make, still hundreds of errors a lot of functions/structures use std::string or stringview to designate an ID. So it takes time Continues slowly replacing ids. There are technically more and more compilation errors I have good hope that there is a point where the amount of errors will dramatically go down as all the main functions use the ESM::RefId type Continue moving forward, changes to the stores slowly moving along Starting to see the fruit of those changes. still many many error, but more and more Irun into a situation where a function is sandwiched between two functions that use the RefId type. More replacements. Things are starting to get easier I can see more and more often the issue is that the function is awaiting a RefId, but is given a string there is less need to go down functions and to fix a long list of them. Still moving forward, and for the first time error count is going down! Good pace, not sure about topics though, mId and mName are actually the same thing and are used interchangeably Cells are back to using string for the name, haven't fixed everything yet. Many other changes Under the bar of 400 compilation errors. more good progress <100 compile errors! More progress Game settings store can use string for find, it was a bit absurd how every use of it required to create refId from string some more progress on other fronts Mostly game settings clean one error opened a lot of other errors. Down to 18, but more will prbably appear only link errors left?? Fixed link errors OpenMW compiles, and launches, with some issues, but still!
2022-09-25 13:17:09 +02:00
return ESM::RefId::sEmpty;
2013-07-17 23:58:21 -07:00
}
// Morrowind ignores land soundgen for NPCs
if (name == "land")
Initial commit: In ESM structures, replace the string members that are RefIds to other records, to a new strong type The strong type is actually just a string underneath, but this will help in the future to have a distinction so it's easier to search and replace when we use an integer ID Slowly going through all the changes to make, still hundreds of errors a lot of functions/structures use std::string or stringview to designate an ID. So it takes time Continues slowly replacing ids. There are technically more and more compilation errors I have good hope that there is a point where the amount of errors will dramatically go down as all the main functions use the ESM::RefId type Continue moving forward, changes to the stores slowly moving along Starting to see the fruit of those changes. still many many error, but more and more Irun into a situation where a function is sandwiched between two functions that use the RefId type. More replacements. Things are starting to get easier I can see more and more often the issue is that the function is awaiting a RefId, but is given a string there is less need to go down functions and to fix a long list of them. Still moving forward, and for the first time error count is going down! Good pace, not sure about topics though, mId and mName are actually the same thing and are used interchangeably Cells are back to using string for the name, haven't fixed everything yet. Many other changes Under the bar of 400 compilation errors. more good progress <100 compile errors! More progress Game settings store can use string for find, it was a bit absurd how every use of it required to create refId from string some more progress on other fronts Mostly game settings clean one error opened a lot of other errors. Down to 18, but more will prbably appear only link errors left?? Fixed link errors OpenMW compiles, and launches, with some issues, but still!
2022-09-25 13:17:09 +02:00
return ESM::RefId::sEmpty;
if (name == "swimleft")
return swimLeft;
if (name == "swimright")
return swimRight;
2013-07-17 23:58:21 -07:00
// TODO: I have no idea what these are supposed to do for NPCs since they use
// voiced dialog for various conditions like health loss and combat taunts. Maybe
// only for biped creatures?
2013-07-17 23:58:21 -07:00
if (name == "moan")
Initial commit: In ESM structures, replace the string members that are RefIds to other records, to a new strong type The strong type is actually just a string underneath, but this will help in the future to have a distinction so it's easier to search and replace when we use an integer ID Slowly going through all the changes to make, still hundreds of errors a lot of functions/structures use std::string or stringview to designate an ID. So it takes time Continues slowly replacing ids. There are technically more and more compilation errors I have good hope that there is a point where the amount of errors will dramatically go down as all the main functions use the ESM::RefId type Continue moving forward, changes to the stores slowly moving along Starting to see the fruit of those changes. still many many error, but more and more Irun into a situation where a function is sandwiched between two functions that use the RefId type. More replacements. Things are starting to get easier I can see more and more often the issue is that the function is awaiting a RefId, but is given a string there is less need to go down functions and to fix a long list of them. Still moving forward, and for the first time error count is going down! Good pace, not sure about topics though, mId and mName are actually the same thing and are used interchangeably Cells are back to using string for the name, haven't fixed everything yet. Many other changes Under the bar of 400 compilation errors. more good progress <100 compile errors! More progress Game settings store can use string for find, it was a bit absurd how every use of it required to create refId from string some more progress on other fronts Mostly game settings clean one error opened a lot of other errors. Down to 18, but more will prbably appear only link errors left?? Fixed link errors OpenMW compiles, and launches, with some issues, but still!
2022-09-25 13:17:09 +02:00
return ESM::RefId::sEmpty;
2013-07-17 23:58:21 -07:00
if (name == "roar")
Initial commit: In ESM structures, replace the string members that are RefIds to other records, to a new strong type The strong type is actually just a string underneath, but this will help in the future to have a distinction so it's easier to search and replace when we use an integer ID Slowly going through all the changes to make, still hundreds of errors a lot of functions/structures use std::string or stringview to designate an ID. So it takes time Continues slowly replacing ids. There are technically more and more compilation errors I have good hope that there is a point where the amount of errors will dramatically go down as all the main functions use the ESM::RefId type Continue moving forward, changes to the stores slowly moving along Starting to see the fruit of those changes. still many many error, but more and more Irun into a situation where a function is sandwiched between two functions that use the RefId type. More replacements. Things are starting to get easier I can see more and more often the issue is that the function is awaiting a RefId, but is given a string there is less need to go down functions and to fix a long list of them. Still moving forward, and for the first time error count is going down! Good pace, not sure about topics though, mId and mName are actually the same thing and are used interchangeably Cells are back to using string for the name, haven't fixed everything yet. Many other changes Under the bar of 400 compilation errors. more good progress <100 compile errors! More progress Game settings store can use string for find, it was a bit absurd how every use of it required to create refId from string some more progress on other fronts Mostly game settings clean one error opened a lot of other errors. Down to 18, but more will prbably appear only link errors left?? Fixed link errors OpenMW compiles, and launches, with some issues, but still!
2022-09-25 13:17:09 +02:00
return ESM::RefId::sEmpty;
2013-07-17 23:58:21 -07:00
if (name == "scream")
Initial commit: In ESM structures, replace the string members that are RefIds to other records, to a new strong type The strong type is actually just a string underneath, but this will help in the future to have a distinction so it's easier to search and replace when we use an integer ID Slowly going through all the changes to make, still hundreds of errors a lot of functions/structures use std::string or stringview to designate an ID. So it takes time Continues slowly replacing ids. There are technically more and more compilation errors I have good hope that there is a point where the amount of errors will dramatically go down as all the main functions use the ESM::RefId type Continue moving forward, changes to the stores slowly moving along Starting to see the fruit of those changes. still many many error, but more and more Irun into a situation where a function is sandwiched between two functions that use the RefId type. More replacements. Things are starting to get easier I can see more and more often the issue is that the function is awaiting a RefId, but is given a string there is less need to go down functions and to fix a long list of them. Still moving forward, and for the first time error count is going down! Good pace, not sure about topics though, mId and mName are actually the same thing and are used interchangeably Cells are back to using string for the name, haven't fixed everything yet. Many other changes Under the bar of 400 compilation errors. more good progress <100 compile errors! More progress Game settings store can use string for find, it was a bit absurd how every use of it required to create refId from string some more progress on other fronts Mostly game settings clean one error opened a lot of other errors. Down to 18, but more will prbably appear only link errors left?? Fixed link errors OpenMW compiles, and launches, with some issues, but still!
2022-09-25 13:17:09 +02:00
return ESM::RefId::sEmpty;
2013-07-17 23:58:21 -07:00
throw std::runtime_error("Unexpected soundgen type: " + std::string(name));
2013-07-17 23:58:21 -07:00
}
2015-12-18 16:24:24 +01:00
MWWorld::Ptr Npc::copyToCellImpl(const MWWorld::ConstPtr& ptr, MWWorld::CellStore& cell) const
{
2015-12-18 16:24:24 +01:00
const MWWorld::LiveCellRef<ESM::NPC>* ref = ptr.get<ESM::NPC>();
return MWWorld::Ptr(cell.insert(ref), &cell);
}
2013-02-15 01:27:57 -08:00
float Npc::getSkill(const MWWorld::Ptr& ptr, int skill) const
{
return getNpcStats(ptr).getSkill(skill).getModified();
}
2015-12-18 16:38:14 +01:00
int Npc::getBloodTexture(const MWWorld::ConstPtr& ptr) const
2014-01-17 10:52:44 +01:00
{
return ptr.get<ESM::NPC>()->mBase->mBloodType;
2014-01-17 10:52:44 +01:00
}
void Npc::readAdditionalState(const MWWorld::Ptr& ptr, const ESM::ObjectState& state) const
{
if (!state.mHasCustomState)
return;
const ESM::NpcState& npcState = state.asNpcState();
2015-06-30 03:58:23 +02:00
if (state.mVersion > 0)
{
2015-06-30 03:58:23 +02:00
if (!ptr.getRefData().getCustomData())
{
if (npcState.mCreatureStats.mMissingACDT)
ensureCustomData(ptr);
else
// Create a CustomData, but don't fill it from ESM records (not needed)
ptr.getRefData().setCustomData(std::make_unique<NpcCustomData>());
2015-06-30 03:58:23 +02:00
}
}
2015-06-30 03:58:23 +02:00
else
ensureCustomData(
ptr); // in openmw 0.30 savegames not all state was saved yet, so need to load it regardless.
NpcCustomData& customData = ptr.getRefData().getCustomData()->asNpcCustomData();
customData.mInventoryStore.readState(npcState.mInventory);
customData.mNpcStats.readState(npcState.mNpcStats);
bool spellsInitialised = customData.mNpcStats.getSpells().setSpells(ptr.get<ESM::NPC>()->mBase->mId);
if (spellsInitialised)
customData.mNpcStats.getSpells().clear();
customData.mNpcStats.readState(npcState.mCreatureStats);
}
void Npc::writeAdditionalState(const MWWorld::ConstPtr& ptr, ESM::ObjectState& state) const
{
if (!ptr.getRefData().getCustomData())
{
state.mHasCustomState = false;
return;
}
const NpcCustomData& customData = ptr.getRefData().getCustomData()->asNpcCustomData();
if (ptr.getRefData().getCount() <= 0
&& (!(ptr.get<ESM::NPC>()->mBase->mFlags & ESM::NPC::Respawn) || !customData.mNpcStats.isDead()))
{
state.mHasCustomState = false;
return;
}
ESM::NpcState& npcState = state.asNpcState();
customData.mInventoryStore.writeState(npcState.mInventory);
customData.mNpcStats.writeState(npcState.mNpcStats);
customData.mNpcStats.writeState(npcState.mCreatureStats);
}
2015-12-18 16:28:20 +01:00
int Npc::getBaseGold(const MWWorld::ConstPtr& ptr) const
{
2015-12-18 16:28:20 +01:00
const MWWorld::LiveCellRef<ESM::NPC>* ref = ptr.get<ESM::NPC>();
return ref->mBase->mNpdt.mGold;
}
bool Npc::isClass(const MWWorld::ConstPtr& ptr, std::string_view className) const
2014-04-01 14:15:55 -04:00
{
return ptr.get<ESM::NPC>()->mBase->mClass == className;
2014-04-01 14:15:55 -04:00
}
2015-12-18 16:15:40 +01:00
bool Npc::canSwim(const MWWorld::ConstPtr& ptr) const
{
return true;
}
bool Npc::canWalk(const MWWorld::ConstPtr& ptr) const
{
return true;
}
void Npc::respawn(const MWWorld::Ptr& ptr) const
{
const MWMechanics::CreatureStats& creatureStats = getCreatureStats(ptr);
if (ptr.getRefData().getCount() > 0 && !creatureStats.isDead())
return;
if (!creatureStats.isDeathAnimationFinished())
return;
const MWWorld::Store<ESM::GameSetting>& gmst
2023-04-20 21:07:53 +02:00
= MWBase::Environment::get().getESMStore()->get<ESM::GameSetting>();
2018-08-29 18:38:12 +03:00
static const float fCorpseRespawnDelay = gmst.find("fCorpseRespawnDelay")->mValue.getFloat();
static const float fCorpseClearDelay = gmst.find("fCorpseClearDelay")->mValue.getFloat();
float delay
= ptr.getRefData().getCount() == 0 ? fCorpseClearDelay : std::min(fCorpseRespawnDelay, fCorpseClearDelay);
if (ptr.get<ESM::NPC>()->mBase->mFlags & ESM::NPC::Respawn
&& creatureStats.getTimeOfDeath() + delay <= MWBase::Environment::get().getWorld()->getTimeStamp())
{
if (ptr.getCellRef().hasContentFile())
{
if (ptr.getRefData().getCount() == 0)
2019-08-06 21:30:21 +02:00
{
ptr.getRefData().setCount(1);
Initial commit: In ESM structures, replace the string members that are RefIds to other records, to a new strong type The strong type is actually just a string underneath, but this will help in the future to have a distinction so it's easier to search and replace when we use an integer ID Slowly going through all the changes to make, still hundreds of errors a lot of functions/structures use std::string or stringview to designate an ID. So it takes time Continues slowly replacing ids. There are technically more and more compilation errors I have good hope that there is a point where the amount of errors will dramatically go down as all the main functions use the ESM::RefId type Continue moving forward, changes to the stores slowly moving along Starting to see the fruit of those changes. still many many error, but more and more Irun into a situation where a function is sandwiched between two functions that use the RefId type. More replacements. Things are starting to get easier I can see more and more often the issue is that the function is awaiting a RefId, but is given a string there is less need to go down functions and to fix a long list of them. Still moving forward, and for the first time error count is going down! Good pace, not sure about topics though, mId and mName are actually the same thing and are used interchangeably Cells are back to using string for the name, haven't fixed everything yet. Many other changes Under the bar of 400 compilation errors. more good progress <100 compile errors! More progress Game settings store can use string for find, it was a bit absurd how every use of it required to create refId from string some more progress on other fronts Mostly game settings clean one error opened a lot of other errors. Down to 18, but more will prbably appear only link errors left?? Fixed link errors OpenMW compiles, and launches, with some issues, but still!
2022-09-25 13:17:09 +02:00
const ESM::RefId& script = getScript(ptr);
2019-08-06 21:30:21 +02:00
if (!script.empty())
MWBase::Environment::get().getWorld()->getLocalScripts().add(script, ptr);
}
MWBase::Environment::get().getWorld()->removeContainerScripts(ptr);
MWBase::Environment::get().getWindowManager()->onDeleteCustomData(ptr);
2018-10-09 10:21:12 +04:00
ptr.getRefData().setCustomData(nullptr);
// Reset to original position
MWBase::Environment::get().getWorld()->moveObject(ptr, ptr.getCellRef().getPosition().asVec3());
2021-09-14 16:53:57 +02:00
MWBase::Environment::get().getWorld()->rotateObject(
ptr, ptr.getCellRef().getPosition().asRotationVec3(), MWBase::RotationFlag_none);
}
}
}
int Npc::getBaseFightRating(const MWWorld::ConstPtr& ptr) const
{
const MWWorld::LiveCellRef<ESM::NPC>* ref = ptr.get<ESM::NPC>();
return ref->mBase->mAiData.mFight;
}
2015-12-18 16:15:40 +01:00
bool Npc::isBipedal(const MWWorld::ConstPtr& ptr) const
{
return true;
}
2015-01-27 17:32:21 +01:00
Initial commit: In ESM structures, replace the string members that are RefIds to other records, to a new strong type The strong type is actually just a string underneath, but this will help in the future to have a distinction so it's easier to search and replace when we use an integer ID Slowly going through all the changes to make, still hundreds of errors a lot of functions/structures use std::string or stringview to designate an ID. So it takes time Continues slowly replacing ids. There are technically more and more compilation errors I have good hope that there is a point where the amount of errors will dramatically go down as all the main functions use the ESM::RefId type Continue moving forward, changes to the stores slowly moving along Starting to see the fruit of those changes. still many many error, but more and more Irun into a situation where a function is sandwiched between two functions that use the RefId type. More replacements. Things are starting to get easier I can see more and more often the issue is that the function is awaiting a RefId, but is given a string there is less need to go down functions and to fix a long list of them. Still moving forward, and for the first time error count is going down! Good pace, not sure about topics though, mId and mName are actually the same thing and are used interchangeably Cells are back to using string for the name, haven't fixed everything yet. Many other changes Under the bar of 400 compilation errors. more good progress <100 compile errors! More progress Game settings store can use string for find, it was a bit absurd how every use of it required to create refId from string some more progress on other fronts Mostly game settings clean one error opened a lot of other errors. Down to 18, but more will prbably appear only link errors left?? Fixed link errors OpenMW compiles, and launches, with some issues, but still!
2022-09-25 13:17:09 +02:00
const ESM::RefId& Npc::getPrimaryFaction(const MWWorld::ConstPtr& ptr) const
2015-01-27 17:32:21 +01:00
{
const MWWorld::LiveCellRef<ESM::NPC>* ref = ptr.get<ESM::NPC>();
2015-01-27 17:32:21 +01:00
return ref->mBase->mFaction;
}
int Npc::getPrimaryFactionRank(const MWWorld::ConstPtr& ptr) const
2015-01-27 17:32:21 +01:00
{
Initial commit: In ESM structures, replace the string members that are RefIds to other records, to a new strong type The strong type is actually just a string underneath, but this will help in the future to have a distinction so it's easier to search and replace when we use an integer ID Slowly going through all the changes to make, still hundreds of errors a lot of functions/structures use std::string or stringview to designate an ID. So it takes time Continues slowly replacing ids. There are technically more and more compilation errors I have good hope that there is a point where the amount of errors will dramatically go down as all the main functions use the ESM::RefId type Continue moving forward, changes to the stores slowly moving along Starting to see the fruit of those changes. still many many error, but more and more Irun into a situation where a function is sandwiched between two functions that use the RefId type. More replacements. Things are starting to get easier I can see more and more often the issue is that the function is awaiting a RefId, but is given a string there is less need to go down functions and to fix a long list of them. Still moving forward, and for the first time error count is going down! Good pace, not sure about topics though, mId and mName are actually the same thing and are used interchangeably Cells are back to using string for the name, haven't fixed everything yet. Many other changes Under the bar of 400 compilation errors. more good progress <100 compile errors! More progress Game settings store can use string for find, it was a bit absurd how every use of it required to create refId from string some more progress on other fronts Mostly game settings clean one error opened a lot of other errors. Down to 18, but more will prbably appear only link errors left?? Fixed link errors OpenMW compiles, and launches, with some issues, but still!
2022-09-25 13:17:09 +02:00
const ESM::RefId& factionID = ptr.getClass().getPrimaryFaction(ptr);
if (factionID.empty())
return -1;
// Search in the NPC data first
if (const MWWorld::CustomData* data = ptr.getRefData().getCustomData())
{
int rank = data->asNpcCustomData().mNpcStats.getFactionRank(factionID);
if (rank >= 0)
return rank;
}
// Use base NPC record as a fallback
const MWWorld::LiveCellRef<ESM::NPC>* ref = ptr.get<ESM::NPC>();
2015-01-27 17:32:21 +01:00
return ref->mBase->getFactionRank();
}
Initial commit: In ESM structures, replace the string members that are RefIds to other records, to a new strong type The strong type is actually just a string underneath, but this will help in the future to have a distinction so it's easier to search and replace when we use an integer ID Slowly going through all the changes to make, still hundreds of errors a lot of functions/structures use std::string or stringview to designate an ID. So it takes time Continues slowly replacing ids. There are technically more and more compilation errors I have good hope that there is a point where the amount of errors will dramatically go down as all the main functions use the ESM::RefId type Continue moving forward, changes to the stores slowly moving along Starting to see the fruit of those changes. still many many error, but more and more Irun into a situation where a function is sandwiched between two functions that use the RefId type. More replacements. Things are starting to get easier I can see more and more often the issue is that the function is awaiting a RefId, but is given a string there is less need to go down functions and to fix a long list of them. Still moving forward, and for the first time error count is going down! Good pace, not sure about topics though, mId and mName are actually the same thing and are used interchangeably Cells are back to using string for the name, haven't fixed everything yet. Many other changes Under the bar of 400 compilation errors. more good progress <100 compile errors! More progress Game settings store can use string for find, it was a bit absurd how every use of it required to create refId from string some more progress on other fronts Mostly game settings clean one error opened a lot of other errors. Down to 18, but more will prbably appear only link errors left?? Fixed link errors OpenMW compiles, and launches, with some issues, but still!
2022-09-25 13:17:09 +02:00
void Npc::setBaseAISetting(const ESM::RefId& id, MWMechanics::AiSetting setting, int value) const
{
MWMechanics::setBaseAISetting<ESM::NPC>(id, setting, value);
}
Initial commit: In ESM structures, replace the string members that are RefIds to other records, to a new strong type The strong type is actually just a string underneath, but this will help in the future to have a distinction so it's easier to search and replace when we use an integer ID Slowly going through all the changes to make, still hundreds of errors a lot of functions/structures use std::string or stringview to designate an ID. So it takes time Continues slowly replacing ids. There are technically more and more compilation errors I have good hope that there is a point where the amount of errors will dramatically go down as all the main functions use the ESM::RefId type Continue moving forward, changes to the stores slowly moving along Starting to see the fruit of those changes. still many many error, but more and more Irun into a situation where a function is sandwiched between two functions that use the RefId type. More replacements. Things are starting to get easier I can see more and more often the issue is that the function is awaiting a RefId, but is given a string there is less need to go down functions and to fix a long list of them. Still moving forward, and for the first time error count is going down! Good pace, not sure about topics though, mId and mName are actually the same thing and are used interchangeably Cells are back to using string for the name, haven't fixed everything yet. Many other changes Under the bar of 400 compilation errors. more good progress <100 compile errors! More progress Game settings store can use string for find, it was a bit absurd how every use of it required to create refId from string some more progress on other fronts Mostly game settings clean one error opened a lot of other errors. Down to 18, but more will prbably appear only link errors left?? Fixed link errors OpenMW compiles, and launches, with some issues, but still!
2022-09-25 13:17:09 +02:00
void Npc::modifyBaseInventory(const ESM::RefId& actorId, const ESM::RefId& itemId, int amount) const
{
MWMechanics::modifyBaseInventory<ESM::NPC>(actorId, itemId, amount);
}
float Npc::getWalkSpeed(const MWWorld::Ptr& ptr) const
{
const GMST& gmst = getGmst();
const MWMechanics::NpcStats& stats = getNpcStats(ptr);
const float normalizedEncumbrance = getNormalizedEncumbrance(ptr);
const bool sneaking = MWBase::Environment::get().getMechanicsManager()->isSneaking(ptr);
float walkSpeed = gmst.fMinWalkSpeed->mValue.getFloat()
+ 0.01f * stats.getAttribute(ESM::Attribute::Speed).getModified()
* (gmst.fMaxWalkSpeed->mValue.getFloat() - gmst.fMinWalkSpeed->mValue.getFloat());
walkSpeed *= 1.0f - gmst.fEncumberedMoveEffect->mValue.getFloat() * normalizedEncumbrance;
walkSpeed = std::max(0.0f, walkSpeed);
if (sneaking)
walkSpeed *= gmst.fSneakSpeedMultiplier->mValue.getFloat();
return walkSpeed;
}
float Npc::getRunSpeed(const MWWorld::Ptr& ptr) const
{
const GMST& gmst = getGmst();
return getWalkSpeed(ptr)
* (0.01f * getSkill(ptr, ESM::Skill::Athletics) * gmst.fAthleticsRunBonus->mValue.getFloat()
+ gmst.fBaseRunMultiplier->mValue.getFloat());
}
float Npc::getSwimSpeed(const MWWorld::Ptr& ptr) const
{
const MWBase::World* world = MWBase::Environment::get().getWorld();
const MWMechanics::NpcStats& stats = getNpcStats(ptr);
const MWMechanics::MagicEffects& mageffects = stats.getMagicEffects();
const bool swimming = world->isSwimming(ptr);
const bool inair = !world->isOnGround(ptr) && !swimming && !world->isFlying(ptr);
const bool running = stats.getStance(MWMechanics::CreatureStats::Stance_Run)
&& (inair || MWBase::Environment::get().getMechanicsManager()->isRunning(ptr));
return getSwimSpeedImpl(ptr, getGmst(), mageffects, running ? getRunSpeed(ptr) : getWalkSpeed(ptr));
}
2010-08-03 13:03:08 +02:00
}