2012-08-11 17:30:55 +02:00
|
|
|
#include "mechanicsmanagerimp.hpp"
|
2015-05-30 01:00:24 +02:00
|
|
|
|
2023-08-31 10:30:37 +04:00
|
|
|
#include <cassert>
|
|
|
|
|
2020-05-22 00:11:23 +02:00
|
|
|
#include <osg/Stats>
|
|
|
|
|
2015-04-22 17:58:55 +02:00
|
|
|
#include <components/misc/rng.hpp>
|
2015-03-15 14:07:47 +13:00
|
|
|
|
2022-09-05 19:35:15 +02:00
|
|
|
#include <components/esm/records.hpp>
|
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
|
|
|
#include <components/esm/refid.hpp>
|
2022-01-22 15:58:41 +01:00
|
|
|
#include <components/esm3/esmwriter.hpp>
|
2022-09-05 19:35:15 +02:00
|
|
|
#include <components/esm3/loadgmst.hpp>
|
|
|
|
#include <components/esm3/loadmgef.hpp>
|
|
|
|
#include <components/esm3/stolenitems.hpp>
|
2015-02-04 21:18:43 +01:00
|
|
|
|
2015-11-20 21:57:04 +01:00
|
|
|
#include <components/sceneutil/positionattitudetransform.hpp>
|
|
|
|
|
2016-06-17 23:07:16 +09:00
|
|
|
#include "../mwworld/class.hpp"
|
2012-10-01 19:17:04 +04:00
|
|
|
#include "../mwworld/esmstore.hpp"
|
2023-02-07 00:37:55 +01:00
|
|
|
#include "../mwworld/globals.hpp"
|
2013-03-16 22:53:33 +01:00
|
|
|
#include "../mwworld/inventorystore.hpp"
|
2016-06-17 23:07:16 +09:00
|
|
|
#include "../mwworld/player.hpp"
|
2017-08-18 17:06:47 +04:00
|
|
|
#include "../mwworld/ptr.hpp"
|
2010-07-26 11:15:38 +02:00
|
|
|
|
2012-11-10 00:42:31 +01:00
|
|
|
#include "../mwbase/dialoguemanager.hpp"
|
2012-04-23 15:27:03 +02:00
|
|
|
#include "../mwbase/environment.hpp"
|
2023-08-18 11:03:37 +04:00
|
|
|
#include "../mwbase/soundmanager.hpp"
|
2018-10-28 15:08:24 +04:00
|
|
|
#include "../mwbase/statemanager.hpp"
|
2012-08-12 18:11:09 +02:00
|
|
|
#include "../mwbase/windowmanager.hpp"
|
2012-11-10 00:42:31 +01:00
|
|
|
#include "../mwbase/world.hpp"
|
2012-04-23 15:27:03 +02:00
|
|
|
|
2022-05-18 19:24:57 +02:00
|
|
|
#include "actor.hpp"
|
2015-08-21 21:12:39 +12:00
|
|
|
#include "actorutil.hpp"
|
2016-06-17 23:07:16 +09:00
|
|
|
#include "aicombat.hpp"
|
|
|
|
#include "aipursue.hpp"
|
2014-07-11 07:31:18 +02:00
|
|
|
#include "autocalcspell.hpp"
|
2016-11-16 20:15:25 +01:00
|
|
|
#include "combat.hpp"
|
2022-05-18 19:24:57 +02:00
|
|
|
#include "npcstats.hpp"
|
2020-04-26 20:46:51 +03:00
|
|
|
#include "spellutil.hpp"
|
2014-08-30 23:11:09 +02:00
|
|
|
|
2014-12-21 02:45:37 +01:00
|
|
|
namespace
|
|
|
|
{
|
|
|
|
|
|
|
|
float getFightDispositionBias(float disposition)
|
|
|
|
{
|
|
|
|
static const float fFightDispMult = MWBase::Environment::get()
|
2023-04-20 21:07:53 +02:00
|
|
|
.getESMStore()
|
|
|
|
->get<ESM::GameSetting>()
|
2018-08-29 18:38:12 +03:00
|
|
|
.find("fFightDispMult")
|
|
|
|
->mValue.getFloat();
|
2014-12-21 02:45:37 +01:00
|
|
|
return ((50.f - disposition) * fFightDispMult);
|
|
|
|
}
|
|
|
|
|
2015-04-22 01:17:01 +02:00
|
|
|
void getPersuasionRatings(
|
|
|
|
const MWMechanics::NpcStats& stats, float& rating1, float& rating2, float& rating3, bool player)
|
|
|
|
{
|
|
|
|
const MWWorld::Store<ESM::GameSetting>& gmst
|
2023-04-20 21:07:53 +02:00
|
|
|
= MWBase::Environment::get().getESMStore()->get<ESM::GameSetting>();
|
2015-04-22 01:17:01 +02:00
|
|
|
|
2018-08-29 18:38:12 +03:00
|
|
|
float persTerm = stats.getAttribute(ESM::Attribute::Personality).getModified()
|
|
|
|
/ gmst.find("fPersonalityMod")->mValue.getFloat();
|
|
|
|
float luckTerm
|
|
|
|
= stats.getAttribute(ESM::Attribute::Luck).getModified() / gmst.find("fLuckMod")->mValue.getFloat();
|
|
|
|
float repTerm = stats.getReputation() * gmst.find("fReputationMod")->mValue.getFloat();
|
2015-04-22 01:17:01 +02:00
|
|
|
float fatigueTerm = stats.getFatigueTerm();
|
2018-08-29 18:38:12 +03:00
|
|
|
float levelTerm = stats.getLevel() * gmst.find("fLevelMod")->mValue.getFloat();
|
2015-04-22 01:17:01 +02:00
|
|
|
|
|
|
|
rating1 = (repTerm + luckTerm + persTerm + stats.getSkill(ESM::Skill::Speechcraft).getModified()) * fatigueTerm;
|
|
|
|
|
|
|
|
if (player)
|
|
|
|
{
|
|
|
|
rating2 = rating1 + levelTerm;
|
|
|
|
rating3 = (stats.getSkill(ESM::Skill::Mercantile).getModified() + luckTerm + persTerm) * fatigueTerm;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
rating2
|
|
|
|
= (levelTerm + repTerm + luckTerm + persTerm + stats.getSkill(ESM::Skill::Speechcraft).getModified())
|
|
|
|
* fatigueTerm;
|
|
|
|
rating3
|
|
|
|
= (stats.getSkill(ESM::Skill::Mercantile).getModified() + repTerm + luckTerm + persTerm) * fatigueTerm;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-12-14 21:06:40 +01:00
|
|
|
bool isOwned(const MWWorld::Ptr& ptr, const MWWorld::Ptr& target, MWWorld::Ptr& victim)
|
|
|
|
{
|
|
|
|
const MWWorld::CellRef& cellref = target.getCellRef();
|
|
|
|
|
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& owner = cellref.getOwner();
|
2022-10-18 09:26:55 +02:00
|
|
|
bool isOwned = !owner.empty() && owner != ESM::RefId::stringRefId("Player");
|
2021-12-14 21:06:40 +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& faction = cellref.getFaction();
|
2021-12-14 21:06:40 +01:00
|
|
|
bool isFactionOwned = false;
|
|
|
|
if (!faction.empty() && ptr.getClass().isNpc())
|
|
|
|
{
|
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 std::map<ESM::RefId, int>& factions = ptr.getClass().getNpcStats(ptr).getFactionRanks();
|
|
|
|
auto found = factions.find(faction);
|
2021-12-14 21:06:40 +01:00
|
|
|
if (found == factions.end() || found->second < cellref.getFactionRank())
|
|
|
|
isFactionOwned = true;
|
|
|
|
}
|
|
|
|
|
|
|
|
const std::string& globalVariable = cellref.getGlobalVariable();
|
|
|
|
if (!globalVariable.empty() && MWBase::Environment::get().getWorld()->getGlobalInt(globalVariable))
|
|
|
|
{
|
|
|
|
isOwned = false;
|
|
|
|
isFactionOwned = false;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!cellref.getOwner().empty())
|
|
|
|
victim = MWBase::Environment::get().getWorld()->searchPtr(cellref.getOwner(), true, false);
|
|
|
|
|
|
|
|
return isOwned || isFactionOwned;
|
|
|
|
}
|
2014-12-21 02:45:37 +01:00
|
|
|
}
|
|
|
|
|
2010-07-26 11:15:38 +02:00
|
|
|
namespace MWMechanics
|
2010-07-28 18:48:01 +02:00
|
|
|
{
|
2010-09-15 13:31:26 +02:00
|
|
|
void MechanicsManager::buildPlayer()
|
|
|
|
{
|
2015-08-21 21:12:39 +12:00
|
|
|
MWWorld::Ptr ptr = getPlayer();
|
2010-09-15 13:31:26 +02:00
|
|
|
|
2014-05-22 20:37:22 +02:00
|
|
|
MWMechanics::CreatureStats& creatureStats = ptr.getClass().getCreatureStats(ptr);
|
|
|
|
MWMechanics::NpcStats& npcStats = ptr.getClass().getNpcStats(ptr);
|
2010-09-15 13:31:26 +02:00
|
|
|
|
2021-10-25 16:54:50 +02:00
|
|
|
npcStats.recalculateMagicka();
|
2017-04-13 10:13:58 +04:00
|
|
|
|
2012-11-05 16:07:59 +04:00
|
|
|
const ESM::NPC* player = ptr.get<ESM::NPC>()->mBase;
|
2010-09-15 13:31:26 +02:00
|
|
|
|
|
|
|
// reset
|
2018-05-09 00:25:07 +02:00
|
|
|
creatureStats.setLevel(player->mNpdt.mLevel);
|
2020-07-28 08:33:28 +02:00
|
|
|
creatureStats.getSpells().clear(true);
|
2021-08-27 20:07:50 +02:00
|
|
|
creatureStats.getActiveSpells().clear(ptr);
|
2010-09-15 13:31:26 +02:00
|
|
|
|
2023-06-03 13:27:45 +02:00
|
|
|
for (size_t i = 0; i < player->mNpdt.mSkills.size(); ++i)
|
2023-06-05 21:21:30 +02:00
|
|
|
npcStats.getSkill(ESM::Skill::indexToRefId(i)).setBase(player->mNpdt.mSkills[i]);
|
2018-05-09 00:25:07 +02:00
|
|
|
|
2023-12-17 15:16:32 +01:00
|
|
|
for (size_t i = 0; i < player->mNpdt.mAttributes.size(); ++i)
|
|
|
|
npcStats.setAttribute(ESM::Attribute::indexToRefId(i), player->mNpdt.mSkills[i]);
|
|
|
|
|
2023-04-20 21:07:53 +02:00
|
|
|
const MWWorld::ESMStore& esmStore = *MWBase::Environment::get().getESMStore();
|
2012-05-28 11:37:56 +02:00
|
|
|
|
2010-09-15 13:31:26 +02:00
|
|
|
// race
|
2010-09-26 10:01:30 +02:00
|
|
|
if (mRaceSelected)
|
|
|
|
{
|
2012-12-09 00:12:24 +01:00
|
|
|
const ESM::Race* race = esmStore.get<ESM::Race>().find(player->mRace);
|
2010-09-15 15:10:13 +02:00
|
|
|
|
2012-11-08 16:37:57 +04:00
|
|
|
bool male = (player->mFlags & ESM::NPC::Female) == 0;
|
2010-09-15 15:10:13 +02:00
|
|
|
|
2023-06-19 20:41:54 +02:00
|
|
|
for (const ESM::Attribute& attribute : esmStore.get<ESM::Attribute>())
|
2023-12-17 13:00:14 +01:00
|
|
|
creatureStats.setAttribute(attribute.mId, race->mData.getAttribute(attribute.mId, male));
|
2010-09-16 10:45:08 +02:00
|
|
|
|
2023-06-05 16:45:45 +02:00
|
|
|
for (const ESM::Skill& skill : esmStore.get<ESM::Skill>())
|
2010-09-16 10:45:08 +02:00
|
|
|
{
|
2012-08-16 15:42:37 +02:00
|
|
|
int bonus = 0;
|
2023-06-15 20:49:14 +02:00
|
|
|
int index = ESM::Skill::refIdToIndex(skill.mId);
|
2023-06-03 10:45:32 +02:00
|
|
|
auto bonusIt = std::find_if(race->mData.mBonus.begin(), race->mData.mBonus.end(),
|
2023-06-15 20:49:14 +02:00
|
|
|
[&](const auto& bonus) { return bonus.mSkill == index; });
|
2023-06-03 10:45:32 +02:00
|
|
|
if (bonusIt != race->mData.mBonus.end())
|
|
|
|
bonus = bonusIt->mBonus;
|
2012-12-09 00:12:24 +01:00
|
|
|
|
2023-06-05 21:21:30 +02:00
|
|
|
npcStats.getSkill(skill.mId).setBase(5 + bonus);
|
2010-09-16 10:45:08 +02:00
|
|
|
}
|
2010-09-26 10:01:30 +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
|
|
|
for (const ESM::RefId& power : race->mPowers.mList)
|
2010-09-30 14:28:01 +02:00
|
|
|
{
|
2018-11-06 01:35:20 +03:00
|
|
|
creatureStats.getSpells().add(power);
|
2010-09-30 14:28:01 +02:00
|
|
|
}
|
2010-09-16 10:45:08 +02:00
|
|
|
}
|
2010-09-15 15:10:13 +02:00
|
|
|
|
2010-09-15 13:31:26 +02:00
|
|
|
// birthsign
|
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& signId = MWBase::Environment::get().getWorld()->getPlayer().getBirthSign();
|
2012-11-08 18:50:18 +04:00
|
|
|
|
|
|
|
if (!signId.empty())
|
2010-09-26 10:01:30 +02:00
|
|
|
{
|
2012-11-08 18:50:18 +04:00
|
|
|
const ESM::BirthSign* sign = esmStore.get<ESM::BirthSign>().find(signId);
|
2010-09-30 14:28:01 +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
|
|
|
for (const ESM::RefId& power : sign->mPowers.mList)
|
2010-09-30 14:28:01 +02:00
|
|
|
{
|
2018-11-06 01:35:20 +03:00
|
|
|
creatureStats.getSpells().add(power);
|
2010-09-30 14:28:01 +02:00
|
|
|
}
|
2010-09-26 10:01:30 +02:00
|
|
|
}
|
2010-09-15 13:31:26 +02:00
|
|
|
|
|
|
|
// class
|
2010-09-26 10:01:30 +02:00
|
|
|
if (mClassSelected)
|
2010-09-15 15:23:38 +02:00
|
|
|
{
|
2012-11-08 16:37:57 +04:00
|
|
|
const ESM::Class* class_ = esmStore.get<ESM::Class>().find(player->mClass);
|
2010-09-26 10:01:30 +02:00
|
|
|
|
2023-06-03 11:58:09 +02:00
|
|
|
for (int attribute : class_->mData.mAttribute)
|
2010-09-15 15:23:38 +02:00
|
|
|
{
|
2023-08-03 20:21:44 +02:00
|
|
|
ESM::RefId id = ESM::Attribute::indexToRefId(attribute);
|
|
|
|
if (!id.empty())
|
2023-06-19 20:41:54 +02:00
|
|
|
creatureStats.setAttribute(id, creatureStats.getAttribute(id).getBase() + 10);
|
2010-09-15 15:23:38 +02:00
|
|
|
}
|
2010-09-26 09:55:00 +02:00
|
|
|
|
2010-09-26 10:01:30 +02:00
|
|
|
for (int i = 0; i < 2; ++i)
|
2010-09-26 09:55:00 +02:00
|
|
|
{
|
2010-09-26 10:01:30 +02:00
|
|
|
int bonus = i == 0 ? 10 : 25;
|
2010-09-26 09:55:00 +02:00
|
|
|
|
2023-06-03 11:58:09 +02:00
|
|
|
for (const auto& skills : class_->mData.mSkills)
|
2010-09-26 09:55:00 +02:00
|
|
|
{
|
2023-06-05 21:21:30 +02:00
|
|
|
ESM::RefId id = ESM::Skill::indexToRefId(skills[i]);
|
|
|
|
if (!id.empty())
|
|
|
|
npcStats.getSkill(id).setBase(npcStats.getSkill(id).getBase() + bonus);
|
2010-09-26 09:55:00 +02:00
|
|
|
}
|
|
|
|
}
|
2010-09-15 13:31:26 +02:00
|
|
|
|
2023-06-05 12:41:01 +02:00
|
|
|
for (const ESM::Skill& skill : esmStore.get<ESM::Skill>())
|
2010-09-26 09:55:00 +02:00
|
|
|
{
|
2023-06-05 12:41:01 +02:00
|
|
|
if (skill.mData.mSpecialization == class_->mData.mSpecialization)
|
2023-06-05 21:21:30 +02:00
|
|
|
npcStats.getSkill(skill.mId).setBase(npcStats.getSkill(skill.mId).getBase() + 5);
|
2010-09-26 09:55:00 +02:00
|
|
|
}
|
|
|
|
}
|
2012-05-18 13:54:07 +02:00
|
|
|
|
2014-07-11 07:31:18 +02:00
|
|
|
// F_PCStart spells
|
2018-10-09 10:21:12 +04:00
|
|
|
const ESM::Race* race = nullptr;
|
2014-07-11 07:31:18 +02:00
|
|
|
if (mRaceSelected)
|
|
|
|
race = esmStore.get<ESM::Race>().find(player->mRace);
|
|
|
|
|
2021-08-27 20:07:50 +02:00
|
|
|
npcStats.updateHealth();
|
2014-07-11 07:31:18 +02:00
|
|
|
|
2023-06-19 20:41:54 +02:00
|
|
|
std::vector<ESM::RefId> selectedSpells
|
|
|
|
= autoCalcPlayerSpells(npcStats.getSkills(), npcStats.getAttributes(), race);
|
2014-07-11 07:31:18 +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
|
|
|
for (const ESM::RefId& spell : selectedSpells)
|
2018-11-06 01:35:20 +03:00
|
|
|
creatureStats.getSpells().add(spell);
|
2014-07-11 07:31:18 +02:00
|
|
|
|
2012-05-18 13:54:07 +02:00
|
|
|
// forced update and current value adjustments
|
2015-10-05 23:07:13 +10:00
|
|
|
mActors.updateActor(ptr, 0);
|
2012-05-18 13:54:07 +02:00
|
|
|
|
2013-04-07 16:18:40 +02:00
|
|
|
for (int i = 0; i < 3; ++i)
|
2012-10-19 13:10:06 +02:00
|
|
|
{
|
|
|
|
DynamicStat<float> stat = creatureStats.getDynamic(i);
|
2022-02-10 20:46:20 +01:00
|
|
|
stat.setCurrent(stat.getModified());
|
2012-10-19 13:10:06 +02:00
|
|
|
creatureStats.setDynamic(i, stat);
|
|
|
|
}
|
2013-04-15 02:56:23 +02:00
|
|
|
|
2014-01-19 11:42:58 +01:00
|
|
|
// auto-equip again. we need this for when the race is changed to a beast race and shoes are no longer
|
|
|
|
// equippable
|
|
|
|
MWWorld::InventoryStore& invStore = ptr.getClass().getInventoryStore(ptr);
|
2013-04-15 02:56:23 +02:00
|
|
|
for (int i = 0; i < MWWorld::InventoryStore::Slots; ++i)
|
2023-01-16 23:51:04 +01:00
|
|
|
invStore.unequipAll();
|
|
|
|
invStore.autoEquip();
|
2010-09-15 13:31:26 +02:00
|
|
|
}
|
|
|
|
|
2012-04-23 15:27:03 +02:00
|
|
|
MechanicsManager::MechanicsManager()
|
2020-06-05 18:22:53 +04:00
|
|
|
: mUpdatePlayer(true)
|
|
|
|
, mClassSelected(false)
|
2013-11-18 23:03:44 +01:00
|
|
|
, mRaceSelected(false)
|
|
|
|
, mAI(true)
|
2023-08-18 11:03:37 +04:00
|
|
|
, mMusicType(MWSound::MusicType::Special)
|
2010-07-26 11:15:38 +02:00
|
|
|
{
|
2016-12-14 16:39:33 +01:00
|
|
|
// buildPlayer no longer here, needs to be done explicitly after all subsystems are up and running
|
2010-07-26 11:15:38 +02:00
|
|
|
}
|
|
|
|
|
2013-01-28 23:39:11 -08:00
|
|
|
void MechanicsManager::add(const MWWorld::Ptr& ptr)
|
2010-07-27 14:05:05 +02:00
|
|
|
{
|
2014-05-22 20:37:22 +02:00
|
|
|
if (ptr.getClass().isActor())
|
2013-01-28 23:39:11 -08:00
|
|
|
mActors.addActor(ptr);
|
2013-03-31 15:12:10 -07:00
|
|
|
else
|
2013-03-31 15:29:41 -07:00
|
|
|
mObjects.addObject(ptr);
|
2010-07-27 14:05:05 +02:00
|
|
|
}
|
2010-07-28 18:48:01 +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 MechanicsManager::castSpell(const MWWorld::Ptr& ptr, const ESM::RefId& spellId, bool manualSpell)
|
2018-06-28 16:58:51 +04:00
|
|
|
{
|
|
|
|
if (ptr.getClass().isActor())
|
|
|
|
mActors.castSpell(ptr, spellId, manualSpell);
|
|
|
|
}
|
|
|
|
|
2021-08-28 14:36:30 +02:00
|
|
|
void MechanicsManager::remove(const MWWorld::Ptr& ptr, bool keepActive)
|
2010-07-27 14:43:46 +02:00
|
|
|
{
|
2020-06-05 18:22:53 +04:00
|
|
|
if (ptr == MWBase::Environment::get().getWindowManager()->getWatchedActor())
|
|
|
|
MWBase::Environment::get().getWindowManager()->watchActor(MWWorld::Ptr());
|
2021-08-28 14:36:30 +02:00
|
|
|
mActors.removeActor(ptr, keepActive);
|
2013-03-31 15:29:41 -07:00
|
|
|
mObjects.removeObject(ptr);
|
2010-07-27 14:43:46 +02:00
|
|
|
}
|
2010-07-28 18:48:01 +02:00
|
|
|
|
2013-02-25 09:57:34 -08:00
|
|
|
void MechanicsManager::updateCell(const MWWorld::Ptr& old, const MWWorld::Ptr& ptr)
|
2013-01-29 00:19:24 -08:00
|
|
|
{
|
2020-06-05 18:22:53 +04:00
|
|
|
if (old == MWBase::Environment::get().getWindowManager()->getWatchedActor())
|
|
|
|
MWBase::Environment::get().getWindowManager()->watchActor(ptr);
|
2013-08-27 17:22:07 -07:00
|
|
|
|
2014-05-22 20:37:22 +02:00
|
|
|
if (ptr.getClass().isActor())
|
2013-02-25 09:57:34 -08:00
|
|
|
mActors.updateActor(old, ptr);
|
2013-03-31 15:12:10 -07:00
|
|
|
else
|
2013-03-31 15:29:41 -07:00
|
|
|
mObjects.updateObject(old, ptr);
|
2013-01-29 00:19:24 -08:00
|
|
|
}
|
|
|
|
|
2013-01-28 23:39:11 -08:00
|
|
|
void MechanicsManager::drop(const MWWorld::CellStore* cellStore)
|
2010-07-27 14:05:05 +02:00
|
|
|
{
|
2020-06-05 18:22:53 +04:00
|
|
|
mActors.dropActors(cellStore, getPlayer());
|
2013-03-31 15:29:41 -07:00
|
|
|
mObjects.dropObjects(cellStore);
|
2010-07-27 14:05:05 +02:00
|
|
|
}
|
2010-07-28 18:48:01 +02:00
|
|
|
|
2013-01-28 23:39:11 -08:00
|
|
|
void MechanicsManager::update(float duration, bool paused)
|
2010-07-27 15:59:41 +02:00
|
|
|
{
|
2020-07-11 20:40:00 +04:00
|
|
|
// Note: we should do it here since game mechanics and world updates use these values
|
|
|
|
MWWorld::Ptr ptr = getPlayer();
|
|
|
|
MWBase::WindowManager* winMgr = MWBase::Environment::get().getWindowManager();
|
|
|
|
|
|
|
|
MWWorld::InventoryStore& inv = ptr.getClass().getInventoryStore(ptr);
|
|
|
|
MWWorld::ContainerStoreIterator weapon = inv.getSlot(MWWorld::InventoryStore::Slot_CarriedRight);
|
|
|
|
|
|
|
|
// Update the selected spell icon
|
|
|
|
MWWorld::ContainerStoreIterator enchantItem = inv.getSelectedEnchantItem();
|
|
|
|
if (enchantItem != inv.end())
|
|
|
|
winMgr->setSelectedEnchantItem(*enchantItem);
|
|
|
|
else
|
|
|
|
{
|
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& spell = winMgr->getSelectedSpell();
|
2020-07-11 20:40:00 +04:00
|
|
|
if (!spell.empty())
|
|
|
|
winMgr->setSelectedSpell(spell, int(MWMechanics::getSpellSuccessChance(spell, ptr)));
|
|
|
|
else
|
|
|
|
winMgr->unsetSelectedSpell();
|
|
|
|
}
|
|
|
|
|
2021-11-29 19:04:34 +08:00
|
|
|
// Update the equipped weapon icon
|
|
|
|
if (weapon == inv.end())
|
|
|
|
winMgr->unsetSelectedWeapon();
|
|
|
|
else
|
|
|
|
winMgr->setSelectedWeapon(*weapon);
|
|
|
|
|
2010-09-15 14:33:02 +02:00
|
|
|
if (mUpdatePlayer)
|
2010-09-15 12:22:06 +02:00
|
|
|
{
|
2010-09-15 14:33:02 +02:00
|
|
|
mUpdatePlayer = false;
|
2010-09-21 17:42:07 +02:00
|
|
|
|
2013-02-04 12:58:06 -08:00
|
|
|
// HACK? The player has been changed, so a new Animation object may
|
|
|
|
// have been made for them. Make sure they're properly updated.
|
2021-08-28 14:36:30 +02:00
|
|
|
mActors.removeActor(ptr, true);
|
2015-04-25 15:19:17 +02:00
|
|
|
mActors.addActor(ptr, true);
|
2010-09-15 12:22:06 +02:00
|
|
|
}
|
2011-02-03 11:43:29 +01:00
|
|
|
|
2015-04-25 15:19:17 +02:00
|
|
|
mActors.update(duration, paused);
|
|
|
|
mObjects.update(duration, paused);
|
2023-08-18 11:03:37 +04:00
|
|
|
|
|
|
|
updateMusicState();
|
2010-07-27 14:46:05 +02:00
|
|
|
}
|
2010-09-13 22:59:28 +02:00
|
|
|
|
2018-09-21 16:34:23 +04:00
|
|
|
void MechanicsManager::processChangedSettings(const Settings::CategorySettingVector& changed)
|
|
|
|
{
|
|
|
|
for (Settings::CategorySettingVector::const_iterator it = changed.begin(); it != changed.end(); ++it)
|
|
|
|
{
|
|
|
|
if (it->first == "Game" && it->second == "actors processing range")
|
|
|
|
{
|
2018-10-28 15:08:24 +04:00
|
|
|
int state = MWBase::Environment::get().getStateManager()->getState();
|
|
|
|
if (state != MWBase::StateManager::State_Running)
|
|
|
|
continue;
|
|
|
|
|
2018-09-21 16:34:23 +04:00
|
|
|
// Update mechanics for new processing range immediately
|
|
|
|
update(0.f, false);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-08-27 22:42:41 +04:00
|
|
|
void MechanicsManager::notifyDied(const MWWorld::Ptr& actor)
|
|
|
|
{
|
|
|
|
mActors.notifyDied(actor);
|
|
|
|
}
|
|
|
|
|
2017-09-18 21:46:57 +04:00
|
|
|
bool MechanicsManager::isActorDetected(const MWWorld::Ptr& actor, const MWWorld::Ptr& observer)
|
|
|
|
{
|
|
|
|
return mActors.isActorDetected(actor, observer);
|
|
|
|
}
|
|
|
|
|
2018-08-16 17:47:06 +04:00
|
|
|
bool MechanicsManager::isAttackPreparing(const MWWorld::Ptr& ptr)
|
2017-09-01 09:34:15 +04:00
|
|
|
{
|
2018-08-16 17:47:06 +04:00
|
|
|
return mActors.isAttackPreparing(ptr);
|
2017-09-01 09:34:15 +04:00
|
|
|
}
|
|
|
|
|
2017-08-16 20:30:47 +04:00
|
|
|
bool MechanicsManager::isRunning(const MWWorld::Ptr& ptr)
|
|
|
|
{
|
|
|
|
return mActors.isRunning(ptr);
|
|
|
|
}
|
|
|
|
|
|
|
|
bool MechanicsManager::isSneaking(const MWWorld::Ptr& ptr)
|
|
|
|
{
|
2019-07-30 20:58:19 +03:00
|
|
|
CreatureStats& stats = ptr.getClass().getCreatureStats(ptr);
|
|
|
|
MWBase::World* world = MWBase::Environment::get().getWorld();
|
|
|
|
bool animActive = mActors.isSneaking(ptr);
|
|
|
|
bool stanceOn = stats.getStance(MWMechanics::CreatureStats::Stance_Sneak);
|
|
|
|
bool inair = !world->isOnGround(ptr) && !world->isSwimming(ptr) && !world->isFlying(ptr);
|
|
|
|
return stanceOn && (animActive || inair);
|
2017-08-16 20:30:47 +04:00
|
|
|
}
|
|
|
|
|
2019-01-25 20:04:35 +04:00
|
|
|
void MechanicsManager::rest(double hours, bool sleep)
|
2012-09-21 17:53:16 +02:00
|
|
|
{
|
2018-09-23 22:03:43 +04:00
|
|
|
if (sleep)
|
2019-01-25 20:04:35 +04:00
|
|
|
MWBase::Environment::get().getWorld()->rest(hours);
|
2018-09-23 22:03:43 +04:00
|
|
|
|
2019-01-25 20:04:35 +04:00
|
|
|
mActors.rest(hours, sleep);
|
2012-09-21 17:53:16 +02:00
|
|
|
}
|
|
|
|
|
2021-06-23 23:13:59 +02:00
|
|
|
void MechanicsManager::restoreDynamicStats(const MWWorld::Ptr& actor, double hours, bool sleep)
|
2018-09-23 22:03:43 +04:00
|
|
|
{
|
2019-01-25 20:04:35 +04:00
|
|
|
mActors.restoreDynamicStats(actor, hours, sleep);
|
2018-09-23 22:03:43 +04:00
|
|
|
}
|
|
|
|
|
2014-01-14 02:52:34 +01:00
|
|
|
int MechanicsManager::getHoursToRest() const
|
|
|
|
{
|
2020-06-05 18:22:53 +04:00
|
|
|
return mActors.getHoursToRest(getPlayer());
|
2014-01-14 02:52:34 +01:00
|
|
|
}
|
|
|
|
|
2010-09-13 22:59:28 +02:00
|
|
|
void MechanicsManager::setPlayerName(const std::string& name)
|
|
|
|
{
|
2012-11-08 16:37:57 +04:00
|
|
|
MWBase::World* world = MWBase::Environment::get().getWorld();
|
|
|
|
|
2014-01-08 18:39:44 +01:00
|
|
|
ESM::NPC player = *world->getPlayerPtr().get<ESM::NPC>()->mBase;
|
2012-11-08 16:37:57 +04:00
|
|
|
player.mName = name;
|
|
|
|
|
2023-04-20 13:37:01 +02:00
|
|
|
world->getStore().insert(player);
|
2012-11-08 16:37:57 +04:00
|
|
|
|
2010-09-15 14:33:02 +02:00
|
|
|
mUpdatePlayer = true;
|
2010-09-13 22:59:28 +02:00
|
|
|
}
|
|
|
|
|
2012-11-10 11:41:12 +04:00
|
|
|
void MechanicsManager::setPlayerRace(
|
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& race, bool male, const ESM::RefId& head, const ESM::RefId& hair)
|
2010-09-13 22:59:28 +02:00
|
|
|
{
|
2012-11-08 16:37:57 +04:00
|
|
|
MWBase::World* world = MWBase::Environment::get().getWorld();
|
|
|
|
|
2014-01-08 18:39:44 +01:00
|
|
|
ESM::NPC player = *world->getPlayerPtr().get<ESM::NPC>()->mBase;
|
2012-11-08 16:37:57 +04:00
|
|
|
|
2023-08-12 12:25:58 +02:00
|
|
|
if (player.mRace != race || player.mHead != head || player.mHair != hair || player.isMale() != male)
|
|
|
|
{
|
|
|
|
player.mRace = race;
|
|
|
|
player.mHead = head;
|
|
|
|
player.mHair = hair;
|
|
|
|
player.setIsMale(male);
|
2012-11-08 16:37:57 +04:00
|
|
|
|
2023-08-12 12:25:58 +02:00
|
|
|
world->getStore().insert(player);
|
|
|
|
world->renderPlayer();
|
|
|
|
}
|
2012-11-08 16:37:57 +04:00
|
|
|
|
2010-09-26 10:01:30 +02:00
|
|
|
mRaceSelected = true;
|
2010-09-15 13:31:26 +02:00
|
|
|
buildPlayer();
|
2010-09-15 14:33:02 +02:00
|
|
|
mUpdatePlayer = true;
|
2010-09-13 22:59:28 +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 MechanicsManager::setPlayerBirthsign(const ESM::RefId& id)
|
2010-09-13 22:59:28 +02:00
|
|
|
{
|
2012-11-08 18:50:18 +04:00
|
|
|
MWBase::Environment::get().getWorld()->getPlayer().setBirthSign(id);
|
2010-09-15 13:31:26 +02:00
|
|
|
buildPlayer();
|
2010-10-23 01:28:30 +02:00
|
|
|
mUpdatePlayer = true;
|
2010-09-13 22:59:28 +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 MechanicsManager::setPlayerClass(const ESM::RefId& id)
|
2010-09-13 22:59:28 +02:00
|
|
|
{
|
2012-11-08 16:37:57 +04:00
|
|
|
MWBase::World* world = MWBase::Environment::get().getWorld();
|
|
|
|
|
2014-01-08 18:39:44 +01:00
|
|
|
ESM::NPC player = *world->getPlayerPtr().get<ESM::NPC>()->mBase;
|
2012-11-08 16:37:57 +04:00
|
|
|
player.mClass = id;
|
|
|
|
|
2023-04-20 13:37:01 +02:00
|
|
|
world->getStore().insert(player);
|
2012-11-08 16:37:57 +04:00
|
|
|
|
2010-09-26 10:01:30 +02:00
|
|
|
mClassSelected = true;
|
2010-09-15 13:31:26 +02:00
|
|
|
buildPlayer();
|
2010-09-15 14:33:02 +02:00
|
|
|
mUpdatePlayer = true;
|
2010-09-13 22:59:28 +02:00
|
|
|
}
|
|
|
|
|
2012-11-08 01:36:43 +04:00
|
|
|
void MechanicsManager::setPlayerClass(const ESM::Class& cls)
|
2010-09-13 22:59:28 +02:00
|
|
|
{
|
2012-11-08 01:36:43 +04:00
|
|
|
MWBase::World* world = MWBase::Environment::get().getWorld();
|
|
|
|
|
2023-04-20 13:37:01 +02:00
|
|
|
const ESM::Class* ptr = world->getStore().insert(cls);
|
2012-11-08 01:36:43 +04:00
|
|
|
|
2014-01-08 18:39:44 +01:00
|
|
|
ESM::NPC player = *world->getPlayerPtr().get<ESM::NPC>()->mBase;
|
2012-11-08 16:37:57 +04:00
|
|
|
player.mClass = ptr->mId;
|
|
|
|
|
2023-04-20 13:37:01 +02:00
|
|
|
world->getStore().insert(player);
|
2012-11-08 01:36:43 +04:00
|
|
|
|
2010-09-26 10:01:30 +02:00
|
|
|
mClassSelected = true;
|
2010-09-15 13:31:26 +02:00
|
|
|
buildPlayer();
|
2010-09-15 14:33:02 +02:00
|
|
|
mUpdatePlayer = true;
|
2010-09-13 22:59:28 +02:00
|
|
|
}
|
2012-11-05 11:07:43 +01:00
|
|
|
|
2021-06-24 22:02:52 +02:00
|
|
|
int MechanicsManager::getDerivedDisposition(const MWWorld::Ptr& ptr, bool clamp)
|
2012-11-05 11:07:43 +01:00
|
|
|
{
|
2023-09-24 21:58:10 +04:00
|
|
|
const MWMechanics::NpcStats& npcStats = ptr.getClass().getNpcStats(ptr);
|
|
|
|
float x = static_cast<float>(npcStats.getBaseDisposition() + npcStats.getCrimeDispositionModifier());
|
2012-11-05 19:55:06 +01:00
|
|
|
|
|
|
|
MWWorld::LiveCellRef<ESM::NPC>* npc = ptr.get<ESM::NPC>();
|
2015-08-21 21:12:39 +12:00
|
|
|
MWWorld::Ptr playerPtr = getPlayer();
|
2012-11-05 19:55:06 +01:00
|
|
|
MWWorld::LiveCellRef<ESM::NPC>* player = playerPtr.get<ESM::NPC>();
|
2014-05-22 20:37:22 +02:00
|
|
|
const MWMechanics::NpcStats& playerStats = playerPtr.getClass().getNpcStats(playerPtr);
|
2012-11-05 19:55:06 +01:00
|
|
|
|
2014-09-27 22:44:20 +02: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 fDispRaceMod = gmst.find("fDispRaceMod")->mValue.getFloat();
|
2022-10-18 09:26:55 +02:00
|
|
|
if (npc->mBase->mRace == player->mBase->mRace)
|
2014-09-27 22:44:20 +02:00
|
|
|
x += fDispRaceMod;
|
2012-11-05 19:55:06 +01:00
|
|
|
|
2018-08-29 18:38:12 +03:00
|
|
|
static const float fDispPersonalityMult = gmst.find("fDispPersonalityMult")->mValue.getFloat();
|
|
|
|
static const float fDispPersonalityBase = gmst.find("fDispPersonalityBase")->mValue.getFloat();
|
2014-09-27 22:44:20 +02:00
|
|
|
x += fDispPersonalityMult
|
|
|
|
* (playerStats.getAttribute(ESM::Attribute::Personality).getModified() - fDispPersonalityBase);
|
2012-11-05 19:55:06 +01:00
|
|
|
|
|
|
|
float reaction = 0;
|
|
|
|
int rank = 0;
|
2022-11-18 01:55:07 +01:00
|
|
|
const ESM::RefId& npcFaction = ptr.getClass().getPrimaryFaction(ptr);
|
2014-01-14 12:46:53 +04:00
|
|
|
|
|
|
|
if (playerStats.getFactionRanks().find(npcFaction) != playerStats.getFactionRanks().end())
|
2012-11-05 19:55:06 +01:00
|
|
|
{
|
2014-05-27 14:54:29 +02:00
|
|
|
if (!playerStats.getExpelled(npcFaction))
|
2012-11-05 19:55:06 +01:00
|
|
|
{
|
2014-06-25 00:11:51 +02:00
|
|
|
// faction reaction towards itself. yes, that exists
|
2015-03-08 13:07:29 +13:00
|
|
|
reaction = static_cast<float>(
|
|
|
|
MWBase::Environment::get().getDialogueManager()->getFactionReaction(npcFaction, npcFaction));
|
2014-05-27 14:54:29 +02:00
|
|
|
|
|
|
|
rank = playerStats.getFactionRanks().find(npcFaction)->second;
|
2012-11-05 19:55:06 +01:00
|
|
|
}
|
|
|
|
}
|
2014-05-27 14:54:29 +02:00
|
|
|
else if (!npcFaction.empty())
|
2012-11-05 19:55:06 +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
|
|
|
auto playerFactionIt = playerStats.getFactionRanks().begin();
|
2014-05-27 14:54:29 +02:00
|
|
|
for (; playerFactionIt != playerStats.getFactionRanks().end(); ++playerFactionIt)
|
2012-11-05 19:55:06 +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& itFaction = playerFactionIt->first;
|
2014-05-27 14:54:29 +02:00
|
|
|
|
2018-02-10 17:58:30 +04:00
|
|
|
// Ignore the faction, if a player was expelled from it.
|
|
|
|
if (playerStats.getExpelled(itFaction))
|
|
|
|
continue;
|
|
|
|
|
2014-05-27 14:54:29 +02:00
|
|
|
int itReaction
|
|
|
|
= MWBase::Environment::get().getDialogueManager()->getFactionReaction(npcFaction, itFaction);
|
|
|
|
if (playerFactionIt == playerStats.getFactionRanks().begin() || itReaction < reaction)
|
2018-02-10 17:58:30 +04:00
|
|
|
{
|
2015-03-08 13:07:29 +13:00
|
|
|
reaction = static_cast<float>(itReaction);
|
2018-02-10 17:58:30 +04:00
|
|
|
rank = playerFactionIt->second;
|
|
|
|
}
|
2012-11-05 19:55:06 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
reaction = 0;
|
|
|
|
rank = 0;
|
|
|
|
}
|
2012-11-08 13:38:20 +01:00
|
|
|
|
2018-08-29 18:38:12 +03:00
|
|
|
static const float fDispFactionRankMult = gmst.find("fDispFactionRankMult")->mValue.getFloat();
|
|
|
|
static const float fDispFactionRankBase = gmst.find("fDispFactionRankBase")->mValue.getFloat();
|
|
|
|
static const float fDispFactionMod = gmst.find("fDispFactionMod")->mValue.getFloat();
|
2014-09-27 22:44:20 +02:00
|
|
|
x += (fDispFactionRankMult * rank + fDispFactionRankBase) * fDispFactionMod * reaction;
|
|
|
|
|
2018-08-29 18:38:12 +03:00
|
|
|
static const float fDispCrimeMod = gmst.find("fDispCrimeMod")->mValue.getFloat();
|
|
|
|
static const float fDispDiseaseMod = gmst.find("fDispDiseaseMod")->mValue.getFloat();
|
2014-09-27 22:44:20 +02:00
|
|
|
x -= fDispCrimeMod * playerStats.getBounty();
|
2012-11-09 18:33:11 +01:00
|
|
|
if (playerStats.hasCommonDisease() || playerStats.hasBlightDisease())
|
2014-09-27 22:44:20 +02:00
|
|
|
x += fDispDiseaseMod;
|
2012-11-09 18:33:11 +01:00
|
|
|
|
2018-08-29 18:38:12 +03:00
|
|
|
static const float fDispWeaponDrawn = gmst.find("fDispWeaponDrawn")->mValue.getFloat();
|
2022-07-17 19:36:48 +03:00
|
|
|
if (playerStats.getDrawState() == MWMechanics::DrawState::Weapon)
|
2014-09-27 22:44:20 +02:00
|
|
|
x += fDispWeaponDrawn;
|
2012-11-05 19:55:06 +01:00
|
|
|
|
2023-05-23 19:06:08 +02:00
|
|
|
x += ptr.getClass()
|
|
|
|
.getCreatureStats(ptr)
|
|
|
|
.getMagicEffects()
|
|
|
|
.getOrDefault(ESM::MagicEffect::Charm)
|
|
|
|
.getMagnitude();
|
2014-01-05 01:56:36 +01:00
|
|
|
|
2021-11-06 07:30:28 +03:00
|
|
|
if (clamp)
|
|
|
|
return std::clamp<int>(x, 0, 100); //, normally clamped to [0..100] when used
|
|
|
|
return static_cast<int>(x);
|
2012-11-05 11:07:43 +01:00
|
|
|
}
|
|
|
|
|
2012-11-09 14:42:09 +01:00
|
|
|
int MechanicsManager::getBarterOffer(const MWWorld::Ptr& ptr, int basePrice, bool buying)
|
2012-11-05 11:07:43 +01:00
|
|
|
{
|
2020-06-25 14:55:27 +03:00
|
|
|
// Make sure zero base price items/services can't be bought/sold for 1 gold
|
|
|
|
// and return the intended base price for creature merchants
|
2021-10-11 11:46:21 +00:00
|
|
|
if (basePrice == 0 || ptr.getType() == ESM::Creature::sRecordId)
|
2012-11-08 22:31:08 +01:00
|
|
|
return basePrice;
|
|
|
|
|
2014-05-22 20:37:22 +02:00
|
|
|
const MWMechanics::NpcStats& sellerStats = ptr.getClass().getNpcStats(ptr);
|
2012-11-05 11:07:43 +01:00
|
|
|
|
2015-08-21 21:12:39 +12:00
|
|
|
MWWorld::Ptr playerPtr = getPlayer();
|
2014-05-22 20:37:22 +02:00
|
|
|
const MWMechanics::NpcStats& playerStats = playerPtr.getClass().getNpcStats(playerPtr);
|
2012-11-05 11:07:43 +01:00
|
|
|
|
2016-03-08 21:30:28 +01:00
|
|
|
// I suppose the temporary disposition change (second param to getDerivedDisposition()) _has_ to be considered
|
2012-11-10 00:42:31 +01:00
|
|
|
// here, otherwise one would get different prices when exiting and re-entering the dialogue window...
|
2016-03-18 00:41:24 +01:00
|
|
|
int clampedDisposition = getDerivedDisposition(ptr);
|
2018-12-23 15:18:33 +04:00
|
|
|
float a = std::min(playerPtr.getClass().getSkill(playerPtr, ESM::Skill::Mercantile), 100.f);
|
2012-11-08 22:37:59 +01:00
|
|
|
float b = std::min(0.1f * playerStats.getAttribute(ESM::Attribute::Luck).getModified(), 10.f);
|
|
|
|
float c = std::min(0.2f * playerStats.getAttribute(ESM::Attribute::Personality).getModified(), 10.f);
|
2018-12-23 15:18:33 +04:00
|
|
|
float d = std::min(ptr.getClass().getSkill(ptr, ESM::Skill::Mercantile), 100.f);
|
2012-11-08 22:37:59 +01:00
|
|
|
float e = std::min(0.1f * sellerStats.getAttribute(ESM::Attribute::Luck).getModified(), 10.f);
|
|
|
|
float f = std::min(0.2f * sellerStats.getAttribute(ESM::Attribute::Personality).getModified(), 10.f);
|
2012-11-05 11:07:43 +01:00
|
|
|
float pcTerm = (clampedDisposition - 50 + a + b + c) * playerStats.getFatigueTerm();
|
|
|
|
float npcTerm = (d + e + f) * sellerStats.getFatigueTerm();
|
2019-05-09 20:42:22 +03:00
|
|
|
float buyTerm = 0.01f * (100 - 0.5f * (pcTerm - npcTerm));
|
|
|
|
float sellTerm = 0.01f * (50 - 0.5f * (npcTerm - pcTerm));
|
2018-03-25 13:05:42 +03:00
|
|
|
int offerPrice = int(basePrice * (buying ? buyTerm : sellTerm));
|
|
|
|
return std::max(1, offerPrice);
|
2012-11-05 11:07:43 +01:00
|
|
|
}
|
2012-11-08 23:16:40 +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
|
|
|
int MechanicsManager::countDeaths(const ESM::RefId& id) const
|
2012-10-27 11:33:18 +02:00
|
|
|
{
|
2015-04-25 15:19:17 +02:00
|
|
|
return mActors.countDeaths(id);
|
2012-10-27 11:33:18 +02:00
|
|
|
}
|
2012-11-09 20:18:38 +01:00
|
|
|
|
2021-06-24 22:02:52 +02:00
|
|
|
void MechanicsManager::getPersuasionDispositionChange(
|
|
|
|
const MWWorld::Ptr& npc, PersuasionType type, bool& success, int& tempChange, int& permChange)
|
2012-11-09 20:18:38 +01:00
|
|
|
{
|
2012-11-10 00:29:36 +01:00
|
|
|
const MWWorld::Store<ESM::GameSetting>& gmst
|
2023-04-20 21:07:53 +02:00
|
|
|
= MWBase::Environment::get().getESMStore()->get<ESM::GameSetting>();
|
2012-11-10 00:29:36 +01:00
|
|
|
|
2014-05-22 20:37:22 +02:00
|
|
|
MWMechanics::NpcStats& npcStats = npc.getClass().getNpcStats(npc);
|
2012-11-10 00:29:36 +01:00
|
|
|
|
2015-08-21 21:12:39 +12:00
|
|
|
MWWorld::Ptr playerPtr = getPlayer();
|
2014-05-22 20:37:22 +02:00
|
|
|
const MWMechanics::NpcStats& playerStats = playerPtr.getClass().getNpcStats(playerPtr);
|
2012-11-10 00:29:36 +01:00
|
|
|
|
2015-04-22 01:17:01 +02:00
|
|
|
float npcRating1, npcRating2, npcRating3;
|
|
|
|
getPersuasionRatings(npcStats, npcRating1, npcRating2, npcRating3, false);
|
2012-11-10 00:29:36 +01:00
|
|
|
|
2015-04-22 01:17:01 +02:00
|
|
|
float playerRating1, playerRating2, playerRating3;
|
|
|
|
getPersuasionRatings(playerStats, playerRating1, playerRating2, playerRating3, true);
|
2012-11-10 00:29:36 +01:00
|
|
|
|
2023-02-14 20:08:11 +01:00
|
|
|
const int currentDisposition = getDerivedDisposition(npc);
|
2012-11-10 00:29:36 +01:00
|
|
|
|
2015-03-08 13:07:29 +13:00
|
|
|
float d = 1 - 0.02f * abs(currentDisposition - 50);
|
2012-11-10 00:29:36 +01:00
|
|
|
float target1 = d * (playerRating1 - npcRating1 + 50);
|
|
|
|
float target2 = d * (playerRating2 - npcRating2 + 50);
|
|
|
|
|
|
|
|
float bribeMod;
|
2018-08-29 18:38:12 +03:00
|
|
|
if (type == PT_Bribe10)
|
|
|
|
bribeMod = gmst.find("fBribe10Mod")->mValue.getFloat();
|
|
|
|
else if (type == PT_Bribe100)
|
|
|
|
bribeMod = gmst.find("fBribe100Mod")->mValue.getFloat();
|
|
|
|
else
|
|
|
|
bribeMod = gmst.find("fBribe1000Mod")->mValue.getFloat();
|
2012-11-10 00:29:36 +01:00
|
|
|
|
|
|
|
float target3 = d * (playerRating3 - npcRating3 + 50) + bribeMod;
|
|
|
|
|
2023-02-14 20:08:11 +01:00
|
|
|
const float iPerMinChance = gmst.find("iPerMinChance")->mValue.getFloat();
|
|
|
|
const float iPerMinChange = gmst.find("iPerMinChange")->mValue.getFloat();
|
|
|
|
const float fPerDieRollMult = gmst.find("fPerDieRollMult")->mValue.getFloat();
|
|
|
|
const float fPerTempMult = gmst.find("fPerTempMult")->mValue.getFloat();
|
2012-11-10 00:29:36 +01:00
|
|
|
|
2013-02-25 16:52:31 +01:00
|
|
|
float x = 0;
|
|
|
|
float y = 0;
|
2012-11-10 00:29:36 +01:00
|
|
|
|
2022-03-06 21:56:02 +02:00
|
|
|
auto& prng = MWBase::Environment::get().getWorld()->getPrng();
|
|
|
|
int roll = Misc::Rng::roll0to99(prng);
|
2012-11-10 00:29:36 +01:00
|
|
|
|
|
|
|
if (type == PT_Admire)
|
|
|
|
{
|
|
|
|
target1 = std::max(iPerMinChance, target1);
|
|
|
|
success = (roll <= target1);
|
2015-03-08 13:07:29 +13:00
|
|
|
float c = floor(fPerDieRollMult * (target1 - roll));
|
2012-11-10 00:29:36 +01:00
|
|
|
x = success ? std::max(iPerMinChange, c) : c;
|
|
|
|
}
|
|
|
|
else if (type == PT_Intimidate)
|
|
|
|
{
|
|
|
|
target2 = std::max(iPerMinChance, target2);
|
|
|
|
|
|
|
|
success = (roll <= target2);
|
|
|
|
|
|
|
|
float r;
|
|
|
|
if (roll != target2)
|
2015-03-08 13:07:29 +13:00
|
|
|
r = floor(target2 - roll);
|
2012-11-10 00:29:36 +01:00
|
|
|
else
|
|
|
|
r = 1;
|
|
|
|
|
|
|
|
if (roll <= target2)
|
|
|
|
{
|
2015-03-08 13:07:29 +13:00
|
|
|
float s = floor(r * fPerDieRollMult * fPerTempMult);
|
2012-11-10 00:29:36 +01:00
|
|
|
|
2022-07-16 16:37:31 +02:00
|
|
|
const int flee = npcStats.getAiSetting(MWMechanics::AiSetting::Flee).getBase();
|
|
|
|
const int fight = npcStats.getAiSetting(MWMechanics::AiSetting::Fight).getBase();
|
|
|
|
npcStats.setAiSetting(
|
2021-11-06 07:30:28 +03:00
|
|
|
MWMechanics::AiSetting::Flee, std::clamp(flee + int(std::max(iPerMinChange, s)), 0, 100));
|
2022-07-16 16:37:31 +02:00
|
|
|
npcStats.setAiSetting(
|
2021-11-06 07:30:28 +03:00
|
|
|
MWMechanics::AiSetting::Fight, std::clamp(fight + int(std::min(-iPerMinChange, -s)), 0, 100));
|
2012-11-10 00:29:36 +01:00
|
|
|
}
|
|
|
|
|
2015-03-08 13:07:29 +13:00
|
|
|
float c = -std::abs(floor(r * fPerDieRollMult));
|
2012-11-10 00:29:36 +01:00
|
|
|
if (success)
|
|
|
|
{
|
|
|
|
if (std::abs(c) < iPerMinChange)
|
|
|
|
{
|
2020-06-25 16:20:51 +03:00
|
|
|
// Deviating from Morrowind here: it doesn't increase disposition on marginal wins,
|
|
|
|
// which seems to be a bug (MCP fixes it too).
|
|
|
|
// Original logic: x = 0, y = -iPerMinChange
|
2021-04-09 18:16:05 +02:00
|
|
|
x = iPerMinChange;
|
2020-06-25 16:20:51 +03:00
|
|
|
y = x; // This goes unused.
|
2012-11-10 00:29:36 +01:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2015-03-08 13:07:29 +13:00
|
|
|
x = -floor(c * fPerTempMult);
|
2012-11-10 00:29:36 +01:00
|
|
|
y = c;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2015-03-08 13:07:29 +13:00
|
|
|
x = floor(c * fPerTempMult);
|
2012-11-10 00:29:36 +01:00
|
|
|
y = c;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else if (type == PT_Taunt)
|
|
|
|
{
|
|
|
|
target1 = std::max(iPerMinChance, target1);
|
|
|
|
success = (roll <= target1);
|
|
|
|
|
2015-03-08 13:07:29 +13:00
|
|
|
float c = std::abs(floor(target1 - roll));
|
2012-11-10 00:29:36 +01:00
|
|
|
|
2014-01-08 02:35:36 +01:00
|
|
|
if (success)
|
2012-11-10 00:29:36 +01:00
|
|
|
{
|
|
|
|
float s = c * fPerDieRollMult * fPerTempMult;
|
2022-07-16 16:37:31 +02:00
|
|
|
const int flee = npcStats.getAiSetting(AiSetting::Flee).getBase();
|
|
|
|
const int fight = npcStats.getAiSetting(AiSetting::Fight).getBase();
|
|
|
|
npcStats.setAiSetting(
|
2021-11-06 07:30:28 +03:00
|
|
|
AiSetting::Flee, std::clamp(flee + std::min(-int(iPerMinChange), int(-s)), 0, 100));
|
2022-07-16 16:37:31 +02:00
|
|
|
npcStats.setAiSetting(
|
2021-11-06 07:30:28 +03:00
|
|
|
AiSetting::Fight, std::clamp(fight + std::max(int(iPerMinChange), int(s)), 0, 100));
|
2012-11-10 00:29:36 +01:00
|
|
|
}
|
2015-03-08 13:07:29 +13:00
|
|
|
x = floor(-c * fPerDieRollMult);
|
2012-11-10 00:29:36 +01:00
|
|
|
|
|
|
|
if (success && std::abs(x) < iPerMinChange)
|
|
|
|
x = -iPerMinChange;
|
|
|
|
}
|
|
|
|
else // Bribe
|
|
|
|
{
|
|
|
|
target3 = std::max(iPerMinChance, target3);
|
|
|
|
success = (roll <= target3);
|
2015-03-08 13:07:29 +13:00
|
|
|
float c = floor((target3 - roll) * fPerDieRollMult);
|
2012-11-10 00:29:36 +01:00
|
|
|
|
|
|
|
x = success ? std::max(iPerMinChange, c) : c;
|
|
|
|
}
|
|
|
|
|
2023-02-14 20:08:11 +01:00
|
|
|
if (type == PT_Intimidate)
|
2021-06-24 22:02:52 +02:00
|
|
|
{
|
2023-02-14 20:08:11 +01:00
|
|
|
tempChange = int(x);
|
|
|
|
if (currentDisposition + tempChange > 100)
|
|
|
|
tempChange = 100 - currentDisposition;
|
|
|
|
else if (currentDisposition + tempChange < 0)
|
|
|
|
tempChange = -currentDisposition;
|
|
|
|
permChange = success ? -int(tempChange / fPerTempMult) : int(y);
|
2021-06-24 22:02:52 +02:00
|
|
|
}
|
2023-02-14 20:08:11 +01:00
|
|
|
else
|
2012-11-10 00:29:36 +01:00
|
|
|
{
|
2023-02-14 20:08:11 +01:00
|
|
|
tempChange = int(x * fPerTempMult);
|
|
|
|
if (currentDisposition + tempChange > 100)
|
|
|
|
tempChange = 100 - currentDisposition;
|
|
|
|
else if (currentDisposition + tempChange < 0)
|
|
|
|
tempChange = -currentDisposition;
|
|
|
|
permChange = int(tempChange / fPerTempMult);
|
2012-11-10 00:29:36 +01:00
|
|
|
}
|
2012-11-09 20:18:38 +01:00
|
|
|
}
|
2013-01-16 17:53:18 -08:00
|
|
|
|
2013-04-25 07:08:11 -07:00
|
|
|
void MechanicsManager::forceStateUpdate(const MWWorld::Ptr& ptr)
|
|
|
|
{
|
2015-04-25 15:19:17 +02:00
|
|
|
if (ptr.getClass().isActor())
|
|
|
|
mActors.forceStateUpdate(ptr);
|
2013-04-25 07:08:11 -07:00
|
|
|
}
|
|
|
|
|
2022-08-23 18:25:25 +02:00
|
|
|
bool MechanicsManager::playAnimationGroup(
|
2023-10-25 19:53:34 +02:00
|
|
|
const MWWorld::Ptr& ptr, std::string_view groupName, int mode, int number, bool scripted)
|
2013-01-16 17:53:18 -08:00
|
|
|
{
|
2014-05-22 20:37:22 +02:00
|
|
|
if (ptr.getClass().isActor())
|
2023-10-25 19:53:34 +02:00
|
|
|
return mActors.playAnimationGroup(ptr, groupName, mode, number, scripted);
|
2013-03-31 15:12:10 -07:00
|
|
|
else
|
2023-10-25 19:53:34 +02:00
|
|
|
return mObjects.playAnimationGroup(ptr, groupName, mode, number, scripted);
|
2013-01-16 17:53:18 -08:00
|
|
|
}
|
|
|
|
void MechanicsManager::skipAnimation(const MWWorld::Ptr& ptr)
|
|
|
|
{
|
2014-05-22 20:37:22 +02:00
|
|
|
if (ptr.getClass().isActor())
|
2013-01-28 23:39:11 -08:00
|
|
|
mActors.skipAnimation(ptr);
|
2013-03-31 15:12:10 -07:00
|
|
|
else
|
2013-03-31 15:29:41 -07:00
|
|
|
mObjects.skipAnimation(ptr);
|
2013-01-16 17:53:18 -08:00
|
|
|
}
|
2013-05-24 20:10:07 -07:00
|
|
|
bool MechanicsManager::checkAnimationPlaying(const MWWorld::Ptr& ptr, const std::string& groupName)
|
|
|
|
{
|
2015-04-25 15:19:17 +02:00
|
|
|
if (ptr.getClass().isActor())
|
|
|
|
return mActors.checkAnimationPlaying(ptr, groupName);
|
|
|
|
else
|
2013-05-24 20:10:07 -07:00
|
|
|
return false;
|
|
|
|
}
|
2013-01-16 17:53:18 -08:00
|
|
|
|
2018-09-22 12:57:50 +04:00
|
|
|
bool MechanicsManager::onOpen(const MWWorld::Ptr& ptr)
|
|
|
|
{
|
|
|
|
if (ptr.getClass().isActor())
|
|
|
|
return true;
|
|
|
|
else
|
|
|
|
return mObjects.onOpen(ptr);
|
|
|
|
}
|
|
|
|
|
|
|
|
void MechanicsManager::onClose(const MWWorld::Ptr& ptr)
|
|
|
|
{
|
|
|
|
if (!ptr.getClass().isActor())
|
|
|
|
mObjects.onClose(ptr);
|
|
|
|
}
|
|
|
|
|
2016-07-30 19:24:03 +02:00
|
|
|
void MechanicsManager::persistAnimationStates()
|
|
|
|
{
|
|
|
|
mActors.persistAnimationStates();
|
|
|
|
mObjects.persistAnimationStates();
|
|
|
|
}
|
|
|
|
|
2013-11-17 23:15:57 +01:00
|
|
|
void MechanicsManager::updateMagicEffects(const MWWorld::Ptr& ptr)
|
|
|
|
{
|
2015-04-25 15:19:17 +02:00
|
|
|
mActors.updateMagicEffects(ptr);
|
2013-11-17 23:15:57 +01:00
|
|
|
}
|
|
|
|
|
2014-03-26 19:55:52 +01:00
|
|
|
bool MechanicsManager::toggleAI()
|
2013-11-18 23:03:44 +01:00
|
|
|
{
|
|
|
|
mAI = !mAI;
|
2014-03-26 19:55:52 +01:00
|
|
|
return mAI;
|
2013-11-18 23:03:44 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
bool MechanicsManager::isAIActive()
|
|
|
|
{
|
|
|
|
return mAI;
|
|
|
|
}
|
2014-01-07 00:51:09 +01:00
|
|
|
|
2013-12-07 13:17:28 +01:00
|
|
|
void MechanicsManager::playerLoaded()
|
|
|
|
{
|
|
|
|
mUpdatePlayer = true;
|
|
|
|
mClassSelected = true;
|
|
|
|
mRaceSelected = true;
|
|
|
|
mAI = true;
|
|
|
|
}
|
2014-01-24 18:21:52 +01:00
|
|
|
|
2017-11-10 09:43:22 +04:00
|
|
|
bool MechanicsManager::isBoundItem(const MWWorld::Ptr& item)
|
|
|
|
{
|
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
|
|
|
static std::set<ESM::RefId> boundItemIDCache;
|
2017-11-10 09:43:22 +04:00
|
|
|
|
|
|
|
// If this is empty then we haven't executed the GMST cache logic yet; or there isn't any sMagicBound* GMST's
|
|
|
|
// for some reason
|
|
|
|
if (boundItemIDCache.empty())
|
|
|
|
{
|
|
|
|
// Build a list of known bound item ID's
|
|
|
|
const MWWorld::Store<ESM::GameSetting>& gameSettings
|
2023-04-20 21:07:53 +02:00
|
|
|
= MWBase::Environment::get().getESMStore()->get<ESM::GameSetting>();
|
2017-11-10 09:43:22 +04:00
|
|
|
|
2018-11-06 01:35:20 +03:00
|
|
|
for (const ESM::GameSetting& currentSetting : gameSettings)
|
2017-11-10 09:43:22 +04:00
|
|
|
{
|
|
|
|
// Don't bother checking this GMST if it's not a sMagicBound* one.
|
2023-03-01 22:48:00 +01:00
|
|
|
if (!currentSetting.mId.startsWith("smagicbound"))
|
2017-11-10 09:43:22 +04:00
|
|
|
continue;
|
|
|
|
|
|
|
|
// All sMagicBound* GMST's should be of type string
|
2018-08-29 18:38:12 +03:00
|
|
|
std::string currentGMSTValue = currentSetting.mValue.getString();
|
2017-11-10 09:43:22 +04:00
|
|
|
Misc::StringUtils::lowerCaseInPlace(currentGMSTValue);
|
|
|
|
|
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
|
|
|
boundItemIDCache.insert(ESM::RefId::stringRefId(currentGMSTValue));
|
2017-11-10 09:43:22 +04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Perform bound item check and assign the Flag_Bound bit if it passes
|
2022-12-01 20:02:39 +01:00
|
|
|
const ESM::RefId& tempItemID = item.getCellRef().getRefId();
|
2017-11-10 09:43:22 +04:00
|
|
|
|
|
|
|
if (boundItemIDCache.count(tempItemID) != 0)
|
|
|
|
return true;
|
|
|
|
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2017-09-30 20:22:26 +04:00
|
|
|
bool MechanicsManager::isAllowedToUse(const MWWorld::Ptr& ptr, const MWWorld::Ptr& target, MWWorld::Ptr& victim)
|
2014-09-22 15:18:19 +02:00
|
|
|
{
|
2017-10-03 09:59:31 +04:00
|
|
|
if (target.isEmpty())
|
|
|
|
return true;
|
|
|
|
|
2017-09-30 20:22:26 +04:00
|
|
|
const MWWorld::CellRef& cellref = target.getCellRef();
|
2017-08-18 17:06:47 +04:00
|
|
|
// there is no harm to use unlocked doors
|
2023-06-08 20:10:32 +02:00
|
|
|
if (target.getClass().isDoor() && !cellref.isLocked() && cellref.getTrap().empty())
|
2018-06-19 14:17:33 +04:00
|
|
|
{
|
2017-08-18 17:06:47 +04:00
|
|
|
return true;
|
2018-06-19 14:17:33 +04:00
|
|
|
}
|
2017-08-18 17:06:47 +04:00
|
|
|
|
2019-09-10 21:56:10 +03:00
|
|
|
if (!target.getClass().hasToolTip(target))
|
2018-12-03 20:21:40 +04:00
|
|
|
return true;
|
|
|
|
|
2017-09-30 20:22:26 +04:00
|
|
|
// TODO: implement a better check to check if target is owned bed
|
2023-03-24 22:15:51 +01:00
|
|
|
if (target.getClass().isActivator() && !target.getClass().getScript(target).startsWith("Bed"))
|
2017-08-18 17:06:47 +04:00
|
|
|
return true;
|
|
|
|
|
2017-09-30 20:22:26 +04:00
|
|
|
if (target.getClass().isNpc())
|
|
|
|
{
|
|
|
|
if (target.getClass().getCreatureStats(target).isDead())
|
|
|
|
return true;
|
|
|
|
|
2017-09-30 21:29:02 +04:00
|
|
|
if (target.getClass().getCreatureStats(target).getAiSequence().isInCombat())
|
|
|
|
return true;
|
|
|
|
|
2017-09-30 20:22:26 +04:00
|
|
|
// check if a player tries to pickpocket a target NPC
|
2019-07-30 20:58:19 +03:00
|
|
|
if (target.getClass().getCreatureStats(target).getKnockedDown() || isSneaking(ptr))
|
2017-09-30 20:22:26 +04:00
|
|
|
return false;
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2021-12-14 21:06:40 +01:00
|
|
|
if (isOwned(ptr, target, victim))
|
2019-09-16 14:18:41 +04:00
|
|
|
return false;
|
|
|
|
|
2021-12-14 21:06:40 +01:00
|
|
|
// A special case for evidence chest - we should not allow to take items even if it is technically permitted
|
2022-10-18 09:26:55 +02:00
|
|
|
return !(cellref.getRefId() == "stolen_goods");
|
2014-09-22 15:18:19 +02:00
|
|
|
}
|
|
|
|
|
2014-01-08 17:19:43 +01:00
|
|
|
bool MechanicsManager::sleepInBed(const MWWorld::Ptr& ptr, const MWWorld::Ptr& bed)
|
2014-01-07 19:49:16 +01:00
|
|
|
{
|
2014-09-05 01:58:57 +02:00
|
|
|
if (ptr.getClass().getNpcStats(ptr).isWerewolf())
|
|
|
|
{
|
|
|
|
MWBase::Environment::get().getWindowManager()->messageBox("#{sWerewolfRefusal}");
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2016-06-07 01:53:16 +02:00
|
|
|
if (MWBase::Environment::get().getWorld()->getPlayer().enemiesNearby())
|
|
|
|
{
|
2014-04-24 22:47:45 -04:00
|
|
|
MWBase::Environment::get().getWindowManager()->messageBox("#{sNotifyMessage2}");
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2014-01-08 17:19:43 +01:00
|
|
|
MWWorld::Ptr victim;
|
2017-08-18 17:06:47 +04:00
|
|
|
if (isAllowedToUse(ptr, bed, victim))
|
2014-01-10 21:26:24 +01:00
|
|
|
return false;
|
2014-01-07 20:24:01 +01:00
|
|
|
|
2019-09-16 14:20:43 +04:00
|
|
|
if (commitCrime(ptr, victim, OT_SleepingInOwnedBed, bed.getCellRef().getFaction()))
|
2014-01-07 20:24:01 +01:00
|
|
|
{
|
2014-01-08 17:19:43 +01:00
|
|
|
MWBase::Environment::get().getWindowManager()->messageBox("#{sNotifyMessage64}");
|
|
|
|
return true;
|
2014-01-07 20:24:01 +01:00
|
|
|
}
|
2014-01-08 17:19:43 +01:00
|
|
|
else
|
|
|
|
return false;
|
|
|
|
}
|
2014-01-07 20:24:01 +01:00
|
|
|
|
2019-09-05 17:36:49 +03:00
|
|
|
void MechanicsManager::unlockAttempted(const MWWorld::Ptr& ptr, const MWWorld::Ptr& item)
|
2014-01-08 17:19:43 +01:00
|
|
|
{
|
2014-01-07 20:24:01 +01:00
|
|
|
MWWorld::Ptr victim;
|
2021-12-14 21:06:40 +01:00
|
|
|
if (isOwned(ptr, item, victim))
|
|
|
|
{
|
2023-06-08 20:10:32 +02:00
|
|
|
// Note that attempting to unlock something that has ever been locked is a crime even if it's already
|
|
|
|
// unlocked. Likewise, it's illegal to unlock something that has a trap but isn't otherwise locked.
|
2021-12-14 21:06:40 +01:00
|
|
|
const auto& cellref = item.getCellRef();
|
2023-06-08 20:10:32 +02:00
|
|
|
if (cellref.getLockLevel() || cellref.isLocked() || !cellref.getTrap().empty())
|
2021-12-14 21:06:40 +01:00
|
|
|
commitCrime(ptr, victim, OT_Trespassing, item.getCellRef().getFaction());
|
|
|
|
}
|
2014-01-10 21:26:24 +01:00
|
|
|
}
|
2014-01-08 01:24:06 +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
|
|
|
std::vector<std::pair<ESM::RefId, int>> MechanicsManager::getStolenItemOwners(const ESM::RefId& itemid)
|
2015-02-04 21:18:43 +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
|
|
|
std::vector<std::pair<ESM::RefId, int>> result;
|
|
|
|
StolenItemsMap::const_iterator it = mStolenItems.find(itemid);
|
2015-02-04 21:18:43 +01:00
|
|
|
if (it == mStolenItems.end())
|
|
|
|
return result;
|
|
|
|
else
|
|
|
|
{
|
|
|
|
const OwnerMap& owners = it->second;
|
|
|
|
for (OwnerMap::const_iterator ownerIt = owners.begin(); ownerIt != owners.end(); ++ownerIt)
|
2020-10-17 12:26:35 +04:00
|
|
|
result.emplace_back(ownerIt->first.first, ownerIt->second);
|
2015-02-04 21:18:43 +01:00
|
|
|
return result;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
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
|
|
|
bool MechanicsManager::isItemStolenFrom(const ESM::RefId& itemid, const MWWorld::Ptr& ptr)
|
2015-02-04 21:18:43 +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
|
|
|
StolenItemsMap::const_iterator it = mStolenItems.find(itemid);
|
2015-02-04 21:18:43 +01:00
|
|
|
if (it == mStolenItems.end())
|
|
|
|
return false;
|
2018-06-03 09:46:12 +03:00
|
|
|
|
2015-02-04 21:18:43 +01:00
|
|
|
const OwnerMap& owners = it->second;
|
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& ownerid = ptr.getCellRef().getRefId();
|
|
|
|
OwnerMap::const_iterator ownerFound = owners.find(std::make_pair(ownerid, false));
|
2018-06-03 10:50:10 +03:00
|
|
|
if (ownerFound != owners.end())
|
|
|
|
return true;
|
2018-06-03 09:46:12 +03: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);
|
2018-06-03 10:50:10 +03:00
|
|
|
if (!factionid.empty())
|
|
|
|
{
|
2022-10-18 09:26:55 +02:00
|
|
|
OwnerMap::const_iterator factionOwnerFound = owners.find(std::make_pair(factionid, true));
|
2018-06-03 10:50:10 +03:00
|
|
|
return factionOwnerFound != owners.end();
|
|
|
|
}
|
|
|
|
|
|
|
|
return false;
|
2015-02-04 21:18:43 +01:00
|
|
|
}
|
|
|
|
|
2017-08-14 10:41:37 +04:00
|
|
|
void MechanicsManager::confiscateStolenItemToOwner(
|
|
|
|
const MWWorld::Ptr& player, const MWWorld::Ptr& item, const MWWorld::Ptr& victim, int count)
|
|
|
|
{
|
|
|
|
if (player != getPlayer())
|
|
|
|
return;
|
|
|
|
|
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& itemId = item.getCellRef().getRefId();
|
2017-08-14 10:41:37 +04:00
|
|
|
|
|
|
|
StolenItemsMap::iterator stolenIt = mStolenItems.find(itemId);
|
|
|
|
if (stolenIt == mStolenItems.end())
|
|
|
|
return;
|
|
|
|
|
|
|
|
Owner owner;
|
|
|
|
owner.first = victim.getCellRef().getRefId();
|
|
|
|
owner.second = false;
|
|
|
|
|
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& victimFaction = victim.getClass().getPrimaryFaction(victim);
|
2022-10-18 09:26:55 +02:00
|
|
|
if (!victimFaction.empty() && item.getCellRef().getFaction() == victimFaction) // Is the item faction-owned?
|
2018-06-03 13:02:27 +03:00
|
|
|
{
|
|
|
|
owner.first = victimFaction;
|
|
|
|
owner.second = true;
|
|
|
|
}
|
|
|
|
|
2017-08-14 10:41:37 +04:00
|
|
|
// decrease count of stolen items
|
|
|
|
int toRemove = std::min(count, mStolenItems[itemId][owner]);
|
|
|
|
mStolenItems[itemId][owner] -= toRemove;
|
|
|
|
if (mStolenItems[itemId][owner] == 0)
|
|
|
|
{
|
|
|
|
// erase owner from stolen items owners
|
|
|
|
OwnerMap& owners = stolenIt->second;
|
|
|
|
OwnerMap::iterator ownersIt = owners.find(owner);
|
|
|
|
if (ownersIt != owners.end())
|
|
|
|
owners.erase(ownersIt);
|
|
|
|
}
|
|
|
|
|
|
|
|
MWWorld::ContainerStore& store = player.getClass().getContainerStore(player);
|
|
|
|
|
|
|
|
// move items from player to owner and report about theft
|
2023-01-16 23:51:04 +01:00
|
|
|
victim.getClass().getContainerStore(victim).add(item, toRemove);
|
|
|
|
store.remove(item, toRemove);
|
2019-09-16 14:20:43 +04:00
|
|
|
commitCrime(
|
|
|
|
player, victim, OT_Theft, item.getCellRef().getFaction(), item.getClass().getValue(item) * toRemove);
|
2017-08-14 10:41:37 +04:00
|
|
|
}
|
|
|
|
|
2015-02-04 21:18:43 +01:00
|
|
|
void MechanicsManager::confiscateStolenItems(const MWWorld::Ptr& player, const MWWorld::Ptr& targetContainer)
|
|
|
|
{
|
|
|
|
MWWorld::ContainerStore& store = player.getClass().getContainerStore(player);
|
2020-10-13 17:46:32 +02:00
|
|
|
MWWorld::ContainerStore& containerStore = targetContainer.getClass().getContainerStore(targetContainer);
|
2015-02-04 21:18:43 +01:00
|
|
|
for (MWWorld::ContainerStoreIterator it = store.begin(); it != store.end(); ++it)
|
|
|
|
{
|
2022-10-18 09:26:55 +02:00
|
|
|
StolenItemsMap::iterator stolenIt = mStolenItems.find(it->getCellRef().getRefId());
|
2015-02-04 21:18:43 +01:00
|
|
|
if (stolenIt == mStolenItems.end())
|
|
|
|
continue;
|
|
|
|
OwnerMap& owners = stolenIt->second;
|
|
|
|
int itemCount = it->getRefData().getCount();
|
|
|
|
for (OwnerMap::iterator ownerIt = owners.begin(); ownerIt != owners.end();)
|
|
|
|
{
|
|
|
|
int toRemove = std::min(itemCount, ownerIt->second);
|
|
|
|
itemCount -= toRemove;
|
|
|
|
ownerIt->second -= toRemove;
|
|
|
|
if (ownerIt->second == 0)
|
|
|
|
owners.erase(ownerIt++);
|
|
|
|
else
|
|
|
|
++ownerIt;
|
|
|
|
}
|
|
|
|
|
|
|
|
int toMove = it->getRefData().getCount() - itemCount;
|
|
|
|
|
2023-01-16 23:51:04 +01:00
|
|
|
containerStore.add(*it, toMove);
|
|
|
|
store.remove(*it, toMove);
|
2015-02-04 21:18:43 +01:00
|
|
|
}
|
|
|
|
// TODO: unhardcode the locklevel
|
2019-09-17 20:30:37 +02:00
|
|
|
targetContainer.getCellRef().lock(50);
|
2015-02-04 21:18:43 +01:00
|
|
|
}
|
|
|
|
|
2015-02-03 23:43:56 +01:00
|
|
|
void MechanicsManager::itemTaken(
|
|
|
|
const MWWorld::Ptr& ptr, const MWWorld::Ptr& item, const MWWorld::Ptr& container, int count, bool alarm)
|
2014-01-10 21:26:24 +01:00
|
|
|
{
|
2015-08-21 21:12:39 +12:00
|
|
|
if (ptr != getPlayer())
|
2015-02-04 21:18:43 +01:00
|
|
|
return;
|
|
|
|
|
2014-01-10 21:26:24 +01:00
|
|
|
MWWorld::Ptr victim;
|
2015-02-03 23:43:56 +01:00
|
|
|
|
2017-09-27 20:00:41 +04:00
|
|
|
bool isAllowed = true;
|
2015-02-04 21:18:43 +01:00
|
|
|
const MWWorld::CellRef* ownerCellRef = &item.getCellRef();
|
2015-02-03 23:43:56 +01:00
|
|
|
if (!container.isEmpty())
|
|
|
|
{
|
|
|
|
// Inherit the owner of the container
|
2015-02-04 21:18:43 +01:00
|
|
|
ownerCellRef = &container.getCellRef();
|
2017-09-27 20:00:41 +04:00
|
|
|
isAllowed = isAllowedToUse(ptr, container, victim);
|
2015-02-03 23:43:56 +01:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2017-09-27 20:00:41 +04:00
|
|
|
isAllowed = isAllowedToUse(ptr, item, victim);
|
2015-02-03 23:43:56 +01:00
|
|
|
}
|
|
|
|
|
2017-09-27 20:00:41 +04:00
|
|
|
if (isAllowed)
|
2015-02-04 21:18:43 +01:00
|
|
|
return;
|
|
|
|
|
|
|
|
Owner owner;
|
|
|
|
owner.second = false;
|
2017-10-05 11:12:43 +04:00
|
|
|
if (!container.isEmpty() && container.getClass().isActor())
|
2015-02-04 21:18:43 +01:00
|
|
|
{
|
2017-10-05 11:12:43 +04:00
|
|
|
// "container" is an actor inventory, so just take actor's ID
|
|
|
|
owner.first = ownerCellRef->getRefId();
|
2015-02-04 21:18:43 +01:00
|
|
|
}
|
2017-10-05 11:12:43 +04:00
|
|
|
else
|
|
|
|
{
|
|
|
|
owner.first = ownerCellRef->getOwner();
|
|
|
|
if (owner.first.empty())
|
|
|
|
{
|
|
|
|
owner.first = ownerCellRef->getFaction();
|
|
|
|
owner.second = true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-10-18 09:26:55 +02:00
|
|
|
if (!(item.getCellRef().getRefId() == MWWorld::ContainerStore::sGoldId))
|
2018-02-26 23:21:51 +03:00
|
|
|
{
|
2020-03-04 15:14:22 +04:00
|
|
|
if (victim.isEmpty()
|
|
|
|
|| (victim.getClass().isActor() && victim.getRefData().getCount() > 0
|
|
|
|
&& !victim.getClass().getCreatureStats(victim).isDead()))
|
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
|
|
|
mStolenItems[item.getCellRef().getRefId()][owner] += count;
|
2018-02-26 23:21:51 +03:00
|
|
|
}
|
2017-10-05 11:12:43 +04:00
|
|
|
if (alarm)
|
2019-09-16 14:20:43 +04:00
|
|
|
commitCrime(ptr, victim, OT_Theft, ownerCellRef->getFaction(), item.getClass().getValue(item) * count);
|
2014-01-07 19:49:16 +01:00
|
|
|
}
|
|
|
|
|
2019-09-16 14:20:43 +04:00
|
|
|
bool MechanicsManager::commitCrime(const MWWorld::Ptr& player, const MWWorld::Ptr& victim, OffenseType type,
|
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, int arg, bool victimAware)
|
2014-01-07 19:49:16 +01:00
|
|
|
{
|
2014-06-16 04:03:53 +02:00
|
|
|
// NOTE: victim may be empty
|
|
|
|
|
2014-04-19 19:03:31 -04:00
|
|
|
// Only player can commit crime
|
2015-08-21 21:12:39 +12:00
|
|
|
if (player != getPlayer())
|
2014-01-11 03:08:16 +01:00
|
|
|
return false;
|
2014-01-08 01:24:06 +01:00
|
|
|
|
2023-02-12 03:59:20 +03:00
|
|
|
if (type == OT_Assault)
|
|
|
|
victimAware = true;
|
|
|
|
|
2014-05-06 18:23:17 +02:00
|
|
|
// Find all the actors within the alarm radius
|
2014-04-01 14:15:55 -04:00
|
|
|
std::vector<MWWorld::Ptr> neighbors;
|
2014-06-15 00:14:18 +04:00
|
|
|
|
2015-06-01 21:41:13 +02:00
|
|
|
osg::Vec3f from(player.getRefData().getPosition().asVec3());
|
2023-04-20 21:07:53 +02:00
|
|
|
const MWWorld::ESMStore& esmStore = *MWBase::Environment::get().getESMStore();
|
2018-08-29 18:38:12 +03:00
|
|
|
float radius = esmStore.get<ESM::GameSetting>().find("fAlarmRadius")->mValue.getFloat();
|
2014-06-15 00:14:18 +04:00
|
|
|
|
2015-04-25 15:19:17 +02:00
|
|
|
mActors.getObjectsInRange(from, radius, neighbors);
|
2014-06-15 00:14:18 +04:00
|
|
|
|
|
|
|
// victim should be considered even beyond alarm radius
|
2015-06-01 21:41:13 +02:00
|
|
|
if (!victim.isEmpty() && (from - victim.getRefData().getPosition().asVec3()).length2() > radius * radius)
|
2014-06-15 00:14:18 +04:00
|
|
|
neighbors.push_back(victim);
|
2014-04-05 10:26:14 -04:00
|
|
|
|
2015-07-19 16:37:19 +02:00
|
|
|
// get the player's followers / allies (works recursively) that will not report crimes
|
|
|
|
std::set<MWWorld::Ptr> playerFollowers;
|
2016-12-20 12:38:51 +01:00
|
|
|
getActorsSidingWith(player, playerFollowers);
|
2015-07-19 16:37:19 +02:00
|
|
|
|
2014-12-19 21:45:26 +01:00
|
|
|
// Did anyone see it?
|
2014-12-01 16:36:01 +01:00
|
|
|
bool crimeSeen = false;
|
2018-11-06 01:35:20 +03:00
|
|
|
for (const MWWorld::Ptr& neighbor : neighbors)
|
2014-04-24 22:47:45 -04:00
|
|
|
{
|
2018-11-06 01:35:20 +03:00
|
|
|
if (!canReportCrime(neighbor, victim, playerFollowers))
|
2014-06-17 03:54:41 +02:00
|
|
|
continue;
|
2014-04-01 14:15:55 -04:00
|
|
|
|
2018-11-06 01:35:20 +03:00
|
|
|
if ((neighbor == victim && victimAware)
|
2014-06-17 03:54:41 +02:00
|
|
|
// Murder crime can be reported even if no one saw it (hearing is enough, I guess).
|
|
|
|
// TODO: Add mod support for stealth executions!
|
2018-11-06 01:35:20 +03:00
|
|
|
|| (type == OT_Murder && neighbor != victim)
|
|
|
|
|| (MWBase::Environment::get().getWorld()->getLOS(player, neighbor)
|
|
|
|
&& awarenessCheck(player, neighbor)))
|
2014-01-07 19:49:16 +01:00
|
|
|
{
|
2017-10-15 11:03:02 +04:00
|
|
|
// NPC will complain about theft even if he will do nothing about it
|
|
|
|
if (type == OT_Theft || type == OT_Pickpocket)
|
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(neighbor, ESM::RefId::stringRefId("thief"));
|
2017-10-15 11:03:02 +04:00
|
|
|
|
2014-12-01 16:36:01 +01:00
|
|
|
crimeSeen = true;
|
|
|
|
}
|
2014-01-07 19:49:16 +01:00
|
|
|
}
|
2014-06-17 01:10:37 +02:00
|
|
|
|
2014-12-19 21:45:26 +01:00
|
|
|
if (crimeSeen)
|
2019-09-16 14:20:43 +04:00
|
|
|
reportCrime(player, victim, type, factionId, arg);
|
2014-12-19 21:45:26 +01:00
|
|
|
else if (type == OT_Assault && !victim.isEmpty())
|
2017-04-30 02:40:52 +09:00
|
|
|
{
|
2018-06-01 12:41:31 +04:00
|
|
|
bool reported = false;
|
2017-04-30 02:40:52 +09:00
|
|
|
if (victim.getClass().isClass(victim, "guard")
|
2020-05-16 21:52:16 +02:00
|
|
|
&& !victim.getClass().getCreatureStats(victim).getAiSequence().hasPackage(AiPackageTypeId::Pursue))
|
2023-02-17 19:20:29 +01:00
|
|
|
reported = reportCrime(player, victim, type, ESM::RefId(), arg);
|
2018-06-01 12:41:31 +04:00
|
|
|
|
|
|
|
if (!reported)
|
2017-04-30 02:40:52 +09:00
|
|
|
startCombat(victim,
|
|
|
|
player); // TODO: combat should be started with an "unaware" flag, which makes the victim flee?
|
|
|
|
}
|
2014-12-19 21:45:26 +01:00
|
|
|
return crimeSeen;
|
2014-01-07 19:49:16 +01:00
|
|
|
}
|
|
|
|
|
2018-06-01 12:41:31 +04:00
|
|
|
bool MechanicsManager::canReportCrime(
|
|
|
|
const MWWorld::Ptr& actor, const MWWorld::Ptr& victim, std::set<MWWorld::Ptr>& playerFollowers)
|
|
|
|
{
|
|
|
|
if (actor == getPlayer() || !actor.getClass().isNpc() || actor.getClass().getCreatureStats(actor).isDead())
|
|
|
|
return false;
|
|
|
|
|
|
|
|
if (actor.getClass().getCreatureStats(actor).getAiSequence().isInCombat(victim))
|
|
|
|
return false;
|
|
|
|
|
|
|
|
// Unconsious actor can not report about crime and should not become hostile
|
|
|
|
if (actor.getClass().getCreatureStats(actor).getKnockedDown())
|
|
|
|
return false;
|
|
|
|
|
|
|
|
// Player's followers should not attack player, or try to arrest him
|
2020-05-16 21:52:16 +02:00
|
|
|
if (actor.getClass().getCreatureStats(actor).getAiSequence().hasPackage(AiPackageTypeId::Follow))
|
2018-06-01 12:41:31 +04:00
|
|
|
{
|
|
|
|
if (playerFollowers.find(actor) != playerFollowers.end())
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2019-09-16 14:20:43 +04:00
|
|
|
bool MechanicsManager::reportCrime(
|
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 MWWorld::Ptr& player, const MWWorld::Ptr& victim, OffenseType type, const ESM::RefId& factionId, int arg)
|
2014-01-07 19:49:16 +01:00
|
|
|
{
|
2014-01-09 01:55:49 +01:00
|
|
|
const MWWorld::Store<ESM::GameSetting>& store
|
2023-04-20 21:07:53 +02:00
|
|
|
= MWBase::Environment::get().getESMStore()->get<ESM::GameSetting>();
|
2014-04-24 22:47:45 -04:00
|
|
|
|
2014-06-17 03:54:41 +02:00
|
|
|
if (type == OT_Murder && !victim.isEmpty())
|
|
|
|
victim.getClass().getCreatureStats(victim).notifyMurder();
|
|
|
|
|
2014-12-21 02:45:37 +01:00
|
|
|
// Bounty and disposition penalty for each type of crime
|
|
|
|
float disp = 0.f, dispVictim = 0.f;
|
2014-01-07 19:49:16 +01:00
|
|
|
if (type == OT_Trespassing || type == OT_SleepingInOwnedBed)
|
2014-12-18 22:27:09 +01:00
|
|
|
{
|
2018-08-29 18:38:12 +03:00
|
|
|
arg = store.find("iCrimeTresspass")->mValue.getInteger();
|
|
|
|
disp = dispVictim = store.find("iDispTresspass")->mValue.getFloat();
|
2014-12-18 22:27:09 +01:00
|
|
|
}
|
2014-01-07 19:49:16 +01:00
|
|
|
else if (type == OT_Pickpocket)
|
2014-12-18 22:27:09 +01:00
|
|
|
{
|
2018-08-29 18:38:12 +03:00
|
|
|
arg = store.find("iCrimePickPocket")->mValue.getInteger();
|
|
|
|
disp = dispVictim = store.find("fDispPickPocketMod")->mValue.getFloat();
|
2014-12-18 22:27:09 +01:00
|
|
|
}
|
2014-01-07 19:49:16 +01:00
|
|
|
else if (type == OT_Assault)
|
2014-12-18 22:27:09 +01:00
|
|
|
{
|
2018-08-29 18:38:12 +03:00
|
|
|
arg = store.find("iCrimeAttack")->mValue.getInteger();
|
|
|
|
disp = store.find("iDispAttackMod")->mValue.getFloat();
|
|
|
|
dispVictim = store.find("fDispAttacking")->mValue.getFloat();
|
2014-12-18 22:27:09 +01:00
|
|
|
}
|
2014-01-07 19:49:16 +01:00
|
|
|
else if (type == OT_Murder)
|
2014-12-18 22:27:09 +01:00
|
|
|
{
|
2018-08-29 18:38:12 +03:00
|
|
|
arg = store.find("iCrimeKilling")->mValue.getInteger();
|
|
|
|
disp = dispVictim = store.find("iDispKilling")->mValue.getFloat();
|
2014-12-18 22:27:09 +01:00
|
|
|
}
|
2014-01-09 01:55:49 +01:00
|
|
|
else if (type == OT_Theft)
|
2014-06-09 03:42:29 +02:00
|
|
|
{
|
2018-08-29 18:38:12 +03:00
|
|
|
disp = dispVictim = store.find("fDispStealing")->mValue.getFloat() * arg;
|
|
|
|
arg = static_cast<int>(arg * store.find("fCrimeStealing")->mValue.getFloat());
|
2014-06-09 03:42:29 +02:00
|
|
|
arg = std::max(1, arg); // Minimum bounty of 1, in case items with zero value are stolen
|
|
|
|
}
|
2014-01-07 19:49:16 +01:00
|
|
|
|
2014-06-17 01:10:37 +02:00
|
|
|
// Make surrounding actors within alarm distance respond to the crime
|
|
|
|
std::vector<MWWorld::Ptr> neighbors;
|
|
|
|
|
2023-04-20 21:07:53 +02:00
|
|
|
const MWWorld::ESMStore& esmStore = *MWBase::Environment::get().getESMStore();
|
2014-06-17 01:10:37 +02:00
|
|
|
|
2015-06-01 21:41:13 +02:00
|
|
|
osg::Vec3f from(player.getRefData().getPosition().asVec3());
|
2018-08-29 18:38:12 +03:00
|
|
|
float radius = esmStore.get<ESM::GameSetting>().find("fAlarmRadius")->mValue.getFloat();
|
2014-06-17 01:10:37 +02:00
|
|
|
|
2015-04-25 15:19:17 +02:00
|
|
|
mActors.getObjectsInRange(from, radius, neighbors);
|
2014-06-17 01:10:37 +02:00
|
|
|
|
|
|
|
// victim should be considered even beyond alarm radius
|
2015-06-01 21:41:13 +02:00
|
|
|
if (!victim.isEmpty() && (from - victim.getRefData().getPosition().asVec3()).length2() > radius * radius)
|
2014-06-17 01:10:37 +02:00
|
|
|
neighbors.push_back(victim);
|
|
|
|
|
|
|
|
int id = MWBase::Environment::get().getWorld()->getPlayer().getNewCrimeId();
|
|
|
|
|
|
|
|
// What amount of provocation did this crime generate?
|
|
|
|
// Controls whether witnesses will engage combat with the criminal.
|
2014-12-18 22:27:09 +01:00
|
|
|
int fight = 0, fightVictim = 0;
|
2014-06-17 01:10:37 +02:00
|
|
|
if (type == OT_Trespassing || type == OT_SleepingInOwnedBed)
|
2018-08-29 18:38:12 +03:00
|
|
|
fight = fightVictim = esmStore.get<ESM::GameSetting>().find("iFightTrespass")->mValue.getInteger();
|
2014-06-17 01:10:37 +02:00
|
|
|
else if (type == OT_Pickpocket)
|
2014-12-18 22:27:09 +01:00
|
|
|
{
|
2018-08-29 18:38:12 +03:00
|
|
|
fight = esmStore.get<ESM::GameSetting>().find("iFightPickpocket")->mValue.getInteger();
|
|
|
|
fightVictim = esmStore.get<ESM::GameSetting>().find("iFightPickpocket")->mValue.getInteger()
|
|
|
|
* 4; // *4 according to research wiki
|
2014-12-18 22:27:09 +01:00
|
|
|
}
|
|
|
|
else if (type == OT_Assault)
|
|
|
|
{
|
2018-08-29 18:38:12 +03:00
|
|
|
fight = esmStore.get<ESM::GameSetting>().find("iFightAttacking")->mValue.getInteger();
|
|
|
|
fightVictim = esmStore.get<ESM::GameSetting>().find("iFightAttack")->mValue.getInteger();
|
2014-12-18 22:27:09 +01:00
|
|
|
}
|
2014-06-17 01:10:37 +02:00
|
|
|
else if (type == OT_Murder)
|
2018-08-29 18:38:12 +03:00
|
|
|
fight = fightVictim = esmStore.get<ESM::GameSetting>().find("iFightKilling")->mValue.getInteger();
|
2014-06-17 01:10:37 +02:00
|
|
|
else if (type == OT_Theft)
|
2018-08-29 18:38:12 +03:00
|
|
|
fight = fightVictim = esmStore.get<ESM::GameSetting>().find("fFightStealing")->mValue.getInteger();
|
2014-06-17 01:10:37 +02:00
|
|
|
|
2014-12-19 21:45:26 +01:00
|
|
|
bool reported = false;
|
|
|
|
|
2018-06-01 12:41:31 +04:00
|
|
|
std::set<MWWorld::Ptr> playerFollowers;
|
|
|
|
getActorsSidingWith(player, playerFollowers);
|
|
|
|
|
2014-06-17 01:10:37 +02:00
|
|
|
// Tell everyone (including the original reporter) in alarm range
|
2018-11-06 01:35:20 +03:00
|
|
|
for (const MWWorld::Ptr& actor : neighbors)
|
2014-06-17 01:10:37 +02:00
|
|
|
{
|
2018-11-06 01:35:20 +03:00
|
|
|
if (!canReportCrime(actor, victim, playerFollowers))
|
2017-09-30 20:31:06 +04:00
|
|
|
continue;
|
|
|
|
|
2014-12-19 21:45:26 +01:00
|
|
|
// Will the witness report the crime?
|
2022-07-16 16:37:31 +02:00
|
|
|
if (actor.getClass().getCreatureStats(actor).getAiSetting(AiSetting::Alarm).getBase() >= 100)
|
2014-12-19 21:45:26 +01:00
|
|
|
{
|
|
|
|
reported = true;
|
2017-08-14 18:42:19 +04:00
|
|
|
|
2017-10-15 11:03:02 +04:00
|
|
|
if (type == OT_Trespassing)
|
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(actor, ESM::RefId::stringRefId("intruder"));
|
2014-12-19 21:45:26 +01:00
|
|
|
}
|
2018-06-01 12:41:31 +04:00
|
|
|
}
|
|
|
|
|
2018-11-06 01:35:20 +03:00
|
|
|
for (const MWWorld::Ptr& actor : neighbors)
|
2018-06-01 12:41:31 +04:00
|
|
|
{
|
2018-11-06 01:35:20 +03:00
|
|
|
if (!canReportCrime(actor, victim, playerFollowers))
|
2018-06-01 12:41:31 +04:00
|
|
|
continue;
|
2014-12-19 21:45:26 +01:00
|
|
|
|
2023-09-24 21:58:10 +04:00
|
|
|
NpcStats& observerStats = actor.getClass().getNpcStats(actor);
|
|
|
|
|
|
|
|
int alarm = observerStats.getAiSetting(AiSetting::Alarm).getBase();
|
|
|
|
float alarmTerm = 0.01f * alarm;
|
|
|
|
|
|
|
|
bool isActorVictim = actor == victim;
|
|
|
|
float dispTerm = isActorVictim ? dispVictim : disp;
|
|
|
|
|
|
|
|
bool isActorGuard = actor.getClass().isClass(actor, "guard");
|
|
|
|
|
|
|
|
int currentDisposition = getDerivedDisposition(actor);
|
|
|
|
|
|
|
|
bool isPermanent = false;
|
|
|
|
bool applyOnlyIfHostile = false;
|
|
|
|
int dispositionModifier = 0;
|
|
|
|
// Murdering and trespassing seem to do not affect disposition
|
|
|
|
if (type == OT_Theft)
|
|
|
|
{
|
|
|
|
dispositionModifier = static_cast<int>(dispTerm * alarmTerm);
|
|
|
|
}
|
|
|
|
else if (type == OT_Pickpocket)
|
|
|
|
{
|
|
|
|
if (alarm >= 100 && isActorGuard)
|
|
|
|
dispositionModifier = static_cast<int>(dispTerm);
|
|
|
|
else if (isActorVictim && isActorGuard)
|
|
|
|
{
|
|
|
|
isPermanent = true;
|
|
|
|
dispositionModifier = static_cast<int>(dispTerm * alarmTerm);
|
|
|
|
}
|
|
|
|
else if (isActorVictim)
|
|
|
|
{
|
|
|
|
isPermanent = true;
|
|
|
|
dispositionModifier = static_cast<int>(dispTerm);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else if (type == OT_Assault)
|
|
|
|
{
|
|
|
|
if (isActorVictim && !isActorGuard)
|
|
|
|
{
|
|
|
|
isPermanent = true;
|
|
|
|
dispositionModifier = static_cast<int>(dispTerm);
|
|
|
|
}
|
|
|
|
else if (alarm >= 100)
|
|
|
|
dispositionModifier = static_cast<int>(dispTerm);
|
|
|
|
else if (isActorVictim && isActorGuard)
|
|
|
|
{
|
|
|
|
isPermanent = true;
|
|
|
|
dispositionModifier = static_cast<int>(dispTerm * alarmTerm);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
applyOnlyIfHostile = true;
|
|
|
|
dispositionModifier = static_cast<int>(dispTerm * alarmTerm);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
bool setCrimeId = false;
|
|
|
|
if (isPermanent && dispositionModifier != 0 && !applyOnlyIfHostile)
|
|
|
|
{
|
|
|
|
setCrimeId = true;
|
|
|
|
dispositionModifier = std::clamp(dispositionModifier, -currentDisposition, 100 - currentDisposition);
|
|
|
|
int baseDisposition = observerStats.getBaseDisposition();
|
|
|
|
observerStats.setBaseDisposition(baseDisposition + dispositionModifier);
|
|
|
|
}
|
|
|
|
else if (dispositionModifier != 0 && !applyOnlyIfHostile)
|
|
|
|
{
|
|
|
|
setCrimeId = true;
|
|
|
|
dispositionModifier = std::clamp(dispositionModifier, -currentDisposition, 100 - currentDisposition);
|
|
|
|
observerStats.modCrimeDispositionModifier(dispositionModifier);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (isActorGuard && alarm >= 100)
|
2014-06-17 01:10:37 +02:00
|
|
|
{
|
|
|
|
// Mark as Alarmed for dialogue
|
2023-09-24 21:58:10 +04:00
|
|
|
observerStats.setAlarmed(true);
|
2014-06-17 01:10:37 +02:00
|
|
|
|
2023-09-24 21:58:10 +04:00
|
|
|
setCrimeId = true;
|
2014-06-17 01:10:37 +02:00
|
|
|
|
2023-09-24 21:58:10 +04:00
|
|
|
if (!observerStats.getAiSequence().isInPursuit())
|
2017-08-05 12:38:26 +04:00
|
|
|
{
|
2023-09-24 21:58:10 +04:00
|
|
|
observerStats.getAiSequence().stack(AiPursue(player), actor);
|
2017-08-05 12:38:26 +04:00
|
|
|
}
|
2014-06-17 01:10:37 +02:00
|
|
|
}
|
|
|
|
else
|
2014-01-08 19:26:03 +01:00
|
|
|
{
|
2023-09-24 21:58:10 +04:00
|
|
|
// If Alarm is 0, treat it like 100 to calculate a Fight modifier for a victim of pickpocketing.
|
|
|
|
// Observers which do not try to arrest player do not care about pickpocketing at all.
|
|
|
|
if (type == OT_Pickpocket && isActorVictim && alarmTerm == 0.0)
|
2014-12-23 16:38:30 +01:00
|
|
|
alarmTerm = 1.0;
|
2023-09-24 21:58:10 +04:00
|
|
|
else if (type == OT_Pickpocket && !isActorVictim)
|
|
|
|
alarmTerm = 0.0;
|
2014-12-23 16:38:30 +01:00
|
|
|
|
2023-09-24 21:58:10 +04:00
|
|
|
float fightTerm = static_cast<float>(isActorVictim ? fightVictim : fight);
|
2014-12-21 02:45:37 +01:00
|
|
|
fightTerm += getFightDispositionBias(dispTerm);
|
2018-11-06 01:35:20 +03:00
|
|
|
fightTerm += getFightDistanceBias(actor, player);
|
2014-12-23 16:38:30 +01:00
|
|
|
fightTerm *= alarmTerm;
|
2014-12-18 22:27:09 +01:00
|
|
|
|
2023-09-24 21:58:10 +04:00
|
|
|
const int observerFightRating = observerStats.getAiSetting(AiSetting::Fight).getBase();
|
2014-12-21 02:45:37 +01:00
|
|
|
if (observerFightRating + fightTerm > 100)
|
2015-03-08 13:07:29 +13:00
|
|
|
fightTerm = static_cast<float>(100 - observerFightRating);
|
2014-12-21 02:45:37 +01:00
|
|
|
fightTerm = std::max(0.f, fightTerm);
|
|
|
|
|
|
|
|
if (observerFightRating + fightTerm >= 100)
|
2014-06-17 01:10:37 +02:00
|
|
|
{
|
2023-09-24 21:58:10 +04:00
|
|
|
if (dispositionModifier != 0 && applyOnlyIfHostile)
|
|
|
|
{
|
|
|
|
dispositionModifier
|
|
|
|
= std::clamp(dispositionModifier, -currentDisposition, 100 - currentDisposition);
|
|
|
|
observerStats.modCrimeDispositionModifier(dispositionModifier);
|
|
|
|
}
|
|
|
|
|
2018-11-06 01:35:20 +03:00
|
|
|
startCombat(actor, player);
|
2014-06-17 01:10:37 +02:00
|
|
|
|
2014-12-14 19:35:34 +01:00
|
|
|
// Apply aggression value to the base Fight rating, so that the actor can continue fighting
|
|
|
|
// after a Calm spell wears off
|
2022-07-16 16:37:31 +02:00
|
|
|
observerStats.setAiSetting(AiSetting::Fight, observerFightRating + static_cast<int>(fightTerm));
|
2014-12-21 02:45:37 +01:00
|
|
|
|
2023-09-24 21:58:10 +04:00
|
|
|
setCrimeId = true;
|
2014-06-17 01:10:37 +02:00
|
|
|
|
|
|
|
// Mark as Alarmed for dialogue
|
2014-12-21 02:45:37 +01:00
|
|
|
observerStats.setAlarmed(true);
|
2014-06-17 01:10:37 +02:00
|
|
|
}
|
2014-01-08 19:26:03 +01:00
|
|
|
}
|
2023-09-24 21:58:10 +04:00
|
|
|
|
|
|
|
// Set the crime ID, which we will use to calm down participants
|
|
|
|
// once the bounty has been paid and restore their disposition to player character.
|
|
|
|
if (setCrimeId)
|
|
|
|
observerStats.setCrimeId(id);
|
2014-01-08 19:26:03 +01:00
|
|
|
}
|
2014-12-19 21:45:26 +01:00
|
|
|
|
|
|
|
if (reported)
|
|
|
|
{
|
2023-12-18 21:52:17 +01:00
|
|
|
player.getClass().getNpcStats(player).setBounty(
|
|
|
|
std::max(0, player.getClass().getNpcStats(player).getBounty() + arg));
|
2014-12-19 21:45:26 +01:00
|
|
|
|
|
|
|
// If committing a crime against a faction member, expell from the faction
|
|
|
|
if (!victim.isEmpty() && victim.getClass().isNpc())
|
|
|
|
{
|
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 = victim.getClass().getPrimaryFaction(victim);
|
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 std::map<ESM::RefId, int>& playerRanks = player.getClass().getNpcStats(player).getFactionRanks();
|
|
|
|
if (playerRanks.find(factionID) != playerRanks.end())
|
2014-12-19 21:45:26 +01:00
|
|
|
{
|
2023-09-06 20:28:35 +04:00
|
|
|
player.getClass().getNpcStats(player).expell(factionID, true);
|
2014-12-19 21:45:26 +01:00
|
|
|
}
|
|
|
|
}
|
2019-09-16 14:20:43 +04:00
|
|
|
else if (!factionId.empty())
|
|
|
|
{
|
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 std::map<ESM::RefId, int>& playerRanks = player.getClass().getNpcStats(player).getFactionRanks();
|
|
|
|
if (playerRanks.find(factionId) != playerRanks.end())
|
2019-09-16 14:20:43 +04:00
|
|
|
{
|
2023-09-06 20:28:35 +04:00
|
|
|
player.getClass().getNpcStats(player).expell(factionId, true);
|
2019-09-16 14:20:43 +04:00
|
|
|
}
|
|
|
|
}
|
2015-01-05 19:59:47 +01:00
|
|
|
|
|
|
|
if (type == OT_Assault && !victim.isEmpty()
|
|
|
|
&& !victim.getClass().getCreatureStats(victim).getAiSequence().isInCombat(player)
|
|
|
|
&& victim.getClass().isNpc())
|
|
|
|
{
|
|
|
|
// Attacker is in combat with us, but we are not in combat with the attacker yet. Time to fight back.
|
|
|
|
// Note: accidental or collateral damage attacks are ignored.
|
2022-02-12 23:50:41 +00:00
|
|
|
if (!victim.getClass().getCreatureStats(victim).getAiSequence().isInPursuit())
|
2017-04-30 02:40:52 +09:00
|
|
|
startCombat(victim, player);
|
2015-01-05 19:59:47 +01:00
|
|
|
|
|
|
|
// Set the crime ID, which we will use to calm down participants
|
|
|
|
// once the bounty has been paid.
|
|
|
|
victim.getClass().getNpcStats(victim).setCrimeId(id);
|
|
|
|
}
|
2014-12-19 21:45:26 +01:00
|
|
|
}
|
2018-06-01 12:41:31 +04:00
|
|
|
|
|
|
|
return reported;
|
2014-01-07 19:49:16 +01:00
|
|
|
}
|
|
|
|
|
2017-02-02 02:15:10 +09:00
|
|
|
bool MechanicsManager::actorAttacked(const MWWorld::Ptr& target, const MWWorld::Ptr& attacker)
|
2014-08-03 15:20:33 +02:00
|
|
|
{
|
2019-04-16 15:09:53 +04:00
|
|
|
const MWWorld::Ptr& player = getPlayer();
|
|
|
|
if (target == player || !attacker.getClass().isActor())
|
2017-02-11 19:59:42 +09:00
|
|
|
return false;
|
|
|
|
|
2017-02-02 02:15:10 +09:00
|
|
|
MWMechanics::CreatureStats& statsTarget = target.getClass().getCreatureStats(target);
|
2019-04-16 15:09:53 +04:00
|
|
|
if (attacker == player)
|
2014-08-03 15:20:33 +02:00
|
|
|
{
|
2019-04-16 15:09:53 +04:00
|
|
|
std::set<MWWorld::Ptr> followersAttacker;
|
|
|
|
getActorsSidingWith(attacker, followersAttacker);
|
|
|
|
if (followersAttacker.find(target) != followersAttacker.end())
|
2014-09-18 05:13:17 +02:00
|
|
|
{
|
2019-04-16 15:09:53 +04:00
|
|
|
statsTarget.friendlyHit();
|
|
|
|
|
|
|
|
if (statsTarget.getFriendlyHits() < 4)
|
|
|
|
{
|
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(target, ESM::RefId::stringRefId("hit"));
|
2019-04-16 15:09:53 +04:00
|
|
|
return false;
|
|
|
|
}
|
2014-09-18 05:13:17 +02:00
|
|
|
}
|
2014-08-03 15:20:33 +02:00
|
|
|
}
|
|
|
|
|
2018-08-16 00:26:02 +01:00
|
|
|
if (canCommitCrimeAgainst(target, attacker))
|
2017-02-02 02:15:10 +09:00
|
|
|
commitCrime(attacker, target, MWBase::MechanicsManager::OT_Assault);
|
2014-08-03 15:20:33 +02:00
|
|
|
|
2018-08-16 00:26:02 +01:00
|
|
|
AiSequence& seq = statsTarget.getAiSequence();
|
|
|
|
|
2019-04-16 15:09:53 +04:00
|
|
|
if (!attacker.isEmpty()
|
|
|
|
&& (attacker.getClass().getCreatureStats(attacker).getAiSequence().isInCombat(target) || attacker == player)
|
|
|
|
&& !seq.isInCombat(attacker))
|
2014-08-03 15:20:33 +02:00
|
|
|
{
|
|
|
|
// Attacker is in combat with us, but we are not in combat with the attacker yet. Time to fight back.
|
|
|
|
// Note: accidental or collateral damage attacks are ignored.
|
2022-02-12 23:50:41 +00:00
|
|
|
if (!target.getClass().getCreatureStats(target).getAiSequence().isInPursuit())
|
2018-04-02 22:27:04 +04:00
|
|
|
{
|
|
|
|
// If an actor has OnPCHitMe declared in his script, his Fight = 0 and the attacker is player,
|
|
|
|
// he will attack the player only if we will force him (e.g. via StartCombat console command)
|
|
|
|
bool peaceful = false;
|
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 = target.getClass().getScript(target);
|
2019-04-16 15:09:53 +04:00
|
|
|
if (!script.empty() && target.getRefData().getLocals().hasVar(script, "onpchitme")
|
|
|
|
&& attacker == player)
|
2018-04-02 22:27:04 +04:00
|
|
|
{
|
2022-07-16 16:37:31 +02:00
|
|
|
const int fight
|
|
|
|
= target.getClass().getCreatureStats(target).getAiSetting(AiSetting::Fight).getModified();
|
2018-04-02 22:27:04 +04:00
|
|
|
peaceful = (fight == 0);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!peaceful)
|
2021-11-23 22:44:47 +01:00
|
|
|
{
|
2018-04-02 22:27:04 +04:00
|
|
|
startCombat(target, attacker);
|
2021-11-23 22:44:47 +01:00
|
|
|
// Force friendly actors into combat to prevent infighting between followers
|
|
|
|
std::set<MWWorld::Ptr> followersTarget;
|
|
|
|
getActorsSidingWith(target, followersTarget);
|
|
|
|
for (const auto& follower : followersTarget)
|
2022-07-06 19:12:36 +02:00
|
|
|
{
|
|
|
|
if (follower != attacker && follower != player)
|
|
|
|
startCombat(follower, attacker);
|
|
|
|
}
|
2021-11-23 22:44:47 +01:00
|
|
|
}
|
2018-04-02 22:27:04 +04:00
|
|
|
}
|
2014-08-03 15:20:33 +02:00
|
|
|
}
|
2014-09-26 22:08:07 +02:00
|
|
|
|
|
|
|
return true;
|
2014-08-03 15:20:33 +02:00
|
|
|
}
|
|
|
|
|
2018-08-16 00:26:02 +01:00
|
|
|
bool MechanicsManager::canCommitCrimeAgainst(const MWWorld::Ptr& target, const MWWorld::Ptr& attacker)
|
|
|
|
{
|
2023-12-15 21:28:09 +03:00
|
|
|
const MWWorld::Class& cls = target.getClass();
|
|
|
|
const MWMechanics::CreatureStats& stats = cls.getCreatureStats(target);
|
|
|
|
const MWMechanics::AiSequence& seq = stats.getAiSequence();
|
|
|
|
return cls.isNpc() && !attacker.isEmpty() && !seq.isInCombat(attacker) && !isAggressive(target, attacker)
|
|
|
|
&& !seq.isEngagedWithActor() && !stats.getAiSequence().isInPursuit()
|
|
|
|
&& !cls.getNpcStats(target).isWerewolf()
|
|
|
|
&& stats.getMagicEffects().getOrDefault(ESM::MagicEffect::Vampirism).getMagnitude() <= 0;
|
2018-08-16 00:26:02 +01:00
|
|
|
}
|
|
|
|
|
2015-07-18 20:39:45 +02:00
|
|
|
void MechanicsManager::actorKilled(const MWWorld::Ptr& victim, const MWWorld::Ptr& attacker)
|
|
|
|
{
|
2018-06-15 14:03:43 +04:00
|
|
|
if (attacker.isEmpty() || victim.isEmpty())
|
2015-07-18 20:39:45 +02:00
|
|
|
return;
|
|
|
|
|
|
|
|
if (victim == attacker)
|
|
|
|
return; // known to happen
|
|
|
|
|
|
|
|
if (!victim.getClass().isNpc())
|
|
|
|
return; // TODO: implement animal rights
|
|
|
|
|
|
|
|
const MWMechanics::NpcStats& victimStats = victim.getClass().getNpcStats(victim);
|
2018-08-16 18:58:51 +01:00
|
|
|
const MWWorld::Ptr& player = getPlayer();
|
2018-08-17 22:35:04 +01:00
|
|
|
bool canCommit = attacker == player && canCommitCrimeAgainst(victim, attacker);
|
2018-06-15 14:03:43 +04:00
|
|
|
|
|
|
|
// For now we report only about crimes of player and player's followers
|
|
|
|
if (attacker != player)
|
|
|
|
{
|
|
|
|
std::set<MWWorld::Ptr> playerFollowers;
|
|
|
|
getActorsSidingWith(player, playerFollowers);
|
|
|
|
if (playerFollowers.find(attacker) == playerFollowers.end())
|
|
|
|
return;
|
|
|
|
}
|
2015-07-18 20:39:45 +02:00
|
|
|
|
2018-08-16 18:58:51 +01:00
|
|
|
if (!canCommit && victimStats.getCrimeId() == -1)
|
|
|
|
return;
|
|
|
|
|
2015-07-18 20:39:45 +02:00
|
|
|
// Simple check for who attacked first: if the player attacked first, a crimeId should be set
|
|
|
|
// Doesn't handle possible edge case where no one reported the assault, but in such a case,
|
|
|
|
// for bystanders it is not possible to tell who attacked first, anyway.
|
2018-06-15 14:03:43 +04:00
|
|
|
commitCrime(player, victim, MWBase::MechanicsManager::OT_Murder);
|
2015-07-18 20:39:45 +02:00
|
|
|
}
|
|
|
|
|
2014-01-07 00:51:09 +01:00
|
|
|
bool MechanicsManager::awarenessCheck(const MWWorld::Ptr& ptr, const MWWorld::Ptr& observer)
|
|
|
|
{
|
2014-12-27 15:02:05 +01:00
|
|
|
if (observer.getClass().getCreatureStats(observer).isDead() || !observer.getRefData().isEnabled())
|
2014-01-11 02:06:54 +01:00
|
|
|
return false;
|
|
|
|
|
2014-01-07 00:51:09 +01:00
|
|
|
const MWWorld::Store<ESM::GameSetting>& store
|
2023-04-20 21:07:53 +02:00
|
|
|
= MWBase::Environment::get().getESMStore()->get<ESM::GameSetting>();
|
2014-01-07 00:51:09 +01:00
|
|
|
|
|
|
|
CreatureStats& stats = ptr.getClass().getCreatureStats(ptr);
|
|
|
|
|
|
|
|
float sneakTerm = 0;
|
2019-07-30 20:58:19 +03:00
|
|
|
if (isSneaking(ptr))
|
2014-01-07 00:51:09 +01:00
|
|
|
{
|
2018-08-29 18:38:12 +03:00
|
|
|
static float fSneakSkillMult = store.find("fSneakSkillMult")->mValue.getFloat();
|
|
|
|
static float fSneakBootMult = store.find("fSneakBootMult")->mValue.getFloat();
|
2015-03-08 13:07:29 +13:00
|
|
|
float sneak = static_cast<float>(ptr.getClass().getSkill(ptr, ESM::Skill::Sneak));
|
2018-12-23 15:18:33 +04:00
|
|
|
float agility = stats.getAttribute(ESM::Attribute::Agility).getModified();
|
|
|
|
float luck = stats.getAttribute(ESM::Attribute::Luck).getModified();
|
2014-01-07 00:51:09 +01:00
|
|
|
float bootWeight = 0;
|
2019-07-30 20:58:19 +03:00
|
|
|
if (ptr.getClass().isNpc() && MWBase::Environment::get().getWorld()->isOnGround(ptr))
|
2014-01-07 00:51:09 +01:00
|
|
|
{
|
2017-02-28 14:31:51 +00:00
|
|
|
const MWWorld::InventoryStore& inv = ptr.getClass().getInventoryStore(ptr);
|
|
|
|
MWWorld::ConstContainerStoreIterator it = inv.getSlot(MWWorld::InventoryStore::Slot_Boots);
|
2014-01-07 00:51:09 +01:00
|
|
|
if (it != inv.end())
|
|
|
|
bootWeight = it->getClass().getWeight(*it);
|
|
|
|
}
|
2015-03-08 13:07:29 +13:00
|
|
|
sneakTerm = fSneakSkillMult * sneak + 0.2f * agility + 0.1f * luck + bootWeight * fSneakBootMult;
|
2014-01-07 00:51:09 +01:00
|
|
|
}
|
|
|
|
|
2018-08-29 18:38:12 +03:00
|
|
|
static float fSneakDistBase = store.find("fSneakDistanceBase")->mValue.getFloat();
|
|
|
|
static float fSneakDistMult = store.find("fSneakDistanceMultiplier")->mValue.getFloat();
|
2014-01-07 00:51:09 +01:00
|
|
|
|
2015-05-30 01:00:24 +02:00
|
|
|
osg::Vec3f pos1(ptr.getRefData().getPosition().asVec3());
|
|
|
|
osg::Vec3f pos2(observer.getRefData().getPosition().asVec3());
|
|
|
|
float distTerm = fSneakDistBase + fSneakDistMult * (pos1 - pos2).length();
|
2014-01-07 00:51:09 +01:00
|
|
|
|
2023-05-23 19:06:08 +02:00
|
|
|
float chameleon = stats.getMagicEffects().getOrDefault(ESM::MagicEffect::Chameleon).getMagnitude();
|
|
|
|
float invisibility = stats.getMagicEffects().getOrDefault(ESM::MagicEffect::Invisibility).getMagnitude();
|
2022-07-29 18:24:02 +03:00
|
|
|
float x = sneakTerm * distTerm * stats.getFatigueTerm() + chameleon;
|
|
|
|
if (invisibility > 0.f)
|
|
|
|
x += 100.f;
|
2014-01-07 00:51:09 +01:00
|
|
|
|
|
|
|
CreatureStats& observerStats = observer.getClass().getCreatureStats(observer);
|
2018-12-23 15:18:33 +04:00
|
|
|
float obsAgility = observerStats.getAttribute(ESM::Attribute::Agility).getModified();
|
|
|
|
float obsLuck = observerStats.getAttribute(ESM::Attribute::Luck).getModified();
|
2023-05-23 19:06:08 +02:00
|
|
|
float obsBlind = observerStats.getMagicEffects().getOrDefault(ESM::MagicEffect::Blind).getMagnitude();
|
2018-12-23 15:18:33 +04:00
|
|
|
float obsSneak = observer.getClass().getSkill(observer, ESM::Skill::Sneak);
|
2014-01-07 00:51:09 +01:00
|
|
|
|
2015-03-08 13:07:29 +13:00
|
|
|
float obsTerm = obsSneak + 0.2f * obsAgility + 0.1f * obsLuck - obsBlind;
|
2014-01-07 00:51:09 +01:00
|
|
|
|
|
|
|
// is ptr behind the observer?
|
2018-08-29 18:38:12 +03:00
|
|
|
static float fSneakNoViewMult = store.find("fSneakNoViewMult")->mValue.getFloat();
|
|
|
|
static float fSneakViewMult = store.find("fSneakViewMult")->mValue.getFloat();
|
2014-01-07 00:51:09 +01:00
|
|
|
float y = 0;
|
2015-05-30 01:00:24 +02:00
|
|
|
osg::Vec3f vec = pos1 - pos2;
|
|
|
|
if (observer.getRefData().getBaseNode())
|
|
|
|
{
|
2015-06-05 03:41:10 +02:00
|
|
|
osg::Vec3f observerDir = (observer.getRefData().getBaseNode()->getAttitude() * osg::Vec3f(0, 1, 0));
|
|
|
|
|
|
|
|
float angleRadians = std::acos(observerDir * vec / (observerDir.length() * vec.length()));
|
2016-01-02 12:24:39 -06:00
|
|
|
if (angleRadians > osg::DegreesToRadians(90.f))
|
2015-05-30 01:00:24 +02:00
|
|
|
y = obsTerm * observerStats.getFatigueTerm() * fSneakNoViewMult;
|
|
|
|
else
|
|
|
|
y = obsTerm * observerStats.getFatigueTerm() * fSneakViewMult;
|
|
|
|
}
|
2014-01-07 00:51:09 +01:00
|
|
|
|
|
|
|
float target = x - y;
|
2022-03-06 21:56:02 +02:00
|
|
|
auto& prng = MWBase::Environment::get().getWorld()->getPrng();
|
|
|
|
return (Misc::Rng::roll0to99(prng) >= target);
|
2014-01-07 00:51:09 +01:00
|
|
|
}
|
2014-01-20 13:00:43 +01:00
|
|
|
|
2023-08-18 11:03:37 +04:00
|
|
|
void MechanicsManager::updateMusicState()
|
|
|
|
{
|
|
|
|
bool musicPlaying = MWBase::Environment::get().getSoundManager()->isMusicPlaying();
|
|
|
|
|
|
|
|
// Can not interrupt scripted music by built-in playlists
|
|
|
|
if (mMusicType == MWSound::MusicType::Scripted && musicPlaying)
|
|
|
|
return;
|
|
|
|
|
|
|
|
const MWWorld::Ptr& player = MWMechanics::getPlayer();
|
|
|
|
bool hasHostiles = mActors.playerHasHostiles();
|
|
|
|
|
|
|
|
// check if we still have any player enemies to switch music
|
|
|
|
if (mMusicType != MWSound::MusicType::Explore && !hasHostiles
|
|
|
|
&& !(player.getClass().getCreatureStats(player).isDead() && musicPlaying))
|
|
|
|
{
|
|
|
|
MWBase::Environment::get().getSoundManager()->playPlaylist(std::string("Explore"));
|
|
|
|
mMusicType = MWSound::MusicType::Explore;
|
|
|
|
}
|
|
|
|
else if (mMusicType != MWSound::MusicType::Battle && hasHostiles)
|
|
|
|
{
|
|
|
|
MWBase::Environment::get().getSoundManager()->playPlaylist(std::string("Battle"));
|
|
|
|
mMusicType = MWSound::MusicType::Battle;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-05-06 00:13:31 +02:00
|
|
|
void MechanicsManager::startCombat(const MWWorld::Ptr& ptr, const MWWorld::Ptr& target)
|
|
|
|
{
|
2019-06-27 19:50:54 +03:00
|
|
|
CreatureStats& stats = ptr.getClass().getCreatureStats(ptr);
|
2017-11-28 12:05:05 +04:00
|
|
|
|
2019-06-27 19:50:54 +03:00
|
|
|
// Don't add duplicate packages nor add packages to dead actors.
|
|
|
|
if (stats.isDead() || stats.getAiSequence().isInCombat(target))
|
2014-07-27 20:30:52 +02:00
|
|
|
return;
|
2017-11-28 12:05:05 +04:00
|
|
|
|
2019-06-27 19:50:54 +03:00
|
|
|
// The target is somehow the same as the actor. Early-out.
|
|
|
|
if (ptr == target)
|
|
|
|
{
|
|
|
|
// We don't care about dialogue filters since the target is invalid.
|
|
|
|
// We still want to play the combat taunt.
|
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("attack"));
|
2019-06-27 19:50:54 +03:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
stats.getAiSequence().stack(MWMechanics::AiCombat(target), ptr);
|
2015-08-21 21:12:39 +12:00
|
|
|
if (target == getPlayer())
|
2014-06-14 23:36:57 +04:00
|
|
|
{
|
|
|
|
// if guard starts combat with player, guards pursuing player should do the same
|
|
|
|
if (ptr.getClass().isClass(ptr, "Guard"))
|
|
|
|
{
|
2019-06-27 19:50:54 +03:00
|
|
|
stats.setHitAttemptActorId(
|
|
|
|
target.getClass()
|
|
|
|
.getCreatureStats(target)
|
|
|
|
.getActorId()); // Stops guard from ending combat if player is unreachable
|
2022-05-18 19:24:57 +02:00
|
|
|
for (const Actor& actor : mActors)
|
2014-06-14 23:36:57 +04:00
|
|
|
{
|
2022-05-18 19:24:57 +02:00
|
|
|
if (actor.getPtr().getClass().isClass(actor.getPtr(), "Guard"))
|
2014-06-14 23:36:57 +04:00
|
|
|
{
|
2022-05-18 19:24:57 +02:00
|
|
|
MWMechanics::AiSequence& aiSeq
|
|
|
|
= actor.getPtr().getClass().getCreatureStats(actor.getPtr()).getAiSequence();
|
2020-05-16 21:52:16 +02:00
|
|
|
if (aiSeq.getTypeId() == MWMechanics::AiPackageTypeId::Pursue)
|
2014-06-14 23:36:57 +04:00
|
|
|
{
|
|
|
|
aiSeq.stopPursuit();
|
|
|
|
aiSeq.stack(MWMechanics::AiCombat(target), ptr);
|
2022-05-18 19:24:57 +02:00
|
|
|
actor.getPtr()
|
|
|
|
.getClass()
|
|
|
|
.getCreatureStats(actor.getPtr())
|
|
|
|
.setHitAttemptActorId(
|
|
|
|
target.getClass()
|
|
|
|
.getCreatureStats(target)
|
|
|
|
.getActorId()); // Stops guard from ending combat if player is unreachable
|
2014-06-14 23:36:57 +04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-05-28 13:59:31 +02:00
|
|
|
// Must be done after the target is set up, so that CreatureTargetted dialogue filter works properly
|
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("attack"));
|
2014-05-06 00:13:31 +02:00
|
|
|
}
|
|
|
|
|
2021-11-25 22:00:52 +01:00
|
|
|
void MechanicsManager::stopCombat(const MWWorld::Ptr& actor)
|
|
|
|
{
|
|
|
|
mActors.stopCombat(actor);
|
|
|
|
}
|
|
|
|
|
2015-06-01 21:41:13 +02:00
|
|
|
void MechanicsManager::getObjectsInRange(
|
|
|
|
const osg::Vec3f& position, float radius, std::vector<MWWorld::Ptr>& objects)
|
2014-01-20 13:00:43 +01:00
|
|
|
{
|
2015-04-25 15:19:17 +02:00
|
|
|
mActors.getObjectsInRange(position, radius, objects);
|
|
|
|
mObjects.getObjectsInRange(position, radius, objects);
|
2014-01-20 13:00:43 +01:00
|
|
|
}
|
2014-01-28 12:33:31 +01:00
|
|
|
|
2015-06-01 21:41:13 +02:00
|
|
|
void MechanicsManager::getActorsInRange(
|
|
|
|
const osg::Vec3f& position, float radius, std::vector<MWWorld::Ptr>& objects)
|
2014-01-12 14:02:15 +01:00
|
|
|
{
|
2015-04-25 15:19:17 +02:00
|
|
|
mActors.getObjectsInRange(position, radius, objects);
|
2014-01-12 14:02:15 +01:00
|
|
|
}
|
2014-04-24 20:40:17 -04:00
|
|
|
|
2017-11-11 12:31:18 +04:00
|
|
|
bool MechanicsManager::isAnyActorInRange(const osg::Vec3f& position, float radius)
|
|
|
|
{
|
|
|
|
return mActors.isAnyObjectInRange(position, radius);
|
|
|
|
}
|
|
|
|
|
2022-02-25 04:02:21 +02:00
|
|
|
std::vector<MWWorld::Ptr> MechanicsManager::getActorsSidingWith(const MWWorld::Ptr& actor)
|
2014-01-12 14:02:15 +01:00
|
|
|
{
|
2015-12-06 23:32:49 +01:00
|
|
|
return mActors.getActorsSidingWith(actor);
|
2014-01-12 14:02:15 +01:00
|
|
|
}
|
2014-04-24 22:47:45 -04:00
|
|
|
|
2022-02-25 04:02:21 +02:00
|
|
|
std::vector<MWWorld::Ptr> MechanicsManager::getActorsFollowing(const MWWorld::Ptr& actor)
|
2015-12-19 15:11:07 +01:00
|
|
|
{
|
|
|
|
return mActors.getActorsFollowing(actor);
|
|
|
|
}
|
|
|
|
|
2022-02-25 04:02:21 +02:00
|
|
|
std::vector<int> MechanicsManager::getActorsFollowingIndices(const MWWorld::Ptr& actor)
|
2014-12-09 16:02:07 +01:00
|
|
|
{
|
2015-04-25 15:19:17 +02:00
|
|
|
return mActors.getActorsFollowingIndices(actor);
|
2014-12-09 16:02:07 +01:00
|
|
|
}
|
|
|
|
|
2020-12-25 23:57:01 +01:00
|
|
|
std::map<int, MWWorld::Ptr> MechanicsManager::getActorsFollowingByIndex(const MWWorld::Ptr& actor)
|
|
|
|
{
|
|
|
|
return mActors.getActorsFollowingByIndex(actor);
|
|
|
|
}
|
|
|
|
|
2022-02-25 04:02:21 +02:00
|
|
|
std::vector<MWWorld::Ptr> MechanicsManager::getActorsFighting(const MWWorld::Ptr& actor)
|
|
|
|
{
|
2015-04-25 15:19:17 +02:00
|
|
|
return mActors.getActorsFighting(actor);
|
2014-04-24 22:47:45 -04:00
|
|
|
}
|
2014-06-13 01:24:58 +02:00
|
|
|
|
2022-02-25 04:02:21 +02:00
|
|
|
std::vector<MWWorld::Ptr> MechanicsManager::getEnemiesNearby(const MWWorld::Ptr& actor)
|
|
|
|
{
|
2016-06-07 01:53:16 +02:00
|
|
|
return mActors.getEnemiesNearby(actor);
|
|
|
|
}
|
|
|
|
|
2016-12-20 12:38:51 +01:00
|
|
|
void MechanicsManager::getActorsFollowing(const MWWorld::Ptr& actor, std::set<MWWorld::Ptr>& out)
|
|
|
|
{
|
|
|
|
mActors.getActorsFollowing(actor, out);
|
|
|
|
}
|
|
|
|
|
|
|
|
void MechanicsManager::getActorsSidingWith(const MWWorld::Ptr& actor, std::set<MWWorld::Ptr>& out)
|
|
|
|
{
|
|
|
|
mActors.getActorsSidingWith(actor, out);
|
|
|
|
}
|
|
|
|
|
2014-06-13 01:24:58 +02:00
|
|
|
int MechanicsManager::countSavedGameRecords() const
|
|
|
|
{
|
2015-02-04 21:18:43 +01:00
|
|
|
return 1 // Death counter
|
|
|
|
+ 1; // Stolen items
|
2014-06-13 01:24:58 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
void MechanicsManager::write(ESM::ESMWriter& writer, Loading::Listener& listener) const
|
|
|
|
{
|
2015-04-25 15:19:17 +02:00
|
|
|
mActors.write(writer, listener);
|
2015-02-04 21:18:43 +01:00
|
|
|
|
|
|
|
ESM::StolenItems items;
|
|
|
|
items.mStolenItems = mStolenItems;
|
|
|
|
writer.startRecord(ESM::REC_STLN);
|
|
|
|
items.write(writer);
|
|
|
|
writer.endRecord(ESM::REC_STLN);
|
2014-06-13 01:24:58 +02:00
|
|
|
}
|
|
|
|
|
2015-01-22 19:04:59 +01:00
|
|
|
void MechanicsManager::readRecord(ESM::ESMReader& reader, uint32_t type)
|
2014-06-13 01:24:58 +02:00
|
|
|
{
|
2015-02-04 21:18:43 +01:00
|
|
|
if (type == ESM::REC_STLN)
|
|
|
|
{
|
|
|
|
ESM::StolenItems items;
|
|
|
|
items.load(reader);
|
|
|
|
mStolenItems = items.mStolenItems;
|
|
|
|
}
|
2015-04-25 15:19:17 +02:00
|
|
|
else
|
|
|
|
mActors.readRecord(reader, type);
|
2014-06-13 01:24:58 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
void MechanicsManager::clear()
|
|
|
|
{
|
2015-04-25 15:19:17 +02:00
|
|
|
mActors.clear();
|
2015-02-04 21:18:43 +01:00
|
|
|
mStolenItems.clear();
|
2016-04-03 20:23:28 +02:00
|
|
|
mClassSelected = false;
|
|
|
|
mRaceSelected = false;
|
2014-06-13 01:24:58 +02:00
|
|
|
}
|
2014-06-16 19:34:53 +02:00
|
|
|
|
2014-12-21 02:45:37 +01:00
|
|
|
bool MechanicsManager::isAggressive(const MWWorld::Ptr& ptr, const MWWorld::Ptr& target)
|
2014-06-16 19:34:53 +02:00
|
|
|
{
|
2017-12-06 00:31:48 +09:00
|
|
|
// Don't become aggressive if a calm effect is active, since it would cause combat to cycle on/off as
|
|
|
|
// combat is activated here and then canceled by the calm effect
|
|
|
|
if ((ptr.getClass().isNpc()
|
|
|
|
&& ptr.getClass()
|
|
|
|
.getCreatureStats(ptr)
|
|
|
|
.getMagicEffects()
|
2023-05-23 19:06:08 +02:00
|
|
|
.getOrDefault(ESM::MagicEffect::CalmHumanoid)
|
2017-12-06 00:31:48 +09:00
|
|
|
.getMagnitude()
|
|
|
|
> 0)
|
|
|
|
|| (!ptr.getClass().isNpc()
|
|
|
|
&& ptr.getClass()
|
|
|
|
.getCreatureStats(ptr)
|
|
|
|
.getMagicEffects()
|
2023-05-23 19:06:08 +02:00
|
|
|
.getOrDefault(ESM::MagicEffect::CalmCreature)
|
2017-12-06 00:31:48 +09:00
|
|
|
.getMagnitude()
|
|
|
|
> 0))
|
|
|
|
return false;
|
|
|
|
|
2014-06-16 19:34:53 +02:00
|
|
|
int disposition = 50;
|
|
|
|
if (ptr.getClass().isNpc())
|
2021-06-24 22:02:52 +02:00
|
|
|
disposition = getDerivedDisposition(ptr);
|
2014-06-16 19:34:53 +02:00
|
|
|
|
2022-07-16 16:37:31 +02:00
|
|
|
int fight = ptr.getClass().getCreatureStats(ptr).getAiSetting(AiSetting::Fight).getModified()
|
2019-07-31 00:07:03 +03:00
|
|
|
+ static_cast<int>(
|
|
|
|
getFightDistanceBias(ptr, target) + getFightDispositionBias(static_cast<float>(disposition)));
|
2014-06-16 19:34:53 +02:00
|
|
|
|
2014-09-06 03:09:11 +02:00
|
|
|
if (ptr.getClass().isNpc() && target.getClass().isNpc())
|
2014-09-05 01:58:57 +02:00
|
|
|
{
|
2014-09-06 03:09:11 +02:00
|
|
|
if (target.getClass().getNpcStats(target).isWerewolf()
|
2023-02-07 00:37:55 +01:00
|
|
|
|| (target == getPlayer()
|
|
|
|
&& MWBase::Environment::get().getWorld()->getGlobalInt(MWWorld::Globals::sPCKnownWerewolf)))
|
2014-09-06 03:09:11 +02:00
|
|
|
{
|
2016-01-21 16:08:04 +01:00
|
|
|
const ESM::GameSetting* iWerewolfFightMod
|
2023-04-20 21:07:53 +02:00
|
|
|
= MWBase::Environment::get().getESMStore()->get<ESM::GameSetting>().find("iWerewolfFightMod");
|
2018-08-29 18:38:12 +03:00
|
|
|
fight += iWerewolfFightMod->mValue.getInteger();
|
2014-09-06 03:09:11 +02:00
|
|
|
}
|
2014-09-05 01:58:57 +02:00
|
|
|
}
|
|
|
|
|
2014-06-16 19:34:53 +02:00
|
|
|
return (fight >= 100);
|
|
|
|
}
|
2014-09-05 17:17:45 +02:00
|
|
|
|
2019-09-21 20:22:45 +04:00
|
|
|
void MechanicsManager::resurrect(const MWWorld::Ptr& ptr)
|
2014-09-05 17:17:45 +02:00
|
|
|
{
|
2019-09-21 20:22:45 +04:00
|
|
|
CreatureStats& stats = ptr.getClass().getCreatureStats(ptr);
|
2014-09-05 17:17:45 +02:00
|
|
|
if (stats.isDead())
|
2019-09-21 20:22:45 +04:00
|
|
|
{
|
2014-09-05 17:17:45 +02:00
|
|
|
stats.resurrect();
|
2019-09-21 20:22:45 +04:00
|
|
|
mActors.resurrect(ptr);
|
|
|
|
}
|
2014-09-05 17:17:45 +02:00
|
|
|
}
|
2014-12-12 16:49:22 +01:00
|
|
|
|
2018-06-28 16:58:51 +04:00
|
|
|
bool MechanicsManager::isCastingSpell(const MWWorld::Ptr& ptr) const
|
|
|
|
{
|
|
|
|
return mActors.isCastingSpell(ptr);
|
|
|
|
}
|
|
|
|
|
2014-12-12 16:49:22 +01:00
|
|
|
bool MechanicsManager::isReadyToBlock(const MWWorld::Ptr& ptr) const
|
|
|
|
{
|
2015-04-25 15:19:17 +02:00
|
|
|
return mActors.isReadyToBlock(ptr);
|
2014-12-12 16:49:22 +01:00
|
|
|
}
|
2015-12-26 18:22:21 +01:00
|
|
|
|
2017-08-18 19:24:34 +04:00
|
|
|
bool MechanicsManager::isAttackingOrSpell(const MWWorld::Ptr& ptr) const
|
|
|
|
{
|
|
|
|
return mActors.isAttackingOrSpell(ptr);
|
|
|
|
}
|
|
|
|
|
2015-12-26 18:22:21 +01:00
|
|
|
void MechanicsManager::setWerewolf(const MWWorld::Ptr& actor, bool werewolf)
|
|
|
|
{
|
|
|
|
MWMechanics::NpcStats& npcStats = actor.getClass().getNpcStats(actor);
|
|
|
|
|
|
|
|
// The actor does not have to change state
|
|
|
|
if (npcStats.isWerewolf() == werewolf)
|
|
|
|
return;
|
|
|
|
|
|
|
|
MWWorld::Player* player = &MWBase::Environment::get().getWorld()->getPlayer();
|
|
|
|
|
2015-12-26 18:26:55 +01:00
|
|
|
// Werewolfs can not cast spells, so we need to unset the prepared spell if there is one.
|
2022-07-17 19:36:48 +03:00
|
|
|
if (npcStats.getDrawState() == MWMechanics::DrawState::Spell)
|
|
|
|
npcStats.setDrawState(MWMechanics::DrawState::Nothing);
|
2015-12-26 18:26:55 +01:00
|
|
|
|
|
|
|
npcStats.setWerewolf(werewolf);
|
|
|
|
|
2016-11-22 16:37:49 +01:00
|
|
|
MWWorld::InventoryStore& inv = actor.getClass().getInventoryStore(actor);
|
|
|
|
|
2015-12-26 18:22:21 +01:00
|
|
|
if (werewolf)
|
|
|
|
{
|
2023-01-16 23:51:04 +01:00
|
|
|
inv.unequipAll();
|
2022-10-18 09:26:55 +02:00
|
|
|
inv.equip(MWWorld::InventoryStore::Slot_Robe,
|
2023-01-16 23:51:04 +01:00
|
|
|
inv.ContainerStore::add(ESM::RefId::stringRefId("werewolfrobe"), 1));
|
2015-12-26 18:22:21 +01:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2023-01-16 23:51:04 +01:00
|
|
|
inv.unequipSlot(MWWorld::InventoryStore::Slot_Robe);
|
|
|
|
inv.ContainerStore::remove(ESM::RefId::stringRefId("werewolfrobe"), 1);
|
2015-12-26 18:22:21 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
if (actor == player->getPlayer())
|
|
|
|
{
|
|
|
|
MWBase::Environment::get().getWorld()->reattachPlayerCamera();
|
|
|
|
|
|
|
|
// Update the GUI only when called on the player
|
|
|
|
MWBase::WindowManager* windowManager = MWBase::Environment::get().getWindowManager();
|
|
|
|
|
2021-10-08 17:32:41 +02:00
|
|
|
// Transforming removes all temporary effects
|
|
|
|
actor.getClass().getCreatureStats(actor).getActiveSpells().purge(
|
|
|
|
[](const auto& params) {
|
|
|
|
return params.getType() == ESM::ActiveSpells::Type_Consumable
|
|
|
|
|| params.getType() == ESM::ActiveSpells::Type_Temporary;
|
|
|
|
},
|
|
|
|
actor);
|
|
|
|
mActors.updateActor(actor, 0.f);
|
|
|
|
|
2015-12-26 18:22:21 +01:00
|
|
|
if (werewolf)
|
|
|
|
{
|
2021-10-07 21:09:43 +02:00
|
|
|
player->saveStats();
|
|
|
|
player->setWerewolfStats();
|
2015-12-26 18:22:21 +01:00
|
|
|
windowManager->forceHide(MWGui::GW_Inventory);
|
|
|
|
windowManager->forceHide(MWGui::GW_Magic);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2021-10-07 21:09:43 +02:00
|
|
|
player->restoreStats();
|
2015-12-26 18:22:21 +01:00
|
|
|
windowManager->unsetForceHide(MWGui::GW_Inventory);
|
|
|
|
windowManager->unsetForceHide(MWGui::GW_Magic);
|
|
|
|
}
|
|
|
|
|
|
|
|
windowManager->setWerewolfOverlay(werewolf);
|
|
|
|
|
|
|
|
// Witnesses of the player's transformation will make them a globally known werewolf
|
2018-11-06 01:35:20 +03:00
|
|
|
std::vector<MWWorld::Ptr> neighbors;
|
2015-12-26 18:22:21 +01:00
|
|
|
const MWWorld::Store<ESM::GameSetting>& gmst
|
2023-04-20 21:07:53 +02:00
|
|
|
= MWBase::Environment::get().getESMStore()->get<ESM::GameSetting>();
|
2018-11-06 01:35:20 +03:00
|
|
|
getActorsInRange(
|
|
|
|
actor.getRefData().getPosition().asVec3(), gmst.find("fAlarmRadius")->mValue.getFloat(), neighbors);
|
2015-12-26 18:22:21 +01:00
|
|
|
|
|
|
|
bool detected = false, reported = false;
|
2018-11-06 01:35:20 +03:00
|
|
|
for (const MWWorld::Ptr& neighbor : neighbors)
|
2015-12-26 18:22:21 +01:00
|
|
|
{
|
2018-11-06 01:35:20 +03:00
|
|
|
if (neighbor == actor || !neighbor.getClass().isNpc())
|
2015-12-26 18:22:21 +01:00
|
|
|
continue;
|
|
|
|
|
2018-11-06 01:35:20 +03:00
|
|
|
if (MWBase::Environment::get().getWorld()->getLOS(neighbor, actor) && awarenessCheck(actor, neighbor))
|
|
|
|
{
|
2015-12-26 18:22:21 +01:00
|
|
|
detected = true;
|
2022-07-16 16:37:31 +02:00
|
|
|
if (neighbor.getClass()
|
|
|
|
.getCreatureStats(neighbor)
|
|
|
|
.getAiSetting(MWMechanics::AiSetting::Alarm)
|
|
|
|
.getModified()
|
|
|
|
> 0)
|
2018-11-06 01:35:20 +03:00
|
|
|
{
|
|
|
|
reported = true;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
2015-12-26 18:22:21 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
if (detected)
|
|
|
|
{
|
|
|
|
windowManager->messageBox("#{sWerewolfAlarmMessage}");
|
2023-02-07 00:37:55 +01:00
|
|
|
MWBase::Environment::get().getWorld()->setGlobalInt(MWWorld::Globals::sPCKnownWerewolf, 1);
|
2015-12-26 18:22:21 +01:00
|
|
|
|
|
|
|
if (reported)
|
|
|
|
{
|
2023-12-18 21:52:17 +01:00
|
|
|
npcStats.setBounty(
|
|
|
|
std::max(0, npcStats.getBounty() + gmst.find("iWereWolfBounty")->mValue.getInteger()));
|
2015-12-26 18:22:21 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void MechanicsManager::applyWerewolfAcrobatics(const MWWorld::Ptr& actor)
|
|
|
|
{
|
2023-05-31 17:45:20 +02:00
|
|
|
const ESM::Skill* acrobatics
|
|
|
|
= MWBase::Environment::get().getESMStore()->get<ESM::Skill>().find(ESM::Skill::Acrobatics);
|
2015-12-26 18:22:21 +01:00
|
|
|
MWMechanics::NpcStats& stats = actor.getClass().getNpcStats(actor);
|
2023-06-05 21:21:30 +02:00
|
|
|
auto& skill = stats.getSkill(acrobatics->mId);
|
2023-05-31 17:45:20 +02:00
|
|
|
skill.setModifier(acrobatics->mWerewolfValue - skill.getModified());
|
2015-12-26 18:22:21 +01:00
|
|
|
}
|
|
|
|
|
2016-06-12 02:43:33 +02:00
|
|
|
void MechanicsManager::cleanupSummonedCreature(const MWWorld::Ptr& caster, int creatureActorId)
|
|
|
|
{
|
|
|
|
mActors.cleanupSummonedCreature(caster.getClass().getCreatureStats(caster), creatureActorId);
|
|
|
|
}
|
|
|
|
|
2020-05-22 00:11:23 +02:00
|
|
|
void MechanicsManager::reportStats(unsigned int frameNumber, osg::Stats& stats) const
|
|
|
|
{
|
|
|
|
stats.setAttribute(frameNumber, "Mechanics Actors", mActors.size());
|
|
|
|
stats.setAttribute(frameNumber, "Mechanics Objects", mObjects.size());
|
|
|
|
}
|
2020-05-17 04:06:39 +03:00
|
|
|
|
|
|
|
int MechanicsManager::getGreetingTimer(const MWWorld::Ptr& ptr) const
|
|
|
|
{
|
|
|
|
return mActors.getGreetingTimer(ptr);
|
|
|
|
}
|
|
|
|
|
|
|
|
float MechanicsManager::getAngleToPlayer(const MWWorld::Ptr& ptr) const
|
|
|
|
{
|
|
|
|
return mActors.getAngleToPlayer(ptr);
|
|
|
|
}
|
|
|
|
|
|
|
|
GreetingState MechanicsManager::getGreetingState(const MWWorld::Ptr& ptr) const
|
|
|
|
{
|
|
|
|
return mActors.getGreetingState(ptr);
|
|
|
|
}
|
|
|
|
|
|
|
|
bool MechanicsManager::isTurningToPlayer(const MWWorld::Ptr& ptr) const
|
|
|
|
{
|
|
|
|
return mActors.isTurningToPlayer(ptr);
|
|
|
|
}
|
2010-07-26 11:15:38 +02:00
|
|
|
}
|