2019-08-06 21:30:21 +02:00
|
|
|
|
#include "npc.hpp"
|
2010-08-03 13:03:08 +02:00
|
|
|
|
|
2022-06-04 15:26:36 +02:00
|
|
|
|
#include <MyGUI_TextIterator.h>
|
|
|
|
|
|
2012-01-25 16:56:49 +01:00
|
|
|
|
#include <memory>
|
|
|
|
|
|
2018-09-17 14:52:43 +04:00
|
|
|
|
#include <components/misc/constants.hpp>
|
2022-06-29 00:32:11 +02:00
|
|
|
|
#include <components/misc/resourcehelpers.hpp>
|
2015-04-22 17:58:55 +02:00
|
|
|
|
#include <components/misc/rng.hpp>
|
2015-03-15 14:07:47 +13:00
|
|
|
|
|
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>
|
2022-06-26 16:42:29 +02:00
|
|
|
|
#include <components/esm3/loadclas.hpp>
|
2022-01-22 15:58:41 +01:00
|
|
|
|
#include <components/esm3/loadmgef.hpp>
|
|
|
|
|
#include <components/esm3/loadnpc.hpp>
|
2022-06-26 16:42:29 +02:00
|
|
|
|
#include <components/esm3/loadrace.hpp>
|
2022-09-05 19:35:15 +02:00
|
|
|
|
#include <components/esm3/loadsoun.hpp>
|
2022-09-08 21:08:59 +02:00
|
|
|
|
#include <components/esm3/npcstate.hpp>
|
2017-07-26 14:42:01 +04:00
|
|
|
|
#include <components/settings/settings.hpp>
|
2010-08-03 13:03:08 +02:00
|
|
|
|
|
2013-07-24 10:02:50 -07:00
|
|
|
|
#include "../mwbase/dialoguemanager.hpp"
|
2012-07-03 12:30:50 +02:00
|
|
|
|
#include "../mwbase/environment.hpp"
|
|
|
|
|
#include "../mwbase/luamanager.hpp"
|
2012-08-11 17:30:55 +02:00
|
|
|
|
#include "../mwbase/mechanicsmanager.hpp"
|
2013-07-25 08:15:42 -07:00
|
|
|
|
#include "../mwbase/soundmanager.hpp"
|
2021-04-21 04:11:11 +02:00
|
|
|
|
#include "../mwbase/windowmanager.hpp"
|
|
|
|
|
#include "../mwbase/world.hpp"
|
2012-07-03 12:30:50 +02:00
|
|
|
|
|
2015-08-21 21:12:39 +12:00
|
|
|
|
#include "../mwmechanics/actorutil.hpp"
|
2022-06-26 16:42:29 +02:00
|
|
|
|
#include "../mwmechanics/aisetting.hpp"
|
2014-07-11 07:31:18 +02:00
|
|
|
|
#include "../mwmechanics/autocalcspell.hpp"
|
2014-01-21 01:01:21 +01:00
|
|
|
|
#include "../mwmechanics/combat.hpp"
|
2022-06-26 16:42:29 +02:00
|
|
|
|
#include "../mwmechanics/creaturecustomdataresetter.hpp"
|
2010-08-03 13:32:37 +02:00
|
|
|
|
#include "../mwmechanics/creaturestats.hpp"
|
2014-07-20 16:22:52 +02:00
|
|
|
|
#include "../mwmechanics/difficultyscaling.hpp"
|
2014-01-03 23:33:14 +01:00
|
|
|
|
#include "../mwmechanics/disease.hpp"
|
2022-06-26 16:42:29 +02:00
|
|
|
|
#include "../mwmechanics/inventory.hpp"
|
|
|
|
|
#include "../mwmechanics/movement.hpp"
|
|
|
|
|
#include "../mwmechanics/npcstats.hpp"
|
2022-07-16 16:37:31 +02:00
|
|
|
|
#include "../mwmechanics/setbaseaisetting.hpp"
|
2013-11-17 23:15:57 +01:00
|
|
|
|
#include "../mwmechanics/spellcasting.hpp"
|
2018-12-26 13:45:28 +04:00
|
|
|
|
#include "../mwmechanics/weapontype.hpp"
|
2010-08-03 13:32:37 +02:00
|
|
|
|
|
2012-10-28 16:04:33 +01:00
|
|
|
|
#include "../mwworld/actionopen.hpp"
|
2010-08-06 18:15:46 +02:00
|
|
|
|
#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"
|
2022-06-26 16:42:29 +02:00
|
|
|
|
#include "../mwworld/esmstore.hpp"
|
2013-08-08 22:34:53 -07:00
|
|
|
|
#include "../mwworld/failedaction.hpp"
|
2012-03-10 12:49:54 +01:00
|
|
|
|
#include "../mwworld/inventorystore.hpp"
|
2019-08-06 21:30:21 +02:00
|
|
|
|
#include "../mwworld/localscripts.hpp"
|
2022-06-26 16:42:29 +02:00
|
|
|
|
#include "../mwworld/ptr.hpp"
|
2010-08-03 13:03:08 +02:00
|
|
|
|
|
2016-02-09 00:26:22 +01:00
|
|
|
|
#include "../mwrender/npcanimation.hpp"
|
2015-04-12 15:34:50 +02:00
|
|
|
|
#include "../mwrender/objects.hpp"
|
2012-07-03 13:15:20 +02:00
|
|
|
|
#include "../mwrender/renderinginterface.hpp"
|
2012-04-16 22:58:16 +02:00
|
|
|
|
|
2012-07-03 13:15:20 +02:00
|
|
|
|
#include "../mwgui/tooltips.hpp"
|
2022-08-24 22:16:03 +02:00
|
|
|
|
#include "../mwgui/ustring.hpp"
|
2012-04-23 15:27:03 +02:00
|
|
|
|
|
2011-01-18 10:45:29 +01:00
|
|
|
|
namespace
|
2011-01-10 16:13:32 -07:00
|
|
|
|
{
|
2013-04-18 23:51:43 +02:00
|
|
|
|
|
2014-07-12 14:05:57 +02:00
|
|
|
|
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)
|
2015-03-08 13:07:29 +13:00
|
|
|
|
return static_cast<int>(i);
|
2014-07-12 14:05:57 +02:00
|
|
|
|
if (d > 0.5)
|
2015-03-08 13:07:29 +13:00
|
|
|
|
return static_cast<int>(i) + 1;
|
2014-07-12 14:05:57 +02:00
|
|
|
|
if (is_even(i))
|
2015-03-08 13:07:29 +13:00
|
|
|
|
return static_cast<int>(i);
|
|
|
|
|
return static_cast<int>(i) + 1;
|
2014-07-12 14:05:57 +02:00
|
|
|
|
}
|
|
|
|
|
|
2013-04-18 23:51:43 +02:00
|
|
|
|
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);
|
2013-04-18 23:51:43 +02:00
|
|
|
|
|
|
|
|
|
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];
|
2013-12-28 17:19:35 +01:00
|
|
|
|
creatureStats.setAttribute(i, male ? attribute.mMale : attribute.mFemale);
|
2013-04-18 23:51:43 +02:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// class bonus
|
2023-04-20 21:07:53 +02:00
|
|
|
|
const ESM::Class* class_ = MWBase::Environment::get().getESMStore()->get<ESM::Class>().find(npc->mClass);
|
2013-04-18 23:51:43 +02:00
|
|
|
|
|
|
|
|
|
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
|
2013-12-08 21:47:43 +01:00
|
|
|
|
for (int attribute = 0; attribute < ESM::Attribute::Length; ++attribute)
|
2013-04-18 23:51:43 +02:00
|
|
|
|
{
|
|
|
|
|
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);
|
2013-04-18 23:51:43 +02:00
|
|
|
|
|
|
|
|
|
if (skill->mData.mAttribute != attribute)
|
|
|
|
|
continue;
|
|
|
|
|
|
|
|
|
|
// is this a minor or major skill?
|
2015-03-08 13:07:29 +13:00
|
|
|
|
float add = 0.2f;
|
2013-04-18 23:51:43 +02:00
|
|
|
|
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;
|
|
|
|
|
}
|
2014-07-12 14:05:57 +02:00
|
|
|
|
creatureStats.setAttribute(attribute,
|
|
|
|
|
std::min(
|
|
|
|
|
round_ieee_754(creatureStats.getAttribute(attribute).getBase() + (level - 1) * modifierSum), 100));
|
2013-04-18 23:51:43 +02:00
|
|
|
|
}
|
2013-07-20 14:52:17 +02:00
|
|
|
|
|
2013-07-21 10:09:08 +02:00
|
|
|
|
// initial health
|
2018-12-23 15:18:33 +04:00
|
|
|
|
float strength = creatureStats.getAttribute(ESM::Attribute::Strength).getBase();
|
|
|
|
|
float endurance = creatureStats.getAttribute(ESM::Attribute::Endurance).getBase();
|
2013-07-23 16:48:54 +02:00
|
|
|
|
|
|
|
|
|
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;
|
|
|
|
|
|
2015-03-08 13:07:29 +13:00
|
|
|
|
creatureStats.setHealth(floor(0.5f * (strength + endurance)) + multiplier * (creatureStats.getLevel() - 1));
|
2013-04-18 23:51:43 +02:00
|
|
|
|
}
|
2013-12-08 21:47:43 +01:00
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* @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.
|
|
|
|
|
*/
|
2020-07-28 08:33:28 +02:00
|
|
|
|
void autoCalculateSkills(
|
|
|
|
|
const ESM::NPC* npc, MWMechanics::NpcStats& npcStats, const MWWorld::Ptr& ptr, bool spellsInitialised)
|
2013-12-08 21:47:43 +01:00
|
|
|
|
{
|
2023-04-20 21:07:53 +02:00
|
|
|
|
const ESM::Class* class_ = MWBase::Environment::get().getESMStore()->get<ESM::Class>().find(npc->mClass);
|
2013-12-08 21:47:43 +01:00
|
|
|
|
|
|
|
|
|
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);
|
2013-12-08 21:47:43 +01:00
|
|
|
|
|
|
|
|
|
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)
|
|
|
|
|
{
|
2014-01-03 03:46:30 +01:00
|
|
|
|
if (race->mData.mBonus[raceSkillIndex].mSkill == skillIndex)
|
|
|
|
|
{
|
|
|
|
|
raceBonus = race->mData.mBonus[raceSkillIndex].mBonus;
|
|
|
|
|
break;
|
|
|
|
|
}
|
2013-12-08 21:47:43 +01:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
for (int k = 0; k < 5; ++k)
|
|
|
|
|
{
|
2014-01-03 03:46:30 +01:00
|
|
|
|
// is this a minor or major skill?
|
|
|
|
|
if ((class_->mData.mSkills[k][0] == skillIndex) || (class_->mData.mSkills[k][1] == skillIndex))
|
|
|
|
|
{
|
|
|
|
|
majorMultiplier = 1.0f;
|
|
|
|
|
break;
|
|
|
|
|
}
|
2013-12-08 21:47:43 +01:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 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);
|
2013-12-08 21:47:43 +01:00
|
|
|
|
if (skill->mData.mSpecialization == class_->mData.mSpecialization)
|
|
|
|
|
{
|
2014-01-03 03:46:30 +01:00
|
|
|
|
specMultiplier = 0.5f;
|
|
|
|
|
specBonus = 5;
|
2013-12-08 21:47:43 +01:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
npcStats.getSkill(skillIndex)
|
2014-07-12 14:05:57 +02:00
|
|
|
|
.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
|
2013-12-08 21:47:43 +01:00
|
|
|
|
}
|
2014-07-11 07:31:18 +02:00
|
|
|
|
|
|
|
|
|
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();
|
|
|
|
|
|
2020-07-28 08:33:28 +02:00
|
|
|
|
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);
|
2020-07-28 08:33:28 +02:00
|
|
|
|
npcStats.getSpells().addAllToInstance(spells);
|
|
|
|
|
}
|
2013-12-08 21:47:43 +01:00
|
|
|
|
}
|
2011-01-10 16:13:32 -07:00
|
|
|
|
}
|
|
|
|
|
|
2010-08-03 13:17:31 +02:00
|
|
|
|
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)
|
|
|
|
|
{
|
|
|
|
|
}
|
2015-11-29 14:13:14 +01:00
|
|
|
|
|
2021-04-03 12:59:44 +02:00
|
|
|
|
class NpcCustomData : public MWWorld::TypedCustomData<NpcCustomData>
|
2015-11-29 14:13:14 +01:00
|
|
|
|
{
|
|
|
|
|
public:
|
|
|
|
|
MWMechanics::NpcStats mNpcStats;
|
|
|
|
|
MWMechanics::Movement mMovement;
|
|
|
|
|
MWWorld::InventoryStore mInventoryStore;
|
|
|
|
|
|
2020-10-16 22:18:54 +04:00
|
|
|
|
NpcCustomData& asNpcCustomData() override { return *this; }
|
|
|
|
|
const NpcCustomData& asNpcCustomData() const override { return *this; }
|
2015-11-29 14:13:14 +01:00
|
|
|
|
};
|
|
|
|
|
|
2014-06-19 02:09:46 +02:00
|
|
|
|
const Npc::GMST& Npc::getGmst()
|
2012-01-25 16:56:49 +01:00
|
|
|
|
{
|
2021-10-24 18:45:04 +04:00
|
|
|
|
static const GMST staticGmst = [] {
|
2020-06-14 17:43:30 +02:00
|
|
|
|
GMST gmst;
|
|
|
|
|
|
2023-04-20 13:37:01 +02:00
|
|
|
|
const MWWorld::Store<ESM::GameSetting>& store
|
2023-04-20 21:07:53 +02:00
|
|
|
|
= MWBase::Environment::get().getESMStore()->get<ESM::GameSetting>();
|
2014-06-19 02:09:46 +02:00
|
|
|
|
|
|
|
|
|
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");
|
2014-07-20 23:08:22 +02:00
|
|
|
|
gmst.fCombatArmorMinMult = store.find("fCombatArmorMinMult");
|
2013-02-15 01:27:57 -08:00
|
|
|
|
|
2020-06-14 17:43:30 +02:00
|
|
|
|
return gmst;
|
|
|
|
|
}();
|
2021-10-24 18:45:04 +04:00
|
|
|
|
return staticGmst;
|
2014-06-19 02:09:46 +02:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void Npc::ensureCustomData(const MWWorld::Ptr& ptr) const
|
|
|
|
|
{
|
2012-01-25 16:56:49 +01:00
|
|
|
|
if (!ptr.getRefData().getCustomData())
|
|
|
|
|
{
|
2021-10-25 16:54:50 +02:00
|
|
|
|
bool recalculate = false;
|
|
|
|
|
auto tempData = std::make_unique<NpcCustomData>();
|
|
|
|
|
NpcCustomData* data = tempData.get();
|
2022-06-26 16:42:29 +02:00
|
|
|
|
MWMechanics::CreatureCustomDataResetter resetter{ ptr };
|
2021-10-25 16:54:50 +02:00
|
|
|
|
ptr.getRefData().setCustomData(std::move(tempData));
|
2012-01-25 16:56:49 +01:00
|
|
|
|
|
2012-06-29 18:54:23 +02:00
|
|
|
|
MWWorld::LiveCellRef<ESM::NPC>* ref = ptr.get<ESM::NPC>();
|
2012-01-25 16:56:49 +01:00
|
|
|
|
|
2020-07-28 08:33:28 +02:00
|
|
|
|
bool spellsInitialised = data->mNpcStats.getSpells().setSpells(ref->mBase->mId);
|
|
|
|
|
|
2012-06-16 16:17:42 +02:00
|
|
|
|
// creature stats
|
2013-11-21 04:27:53 +01:00
|
|
|
|
int gold = 0;
|
2013-12-08 21:47:43 +01:00
|
|
|
|
if (ref->mBase->mNpdtType != ESM::NPC::NPC_WITH_AUTOCALCULATED_STATS)
|
2012-04-12 17:08:57 +02:00
|
|
|
|
{
|
2018-05-09 00:25:07 +02:00
|
|
|
|
gold = ref->mBase->mNpdt.mGold;
|
2013-11-21 04:27:53 +01:00
|
|
|
|
|
2013-12-08 21:47:43 +01:00
|
|
|
|
for (unsigned int i = 0; i < ESM::Skill::Length; ++i)
|
2018-05-09 00:25:07 +02:00
|
|
|
|
data->mNpcStats.getSkill(i).setBase(ref->mBase->mNpdt.mSkills[i]);
|
2012-11-05 16:07:59 +04:00
|
|
|
|
|
2018-05-09 00:25:07 +02: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);
|
2013-12-28 17:19:35 +01:00
|
|
|
|
|
2018-05-09 00:25:07 +02:00
|
|
|
|
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
|
|
|
|
|
2018-05-09 00:25:07 +02:00
|
|
|
|
data->mNpcStats.setLevel(ref->mBase->mNpdt.mLevel);
|
|
|
|
|
data->mNpcStats.setBaseDisposition(ref->mBase->mNpdt.mDisposition);
|
|
|
|
|
data->mNpcStats.setReputation(ref->mBase->mNpdt.mReputation);
|
2012-04-12 17:08:57 +02:00
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
2018-05-09 00:25:07 +02:00
|
|
|
|
gold = ref->mBase->mNpdt.mGold;
|
2013-11-21 04:27:53 +01:00
|
|
|
|
|
2012-10-23 13:54:36 +02:00
|
|
|
|
for (int i = 0; i < 3; ++i)
|
2013-08-08 23:27:03 -07:00
|
|
|
|
data->mNpcStats.setDynamic(i, 10);
|
2012-10-23 13:54:36 +02:00
|
|
|
|
|
2018-05-09 00:25:07 +02:00
|
|
|
|
data->mNpcStats.setLevel(ref->mBase->mNpdt.mLevel);
|
|
|
|
|
data->mNpcStats.setBaseDisposition(ref->mBase->mNpdt.mDisposition);
|
|
|
|
|
data->mNpcStats.setReputation(ref->mBase->mNpdt.mReputation);
|
2013-04-18 23:51:43 +02:00
|
|
|
|
|
2013-08-08 23:27:03 -07:00
|
|
|
|
autoCalculateAttributes(ref->mBase, data->mNpcStats);
|
2020-07-28 08:33:28 +02:00
|
|
|
|
autoCalculateSkills(ref->mBase, data->mNpcStats, ptr, spellsInitialised);
|
2014-09-21 11:38:55 +02:00
|
|
|
|
|
2021-10-25 16:54:50 +02:00
|
|
|
|
recalculate = true;
|
2012-04-12 17:08:57 +02:00
|
|
|
|
}
|
2018-06-12 10:00:38 +04:00
|
|
|
|
|
|
|
|
|
// Persistent actors with 0 health do not play death animation
|
2016-06-12 00:04:50 +02:00
|
|
|
|
if (data->mNpcStats.isDead())
|
2018-10-28 17:03:38 +03:00
|
|
|
|
data->mNpcStats.setDeathAnimationFinished(isPersistent(ptr));
|
2012-01-26 11:35:47 +01:00
|
|
|
|
|
2014-01-20 16:02:39 +01:00
|
|
|
|
// 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);
|
2020-07-28 08:33:28 +02:00
|
|
|
|
data->mNpcStats.getSpells().addAllToInstance(race->mPowers.mList);
|
2014-01-20 16:02:39 +01:00
|
|
|
|
|
2015-01-27 17:32:21 +01:00
|
|
|
|
if (!ref->mBase->mFaction.empty())
|
2014-01-11 04:03:13 +01:00
|
|
|
|
{
|
|
|
|
|
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();
|
2014-01-11 04:03:13 +01:00
|
|
|
|
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();
|
2014-01-11 04:03:13 +01:00
|
|
|
|
|
|
|
|
|
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);
|
2013-07-31 00:55:08 +02:00
|
|
|
|
|
2022-07-16 16:37:31 +02:00
|
|
|
|
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);
|
2012-06-16 16:17:42 +02:00
|
|
|
|
|
2012-09-10 13:04:00 +02:00
|
|
|
|
// spells
|
2020-07-28 08:33:28 +02:00
|
|
|
|
if (!spellsInitialised)
|
|
|
|
|
data->mNpcStats.getSpells().addAllToInstance(ref->mBase->mSpells.mList);
|
2012-09-10 13:04:00 +02:00
|
|
|
|
|
2014-03-27 01:23:56 -04:00
|
|
|
|
data->mNpcStats.setGoldPool(gold);
|
|
|
|
|
|
2012-01-26 11:35:47 +01:00
|
|
|
|
// store
|
2021-10-25 16:54:50 +02:00
|
|
|
|
resetter.mPtr = {};
|
|
|
|
|
if (recalculate)
|
|
|
|
|
data->mNpcStats.recalculateMagicka();
|
2013-07-31 16:30:22 +02:00
|
|
|
|
|
2021-07-18 15:04:25 +02:00
|
|
|
|
// inventory
|
|
|
|
|
// setting ownership is used to make the NPC auto-equip his initial equipment only, and not bartered items
|
2022-03-06 21:56:02 +02:00
|
|
|
|
auto& prng = MWBase::Environment::get().getWorld()->getPrng();
|
|
|
|
|
getInventoryStore(ptr).fill(ref->mBase->mInventory, ptr.getCellRef().getRefId(), prng);
|
2021-07-18 15:04:25 +02:00
|
|
|
|
|
2023-01-16 23:51:04 +01:00
|
|
|
|
getInventoryStore(ptr).autoEquip();
|
2012-01-25 16:56:49 +01:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2015-01-12 11:29:56 +01:00
|
|
|
|
void Npc::insertObjectRendering(
|
|
|
|
|
const MWWorld::Ptr& ptr, const std::string& model, MWRender::RenderingInterface& renderingInterface) const
|
2010-08-14 10:02:54 +02:00
|
|
|
|
{
|
2015-04-12 15:34:50 +02:00
|
|
|
|
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>();
|
2021-07-06 12:37:02 +10:00
|
|
|
|
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>();
|
2011-12-25 01:52:57 -05:00
|
|
|
|
|
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);
|
2013-03-12 02:50:23 +01:00
|
|
|
|
if (race->mData.mFlags & ESM::Race::Beast)
|
2020-12-30 22:11:32 +02:00
|
|
|
|
model = Settings::Manager::getString("baseanimkna", "Models");
|
2013-03-12 02:50:23 +01:00
|
|
|
|
|
2012-07-24 20:22:11 +04:00
|
|
|
|
return model;
|
2010-08-14 11:27:13 +02:00
|
|
|
|
}
|
|
|
|
|
|
2016-02-08 20:52:32 +01:00
|
|
|
|
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);
|
2016-02-08 20:52:32 +01:00
|
|
|
|
if (race && race->mData.mFlags & ESM::Race::Beast)
|
2020-12-30 22:11:32 +02:00
|
|
|
|
models.emplace_back(Settings::Manager::getString("baseanimkna", "Models"));
|
2016-02-08 20:52:32 +01:00
|
|
|
|
|
|
|
|
|
// keep these always loaded just in case
|
2020-12-30 22:11:32 +02:00
|
|
|
|
models.emplace_back(Settings::Manager::getString("xargonianswimkna", "Models"));
|
|
|
|
|
models.emplace_back(Settings::Manager::getString("xbaseanimfemale", "Models"));
|
|
|
|
|
models.emplace_back(Settings::Manager::getString("xbaseanim", "Models"));
|
2016-02-08 20:52:32 +01:00
|
|
|
|
|
2022-06-29 00:32:11 +02:00
|
|
|
|
const VFS::Manager* const vfs = MWBase::Environment::get().getResourceSystem()->getVFS();
|
|
|
|
|
|
2016-02-08 20:52:32 +01:00
|
|
|
|
if (!npc->mBase->mModel.empty())
|
2022-06-29 00:32:11 +02:00
|
|
|
|
models.push_back(Misc::ResourceHelpers::correctMeshPath(npc->mBase->mModel, vfs));
|
2016-02-08 20:52:32 +01:00
|
|
|
|
|
|
|
|
|
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);
|
2016-02-08 20:52:32 +01:00
|
|
|
|
if (head)
|
2022-06-29 00:32:11 +02:00
|
|
|
|
models.push_back(Misc::ResourceHelpers::correctMeshPath(head->mModel, vfs));
|
2016-02-08 20:52:32 +01:00
|
|
|
|
}
|
|
|
|
|
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);
|
2016-02-08 20:52:32 +01:00
|
|
|
|
if (hair)
|
2022-06-29 00:32:11 +02:00
|
|
|
|
models.push_back(Misc::ResourceHelpers::correctMeshPath(hair->mModel, vfs));
|
2016-02-08 20:52:32 +01:00
|
|
|
|
}
|
|
|
|
|
|
2016-02-09 00:26:22 +01:00
|
|
|
|
bool female = (npc->mBase->mFlags & ESM::NPC::Female);
|
|
|
|
|
|
2016-02-08 20:52:32 +01:00
|
|
|
|
// FIXME: use const version of InventoryStore functions once they are available
|
2016-02-09 00:26:22 +01:00
|
|
|
|
// preload equipped items
|
2018-10-28 17:03:38 +03:00
|
|
|
|
const MWWorld::InventoryStore& invStore = getInventoryStore(ptr);
|
|
|
|
|
for (int slot = 0; slot < MWWorld::InventoryStore::Slots; ++slot)
|
2016-02-08 20:52:32 +01:00
|
|
|
|
{
|
2018-10-28 17:03:38 +03:00
|
|
|
|
MWWorld::ConstContainerStoreIterator equipped = invStore.getSlot(slot);
|
|
|
|
|
if (equipped != invStore.end())
|
2016-02-08 20:52:32 +01:00
|
|
|
|
{
|
2018-10-28 17:03:38 +03:00
|
|
|
|
std::vector<ESM::PartReference> parts;
|
2021-10-11 11:46:21 +00:00
|
|
|
|
if (equipped->getType() == ESM::Clothing::sRecordId)
|
2016-02-08 20:52:32 +01:00
|
|
|
|
{
|
2018-10-28 17:03:38 +03:00
|
|
|
|
const ESM::Clothing* clothes = equipped->get<ESM::Clothing>()->mBase;
|
|
|
|
|
parts = clothes->mParts.mParts;
|
|
|
|
|
}
|
2021-10-11 11:46:21 +00:00
|
|
|
|
else if (equipped->getType() == ESM::Armor::sRecordId)
|
2018-10-28 17:03:38 +03:00
|
|
|
|
{
|
|
|
|
|
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);
|
|
|
|
|
}
|
2016-02-08 20:52:32 +01:00
|
|
|
|
|
2018-10-28 17:03:38 +03:00
|
|
|
|
for (std::vector<ESM::PartReference>::const_iterator it = parts.begin(); it != parts.end(); ++it)
|
|
|
|
|
{
|
2022-11-10 23:29:18 +01:00
|
|
|
|
const ESM::RefId& partname
|
|
|
|
|
= (female && !it->mFemale.empty()) || (!female && it->mMale.empty()) ? it->mFemale : it->mMale;
|
|
|
|
|
|
2018-10-28 17:03:38 +03:00
|
|
|
|
const ESM::BodyPart* part
|
2023-04-20 21:07:53 +02:00
|
|
|
|
= MWBase::Environment::get().getESMStore()->get<ESM::BodyPart>().search(partname);
|
2018-10-28 17:03:38 +03:00
|
|
|
|
if (part && !part->mModel.empty())
|
2022-06-29 00:32:11 +02:00
|
|
|
|
models.push_back(Misc::ResourceHelpers::correctMeshPath(part->mModel, vfs));
|
2016-02-08 20:52:32 +01:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
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())
|
2022-06-29 00:32:11 +02:00
|
|
|
|
models.push_back(Misc::ResourceHelpers::correctMeshPath(part->mModel, vfs));
|
2016-02-09 00:26:22 +01:00
|
|
|
|
}
|
|
|
|
|
}
|
2016-02-08 20:52:32 +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
|
|
|
|
{
|
2015-12-18 15:27:06 +01:00
|
|
|
|
if (ptr.getRefData().getCustomData()
|
|
|
|
|
&& ptr.getRefData().getCustomData()->asNpcCustomData().mNpcStats.isWerewolf())
|
2013-08-08 03:57:32 -07:00
|
|
|
|
{
|
2023-04-20 13:37:01 +02:00
|
|
|
|
const MWWorld::Store<ESM::GameSetting>& store
|
2023-04-20 21:07:53 +02:00
|
|
|
|
= MWBase::Environment::get().getESMStore()->get<ESM::GameSetting>();
|
2013-08-08 03:57:32 -07:00
|
|
|
|
|
2018-08-29 18:38:12 +03:00
|
|
|
|
return store.find("sWerewolfPopup")->mValue.getString();
|
2013-08-08 03:57:32 -07:00
|
|
|
|
}
|
2010-08-03 17:11:41 +02:00
|
|
|
|
|
2015-12-18 15:27:06 +01:00
|
|
|
|
const MWWorld::LiveCellRef<ESM::NPC>* ref = ptr.get<ESM::NPC>();
|
2019-09-11 00:06:50 +03:00
|
|
|
|
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
|
|
|
|
}
|
|
|
|
|
|
2010-08-03 13:17:31 +02:00
|
|
|
|
MWMechanics::CreatureStats& Npc::getCreatureStats(const MWWorld::Ptr& ptr) const
|
2010-08-03 13:03:08 +02:00
|
|
|
|
{
|
2012-01-26 11:35:47 +01:00
|
|
|
|
ensureCustomData(ptr);
|
2010-08-03 13:03:08 +02:00
|
|
|
|
|
2015-11-29 14:13:14 +01: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
|
|
|
|
|
{
|
2012-01-25 16:56:49 +01:00
|
|
|
|
ensureCustomData(ptr);
|
2010-08-19 12:49:13 +02:00
|
|
|
|
|
2015-11-29 14:13:14 +01:00
|
|
|
|
return ptr.getRefData().getCustomData()->asNpcCustomData().mNpcStats;
|
2010-08-19 12:49:13 +02:00
|
|
|
|
}
|
|
|
|
|
|
2022-08-11 21:50:38 +03:00
|
|
|
|
bool Npc::evaluateHit(const MWWorld::Ptr& ptr, MWWorld::Ptr& victim, osg::Vec3f& hitPosition) const
|
2013-07-24 02:51:42 -07:00
|
|
|
|
{
|
2022-08-11 21:50:38 +03:00
|
|
|
|
victim = MWWorld::Ptr();
|
|
|
|
|
hitPosition = osg::Vec3f();
|
2013-07-25 12:58:43 -07:00
|
|
|
|
|
2013-07-25 08:15:42 -07:00
|
|
|
|
// Get the weapon used (if hand-to-hand, weapon = inv.end())
|
|
|
|
|
MWWorld::InventoryStore& inv = getInventoryStore(ptr);
|
2013-07-26 03:21:54 -07:00
|
|
|
|
MWWorld::ContainerStoreIterator weaponslot = inv.getSlot(MWWorld::InventoryStore::Slot_CarriedRight);
|
2022-08-11 21:50:38 +03:00
|
|
|
|
MWWorld::Ptr weapon;
|
|
|
|
|
if (weaponslot != inv.end() && weaponslot->getType() == ESM::Weapon::sRecordId)
|
|
|
|
|
weapon = *weaponslot;
|
2014-01-11 22:26:26 +01:00
|
|
|
|
|
2022-08-11 21:50:38 +03:00
|
|
|
|
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
|
2013-07-26 03:21:54 -07:00
|
|
|
|
* (!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
|
|
|
|
|
2017-02-02 16:20:34 +09: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;
|
2018-10-28 17:03:38 +03:00
|
|
|
|
if (ptr != MWMechanics::getPlayer())
|
|
|
|
|
getCreatureStats(ptr).getAiSequence().getCombatTargets(targetActors);
|
2017-02-02 16:20:34 +09:00
|
|
|
|
|
2014-01-17 17:19:08 +01:00
|
|
|
|
// TODO: Use second to work out the hit angle
|
2017-02-02 16:20:34 +09:00
|
|
|
|
std::pair<MWWorld::Ptr, osg::Vec3f> result = world->getHitContact(ptr, dist, targetActors);
|
2022-08-11 21:50:38 +03:00
|
|
|
|
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;
|
|
|
|
|
|
2014-05-22 20:37:22 +02:00
|
|
|
|
const MWWorld::Class& othercls = victim.getClass();
|
|
|
|
|
MWMechanics::CreatureStats& otherstats = othercls.getCreatureStats(victim);
|
2022-08-11 21:50:38 +03:00
|
|
|
|
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
|
|
|
|
|
2022-08-11 21:50:38 +03:00
|
|
|
|
if (!success)
|
2013-07-25 08:15:42 -07:00
|
|
|
|
{
|
2016-09-12 20:40:40 +09:00
|
|
|
|
othercls.onHit(victim, 0.0f, false, weapon, ptr, osg::Vec3f(), false);
|
2014-08-02 23:14:17 +02:00
|
|
|
|
MWMechanics::reduceWeaponCondition(0.f, false, weapon, ptr);
|
2013-07-25 08:15:42 -07:00
|
|
|
|
return;
|
|
|
|
|
}
|
2013-07-24 02:51:42 -07:00
|
|
|
|
|
2013-07-28 06:48:25 -07:00
|
|
|
|
bool healthdmg;
|
2013-07-26 03:21:54 -07:00
|
|
|
|
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)
|
2013-07-26 03:21:54 -07:00
|
|
|
|
attack = weapon.get<ESM::Weapon>()->mBase->mData.mChop;
|
2014-01-28 21:07:26 +02:00
|
|
|
|
else if (type == ESM::Weapon::AT_Slash)
|
2013-07-26 03:21:54 -07:00
|
|
|
|
attack = weapon.get<ESM::Weapon>()->mBase->mData.mSlash;
|
2014-01-28 21:07:26 +02:00
|
|
|
|
else if (type == ESM::Weapon::AT_Thrust)
|
2013-07-26 03:21:54 -07:00
|
|
|
|
attack = weapon.get<ESM::Weapon>()->mBase->mData.mThrust;
|
2013-07-25 08:15:42 -07:00
|
|
|
|
if (attack)
|
2013-07-24 03:18:53 -07:00
|
|
|
|
{
|
2015-06-26 05:15:07 +02:00
|
|
|
|
damage = attack[0] + ((attack[1] - attack[0]) * attackStrength);
|
2013-07-24 03:18:53 -07:00
|
|
|
|
}
|
2015-03-12 03:08:58 +01:00
|
|
|
|
MWMechanics::adjustWeaponDamage(damage, weapon, ptr);
|
2022-02-23 10:10:50 +03:00
|
|
|
|
MWMechanics::reduceWeaponCondition(damage, true, weapon, ptr);
|
2018-12-08 21:55:08 +03:00
|
|
|
|
MWMechanics::resistNormalWeapon(victim, ptr, weapon, damage);
|
2018-12-08 21:47:39 +03:00
|
|
|
|
MWMechanics::applyWerewolfDamageMult(victim, weapon, damage);
|
2013-07-28 06:48:25 -07:00
|
|
|
|
healthdmg = true;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
2015-06-26 05:15:07 +02:00
|
|
|
|
MWMechanics::getHandToHandDamage(ptr, victim, damage, healthdmg, attackStrength);
|
2013-07-24 02:51:42 -07:00
|
|
|
|
}
|
2022-08-11 21:50:38 +03: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())
|
2014-07-20 22:35:35 +02:00
|
|
|
|
{
|
2022-08-11 21:50:38 +03:00
|
|
|
|
int weapskill = ESM::Skill::HandToHand;
|
|
|
|
|
if (!weapon.isEmpty())
|
|
|
|
|
weapskill = weapon.getClass().getEquipmentSkill(weapon);
|
2013-07-26 05:26:01 -07:00
|
|
|
|
skillUsageSucceeded(ptr, weapskill, 0);
|
2013-07-26 03:21:54 -07:00
|
|
|
|
|
2014-07-20 22:35:35 +02:00
|
|
|
|
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();
|
2014-07-20 22:35:35 +02:00
|
|
|
|
MWBase::Environment::get().getWindowManager()->messageBox("#{sTargetCriticalStrike}");
|
2022-10-18 09:26:55 +02:00
|
|
|
|
MWBase::Environment::get().getSoundManager()->playSound3D(
|
|
|
|
|
victim, ESM::RefId::stringRefId("critical damage"), 1.0f, 1.0f);
|
2014-07-20 22:35:35 +02:00
|
|
|
|
}
|
2014-01-13 01:47:10 +01:00
|
|
|
|
}
|
2014-07-20 22:35:35 +02:00
|
|
|
|
|
2014-01-13 01:47:10 +01:00
|
|
|
|
if (othercls.getCreatureStats(victim).getKnockedDown())
|
2018-08-29 18:38:12 +03:00
|
|
|
|
damage *= store.find("fCombatKODamageMult")->mValue.getFloat();
|
2014-01-13 01:47:10 +01:00
|
|
|
|
|
2013-11-12 02:07:51 +01:00
|
|
|
|
// Apply "On hit" enchanted weapons
|
2016-02-22 19:37:19 +01:00
|
|
|
|
MWMechanics::applyOnStrikeEnchantment(ptr, victim, weapon, hitPosition);
|
2013-11-12 02:07:51 +01:00
|
|
|
|
|
2014-07-15 21:53:11 +02:00
|
|
|
|
MWMechanics::applyElementalShields(ptr, victim);
|
|
|
|
|
|
2015-06-26 05:15:07 +02:00
|
|
|
|
if (MWMechanics::blockMeleeAttack(ptr, victim, weapon, damage, attackStrength))
|
2022-11-07 21:52:34 +03:00
|
|
|
|
{
|
2014-01-21 01:01:21 +01:00
|
|
|
|
damage = 0;
|
2022-12-26 18:52:18 +03:00
|
|
|
|
victim.getClass().block(victim);
|
2022-11-07 21:52:34 +03:00
|
|
|
|
}
|
2014-01-21 01:01:21 +01:00
|
|
|
|
|
2017-03-25 22:40:11 +04:00
|
|
|
|
if (victim == MWMechanics::getPlayer() && MWBase::Environment::get().getWorld()->getGodModeState())
|
|
|
|
|
damage = 0;
|
|
|
|
|
|
2014-03-08 05:51:47 +01:00
|
|
|
|
MWMechanics::diseaseContact(victim, ptr);
|
|
|
|
|
|
2016-09-12 20:40:40 +09:00
|
|
|
|
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();
|
2018-10-28 17:03:38 +03:00
|
|
|
|
MWMechanics::CreatureStats& stats = getCreatureStats(ptr);
|
2017-02-02 02:15:10 +09:00
|
|
|
|
bool wasDead = stats.isDead();
|
2014-06-17 03:54:41 +02:00
|
|
|
|
|
2014-09-26 22:08:07 +02:00
|
|
|
|
// Note OnPcHitMe is not set for friendly hits.
|
|
|
|
|
bool setOnPcHitMe = true;
|
2014-05-02 22:38:39 +02:00
|
|
|
|
|
2017-02-02 02:15:10 +09:00
|
|
|
|
// NOTE: 'object' and/or 'attacker' may be empty.
|
2017-02-11 19:59:42 +09:00
|
|
|
|
if (!attacker.isEmpty() && attacker.getClass().isActor() && !stats.getAiSequence().isInCombat(attacker))
|
2017-02-02 02:15:10 +09:00
|
|
|
|
{
|
|
|
|
|
stats.setAttacked(true);
|
2014-09-26 22:08:07 +02:00
|
|
|
|
setOnPcHitMe = MWBase::Environment::get().getMechanicsManager()->actorAttacked(ptr, attacker);
|
2014-09-14 10:35:57 +02:00
|
|
|
|
}
|
2014-08-03 15:20:33 +02:00
|
|
|
|
|
2017-02-02 02:15:10 +09:00
|
|
|
|
// Attacker and target store each other as hitattemptactor if they have no one stored yet
|
2018-10-28 17:03:38 +03:00
|
|
|
|
if (!attacker.isEmpty() && attacker.getClass().isActor())
|
2017-02-02 02:15:10 +09:00
|
|
|
|
{
|
|
|
|
|
MWMechanics::CreatureStats& statsAttacker = attacker.getClass().getCreatureStats(attacker);
|
|
|
|
|
// First handle the attacked actor
|
2017-02-06 21:32:36 +09:00
|
|
|
|
if ((stats.getHitAttemptActorId() == -1)
|
2017-02-02 02:15:10 +09:00
|
|
|
|
&& (statsAttacker.getAiSequence().isInCombat(ptr) || attacker == MWMechanics::getPlayer()))
|
2017-02-06 21:32:36 +09:00
|
|
|
|
stats.setHitAttemptActorId(statsAttacker.getActorId());
|
2017-02-02 02:15:10 +09:00
|
|
|
|
|
|
|
|
|
// Next handle the attacking actor
|
2017-02-06 21:32:36 +09:00
|
|
|
|
if ((statsAttacker.getHitAttemptActorId() == -1)
|
2017-02-02 02:15:10 +09:00
|
|
|
|
&& (statsAttacker.getAiSequence().isInCombat(ptr) || attacker == MWMechanics::getPlayer()))
|
2017-02-06 21:32:36 +09:00
|
|
|
|
statsAttacker.setHitAttemptActorId(stats.getActorId());
|
2017-02-02 02:15:10 +09:00
|
|
|
|
}
|
|
|
|
|
|
2016-09-12 20:40:40 +09:00
|
|
|
|
if (!object.isEmpty())
|
2017-02-02 02:15:10 +09:00
|
|
|
|
stats.setLastHitAttemptObject(object.getCellRef().getRefId());
|
2014-12-11 22:25:41 +01:00
|
|
|
|
|
2016-09-12 20:40:40 +09:00
|
|
|
|
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);
|
|
|
|
|
}
|
|
|
|
|
|
2016-09-12 20:40:40 +09:00
|
|
|
|
if (!successful)
|
2013-07-26 03:21:54 -07:00
|
|
|
|
{
|
|
|
|
|
// Missed
|
2019-04-10 22:20:56 +03:00
|
|
|
|
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);
|
2013-07-26 03:21:54 -07:00
|
|
|
|
return;
|
|
|
|
|
}
|
2013-07-24 02:51:42 -07:00
|
|
|
|
|
2016-09-12 20:40:40 +09:00
|
|
|
|
if (!object.isEmpty())
|
2017-02-02 02:15:10 +09:00
|
|
|
|
stats.setLastHitObject(object.getCellRef().getRefId());
|
2013-07-26 07:04:36 -07:00
|
|
|
|
|
2014-01-22 12:09:44 +01:00
|
|
|
|
if (damage > 0.0f && !object.isEmpty())
|
|
|
|
|
MWMechanics::resistNormalWeapon(ptr, attacker, object, damage);
|
|
|
|
|
|
2014-07-20 23:08:22 +02:00
|
|
|
|
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;
|
|
|
|
|
|
2016-09-12 20:40:40 +09:00
|
|
|
|
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.
|
2013-07-24 10:02:50 -07:00
|
|
|
|
|
2023-04-20 21:07:53 +02:00
|
|
|
|
const MWWorld::ESMStore& store = *MWBase::Environment::get().getESMStore();
|
2014-06-19 02:09:46 +02:00
|
|
|
|
const GMST& gmst = getGmst();
|
|
|
|
|
|
2022-03-06 21:56:02 +02:00
|
|
|
|
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"));
|
2014-01-13 01:42:19 +01:00
|
|
|
|
|
|
|
|
|
// Check for knockdown
|
2018-08-29 18:38:12 +03:00
|
|
|
|
float agilityTerm
|
|
|
|
|
= stats.getAttribute(ESM::Attribute::Agility).getModified() * gmst.fKnockDownMult->mValue.getFloat();
|
2017-02-02 02:15:10 +09:00
|
|
|
|
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();
|
2022-03-06 21:56:02 +02:00
|
|
|
|
if (ishealth && agilityTerm <= damage && knockdownTerm <= Misc::Rng::roll0to99(prng))
|
2017-02-02 02:15:10 +09:00
|
|
|
|
stats.setKnockedDown(true);
|
2014-01-13 01:42:19 +01:00
|
|
|
|
else
|
2017-02-02 02:15:10 +09:00
|
|
|
|
stats.setHitRecovery(true); // Is this supposed to always occur?
|
2013-07-27 11:20:39 -07:00
|
|
|
|
|
2016-09-12 20:40:40 +09:00
|
|
|
|
if (damage > 0 && ishealth)
|
2013-07-27 11:20:39 -07:00
|
|
|
|
{
|
2013-07-28 15:17:01 -07:00
|
|
|
|
// 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 };
|
2022-03-06 21:56:02 +02:00
|
|
|
|
int hitslot = hitslots[Misc::Rng::rollDice(20, prng)];
|
2013-07-28 15:17:01 -07:00
|
|
|
|
|
2014-07-20 23:08:22 +02:00
|
|
|
|
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);
|
2015-03-08 13:07:29 +13:00
|
|
|
|
int damageDiff = static_cast<int>(unmitigatedDamage - damage);
|
2018-06-29 19:57:09 +03:00
|
|
|
|
damage = std::max(1.f, damage);
|
|
|
|
|
damageDiff = std::max(1, damageDiff);
|
2013-07-28 15:51:17 -07:00
|
|
|
|
|
2013-07-28 15:17:01 -07:00
|
|
|
|
MWWorld::InventoryStore& inv = getInventoryStore(ptr);
|
|
|
|
|
MWWorld::ContainerStoreIterator armorslot = inv.getSlot(hitslot);
|
|
|
|
|
MWWorld::Ptr armor = ((armorslot != inv.end()) ? *armorslot : MWWorld::Ptr());
|
2021-10-11 11:46:21 +00:00
|
|
|
|
bool hasArmor = !armor.isEmpty() && armor.getType() == ESM::Armor::sRecordId;
|
2020-06-25 15:44:40 +03:00
|
|
|
|
// 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)
|
|
|
|
|
{
|
2022-03-06 21:56:02 +02:00
|
|
|
|
if (Misc::Rng::rollDice(2, prng) == 0)
|
2020-06-25 15:44:40 +03:00
|
|
|
|
hitslot = MWWorld::InventoryStore::Slot_Cuirass;
|
|
|
|
|
else
|
|
|
|
|
hitslot = MWWorld::InventoryStore::Slot_LeftPauldron;
|
|
|
|
|
armorslot = inv.getSlot(hitslot);
|
|
|
|
|
if (armorslot != inv.end())
|
|
|
|
|
{
|
|
|
|
|
armor = *armorslot;
|
2021-10-11 11:46:21 +00:00
|
|
|
|
hasArmor = !armor.isEmpty() && armor.getType() == ESM::Armor::sRecordId;
|
2020-06-25 15:44:40 +03:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if (hasArmor)
|
2013-07-27 11:20:39 -07:00
|
|
|
|
{
|
2022-07-29 13:24:16 +00:00
|
|
|
|
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.
|
2018-06-29 19:57:09 +03:00
|
|
|
|
{
|
|
|
|
|
int armorhealth = armor.getClass().getItemHealth(armor);
|
|
|
|
|
armorhealth -= std::min(damageDiff, armorhealth);
|
|
|
|
|
armor.getCellRef().setCharge(armorhealth);
|
|
|
|
|
|
|
|
|
|
// Armor broken? unequip it
|
|
|
|
|
if (armorhealth == 0)
|
2023-01-16 23:51:04 +01:00
|
|
|
|
armor = *inv.unequipItem(armor);
|
2018-06-29 19:57:09 +03:00
|
|
|
|
}
|
2014-01-02 01:03:44 +01:00
|
|
|
|
|
2015-08-21 21:12:39 +12:00
|
|
|
|
if (ptr == MWMechanics::getPlayer())
|
2014-05-22 20:37:22 +02:00
|
|
|
|
skillUsageSucceeded(ptr, armor.getClass().getEquipmentSkill(armor), 0);
|
2014-01-26 22:00:36 +01:00
|
|
|
|
|
2014-05-22 20:37:22 +02:00
|
|
|
|
switch (armor.getClass().getEquipmentSkill(armor))
|
2013-07-28 15:17:01 -07:00
|
|
|
|
{
|
|
|
|
|
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);
|
2013-07-28 15:17:01 -07:00
|
|
|
|
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);
|
2013-07-28 15:17:01 -07:00
|
|
|
|
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);
|
2013-07-28 15:17:01 -07:00
|
|
|
|
break;
|
|
|
|
|
}
|
2013-07-27 11:20:39 -07:00
|
|
|
|
}
|
2015-08-21 21:12:39 +12:00
|
|
|
|
else if (ptr == MWMechanics::getPlayer())
|
2014-01-26 22:00:36 +01:00
|
|
|
|
skillUsageSucceeded(ptr, ESM::Skill::Unarmored, 0);
|
2013-07-27 11:20:39 -07:00
|
|
|
|
}
|
2013-07-24 02:51:42 -07:00
|
|
|
|
}
|
|
|
|
|
|
2016-09-12 20:40:40 +09:00
|
|
|
|
if (ishealth)
|
2013-07-28 06:48:25 -07:00
|
|
|
|
{
|
2017-03-25 22:40:11 +04:00
|
|
|
|
if (!attacker.isEmpty() && !godmode)
|
2014-07-20 16:22:52 +02:00
|
|
|
|
damage = scaleDamage(damage, attacker, ptr);
|
|
|
|
|
|
2016-09-12 20:40:40 +09:00
|
|
|
|
if (damage > 0.0f)
|
2014-10-06 18:31:02 +02:00
|
|
|
|
{
|
2022-10-18 09:26:55 +02:00
|
|
|
|
sndMgr->playSound3D(ptr, ESM::RefId::stringRefId("Health Damage"), 1.0f, 1.0f);
|
2015-08-21 21:12:39 +12:00
|
|
|
|
if (ptr == MWMechanics::getPlayer())
|
2014-10-06 18:31:02 +02:00
|
|
|
|
MWBase::Environment::get().getWindowManager()->activateHitOverlay();
|
2016-09-12 20:40:40 +09:00
|
|
|
|
if (!attacker.isEmpty())
|
|
|
|
|
MWBase::Environment::get().getWorld()->spawnBloodEffect(ptr, hitPosition);
|
2014-10-06 18:31:02 +02:00
|
|
|
|
}
|
2015-07-24 20:23:27 +02:00
|
|
|
|
MWMechanics::DynamicStat<float> health(getCreatureStats(ptr).getHealth());
|
|
|
|
|
health.setCurrent(health.getCurrent() - damage);
|
2017-02-02 02:15:10 +09:00
|
|
|
|
stats.setHealth(health);
|
2013-07-28 06:48:25 -07:00
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
MWMechanics::DynamicStat<float> fatigue(getCreatureStats(ptr).getFatigue());
|
2013-12-09 21:13:06 +01:00
|
|
|
|
fatigue.setCurrent(fatigue.getCurrent() - damage, true);
|
2017-02-02 02:15:10 +09:00
|
|
|
|
stats.setFatigue(fatigue);
|
2013-07-28 06:48:25 -07:00
|
|
|
|
}
|
2014-06-17 03:54:41 +02: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();
|
|
|
|
|
}
|
|
|
|
|
|
2015-07-18 20:39:45 +02:00
|
|
|
|
MWBase::Environment::get().getMechanicsManager()->actorKilled(ptr, attacker);
|
2014-06-17 03:54:41 +02:00
|
|
|
|
}
|
2013-07-26 03:21:54 -07:00
|
|
|
|
}
|
|
|
|
|
|
2022-04-06 17:06:55 +02:00
|
|
|
|
std::unique_ptr<MWWorld::Action> Npc::activate(const MWWorld::Ptr& ptr, const MWWorld::Ptr& actor) const
|
2010-08-06 18:15:46 +02:00
|
|
|
|
{
|
2014-05-08 20:40:45 +02:00
|
|
|
|
// 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);
|
2014-05-08 20:40:45 +02:00
|
|
|
|
|
2014-07-21 18:19:45 +02:00
|
|
|
|
// Werewolfs can't activate NPCs
|
2014-05-22 20:37:22 +02:00
|
|
|
|
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();
|
2022-03-06 21:56:02 +02:00
|
|
|
|
auto& prng = MWBase::Environment::get().getWorld()->getPrng();
|
2022-10-12 19:51:42 +02:00
|
|
|
|
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;
|
|
|
|
|
}
|
2014-07-21 18:19:45 +02:00
|
|
|
|
|
2017-07-26 14:42:01 +04:00
|
|
|
|
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);
|
2017-07-26 14:42:01 +04:00
|
|
|
|
|
|
|
|
|
// otherwise wait until death animation
|
|
|
|
|
if (stats.isDeathAnimationFinished())
|
2022-05-29 13:24:48 +02:00
|
|
|
|
return std::make_unique<MWWorld::ActionOpen>(ptr);
|
2017-07-26 14:42:01 +04:00
|
|
|
|
}
|
2019-09-15 23:17:36 +03:00
|
|
|
|
else if (!stats.getAiSequence().isInCombat())
|
|
|
|
|
{
|
2020-07-26 12:17:06 +03:00
|
|
|
|
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
|
2017-07-26 14:42:01 +04:00
|
|
|
|
|
2019-09-15 23:17:36 +03:00
|
|
|
|
// Can't talk to werewolves
|
|
|
|
|
if (!getNpcStats(ptr).isWerewolf())
|
2022-05-29 13:24:48 +02:00
|
|
|
|
return std::make_unique<MWWorld::ActionTalk>(ptr);
|
2019-09-15 23:17:36 +03:00
|
|
|
|
}
|
2020-07-26 13:02:12 +03:00
|
|
|
|
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
|
2020-07-26 13:02:12 +03:00
|
|
|
|
}
|
2017-08-12 21:18:05 +04:00
|
|
|
|
|
2019-09-15 23:17:36 +03: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);
|
2017-07-26 14:42:01 +04:00
|
|
|
|
|
2022-05-29 13:24:48 +02:00
|
|
|
|
return std::make_unique<MWWorld::FailedAction>();
|
2010-08-14 10:02:54 +02:00
|
|
|
|
}
|
2010-08-07 20:33:07 +02:00
|
|
|
|
|
2012-01-28 11:45:55 +01:00
|
|
|
|
MWWorld::ContainerStore& Npc::getContainerStore(const MWWorld::Ptr& ptr) const
|
2010-08-04 14:37:23 +02:00
|
|
|
|
{
|
2012-01-27 14:55:58 +01:00
|
|
|
|
ensureCustomData(ptr);
|
2023-01-16 23:51:04 +01:00
|
|
|
|
auto& store = ptr.getRefData().getCustomData()->asNpcCustomData().mInventoryStore;
|
|
|
|
|
store.setActor(ptr);
|
|
|
|
|
return store;
|
2012-03-10 12:49:54 +01:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
MWWorld::InventoryStore& Npc::getInventoryStore(const MWWorld::Ptr& ptr) const
|
|
|
|
|
{
|
|
|
|
|
ensureCustomData(ptr);
|
2023-01-16 23:51:04 +01:00
|
|
|
|
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
|
2010-08-05 15:40:03 +02:00
|
|
|
|
{
|
2015-12-18 00:12:03 +01:00
|
|
|
|
const MWWorld::LiveCellRef<ESM::NPC>* ref = ptr.get<ESM::NPC>();
|
2010-08-05 15:40:03 +02:00
|
|
|
|
|
2012-11-05 16:07:59 +04:00
|
|
|
|
return ref->mBase->mScript;
|
2010-08-05 15:40:03 +02:00
|
|
|
|
}
|
|
|
|
|
|
2020-08-27 11:48:59 +00:00
|
|
|
|
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.
|
2022-07-13 21:17:11 +02:00
|
|
|
|
const MWMechanics::NpcStats& stats = getNpcStats(ptr);
|
2020-10-09 20:34:36 +03:00
|
|
|
|
bool godmode = ptr == MWMechanics::getPlayer() && MWBase::Environment::get().getWorld()->getGodModeState();
|
|
|
|
|
if ((!godmode && stats.isParalyzed()) || stats.getKnockedDown() || stats.isDead())
|
2018-07-19 20:17:32 +04:00
|
|
|
|
return 0.f;
|
|
|
|
|
|
2013-02-15 01:27:57 -08:00
|
|
|
|
const MWBase::World* world = MWBase::Environment::get().getWorld();
|
2014-06-19 02:09:46 +02:00
|
|
|
|
const GMST& gmst = getGmst();
|
|
|
|
|
|
2022-07-13 21:17:11 +02:00
|
|
|
|
const MWMechanics::MagicEffects& mageffects = stats.getMagicEffects();
|
2013-02-19 02:10:36 -08:00
|
|
|
|
|
2014-10-05 15:50:01 +02: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);
|
2019-07-30 20:58:19 +03:00
|
|
|
|
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));
|
2014-01-15 07:47:21 +01:00
|
|
|
|
|
2013-02-15 01:27:57 -08:00
|
|
|
|
float moveSpeed;
|
2014-10-05 15:52:33 +02:00
|
|
|
|
if (getEncumbrance(ptr) > getCapacity(ptr))
|
2013-02-15 01:27:57 -08:00
|
|
|
|
moveSpeed = 0.0f;
|
2014-08-16 22:38:22 +02:00
|
|
|
|
else if (mageffects.get(ESM::MagicEffect::Levitate).getMagnitude() > 0 && world->isLevitationEnabled())
|
2013-02-15 01:27:57 -08:00
|
|
|
|
{
|
2022-07-13 21:17:11 +02:00
|
|
|
|
float flySpeed = 0.01f
|
|
|
|
|
* (stats.getAttribute(ESM::Attribute::Speed).getModified()
|
2014-08-16 22:38:22 +02:00
|
|
|
|
+ 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)
|
2020-06-13 01:04:55 +02:00
|
|
|
|
moveSpeed = getSwimSpeed(ptr);
|
2019-02-18 16:21:42 +03:00
|
|
|
|
else if (running && !sneaking)
|
2020-06-13 01:04:55 +02:00
|
|
|
|
moveSpeed = getRunSpeed(ptr);
|
2013-02-15 01:27:57 -08:00
|
|
|
|
else
|
2020-06-13 01:04:55 +02:00
|
|
|
|
moveSpeed = getWalkSpeed(ptr);
|
2013-02-15 01:27:57 -08:00
|
|
|
|
|
2022-07-17 19:36:48 +03:00
|
|
|
|
if (stats.isWerewolf() && running && stats.getDrawState() == MWMechanics::DrawState::Nothing)
|
2018-08-29 18:38:12 +03:00
|
|
|
|
moveSpeed *= gmst.fWereWolfRunMult->mValue.getFloat();
|
2014-08-12 01:10:18 +02:00
|
|
|
|
|
2013-02-15 01:27:57 -08:00
|
|
|
|
return moveSpeed;
|
2011-01-18 10:45:29 +01:00
|
|
|
|
}
|
|
|
|
|
|
2013-02-24 03:30:33 -08:00
|
|
|
|
float Npc::getJump(const MWWorld::Ptr& ptr) const
|
|
|
|
|
{
|
2014-12-02 18:42:13 +01:00
|
|
|
|
if (getEncumbrance(ptr) > getCapacity(ptr))
|
|
|
|
|
return 0.f;
|
|
|
|
|
|
2022-07-13 21:17:11 +02:00
|
|
|
|
const MWMechanics::NpcStats& stats = getNpcStats(ptr);
|
2020-10-09 20:34:36 +03:00
|
|
|
|
bool godmode = ptr == MWMechanics::getPlayer() && MWBase::Environment::get().getWorld()->getGodModeState();
|
|
|
|
|
if ((!godmode && stats.isParalyzed()) || stats.getKnockedDown() || stats.isDead())
|
2018-08-28 16:42:15 +03:00
|
|
|
|
return 0.f;
|
|
|
|
|
|
2014-06-19 02:09:46 +02:00
|
|
|
|
const GMST& gmst = getGmst();
|
2022-07-13 21:17:11 +02:00
|
|
|
|
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));
|
2013-02-24 03:30:33 -08:00
|
|
|
|
|
2018-12-23 15:18:33 +04:00
|
|
|
|
float a = getSkill(ptr, ESM::Skill::Acrobatics);
|
2013-02-24 03:30:33 -08:00
|
|
|
|
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();
|
2014-08-16 22:38:22 +02:00
|
|
|
|
x += mageffects.get(ESM::MagicEffect::Jump).getMagnitude() * 64;
|
2013-02-24 03:30:33 -08:00
|
|
|
|
x *= encumbranceTerm;
|
|
|
|
|
|
2018-08-28 16:42:15 +03:00
|
|
|
|
if (stats.getStance(MWMechanics::CreatureStats::Stance_Run))
|
2018-08-29 18:38:12 +03:00
|
|
|
|
x *= gmst.fJumpRunMultiplier->mValue.getFloat();
|
2022-07-13 21:17:11 +02:00
|
|
|
|
x *= stats.getFatigueTerm();
|
2018-09-17 14:52:43 +04:00
|
|
|
|
x -= -Constants::GravityConst * Constants::UnitsPerMeter;
|
2013-08-03 00:07:52 -07:00
|
|
|
|
x /= 3.0f;
|
2013-02-24 03:30:33 -08:00
|
|
|
|
|
|
|
|
|
return x;
|
|
|
|
|
}
|
|
|
|
|
|
2011-02-03 11:37:17 +01:00
|
|
|
|
MWMechanics::Movement& Npc::getMovementSettings(const MWWorld::Ptr& ptr) const
|
|
|
|
|
{
|
2012-01-27 13:17:30 +01:00
|
|
|
|
ensureCustomData(ptr);
|
2011-02-03 11:37:17 +01:00
|
|
|
|
|
2015-11-29 14:13:14 +01:00
|
|
|
|
return ptr.getRefData().getCustomData()->asNpcCustomData().mMovement;
|
2011-02-03 11:37:17 +01:00
|
|
|
|
}
|
|
|
|
|
|
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>();
|
2011-02-03 11:37:17 +01:00
|
|
|
|
|
2015-03-06 23:19:57 +13:00
|
|
|
|
return (ref->mBase->mFlags & ESM::NPC::Essential) != 0;
|
2012-10-27 13:33:54 +02:00
|
|
|
|
}
|
2014-02-01 17:36:23 +01:00
|
|
|
|
|
2015-12-19 16:13:00 +01:00
|
|
|
|
bool Npc::hasToolTip(const MWWorld::ConstPtr& ptr) const
|
|
|
|
|
{
|
2017-03-22 19:55:48 +09:00
|
|
|
|
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();
|
2017-07-26 14:42:01 +04:00
|
|
|
|
|
|
|
|
|
if (customData.mNpcStats.isDead() && customData.mNpcStats.isDeathAnimationFinished())
|
|
|
|
|
return true;
|
|
|
|
|
|
2020-07-26 13:02:12 +03:00
|
|
|
|
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
|
2012-04-16 22:58:16 +02:00
|
|
|
|
{
|
2015-12-18 15:27:06 +01:00
|
|
|
|
const MWWorld::LiveCellRef<ESM::NPC>* ref = ptr.get<ESM::NPC>();
|
2012-04-16 22:58:16 +02:00
|
|
|
|
|
2013-08-08 03:57:32 -07:00
|
|
|
|
bool fullHelp = MWBase::Environment::get().getWindowManager()->getFullHelp();
|
2012-04-16 22:58:16 +02:00
|
|
|
|
MWGui::ToolTipInfo info;
|
|
|
|
|
|
2022-08-16 21:15:03 +02:00
|
|
|
|
std::string_view name = getName(ptr);
|
2022-08-24 22:16:03 +02:00
|
|
|
|
info.caption = MyGUI::TextIterator::toTagsString(MWGui::toUString(name));
|
2019-09-10 21:56:10 +03:00
|
|
|
|
if (fullHelp && !ref->mBase->mName.empty() && ptr.getRefData().getCustomData()
|
|
|
|
|
&& ptr.getRefData().getCustomData()->asNpcCustomData().mNpcStats.isWerewolf())
|
2013-08-08 03:57:32 -07:00
|
|
|
|
{
|
|
|
|
|
info.caption += " (";
|
2019-08-17 21:53:52 +03:00
|
|
|
|
info.caption += MyGUI::TextIterator::toTagsString(ref->mBase->mName);
|
2013-08-08 03:57:32 -07:00
|
|
|
|
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");
|
2012-04-16 22:58:16 +02:00
|
|
|
|
|
|
|
|
|
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();
|
2018-07-26 18:06:36 +04:00
|
|
|
|
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
|
|
|
|
|
{
|
2013-08-10 20:25:18 -07:00
|
|
|
|
// According to UESP, inventory weight is ignored in werewolf form. Does that include
|
|
|
|
|
// feather and burden effects?
|
2015-08-25 18:19:16 +12:00
|
|
|
|
return getNpcStats(ptr).isWerewolf() ? 0.0f : Actor::getEncumbrance(ptr);
|
2012-05-15 21:34:00 +02:00
|
|
|
|
}
|
2012-07-13 09:16:27 +02:00
|
|
|
|
|
2022-05-12 17:29:12 +02:00
|
|
|
|
bool Npc::consume(const MWWorld::Ptr& consumable, const MWWorld::Ptr& actor) const
|
2012-07-13 09:16:27 +02:00
|
|
|
|
{
|
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();
|
2022-05-12 18:03:50 +02:00
|
|
|
|
MWBase::Environment::get().getLuaManager()->itemConsumed(consumable, actor);
|
2023-01-16 23:51:04 +01:00
|
|
|
|
actor.getClass().getContainerStore(actor).remove(consumable, 1);
|
2022-05-12 17:29:12 +02:00
|
|
|
|
return cast.cast(recordId);
|
2012-07-13 09:16:27 +02:00
|
|
|
|
}
|
|
|
|
|
|
2014-09-25 12:25:57 +02:00
|
|
|
|
void Npc::skillUsageSucceeded(const MWWorld::Ptr& ptr, int skill, int usageType, float extraFactor) const
|
2012-07-13 09:16:27 +02:00
|
|
|
|
{
|
|
|
|
|
MWMechanics::NpcStats& stats = getNpcStats(ptr);
|
|
|
|
|
|
2014-09-25 00:03:55 +02:00
|
|
|
|
if (stats.isWerewolf())
|
|
|
|
|
return;
|
|
|
|
|
|
2012-07-13 09:16:27 +02:00
|
|
|
|
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);
|
2012-07-13 09:16:27 +02:00
|
|
|
|
|
2014-09-25 12:25:57 +02:00
|
|
|
|
stats.useSkill(skill, *class_, usageType, extraFactor);
|
2012-07-13 09:16:27 +02:00
|
|
|
|
}
|
2012-07-17 10:32:18 +02:00
|
|
|
|
|
2013-03-17 22:29:12 +01:00
|
|
|
|
float Npc::getArmorRating(const MWWorld::Ptr& ptr) const
|
|
|
|
|
{
|
2023-04-20 13:37:01 +02:00
|
|
|
|
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
|
|
|
|
|
2013-07-27 09:31:16 -07:00
|
|
|
|
MWMechanics::NpcStats& stats = getNpcStats(ptr);
|
2017-02-27 21:50:10 +00:00
|
|
|
|
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();
|
2018-12-23 15:18:33 +04:00
|
|
|
|
float unarmoredSkill = getSkill(ptr, ESM::Skill::Unarmored);
|
2013-03-17 22:29:12 +01:00
|
|
|
|
|
2017-02-17 03:11:37 +01:00
|
|
|
|
float ratings[MWWorld::InventoryStore::Slots];
|
2013-07-27 09:31:16 -07:00
|
|
|
|
for (int i = 0; i < MWWorld::InventoryStore::Slots; i++)
|
2013-03-17 22:29:12 +01:00
|
|
|
|
{
|
2017-02-27 21:50:10 +00:00
|
|
|
|
MWWorld::ConstContainerStoreIterator it = invStore.getSlot(i);
|
2021-10-11 11:46:21 +00:00
|
|
|
|
if (it == invStore.end() || it->getType() != ESM::Armor::sRecordId)
|
2013-03-17 22:29:12 +01:00
|
|
|
|
{
|
|
|
|
|
// unarmored
|
2017-02-17 03:11:37 +01:00
|
|
|
|
ratings[i] = (fUnarmoredBase1 * unarmoredSkill) * (fUnarmoredBase2 * unarmoredSkill);
|
2013-03-17 22:29:12 +01:00
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
2015-03-01 19:28:20 +01:00
|
|
|
|
ratings[i] = it->getClass().getEffectiveArmorRating(*it, ptr);
|
2017-12-07 22:43:32 +04:00
|
|
|
|
|
|
|
|
|
// Take in account armor condition
|
|
|
|
|
const bool hasHealth = it->getClass().hasItemHealth(*it);
|
|
|
|
|
if (hasHealth)
|
|
|
|
|
{
|
2018-10-25 15:45:31 +03:00
|
|
|
|
ratings[i] *= it->getClass().getItemNormalizedHealth(*it);
|
2017-12-07 22:43:32 +04:00
|
|
|
|
}
|
2013-03-17 22:29:12 +01:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2014-08-16 22:38:22 +02:00
|
|
|
|
float shield = stats.getMagicEffects().get(ESM::MagicEffect::Shield).getMagnitude();
|
2013-03-17 22:29:12 +01:00
|
|
|
|
|
2013-07-27 09:31:16 -07: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])
|
2013-07-27 09:31:16 -07:00
|
|
|
|
* 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
|
|
|
|
{
|
2015-11-01 21:45:58 +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
|
|
|
|
|
2019-01-07 12:58:47 +04:00
|
|
|
|
// Race weight should not affect 1st-person meshes, otherwise it will change hand proportions and can break
|
|
|
|
|
// aiming.
|
2019-07-31 17:34:32 +03:00
|
|
|
|
if (ptr == MWMechanics::getPlayer() && ptr.isInCell() && MWBase::Environment::get().getWorld()->isFirstPerson())
|
2019-01-07 12:58:47 +04:00
|
|
|
|
{
|
|
|
|
|
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())
|
2015-04-24 14:49:20 +02:00
|
|
|
|
{
|
|
|
|
|
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
|
2015-04-24 14:49:20 +02:00
|
|
|
|
{
|
|
|
|
|
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
|
|
|
|
{
|
2022-10-08 17:00:33 +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);
|
2022-10-08 17:00:33 +02:00
|
|
|
|
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
|
|
|
|
{
|
2022-10-12 19:51:42 +02: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");
|
|
|
|
|
|
2014-10-06 18:48:22 +02:00
|
|
|
|
if (name == "left" || name == "right")
|
2013-07-17 23:58:21 -07:00
|
|
|
|
{
|
|
|
|
|
MWBase::World* world = MWBase::Environment::get().getWorld();
|
2019-04-04 17:19:25 +03:00
|
|
|
|
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());
|
2013-08-08 01:35:22 -07:00
|
|
|
|
if (world->isSwimming(ptr))
|
2022-10-18 09:26:55 +02:00
|
|
|
|
return (name == "left") ? swimLeft : swimRight;
|
2014-10-05 22:26:08 +02:00
|
|
|
|
if (world->isUnderwater(ptr.getCell(), pos) || world->isWalkingOnWater(ptr))
|
2022-10-18 09:26:55 +02:00
|
|
|
|
return (name == "left") ? footWaterLeft : footWaterRight;
|
2013-07-17 23:58:21 -07:00
|
|
|
|
if (world->isOnGround(ptr))
|
2013-07-18 18:01:01 -07:00
|
|
|
|
{
|
2018-10-28 17:03:38 +03:00
|
|
|
|
if (getNpcStats(ptr).isWerewolf()
|
|
|
|
|
&& getCreatureStats(ptr).getStance(MWMechanics::CreatureStats::Stance_Run))
|
2013-07-18 18:01:01 -07:00
|
|
|
|
{
|
2018-12-26 13:45:28 +04:00
|
|
|
|
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;
|
2013-07-18 18:01:01 -07:00
|
|
|
|
}
|
2014-10-06 18:48:22 +02:00
|
|
|
|
|
2017-02-27 21:50:10 +00:00
|
|
|
|
const MWWorld::InventoryStore& inv = Npc::getInventoryStore(ptr);
|
|
|
|
|
MWWorld::ConstContainerStoreIterator boots = inv.getSlot(MWWorld::InventoryStore::Slot_Boots);
|
2021-10-11 11:46:21 +00:00
|
|
|
|
if (boots == inv.end() || boots->getType() != ESM::Armor::sRecordId)
|
2022-10-18 09:26:55 +02:00
|
|
|
|
return (name == "left") ? footBareLeft : footBareRight;
|
2013-07-18 18:01:01 -07:00
|
|
|
|
|
2014-05-22 20:37:22 +02:00
|
|
|
|
switch (boots->getClass().getEquipmentSkill(*boots))
|
2013-07-18 18:01:01 -07:00
|
|
|
|
{
|
|
|
|
|
case ESM::Skill::LightArmor:
|
2022-10-18 09:26:55 +02:00
|
|
|
|
return (name == "left") ? footLightLeft : footLightRight;
|
|
|
|
|
break;
|
2013-07-18 18:01:01 -07:00
|
|
|
|
case ESM::Skill::MediumArmor:
|
2022-10-18 09:26:55 +02:00
|
|
|
|
return (name == "left") ? footMediumLeft : footMediumRight;
|
|
|
|
|
break;
|
2013-07-18 18:01:01 -07:00
|
|
|
|
case ESM::Skill::HeavyArmor:
|
2022-10-18 09:26:55 +02:00
|
|
|
|
return (name == "left") ? footHeavyLeft : footHeavyRight;
|
|
|
|
|
break;
|
2013-07-18 18:01:01 -07: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
|
|
|
|
return ESM::RefId::sEmpty;
|
2013-07-17 23:58:21 -07:00
|
|
|
|
}
|
2014-10-06 18:48:22 +02:00
|
|
|
|
|
2018-10-14 20:11:21 +03:00
|
|
|
|
// Morrowind ignores land soundgen for NPCs
|
2013-08-19 08:58:50 -07:00
|
|
|
|
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;
|
2013-08-08 01:35:22 -07:00
|
|
|
|
if (name == "swimleft")
|
2022-10-18 09:26:55 +02:00
|
|
|
|
return swimLeft;
|
2013-08-08 01:35:22 -07:00
|
|
|
|
if (name == "swimright")
|
2022-10-18 09:26:55 +02:00
|
|
|
|
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?
|
2014-12-14 19:35:34 +01:00
|
|
|
|
|
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
|
|
|
|
|
2022-10-18 09:26:55 +02: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
|
2012-07-25 17:18:17 +04:00
|
|
|
|
{
|
2015-12-18 16:24:24 +01:00
|
|
|
|
const MWWorld::LiveCellRef<ESM::NPC>* ref = ptr.get<ESM::NPC>();
|
2012-07-25 17:18:17 +04:00
|
|
|
|
|
2015-11-14 17:12:05 +01:00
|
|
|
|
return MWWorld::Ptr(cell.insert(ref), &cell);
|
2012-07-25 17:18:17 +04:00
|
|
|
|
}
|
2013-02-15 01:27:57 -08:00
|
|
|
|
|
2018-12-23 15:18:33 +04:00
|
|
|
|
float Npc::getSkill(const MWWorld::Ptr& ptr, int skill) const
|
2014-01-15 15:50:45 +01:00
|
|
|
|
{
|
2018-10-28 17:03:38 +03:00
|
|
|
|
return getNpcStats(ptr).getSkill(skill).getModified();
|
2014-01-15 15:50:45 +01:00
|
|
|
|
}
|
|
|
|
|
|
2015-12-18 16:38:14 +01:00
|
|
|
|
int Npc::getBloodTexture(const MWWorld::ConstPtr& ptr) const
|
2014-01-17 10:52:44 +01:00
|
|
|
|
{
|
2018-12-31 17:55:46 +03:00
|
|
|
|
return ptr.get<ESM::NPC>()->mBase->mBloodType;
|
2014-01-17 10:52:44 +01:00
|
|
|
|
}
|
|
|
|
|
|
2014-02-01 17:36:23 +01:00
|
|
|
|
void Npc::readAdditionalState(const MWWorld::Ptr& ptr, const ESM::ObjectState& state) const
|
|
|
|
|
{
|
2015-01-19 23:29:06 +01:00
|
|
|
|
if (!state.mHasCustomState)
|
|
|
|
|
return;
|
|
|
|
|
|
2021-08-17 12:29:28 +10:00
|
|
|
|
const ESM::NpcState& npcState = state.asNpcState();
|
|
|
|
|
|
2015-06-30 03:58:23 +02:00
|
|
|
|
if (state.mVersion > 0)
|
2014-06-18 22:59:18 +02:00
|
|
|
|
{
|
2015-06-30 03:58:23 +02:00
|
|
|
|
if (!ptr.getRefData().getCustomData())
|
|
|
|
|
{
|
2021-12-24 23:17:50 +01:00
|
|
|
|
if (npcState.mCreatureStats.mMissingACDT)
|
2021-08-17 12:29:28 +10:00
|
|
|
|
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
|
|
|
|
}
|
2014-06-18 22:59:18 +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.
|
2014-02-01 17:36:23 +01:00
|
|
|
|
|
2015-11-29 14:13:14 +01:00
|
|
|
|
NpcCustomData& customData = ptr.getRefData().getCustomData()->asNpcCustomData();
|
2021-08-17 12:29:28 +10:00
|
|
|
|
|
2020-03-17 14:15:19 +04:00
|
|
|
|
customData.mInventoryStore.readState(npcState.mInventory);
|
|
|
|
|
customData.mNpcStats.readState(npcState.mNpcStats);
|
2020-07-28 08:33:28 +02:00
|
|
|
|
bool spellsInitialised = customData.mNpcStats.getSpells().setSpells(ptr.get<ESM::NPC>()->mBase->mId);
|
|
|
|
|
if (spellsInitialised)
|
|
|
|
|
customData.mNpcStats.getSpells().clear();
|
2020-03-17 14:15:19 +04:00
|
|
|
|
customData.mNpcStats.readState(npcState.mCreatureStats);
|
2014-02-01 17:36:23 +01:00
|
|
|
|
}
|
|
|
|
|
|
2015-12-18 00:18:06 +01:00
|
|
|
|
void Npc::writeAdditionalState(const MWWorld::ConstPtr& ptr, ESM::ObjectState& state) const
|
2014-02-01 17:36:23 +01:00
|
|
|
|
{
|
2015-01-19 23:29:06 +01:00
|
|
|
|
if (!ptr.getRefData().getCustomData())
|
|
|
|
|
{
|
|
|
|
|
state.mHasCustomState = false;
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
2022-08-02 19:33:27 +02:00
|
|
|
|
const NpcCustomData& customData = ptr.getRefData().getCustomData()->asNpcCustomData();
|
|
|
|
|
if (ptr.getRefData().getCount() <= 0
|
|
|
|
|
&& (!(ptr.get<ESM::NPC>()->mBase->mFlags & ESM::NPC::Respawn) || !customData.mNpcStats.isDead()))
|
2020-03-04 15:14:22 +04:00
|
|
|
|
{
|
|
|
|
|
state.mHasCustomState = false;
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
2020-03-17 14:15:19 +04:00
|
|
|
|
ESM::NpcState& npcState = state.asNpcState();
|
|
|
|
|
customData.mInventoryStore.writeState(npcState.mInventory);
|
|
|
|
|
customData.mNpcStats.writeState(npcState.mNpcStats);
|
|
|
|
|
customData.mNpcStats.writeState(npcState.mCreatureStats);
|
2014-02-01 17:36:23 +01:00
|
|
|
|
}
|
|
|
|
|
|
2015-12-18 16:28:20 +01:00
|
|
|
|
int Npc::getBaseGold(const MWWorld::ConstPtr& ptr) const
|
2014-03-28 14:21:38 -04:00
|
|
|
|
{
|
2015-12-18 16:28:20 +01:00
|
|
|
|
const MWWorld::LiveCellRef<ESM::NPC>* ref = ptr.get<ESM::NPC>();
|
2018-05-09 00:25:07 +02:00
|
|
|
|
return ref->mBase->mNpdt.mGold;
|
2014-03-28 14:21:38 -04:00
|
|
|
|
}
|
|
|
|
|
|
2022-08-23 22:14:27 +02:00
|
|
|
|
bool Npc::isClass(const MWWorld::ConstPtr& ptr, std::string_view className) const
|
2014-04-01 14:15:55 -04:00
|
|
|
|
{
|
2023-03-01 22:48:00 +01: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;
|
|
|
|
|
}
|
|
|
|
|
|
2014-05-17 09:05:41 +02:00
|
|
|
|
void Npc::respawn(const MWWorld::Ptr& ptr) const
|
|
|
|
|
{
|
2018-10-28 17:03:38 +03:00
|
|
|
|
const MWMechanics::CreatureStats& creatureStats = getCreatureStats(ptr);
|
2016-02-27 12:53:07 +01:00
|
|
|
|
if (ptr.getRefData().getCount() > 0 && !creatureStats.isDead())
|
|
|
|
|
return;
|
|
|
|
|
|
2018-06-11 22:29:32 +04:00
|
|
|
|
if (!creatureStats.isDeathAnimationFinished())
|
|
|
|
|
return;
|
|
|
|
|
|
2016-02-27 12:53:07 +01:00
|
|
|
|
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();
|
2016-02-27 12:53:07 +01:00
|
|
|
|
|
|
|
|
|
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())
|
2014-05-17 09:05:41 +02:00
|
|
|
|
{
|
2015-01-11 12:20:22 +13:00
|
|
|
|
if (ptr.getCellRef().hasContentFile())
|
2014-05-17 09:05:41 +02:00
|
|
|
|
{
|
|
|
|
|
if (ptr.getRefData().getCount() == 0)
|
2019-08-06 21:30:21 +02:00
|
|
|
|
{
|
2014-05-17 09:05:41 +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);
|
|
|
|
|
}
|
2014-05-17 09:05:41 +02:00
|
|
|
|
|
2015-12-14 02:57:55 +01:00
|
|
|
|
MWBase::Environment::get().getWorld()->removeContainerScripts(ptr);
|
2021-07-15 22:31:26 +02:00
|
|
|
|
MWBase::Environment::get().getWindowManager()->onDeleteCustomData(ptr);
|
2018-10-09 10:21:12 +04:00
|
|
|
|
ptr.getRefData().setCustomData(nullptr);
|
2016-02-07 19:43:38 +01:00
|
|
|
|
|
|
|
|
|
// Reset to original position
|
2021-04-11 18:18:10 +02:00
|
|
|
|
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);
|
2014-05-17 09:05:41 +02:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2015-12-18 16:12:35 +01:00
|
|
|
|
int Npc::getBaseFightRating(const MWWorld::ConstPtr& ptr) const
|
2014-12-14 19:35:34 +01:00
|
|
|
|
{
|
2015-12-18 16:12:35 +01:00
|
|
|
|
const MWWorld::LiveCellRef<ESM::NPC>* ref = ptr.get<ESM::NPC>();
|
2014-12-14 19:35:34 +01:00
|
|
|
|
return ref->mBase->mAiData.mFight;
|
|
|
|
|
}
|
2014-12-28 15:34:47 +01:00
|
|
|
|
|
2015-12-18 16:15:40 +01:00
|
|
|
|
bool Npc::isBipedal(const MWWorld::ConstPtr& ptr) const
|
2014-12-28 15:34:47 +01:00
|
|
|
|
{
|
|
|
|
|
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
|
|
|
|
{
|
2015-12-18 16:33:54 +01:00
|
|
|
|
const MWWorld::LiveCellRef<ESM::NPC>* ref = ptr.get<ESM::NPC>();
|
2015-01-27 17:32:21 +01:00
|
|
|
|
return ref->mBase->mFaction;
|
|
|
|
|
}
|
|
|
|
|
|
2015-12-18 16:33:54 +01:00
|
|
|
|
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);
|
2019-05-14 10:12:40 +04:00
|
|
|
|
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
|
2015-12-18 16:33:54 +01:00
|
|
|
|
const MWWorld::LiveCellRef<ESM::NPC>* ref = ptr.get<ESM::NPC>();
|
2015-01-27 17:32:21 +01:00
|
|
|
|
return ref->mBase->getFactionRank();
|
|
|
|
|
}
|
2020-06-02 21:59:37 +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
|
|
|
|
void Npc::setBaseAISetting(const ESM::RefId& id, MWMechanics::AiSetting setting, int value) const
|
2020-06-02 21:59:37 +02:00
|
|
|
|
{
|
|
|
|
|
MWMechanics::setBaseAISetting<ESM::NPC>(id, setting, value);
|
|
|
|
|
}
|
2020-06-13 01:04:55 +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
|
|
|
|
void Npc::modifyBaseInventory(const ESM::RefId& actorId, const ESM::RefId& itemId, int amount) const
|
2020-07-26 11:07:18 +02:00
|
|
|
|
{
|
|
|
|
|
MWMechanics::modifyBaseInventory<ESM::NPC>(actorId, itemId, amount);
|
|
|
|
|
}
|
|
|
|
|
|
2020-06-13 01:04:55 +02:00
|
|
|
|
float Npc::getWalkSpeed(const MWWorld::Ptr& ptr) const
|
|
|
|
|
{
|
|
|
|
|
const GMST& gmst = getGmst();
|
2022-07-13 21:17:11 +02:00
|
|
|
|
const MWMechanics::NpcStats& stats = getNpcStats(ptr);
|
2020-06-13 01:04:55 +02:00
|
|
|
|
const float normalizedEncumbrance = getNormalizedEncumbrance(ptr);
|
|
|
|
|
const bool sneaking = MWBase::Environment::get().getMechanicsManager()->isSneaking(ptr);
|
|
|
|
|
|
|
|
|
|
float walkSpeed = gmst.fMinWalkSpeed->mValue.getFloat()
|
2022-07-13 21:17:11 +02:00
|
|
|
|
+ 0.01f * stats.getAttribute(ESM::Attribute::Speed).getModified()
|
2020-06-13 01:04:55 +02:00
|
|
|
|
* (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();
|
2022-07-13 21:17:11 +02:00
|
|
|
|
const MWMechanics::NpcStats& stats = getNpcStats(ptr);
|
|
|
|
|
const MWMechanics::MagicEffects& mageffects = stats.getMagicEffects();
|
2020-06-13 01:04:55 +02:00
|
|
|
|
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));
|
|
|
|
|
|
2020-06-14 18:01:22 +02:00
|
|
|
|
return getSwimSpeedImpl(ptr, getGmst(), mageffects, running ? getRunSpeed(ptr) : getWalkSpeed(ptr));
|
2020-06-13 01:04:55 +02:00
|
|
|
|
}
|
2010-08-03 13:03:08 +02:00
|
|
|
|
}
|