mirror of
https://github.com/TES3MP/openmw-tes3mp.git
synced 2025-07-21 05:14:10 +00:00
Add OpenMW commits up to 11 Jun 2020
# Conflicts: # apps/openmw/mwbase/world.hpp # apps/openmw/mwgui/jailscreen.cpp # apps/openmw/mwmechanics/activespells.cpp # apps/openmw/mwmechanics/aiactivate.cpp # apps/openmw/mwmechanics/aiactivate.hpp # apps/openmw/mwmechanics/creaturestats.cpp # apps/openmw/mwscript/aiextensions.cpp # apps/openmw/mwscript/statsextensions.cpp # apps/openmw/mwworld/worldimp.cpp # apps/openmw/mwworld/worldimp.hpp
This commit is contained in:
commit
e5b1843089
138 changed files with 2108 additions and 1543 deletions
|
@ -4,6 +4,9 @@
|
||||||
Bug #1952: Incorrect particle lighting
|
Bug #1952: Incorrect particle lighting
|
||||||
Bug #2311: Targeted scripts are not properly supported on non-unique RefIDs
|
Bug #2311: Targeted scripts are not properly supported on non-unique RefIDs
|
||||||
Bug #3676: NiParticleColorModifier isn't applied properly
|
Bug #3676: NiParticleColorModifier isn't applied properly
|
||||||
|
Bug #3714: Savegame fails to load due to conflict between SpellState and MagicEffects
|
||||||
|
Bug #4021: Attributes and skills are not stored as floats
|
||||||
|
Bug #4623: Corprus implementation is incorrect
|
||||||
Bug #4774: Guards are ignorant of an invisible player that tries to attack them
|
Bug #4774: Guards are ignorant of an invisible player that tries to attack them
|
||||||
Bug #5108: Savegame bloating due to inefficient fog textures format
|
Bug #5108: Savegame bloating due to inefficient fog textures format
|
||||||
Bug #5165: Active spells should use real time intead of timestamps
|
Bug #5165: Active spells should use real time intead of timestamps
|
||||||
|
@ -15,6 +18,7 @@
|
||||||
Bug #5370: Opening an unlocked but trapped door uses the key
|
Bug #5370: Opening an unlocked but trapped door uses the key
|
||||||
Bug #5397: NPC greeting does not reset if you leave + reenter area
|
Bug #5397: NPC greeting does not reset if you leave + reenter area
|
||||||
Bug #5400: Editor: Verifier checks race of non-skin bodyparts
|
Bug #5400: Editor: Verifier checks race of non-skin bodyparts
|
||||||
|
Bug #5403: Enchantment effect doesn't show on an enemy during death animation
|
||||||
Bug #5415: Environment maps in ebony cuirass and HiRez Armors Indoril cuirass don't work
|
Bug #5415: Environment maps in ebony cuirass and HiRez Armors Indoril cuirass don't work
|
||||||
Bug #5416: Junk non-node records before the root node are not handled gracefully
|
Bug #5416: Junk non-node records before the root node are not handled gracefully
|
||||||
Bug #5424: Creatures do not headtrack player
|
Bug #5424: Creatures do not headtrack player
|
||||||
|
@ -22,7 +26,10 @@
|
||||||
Bug #5427: GetDistance unknown ID error is misleading
|
Bug #5427: GetDistance unknown ID error is misleading
|
||||||
Bug #5435: Enemies can't hurt the player when collision is off
|
Bug #5435: Enemies can't hurt the player when collision is off
|
||||||
Bug #5441: Enemies can't push a player character when in critical strike stance
|
Bug #5441: Enemies can't push a player character when in critical strike stance
|
||||||
|
Bug #5451: Magic projectiles don't disappear with the caster
|
||||||
|
Bug #5452: Autowalk is being included in savegames
|
||||||
Feature #5362: Show the soul gems' trapped soul in count dialog
|
Feature #5362: Show the soul gems' trapped soul in count dialog
|
||||||
|
Feature #5445: Handle NiLines
|
||||||
|
|
||||||
0.46.0
|
0.46.0
|
||||||
------
|
------
|
||||||
|
@ -294,7 +301,7 @@
|
||||||
Feature #5147: Show spell magicka cost in spell buying window
|
Feature #5147: Show spell magicka cost in spell buying window
|
||||||
Feature #5170: Editor: Land shape editing, land selection
|
Feature #5170: Editor: Land shape editing, land selection
|
||||||
Feature #5172: Editor: Delete instances/references with keypress in scene window
|
Feature #5172: Editor: Delete instances/references with keypress in scene window
|
||||||
Feature #5193: Weapon sheathing
|
Feature #5193: Shields sheathing
|
||||||
Feature #5201: Editor: Show tool outline in scene view, when using editmodes
|
Feature #5201: Editor: Show tool outline in scene view, when using editmodes
|
||||||
Feature #5219: Impelement TestCells console command
|
Feature #5219: Impelement TestCells console command
|
||||||
Feature #5224: Handle NiKeyframeController for NiTriShape
|
Feature #5224: Handle NiKeyframeController for NiTriShape
|
||||||
|
|
|
@ -13,7 +13,16 @@ MISSINGTOOLS=0
|
||||||
|
|
||||||
command -v 7z >/dev/null 2>&1 || { echo "Error: 7z (7zip) is not on the path."; MISSINGTOOLS=1; }
|
command -v 7z >/dev/null 2>&1 || { echo "Error: 7z (7zip) is not on the path."; MISSINGTOOLS=1; }
|
||||||
command -v cmake >/dev/null 2>&1 || { echo "Error: cmake (CMake) is not on the path."; MISSINGTOOLS=1; }
|
command -v cmake >/dev/null 2>&1 || { echo "Error: cmake (CMake) is not on the path."; MISSINGTOOLS=1; }
|
||||||
command -v python >/dev/null 2>&1 || { echo "Warning: Python is not on the path, automatic Qt installation impossible."; }
|
|
||||||
|
MISSINGPYTHON=0
|
||||||
|
if ! command -v python >/dev/null 2>&1; then
|
||||||
|
echo "Warning: Python is not on the path, automatic Qt installation impossible."
|
||||||
|
MISSINGPYTHON=1
|
||||||
|
elif ! python --version >/dev/null 2>&1; then
|
||||||
|
echo "Warning: Python is (probably) fake stub Python that comes bundled with newer versions of Windows, automatic Qt installation impossible."
|
||||||
|
echo "If you think you have Python installed, try changing the order of your PATH environment variable in Advanced System Settings."
|
||||||
|
MISSINGPYTHON=1
|
||||||
|
fi
|
||||||
|
|
||||||
if [ $MISSINGTOOLS -ne 0 ]; then
|
if [ $MISSINGTOOLS -ne 0 ]; then
|
||||||
wrappedExit 1
|
wrappedExit 1
|
||||||
|
@ -745,6 +754,11 @@ fi
|
||||||
if [ -d 'Qt/5.15.0' ]; then
|
if [ -d 'Qt/5.15.0' ]; then
|
||||||
printf "Exists. "
|
printf "Exists. "
|
||||||
elif [ -z $SKIP_EXTRACT ]; then
|
elif [ -z $SKIP_EXTRACT ]; then
|
||||||
|
if [ $MISSINGPYTHON -ne 0 ]; then
|
||||||
|
echo "Can't be automatically installed without Python."
|
||||||
|
wrappedExit 1
|
||||||
|
fi
|
||||||
|
|
||||||
pushd "$DEPS" > /dev/null
|
pushd "$DEPS" > /dev/null
|
||||||
if ! [ -d 'aqt-venv' ]; then
|
if ! [ -d 'aqt-venv' ]; then
|
||||||
echo " Creating Virtualenv for aqt..."
|
echo " Creating Virtualenv for aqt..."
|
||||||
|
@ -988,6 +1002,11 @@ RET=$?
|
||||||
if [ -z $VERBOSE ]; then
|
if [ -z $VERBOSE ]; then
|
||||||
if [ $RET -eq 0 ]; then
|
if [ $RET -eq 0 ]; then
|
||||||
echo Done.
|
echo Done.
|
||||||
|
else
|
||||||
|
echo Failed.
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
if [ -n $ACTIVATE_MSVC ]; then
|
if [ -n $ACTIVATE_MSVC ]; then
|
||||||
echo
|
echo
|
||||||
echo "Note: you must manually activate MSVC for the shell in which you want to do the build."
|
echo "Note: you must manually activate MSVC for the shell in which you want to do the build."
|
||||||
|
@ -1014,8 +1033,5 @@ if [ -z $VERBOSE ]; then
|
||||||
fi
|
fi
|
||||||
echo "In Visual Studio 15.3 (2017 Update 3) or later, try setting '\"inheritEnvironments\": [ \"$inheritEnvironments\" ]' in CMakeSettings.json to build in the IDE."
|
echo "In Visual Studio 15.3 (2017 Update 3) or later, try setting '\"inheritEnvironments\": [ \"$inheritEnvironments\" ]' in CMakeSettings.json to build in the IDE."
|
||||||
fi
|
fi
|
||||||
else
|
|
||||||
echo Failed.
|
|
||||||
fi
|
|
||||||
fi
|
|
||||||
wrappedExit $RET
|
wrappedExit $RET
|
||||||
|
|
|
@ -183,19 +183,19 @@ int list(Bsa::BSAFile& bsa, Arguments& info)
|
||||||
{
|
{
|
||||||
// List all files
|
// List all files
|
||||||
const Bsa::BSAFile::FileList &files = bsa.getList();
|
const Bsa::BSAFile::FileList &files = bsa.getList();
|
||||||
for(unsigned int i=0; i<files.size(); i++)
|
for (const auto& file : files)
|
||||||
{
|
{
|
||||||
if(info.longformat)
|
if(info.longformat)
|
||||||
{
|
{
|
||||||
// Long format
|
// Long format
|
||||||
std::ios::fmtflags f(std::cout.flags());
|
std::ios::fmtflags f(std::cout.flags());
|
||||||
std::cout << std::setw(50) << std::left << files[i].name;
|
std::cout << std::setw(50) << std::left << file.name;
|
||||||
std::cout << std::setw(8) << std::left << std::dec << files[i].fileSize;
|
std::cout << std::setw(8) << std::left << std::dec << file.fileSize;
|
||||||
std::cout << "@ 0x" << std::hex << files[i].offset << std::endl;
|
std::cout << "@ 0x" << std::hex << file.offset << std::endl;
|
||||||
std::cout.flags(f);
|
std::cout.flags(f);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
std::cout << files[i].name << std::endl;
|
std::cout << file.name << std::endl;
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -252,14 +252,9 @@ int extract(Bsa::BSAFile& bsa, Arguments& info)
|
||||||
|
|
||||||
int extractAll(Bsa::BSAFile& bsa, Arguments& info)
|
int extractAll(Bsa::BSAFile& bsa, Arguments& info)
|
||||||
{
|
{
|
||||||
// Get the list of files present in the archive
|
for (const auto &file : bsa.getList())
|
||||||
Bsa::BSAFile::FileList list = bsa.getList();
|
{
|
||||||
|
std::string extractPath(file.name);
|
||||||
// Iter on the list
|
|
||||||
for(Bsa::BSAFile::FileList::iterator it = list.begin(); it != list.end(); ++it) {
|
|
||||||
const char* archivePath = it->name;
|
|
||||||
|
|
||||||
std::string extractPath (archivePath);
|
|
||||||
replaceAll(extractPath, "\\", "/");
|
replaceAll(extractPath, "\\", "/");
|
||||||
|
|
||||||
// Get the target path (the path the file will be extracted to)
|
// Get the target path (the path the file will be extracted to)
|
||||||
|
@ -278,7 +273,7 @@ int extractAll(Bsa::BSAFile& bsa, Arguments& info)
|
||||||
|
|
||||||
// Get a stream for the file to extract
|
// Get a stream for the file to extract
|
||||||
// (inefficient because getFile iter on the list again)
|
// (inefficient because getFile iter on the list again)
|
||||||
Files::IStreamPtr data = bsa.getFile(archivePath);
|
Files::IStreamPtr data = bsa.getFile(file.name);
|
||||||
bfs::ofstream out(target, std::ios::binary);
|
bfs::ofstream out(target, std::ios::binary);
|
||||||
|
|
||||||
// Write the file to disk
|
// Write the file to disk
|
||||||
|
|
|
@ -352,12 +352,12 @@ int load(Arguments& info)
|
||||||
std::cout << "Author: " << esm.getAuthor() << std::endl
|
std::cout << "Author: " << esm.getAuthor() << std::endl
|
||||||
<< "Description: " << esm.getDesc() << std::endl
|
<< "Description: " << esm.getDesc() << std::endl
|
||||||
<< "File format version: " << esm.getFVer() << std::endl;
|
<< "File format version: " << esm.getFVer() << std::endl;
|
||||||
std::vector<ESM::Header::MasterData> m = esm.getGameFiles();
|
std::vector<ESM::Header::MasterData> masterData = esm.getGameFiles();
|
||||||
if (!m.empty())
|
if (!masterData.empty())
|
||||||
{
|
{
|
||||||
std::cout << "Masters:" << std::endl;
|
std::cout << "Masters:" << std::endl;
|
||||||
for(unsigned int i=0;i<m.size();i++)
|
for(const auto& master : masterData)
|
||||||
std::cout << " " << m[i].name << ", " << m[i].size << " bytes" << std::endl;
|
std::cout << " " << master.name << ", " << master.size << " bytes" << std::endl;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -369,7 +369,7 @@ int load(Arguments& info)
|
||||||
esm.getRecHeader(flags);
|
esm.getRecHeader(flags);
|
||||||
|
|
||||||
EsmTool::RecordBase *record = EsmTool::RecordBase::create(n);
|
EsmTool::RecordBase *record = EsmTool::RecordBase::create(n);
|
||||||
if (record == 0)
|
if (record == nullptr)
|
||||||
{
|
{
|
||||||
if (std::find(skipped.begin(), skipped.end(), n.intval) == skipped.end())
|
if (std::find(skipped.begin(), skipped.end(), n.intval) == skipped.end())
|
||||||
{
|
{
|
||||||
|
@ -538,8 +538,8 @@ int comp(Arguments& info)
|
||||||
Arguments fileOne;
|
Arguments fileOne;
|
||||||
Arguments fileTwo;
|
Arguments fileTwo;
|
||||||
|
|
||||||
fileOne.raw_given = 0;
|
fileOne.raw_given = false;
|
||||||
fileTwo.raw_given = 0;
|
fileTwo.raw_given = false;
|
||||||
|
|
||||||
fileOne.mode = "clone";
|
fileOne.mode = "clone";
|
||||||
fileTwo.mode = "clone";
|
fileTwo.mode = "clone";
|
||||||
|
|
|
@ -779,7 +779,7 @@ std::string creatureListFlags(int flags)
|
||||||
|
|
||||||
std::string lightFlags(int flags)
|
std::string lightFlags(int flags)
|
||||||
{
|
{
|
||||||
std::string properties = "";
|
std::string properties;
|
||||||
if (flags == 0) properties += "[None] ";
|
if (flags == 0) properties += "[None] ";
|
||||||
if (flags & ESM::Light::Dynamic) properties += "Dynamic ";
|
if (flags & ESM::Light::Dynamic) properties += "Dynamic ";
|
||||||
if (flags & ESM::Light::Fire) properties += "Fire ";
|
if (flags & ESM::Light::Fire) properties += "Fire ";
|
||||||
|
|
|
@ -9,7 +9,7 @@
|
||||||
namespace
|
namespace
|
||||||
{
|
{
|
||||||
|
|
||||||
void printAIPackage(ESM::AIPackage p)
|
void printAIPackage(const ESM::AIPackage& p)
|
||||||
{
|
{
|
||||||
std::cout << " AI Type: " << aiTypeLabel(p.mType)
|
std::cout << " AI Type: " << aiTypeLabel(p.mType)
|
||||||
<< " (" << Misc::StringUtils::format("0x%08X", p.mType) << ")" << std::endl;
|
<< " (" << Misc::StringUtils::format("0x%08X", p.mType) << ")" << std::endl;
|
||||||
|
@ -53,7 +53,7 @@ void printAIPackage(ESM::AIPackage p)
|
||||||
std::cout << " Cell Name: " << p.mCellName << std::endl;
|
std::cout << " Cell Name: " << p.mCellName << std::endl;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string ruleString(ESM::DialInfo::SelectStruct ss)
|
std::string ruleString(const ESM::DialInfo::SelectStruct& ss)
|
||||||
{
|
{
|
||||||
std::string rule = ss.mSelectRule;
|
std::string rule = ss.mSelectRule;
|
||||||
|
|
||||||
|
@ -126,7 +126,7 @@ std::string ruleString(ESM::DialInfo::SelectStruct ss)
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
void printEffectList(ESM::EffectList effects)
|
void printEffectList(const ESM::EffectList& effects)
|
||||||
{
|
{
|
||||||
int i = 0;
|
int i = 0;
|
||||||
for (const ESM::ENAMstruct& effect : effects.mList)
|
for (const ESM::ENAMstruct& effect : effects.mList)
|
||||||
|
@ -174,7 +174,7 @@ namespace EsmTool {
|
||||||
RecordBase *
|
RecordBase *
|
||||||
RecordBase::create(ESM::NAME type)
|
RecordBase::create(ESM::NAME type)
|
||||||
{
|
{
|
||||||
RecordBase *record = 0;
|
RecordBase *record = nullptr;
|
||||||
|
|
||||||
switch (type.intval) {
|
switch (type.intval) {
|
||||||
case ESM::REC_ACTI:
|
case ESM::REC_ACTI:
|
||||||
|
@ -388,7 +388,7 @@ RecordBase::create(ESM::NAME type)
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
record = 0;
|
record = nullptr;
|
||||||
}
|
}
|
||||||
if (record) {
|
if (record) {
|
||||||
record->mType = type;
|
record->mType = type;
|
||||||
|
@ -728,10 +728,9 @@ void Record<ESM::Faction>::print()
|
||||||
<< " (" << mData.mData.mAttribute[0] << ")" << std::endl;
|
<< " (" << mData.mData.mAttribute[0] << ")" << std::endl;
|
||||||
std::cout << " Attribute2: " << attributeLabel(mData.mData.mAttribute[1])
|
std::cout << " Attribute2: " << attributeLabel(mData.mData.mAttribute[1])
|
||||||
<< " (" << mData.mData.mAttribute[1] << ")" << std::endl;
|
<< " (" << mData.mData.mAttribute[1] << ")" << std::endl;
|
||||||
for (int i = 0; i < 7; i++)
|
for (int skill : mData.mData.mSkills)
|
||||||
if (mData.mData.mSkills[i] != -1)
|
if (skill != -1)
|
||||||
std::cout << " Skill: " << skillLabel(mData.mData.mSkills[i])
|
std::cout << " Skill: " << skillLabel(skill) << " (" << skill << ")" << std::endl;
|
||||||
<< " (" << mData.mData.mSkills[i] << ")" << std::endl;
|
|
||||||
for (int i = 0; i != 10; i++)
|
for (int i = 0; i != 10; i++)
|
||||||
if (!mData.mRanks[i].empty())
|
if (!mData.mRanks[i].empty())
|
||||||
{
|
{
|
||||||
|
|
|
@ -74,7 +74,7 @@ namespace EsmTool
|
||||||
: mIsDeleted(false)
|
: mIsDeleted(false)
|
||||||
{}
|
{}
|
||||||
|
|
||||||
std::string getId() const {
|
std::string getId() const override {
|
||||||
return mData.mId;
|
return mData.mId;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -82,15 +82,15 @@ namespace EsmTool
|
||||||
return mData;
|
return mData;
|
||||||
}
|
}
|
||||||
|
|
||||||
void save(ESM::ESMWriter &esm) {
|
void save(ESM::ESMWriter &esm) override {
|
||||||
mData.save(esm, mIsDeleted);
|
mData.save(esm, mIsDeleted);
|
||||||
}
|
}
|
||||||
|
|
||||||
void load(ESM::ESMReader &esm) {
|
void load(ESM::ESMReader &esm) override {
|
||||||
mData.load(esm, mIsDeleted);
|
mData.load(esm, mIsDeleted);
|
||||||
}
|
}
|
||||||
|
|
||||||
void print();
|
void print() override;
|
||||||
};
|
};
|
||||||
|
|
||||||
template<> std::string Record<ESM::Cell>::getId() const;
|
template<> std::string Record<ESM::Cell>::getId() const;
|
||||||
|
|
|
@ -52,9 +52,7 @@ namespace
|
||||||
// a dynamically created record e.g. player-enchanted weapon
|
// a dynamically created record e.g. player-enchanted weapon
|
||||||
|
|
||||||
std::string index = indexedRefId.substr(indexedRefId.size()-8);
|
std::string index = indexedRefId.substr(indexedRefId.size()-8);
|
||||||
if(index.find_first_not_of("0123456789ABCDEF") == std::string::npos )
|
return index.find_first_not_of("0123456789ABCDEF") == std::string::npos;
|
||||||
return true;
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void splitIndexedRefId(const std::string& indexedRefId, int& refIndex, std::string& refId)
|
void splitIndexedRefId(const std::string& indexedRefId, int& refIndex, std::string& refId)
|
||||||
|
@ -139,12 +137,12 @@ namespace ESSImport
|
||||||
image2->allocateImage(width, height, 1, GL_RGBA, GL_UNSIGNED_BYTE);
|
image2->allocateImage(width, height, 1, GL_RGBA, GL_UNSIGNED_BYTE);
|
||||||
memcpy(image2->data(), &data[0], data.size());
|
memcpy(image2->data(), &data[0], data.size());
|
||||||
|
|
||||||
for (std::set<std::pair<int, int> >::const_iterator it = mContext->mExploredCells.begin(); it != mContext->mExploredCells.end(); ++it)
|
for (const auto & exploredCell : mContext->mExploredCells)
|
||||||
{
|
{
|
||||||
if (it->first > mContext->mGlobalMapState.mBounds.mMaxX
|
if (exploredCell.first > mContext->mGlobalMapState.mBounds.mMaxX
|
||||||
|| it->first < mContext->mGlobalMapState.mBounds.mMinX
|
|| exploredCell.first < mContext->mGlobalMapState.mBounds.mMinX
|
||||||
|| it->second > mContext->mGlobalMapState.mBounds.mMaxY
|
|| exploredCell.second > mContext->mGlobalMapState.mBounds.mMaxY
|
||||||
|| it->second < mContext->mGlobalMapState.mBounds.mMinY)
|
|| exploredCell.second < mContext->mGlobalMapState.mBounds.mMinY)
|
||||||
{
|
{
|
||||||
// out of bounds, I think this could happen, since the original engine had a fixed-size map
|
// out of bounds, I think this could happen, since the original engine had a fixed-size map
|
||||||
continue;
|
continue;
|
||||||
|
@ -152,12 +150,12 @@ namespace ESSImport
|
||||||
|
|
||||||
int imageLeftSrc = mGlobalMapImage->s()/2;
|
int imageLeftSrc = mGlobalMapImage->s()/2;
|
||||||
int imageTopSrc = mGlobalMapImage->t()/2;
|
int imageTopSrc = mGlobalMapImage->t()/2;
|
||||||
imageLeftSrc += it->first * cellSize;
|
imageLeftSrc += exploredCell.first * cellSize;
|
||||||
imageTopSrc -= it->second * cellSize;
|
imageTopSrc -= exploredCell.second * cellSize;
|
||||||
int imageLeftDst = width/2;
|
int imageLeftDst = width/2;
|
||||||
int imageTopDst = height/2;
|
int imageTopDst = height/2;
|
||||||
imageLeftDst += it->first * cellSize;
|
imageLeftDst += exploredCell.first * cellSize;
|
||||||
imageTopDst -= it->second * cellSize;
|
imageTopDst -= exploredCell.second * cellSize;
|
||||||
for (int x=0; x<cellSize; ++x)
|
for (int x=0; x<cellSize; ++x)
|
||||||
for (int y=0; y<cellSize; ++y)
|
for (int y=0; y<cellSize; ++y)
|
||||||
{
|
{
|
||||||
|
@ -329,9 +327,8 @@ namespace ESSImport
|
||||||
csta.mWaterLevel = esmcell.mWater;
|
csta.mWaterLevel = esmcell.mWater;
|
||||||
csta.save(esm);
|
csta.save(esm);
|
||||||
|
|
||||||
for (std::vector<CellRef>::const_iterator refIt = cell.mRefs.begin(); refIt != cell.mRefs.end(); ++refIt)
|
for (const auto & cellref : cell.mRefs)
|
||||||
{
|
{
|
||||||
const CellRef& cellref = *refIt;
|
|
||||||
ESM::CellRef out (cellref);
|
ESM::CellRef out (cellref);
|
||||||
|
|
||||||
// TODO: use mContext->mCreatures/mNpcs
|
// TODO: use mContext->mCreatures/mNpcs
|
||||||
|
@ -437,16 +434,16 @@ namespace ESSImport
|
||||||
|
|
||||||
void ConvertCell::write(ESM::ESMWriter &esm)
|
void ConvertCell::write(ESM::ESMWriter &esm)
|
||||||
{
|
{
|
||||||
for (std::map<std::string, Cell>::const_iterator it = mIntCells.begin(); it != mIntCells.end(); ++it)
|
for (const auto & cell : mIntCells)
|
||||||
writeCell(it->second, esm);
|
writeCell(cell.second, esm);
|
||||||
|
|
||||||
for (std::map<std::pair<int, int>, Cell>::const_iterator it = mExtCells.begin(); it != mExtCells.end(); ++it)
|
for (const auto & cell : mExtCells)
|
||||||
writeCell(it->second, esm);
|
writeCell(cell.second, esm);
|
||||||
|
|
||||||
for (std::vector<ESM::CustomMarker>::const_iterator it = mMarkers.begin(); it != mMarkers.end(); ++it)
|
for (const auto & marker : mMarkers)
|
||||||
{
|
{
|
||||||
esm.startRecord(ESM::REC_MARK);
|
esm.startRecord(ESM::REC_MARK);
|
||||||
it->save(esm);
|
marker.save(esm);
|
||||||
esm.endRecord(ESM::REC_MARK);
|
esm.endRecord(ESM::REC_MARK);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -79,9 +79,9 @@ template <typename T>
|
||||||
class DefaultConverter : public Converter
|
class DefaultConverter : public Converter
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
virtual int getStage() { return 0; }
|
int getStage() override { return 0; }
|
||||||
|
|
||||||
virtual void read(ESM::ESMReader& esm)
|
void read(ESM::ESMReader& esm) override
|
||||||
{
|
{
|
||||||
T record;
|
T record;
|
||||||
bool isDeleted = false;
|
bool isDeleted = false;
|
||||||
|
@ -90,7 +90,7 @@ public:
|
||||||
mRecords[record.mId] = record;
|
mRecords[record.mId] = record;
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual void write(ESM::ESMWriter& esm)
|
void write(ESM::ESMWriter& esm) override
|
||||||
{
|
{
|
||||||
for (typename std::map<std::string, T>::const_iterator it = mRecords.begin(); it != mRecords.end(); ++it)
|
for (typename std::map<std::string, T>::const_iterator it = mRecords.begin(); it != mRecords.end(); ++it)
|
||||||
{
|
{
|
||||||
|
@ -107,7 +107,7 @@ protected:
|
||||||
class ConvertNPC : public Converter
|
class ConvertNPC : public Converter
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
virtual void read(ESM::ESMReader &esm)
|
void read(ESM::ESMReader &esm) override
|
||||||
{
|
{
|
||||||
ESM::NPC npc;
|
ESM::NPC npc;
|
||||||
bool isDeleted = false;
|
bool isDeleted = false;
|
||||||
|
@ -127,8 +127,8 @@ public:
|
||||||
ESM::SpellState::SpellParams empty;
|
ESM::SpellState::SpellParams empty;
|
||||||
// FIXME: player start spells and birthsign spells aren't listed here,
|
// FIXME: player start spells and birthsign spells aren't listed here,
|
||||||
// need to fix openmw to account for this
|
// need to fix openmw to account for this
|
||||||
for (std::vector<std::string>::const_iterator it = npc.mSpells.mList.begin(); it != npc.mSpells.mList.end(); ++it)
|
for (const auto & spell : npc.mSpells.mList)
|
||||||
mContext->mPlayer.mObject.mCreatureStats.mSpells.mSpells[*it] = empty;
|
mContext->mPlayer.mObject.mCreatureStats.mSpells.mSpells[spell] = empty;
|
||||||
|
|
||||||
// Clear the list now that we've written it, this prevents issues cropping up with
|
// Clear the list now that we've written it, this prevents issues cropping up with
|
||||||
// ensureCustomData() in OpenMW tripping over no longer existing spells, where an error would be fatal.
|
// ensureCustomData() in OpenMW tripping over no longer existing spells, where an error would be fatal.
|
||||||
|
@ -144,7 +144,7 @@ public:
|
||||||
class ConvertCREA : public Converter
|
class ConvertCREA : public Converter
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
virtual void read(ESM::ESMReader &esm)
|
void read(ESM::ESMReader &esm) override
|
||||||
{
|
{
|
||||||
// See comment in ConvertNPC
|
// See comment in ConvertNPC
|
||||||
ESM::Creature creature;
|
ESM::Creature creature;
|
||||||
|
@ -162,7 +162,7 @@ public:
|
||||||
class ConvertGlobal : public DefaultConverter<ESM::Global>
|
class ConvertGlobal : public DefaultConverter<ESM::Global>
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
virtual void read(ESM::ESMReader &esm)
|
void read(ESM::ESMReader &esm) override
|
||||||
{
|
{
|
||||||
ESM::Global global;
|
ESM::Global global;
|
||||||
bool isDeleted = false;
|
bool isDeleted = false;
|
||||||
|
@ -183,7 +183,7 @@ public:
|
||||||
class ConvertClass : public DefaultConverter<ESM::Class>
|
class ConvertClass : public DefaultConverter<ESM::Class>
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
virtual void read(ESM::ESMReader &esm)
|
void read(ESM::ESMReader &esm) override
|
||||||
{
|
{
|
||||||
ESM::Class class_;
|
ESM::Class class_;
|
||||||
bool isDeleted = false;
|
bool isDeleted = false;
|
||||||
|
@ -199,7 +199,7 @@ public:
|
||||||
class ConvertBook : public DefaultConverter<ESM::Book>
|
class ConvertBook : public DefaultConverter<ESM::Book>
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
virtual void read(ESM::ESMReader &esm)
|
void read(ESM::ESMReader &esm) override
|
||||||
{
|
{
|
||||||
ESM::Book book;
|
ESM::Book book;
|
||||||
bool isDeleted = false;
|
bool isDeleted = false;
|
||||||
|
@ -215,7 +215,7 @@ public:
|
||||||
class ConvertNPCC : public Converter
|
class ConvertNPCC : public Converter
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
virtual void read(ESM::ESMReader &esm)
|
void read(ESM::ESMReader &esm) override
|
||||||
{
|
{
|
||||||
std::string id = esm.getHNString("NAME");
|
std::string id = esm.getHNString("NAME");
|
||||||
NPCC npcc;
|
NPCC npcc;
|
||||||
|
@ -235,7 +235,7 @@ public:
|
||||||
class ConvertREFR : public Converter
|
class ConvertREFR : public Converter
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
virtual void read(ESM::ESMReader &esm)
|
void read(ESM::ESMReader &esm) override
|
||||||
{
|
{
|
||||||
REFR refr;
|
REFR refr;
|
||||||
refr.load(esm);
|
refr.load(esm);
|
||||||
|
@ -261,7 +261,7 @@ public:
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
virtual void write(ESM::ESMWriter& esm)
|
void write(ESM::ESMWriter& esm) override
|
||||||
{
|
{
|
||||||
esm.startRecord(ESM::REC_ASPL);
|
esm.startRecord(ESM::REC_ASPL);
|
||||||
esm.writeHNString("ID__", mSelectedSpell);
|
esm.writeHNString("ID__", mSelectedSpell);
|
||||||
|
@ -280,14 +280,14 @@ public:
|
||||||
mLevitationEnabled(true)
|
mLevitationEnabled(true)
|
||||||
{}
|
{}
|
||||||
|
|
||||||
virtual void read(ESM::ESMReader &esm)
|
void read(ESM::ESMReader &esm) override
|
||||||
{
|
{
|
||||||
PCDT pcdt;
|
PCDT pcdt;
|
||||||
pcdt.load(esm);
|
pcdt.load(esm);
|
||||||
|
|
||||||
convertPCDT(pcdt, mContext->mPlayer, mContext->mDialogueState.mKnownTopics, mFirstPersonCam, mTeleportingEnabled, mLevitationEnabled, mContext->mControlsState);
|
convertPCDT(pcdt, mContext->mPlayer, mContext->mDialogueState.mKnownTopics, mFirstPersonCam, mTeleportingEnabled, mLevitationEnabled, mContext->mControlsState);
|
||||||
}
|
}
|
||||||
virtual void write(ESM::ESMWriter &esm)
|
void write(ESM::ESMWriter &esm) override
|
||||||
{
|
{
|
||||||
esm.startRecord(ESM::REC_ENAB);
|
esm.startRecord(ESM::REC_ENAB);
|
||||||
esm.writeHNT("TELE", mTeleportingEnabled);
|
esm.writeHNT("TELE", mTeleportingEnabled);
|
||||||
|
@ -306,7 +306,7 @@ private:
|
||||||
|
|
||||||
class ConvertCNTC : public Converter
|
class ConvertCNTC : public Converter
|
||||||
{
|
{
|
||||||
virtual void read(ESM::ESMReader &esm)
|
void read(ESM::ESMReader &esm) override
|
||||||
{
|
{
|
||||||
std::string id = esm.getHNString("NAME");
|
std::string id = esm.getHNString("NAME");
|
||||||
CNTC cntc;
|
CNTC cntc;
|
||||||
|
@ -318,7 +318,7 @@ class ConvertCNTC : public Converter
|
||||||
class ConvertCREC : public Converter
|
class ConvertCREC : public Converter
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
virtual void read(ESM::ESMReader &esm)
|
void read(ESM::ESMReader &esm) override
|
||||||
{
|
{
|
||||||
std::string id = esm.getHNString("NAME");
|
std::string id = esm.getHNString("NAME");
|
||||||
CREC crec;
|
CREC crec;
|
||||||
|
@ -330,8 +330,8 @@ public:
|
||||||
class ConvertFMAP : public Converter
|
class ConvertFMAP : public Converter
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
virtual void read(ESM::ESMReader &esm);
|
void read(ESM::ESMReader &esm) override;
|
||||||
virtual void write(ESM::ESMWriter &esm);
|
void write(ESM::ESMWriter &esm) override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
osg::ref_ptr<osg::Image> mGlobalMapImage;
|
osg::ref_ptr<osg::Image> mGlobalMapImage;
|
||||||
|
@ -340,8 +340,8 @@ private:
|
||||||
class ConvertCell : public Converter
|
class ConvertCell : public Converter
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
virtual void read(ESM::ESMReader& esm);
|
void read(ESM::ESMReader& esm) override;
|
||||||
virtual void write(ESM::ESMWriter& esm);
|
void write(ESM::ESMWriter& esm) override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
struct Cell
|
struct Cell
|
||||||
|
@ -362,7 +362,7 @@ private:
|
||||||
class ConvertKLST : public Converter
|
class ConvertKLST : public Converter
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
virtual void read(ESM::ESMReader& esm)
|
void read(ESM::ESMReader& esm) override
|
||||||
{
|
{
|
||||||
KLST klst;
|
KLST klst;
|
||||||
klst.load(esm);
|
klst.load(esm);
|
||||||
|
@ -371,7 +371,7 @@ public:
|
||||||
mContext->mPlayer.mObject.mNpcStats.mWerewolfKills = klst.mWerewolfKills;
|
mContext->mPlayer.mObject.mNpcStats.mWerewolfKills = klst.mWerewolfKills;
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual void write(ESM::ESMWriter &esm)
|
void write(ESM::ESMWriter &esm) override
|
||||||
{
|
{
|
||||||
esm.startRecord(ESM::REC_DCOU);
|
esm.startRecord(ESM::REC_DCOU);
|
||||||
for (std::map<std::string, int>::const_iterator it = mKillCounter.begin(); it != mKillCounter.end(); ++it)
|
for (std::map<std::string, int>::const_iterator it = mKillCounter.begin(); it != mKillCounter.end(); ++it)
|
||||||
|
@ -389,7 +389,7 @@ private:
|
||||||
class ConvertFACT : public Converter
|
class ConvertFACT : public Converter
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
virtual void read(ESM::ESMReader& esm)
|
void read(ESM::ESMReader& esm) override
|
||||||
{
|
{
|
||||||
ESM::Faction faction;
|
ESM::Faction faction;
|
||||||
bool isDeleted = false;
|
bool isDeleted = false;
|
||||||
|
@ -409,7 +409,7 @@ public:
|
||||||
class ConvertSTLN : public Converter
|
class ConvertSTLN : public Converter
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
virtual void read(ESM::ESMReader &esm)
|
void read(ESM::ESMReader &esm) override
|
||||||
{
|
{
|
||||||
std::string itemid = esm.getHNString("NAME");
|
std::string itemid = esm.getHNString("NAME");
|
||||||
Misc::StringUtils::lowerCaseInPlace(itemid);
|
Misc::StringUtils::lowerCaseInPlace(itemid);
|
||||||
|
@ -428,15 +428,15 @@ public:
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
virtual void write(ESM::ESMWriter &esm)
|
void write(ESM::ESMWriter &esm) override
|
||||||
{
|
{
|
||||||
ESM::StolenItems items;
|
ESM::StolenItems items;
|
||||||
for (std::map<std::string, std::set<Owner> >::const_iterator it = mStolenItems.begin(); it != mStolenItems.end(); ++it)
|
for (std::map<std::string, std::set<Owner> >::const_iterator it = mStolenItems.begin(); it != mStolenItems.end(); ++it)
|
||||||
{
|
{
|
||||||
std::map<std::pair<std::string, bool>, int> owners;
|
std::map<std::pair<std::string, bool>, int> owners;
|
||||||
for (std::set<Owner>::const_iterator ownerIt = it->second.begin(); ownerIt != it->second.end(); ++ownerIt)
|
for (const auto & ownerIt : it->second)
|
||||||
{
|
{
|
||||||
owners.insert(std::make_pair(std::make_pair(ownerIt->first, ownerIt->second)
|
owners.insert(std::make_pair(std::make_pair(ownerIt.first, ownerIt.second)
|
||||||
// Since OpenMW doesn't suffer from the owner contamination bug,
|
// Since OpenMW doesn't suffer from the owner contamination bug,
|
||||||
// it needs a count argument. But for legacy savegames, we don't know
|
// it needs a count argument. But for legacy savegames, we don't know
|
||||||
// this count, so must assume all items of that ID are stolen,
|
// this count, so must assume all items of that ID are stolen,
|
||||||
|
@ -467,7 +467,7 @@ private:
|
||||||
class ConvertINFO : public Converter
|
class ConvertINFO : public Converter
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
virtual void read(ESM::ESMReader& esm)
|
void read(ESM::ESMReader& esm) override
|
||||||
{
|
{
|
||||||
INFO info;
|
INFO info;
|
||||||
info.load(esm);
|
info.load(esm);
|
||||||
|
@ -477,7 +477,7 @@ public:
|
||||||
class ConvertDIAL : public Converter
|
class ConvertDIAL : public Converter
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
virtual void read(ESM::ESMReader& esm)
|
void read(ESM::ESMReader& esm) override
|
||||||
{
|
{
|
||||||
std::string id = esm.getHNString("NAME");
|
std::string id = esm.getHNString("NAME");
|
||||||
DIAL dial;
|
DIAL dial;
|
||||||
|
@ -485,7 +485,7 @@ public:
|
||||||
if (dial.mIndex > 0)
|
if (dial.mIndex > 0)
|
||||||
mDials[id] = dial;
|
mDials[id] = dial;
|
||||||
}
|
}
|
||||||
virtual void write(ESM::ESMWriter &esm)
|
void write(ESM::ESMWriter &esm) override
|
||||||
{
|
{
|
||||||
for (std::map<std::string, DIAL>::const_iterator it = mDials.begin(); it != mDials.end(); ++it)
|
for (std::map<std::string, DIAL>::const_iterator it = mDials.begin(); it != mDials.end(); ++it)
|
||||||
{
|
{
|
||||||
|
@ -505,7 +505,7 @@ private:
|
||||||
class ConvertQUES : public Converter
|
class ConvertQUES : public Converter
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
virtual void read(ESM::ESMReader& esm)
|
void read(ESM::ESMReader& esm) override
|
||||||
{
|
{
|
||||||
std::string id = esm.getHNString("NAME");
|
std::string id = esm.getHNString("NAME");
|
||||||
QUES quest;
|
QUES quest;
|
||||||
|
@ -516,7 +516,7 @@ public:
|
||||||
class ConvertJOUR : public Converter
|
class ConvertJOUR : public Converter
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
virtual void read(ESM::ESMReader& esm)
|
void read(ESM::ESMReader& esm) override
|
||||||
{
|
{
|
||||||
JOUR journal;
|
JOUR journal;
|
||||||
journal.load(esm);
|
journal.load(esm);
|
||||||
|
@ -531,7 +531,7 @@ public:
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual void read(ESM::ESMReader &esm)
|
void read(ESM::ESMReader &esm) override
|
||||||
{
|
{
|
||||||
mGame.load(esm);
|
mGame.load(esm);
|
||||||
mHasGame = true;
|
mHasGame = true;
|
||||||
|
@ -551,7 +551,7 @@ public:
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual void write(ESM::ESMWriter &esm)
|
void write(ESM::ESMWriter &esm) override
|
||||||
{
|
{
|
||||||
if (!mHasGame)
|
if (!mHasGame)
|
||||||
return;
|
return;
|
||||||
|
@ -578,7 +578,7 @@ private:
|
||||||
class ConvertSCPT : public Converter
|
class ConvertSCPT : public Converter
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
virtual void read(ESM::ESMReader &esm)
|
void read(ESM::ESMReader &esm) override
|
||||||
{
|
{
|
||||||
SCPT script;
|
SCPT script;
|
||||||
script.load(esm);
|
script.load(esm);
|
||||||
|
@ -586,12 +586,12 @@ public:
|
||||||
convertSCPT(script, out);
|
convertSCPT(script, out);
|
||||||
mScripts.push_back(out);
|
mScripts.push_back(out);
|
||||||
}
|
}
|
||||||
virtual void write(ESM::ESMWriter &esm)
|
void write(ESM::ESMWriter &esm) override
|
||||||
{
|
{
|
||||||
for (std::vector<ESM::GlobalScript>::const_iterator it = mScripts.begin(); it != mScripts.end(); ++it)
|
for (const auto & script : mScripts)
|
||||||
{
|
{
|
||||||
esm.startRecord(ESM::REC_GSCR);
|
esm.startRecord(ESM::REC_GSCR);
|
||||||
it->save(esm);
|
script.save(esm);
|
||||||
esm.endRecord(ESM::REC_GSCR);
|
esm.endRecord(ESM::REC_GSCR);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -603,9 +603,9 @@ private:
|
||||||
class ConvertPROJ : public Converter
|
class ConvertPROJ : public Converter
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
virtual int getStage() override { return 2; }
|
int getStage() override { return 2; }
|
||||||
virtual void read(ESM::ESMReader& esm) override;
|
void read(ESM::ESMReader& esm) override;
|
||||||
virtual void write(ESM::ESMWriter& esm) override;
|
void write(ESM::ESMWriter& esm) override;
|
||||||
private:
|
private:
|
||||||
void convertBaseState(ESM::BaseProjectileState& base, const PROJ::PNAM& pnam);
|
void convertBaseState(ESM::BaseProjectileState& base, const PROJ::PNAM& pnam);
|
||||||
PROJ mProj;
|
PROJ mProj;
|
||||||
|
@ -614,8 +614,8 @@ private:
|
||||||
class ConvertSPLM : public Converter
|
class ConvertSPLM : public Converter
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
virtual void read(ESM::ESMReader& esm) override;
|
void read(ESM::ESMReader& esm) override;
|
||||||
virtual void write(ESM::ESMWriter& esm) override;
|
void write(ESM::ESMWriter& esm) override;
|
||||||
private:
|
private:
|
||||||
SPLM mSPLM;
|
SPLM mSPLM;
|
||||||
};
|
};
|
||||||
|
|
|
@ -9,21 +9,20 @@ namespace ESSImport
|
||||||
void convertInventory(const Inventory &inventory, ESM::InventoryState &state)
|
void convertInventory(const Inventory &inventory, ESM::InventoryState &state)
|
||||||
{
|
{
|
||||||
int index = 0;
|
int index = 0;
|
||||||
for (std::vector<Inventory::InventoryItem>::const_iterator it = inventory.mItems.begin();
|
for (const auto & item : inventory.mItems)
|
||||||
it != inventory.mItems.end(); ++it)
|
|
||||||
{
|
{
|
||||||
ESM::ObjectState objstate;
|
ESM::ObjectState objstate;
|
||||||
objstate.blank();
|
objstate.blank();
|
||||||
objstate.mRef = *it;
|
objstate.mRef = item;
|
||||||
objstate.mRef.mRefID = Misc::StringUtils::lowerCase(it->mId);
|
objstate.mRef.mRefID = Misc::StringUtils::lowerCase(item.mId);
|
||||||
objstate.mCount = std::abs(it->mCount); // restocking items have negative count in the savefile
|
objstate.mCount = std::abs(item.mCount); // restocking items have negative count in the savefile
|
||||||
// openmw handles them differently, so no need to set any flags
|
// openmw handles them differently, so no need to set any flags
|
||||||
state.mItems.push_back(objstate);
|
state.mItems.push_back(objstate);
|
||||||
if (it->mRelativeEquipmentSlot != -1)
|
if (item.mRelativeEquipmentSlot != -1)
|
||||||
// Note we should really write the absolute slot here, which we do not know about
|
// Note we should really write the absolute slot here, which we do not know about
|
||||||
// Not a big deal, OpenMW will auto-correct to a valid slot, the only problem is when
|
// Not a big deal, OpenMW will auto-correct to a valid slot, the only problem is when
|
||||||
// an item could be equipped in two different slots (e.g. equipped two rings)
|
// an item could be equipped in two different slots (e.g. equipped two rings)
|
||||||
state.mEquipmentSlots[index] = it->mRelativeEquipmentSlot;
|
state.mEquipmentSlots[index] = item.mRelativeEquipmentSlot;
|
||||||
++index;
|
++index;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,13 +10,13 @@ namespace ESSImport
|
||||||
{
|
{
|
||||||
out.mBirthsign = pcdt.mBirthsign;
|
out.mBirthsign = pcdt.mBirthsign;
|
||||||
out.mObject.mNpcStats.mBounty = pcdt.mBounty;
|
out.mObject.mNpcStats.mBounty = pcdt.mBounty;
|
||||||
for (std::vector<PCDT::FNAM>::const_iterator it = pcdt.mFactions.begin(); it != pcdt.mFactions.end(); ++it)
|
for (const auto & essFaction : pcdt.mFactions)
|
||||||
{
|
{
|
||||||
ESM::NpcStats::Faction faction;
|
ESM::NpcStats::Faction faction;
|
||||||
faction.mExpelled = (it->mFlags & 0x2) != 0;
|
faction.mExpelled = (essFaction.mFlags & 0x2) != 0;
|
||||||
faction.mRank = it->mRank;
|
faction.mRank = essFaction.mRank;
|
||||||
faction.mReputation = it->mReputation;
|
faction.mReputation = essFaction.mReputation;
|
||||||
out.mObject.mNpcStats.mFactions[Misc::StringUtils::lowerCase(it->mFactionName.toString())] = faction;
|
out.mObject.mNpcStats.mFactions[Misc::StringUtils::lowerCase(essFaction.mFactionName.toString())] = faction;
|
||||||
}
|
}
|
||||||
for (int i=0; i<3; ++i)
|
for (int i=0; i<3; ++i)
|
||||||
out.mObject.mNpcStats.mSpecIncreases[i] = pcdt.mPNAM.mSpecIncreases[i];
|
out.mObject.mNpcStats.mSpecIncreases[i] = pcdt.mPNAM.mSpecIncreases[i];
|
||||||
|
@ -35,10 +35,9 @@ namespace ESSImport
|
||||||
teleportingEnabled = !(pcdt.mPNAM.mPlayerFlags & PCDT::PlayerFlags_TeleportingDisabled);
|
teleportingEnabled = !(pcdt.mPNAM.mPlayerFlags & PCDT::PlayerFlags_TeleportingDisabled);
|
||||||
levitationEnabled = !(pcdt.mPNAM.mPlayerFlags & PCDT::PlayerFlags_LevitationDisabled);
|
levitationEnabled = !(pcdt.mPNAM.mPlayerFlags & PCDT::PlayerFlags_LevitationDisabled);
|
||||||
|
|
||||||
for (std::vector<std::string>::const_iterator it = pcdt.mKnownDialogueTopics.begin();
|
for (const auto & knownDialogueTopic : pcdt.mKnownDialogueTopics)
|
||||||
it != pcdt.mKnownDialogueTopics.end(); ++it)
|
|
||||||
{
|
{
|
||||||
outDialogueTopics.push_back(Misc::StringUtils::lowerCase(*it));
|
outDialogueTopics.push_back(Misc::StringUtils::lowerCase(knownDialogueTopic));
|
||||||
}
|
}
|
||||||
|
|
||||||
controls.mViewSwitchDisabled = pcdt.mPNAM.mPlayerFlags & PCDT::PlayerFlags_ViewSwitchDisabled;
|
controls.mViewSwitchDisabled = pcdt.mPNAM.mPlayerFlags & PCDT::PlayerFlags_ViewSwitchDisabled;
|
||||||
|
|
|
@ -1,18 +1,16 @@
|
||||||
#include "convertscri.hpp"
|
#include "convertscri.hpp"
|
||||||
|
|
||||||
#include <iostream>
|
|
||||||
|
|
||||||
namespace
|
namespace
|
||||||
{
|
{
|
||||||
|
|
||||||
template <typename T, ESM::VarType VariantType>
|
template <typename T, ESM::VarType VariantType>
|
||||||
void storeVariables(const std::vector<T>& variables, ESM::Locals& locals, const std::string& scriptname)
|
void storeVariables(const std::vector<T>& variables, ESM::Locals& locals, const std::string& scriptname)
|
||||||
{
|
{
|
||||||
for (typename std::vector<T>::const_iterator it = variables.begin(); it != variables.end(); ++it)
|
for (const auto& variable : variables)
|
||||||
{
|
{
|
||||||
ESM::Variant val(*it);
|
ESM::Variant val(variable);
|
||||||
val.setType(VariantType);
|
val.setType(VariantType);
|
||||||
locals.mVariables.push_back(std::make_pair(std::string(), val));
|
locals.mVariables.emplace_back(std::string(), val);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -86,7 +86,9 @@ namespace ESSImport
|
||||||
bool mHasANIS;
|
bool mHasANIS;
|
||||||
ANIS mANIS; // scripted animation state
|
ANIS mANIS; // scripted animation state
|
||||||
|
|
||||||
void load(ESM::ESMReader& esm);
|
virtual void load(ESM::ESMReader& esm);
|
||||||
|
|
||||||
|
virtual ~ActorData() = default;
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -25,7 +25,9 @@ namespace ESSImport
|
||||||
|
|
||||||
bool mDeleted;
|
bool mDeleted;
|
||||||
|
|
||||||
void load(ESM::ESMReader& esm);
|
void load(ESM::ESMReader& esm) override;
|
||||||
|
|
||||||
|
virtual ~CellRef() = default;
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -16,15 +16,12 @@
|
||||||
#include <components/esm/player.hpp>
|
#include <components/esm/player.hpp>
|
||||||
|
|
||||||
#include <components/esm/loadalch.hpp>
|
#include <components/esm/loadalch.hpp>
|
||||||
#include <components/esm/loadclas.hpp>
|
|
||||||
#include <components/esm/loadspel.hpp>
|
#include <components/esm/loadspel.hpp>
|
||||||
#include <components/esm/loadarmo.hpp>
|
#include <components/esm/loadarmo.hpp>
|
||||||
#include <components/esm/loadweap.hpp>
|
#include <components/esm/loadweap.hpp>
|
||||||
#include <components/esm/loadclot.hpp>
|
#include <components/esm/loadclot.hpp>
|
||||||
#include <components/esm/loadench.hpp>
|
#include <components/esm/loadench.hpp>
|
||||||
#include <components/esm/loadweap.hpp>
|
|
||||||
#include <components/esm/loadlevlist.hpp>
|
#include <components/esm/loadlevlist.hpp>
|
||||||
#include <components/esm/loadglob.hpp>
|
|
||||||
|
|
||||||
#include <components/misc/constants.hpp>
|
#include <components/misc/constants.hpp>
|
||||||
|
|
||||||
|
@ -49,7 +46,7 @@ namespace
|
||||||
image->allocateImage(128, 128, 1, GL_RGB, GL_UNSIGNED_BYTE);
|
image->allocateImage(128, 128, 1, GL_RGB, GL_UNSIGNED_BYTE);
|
||||||
|
|
||||||
// need to convert pixel format from BGRA to RGB as the jpg readerwriter doesn't support it otherwise
|
// need to convert pixel format from BGRA to RGB as the jpg readerwriter doesn't support it otherwise
|
||||||
std::vector<unsigned char>::const_iterator it = fileHeader.mSCRS.begin();
|
auto it = fileHeader.mSCRS.begin();
|
||||||
for (int y=0; y<128; ++y)
|
for (int y=0; y<128; ++y)
|
||||||
{
|
{
|
||||||
for (int x=0; x<128; ++x)
|
for (int x=0; x<128; ++x)
|
||||||
|
@ -317,10 +314,9 @@ namespace ESSImport
|
||||||
|
|
||||||
std::set<unsigned int> unknownRecords;
|
std::set<unsigned int> unknownRecords;
|
||||||
|
|
||||||
for (std::map<unsigned int, std::shared_ptr<Converter> >::const_iterator it = converters.begin();
|
for (const auto & converter : converters)
|
||||||
it != converters.end(); ++it)
|
|
||||||
{
|
{
|
||||||
it->second->setContext(context);
|
converter.second->setContext(context);
|
||||||
}
|
}
|
||||||
|
|
||||||
while (esm.hasMoreRecs())
|
while (esm.hasMoreRecs())
|
||||||
|
@ -328,7 +324,7 @@ namespace ESSImport
|
||||||
ESM::NAME n = esm.getRecName();
|
ESM::NAME n = esm.getRecName();
|
||||||
esm.getRecHeader();
|
esm.getRecHeader();
|
||||||
|
|
||||||
std::map<unsigned int, std::shared_ptr<Converter> >::iterator it = converters.find(n.intval);
|
auto it = converters.find(n.intval);
|
||||||
if (it != converters.end())
|
if (it != converters.end())
|
||||||
{
|
{
|
||||||
it->second->read(esm);
|
it->second->read(esm);
|
||||||
|
@ -358,17 +354,15 @@ namespace ESSImport
|
||||||
writer.setDescription("");
|
writer.setDescription("");
|
||||||
writer.setRecordCount (0);
|
writer.setRecordCount (0);
|
||||||
|
|
||||||
for (std::vector<ESM::Header::MasterData>::const_iterator it = header.mMaster.begin();
|
for (const auto & master : header.mMaster)
|
||||||
it != header.mMaster.end(); ++it)
|
writer.addMaster(master.name, 0); // not using the size information anyway -> use value of 0
|
||||||
writer.addMaster (it->name, 0); // not using the size information anyway -> use value of 0
|
|
||||||
|
|
||||||
writer.save (stream);
|
writer.save (stream);
|
||||||
|
|
||||||
ESM::SavedGame profile;
|
ESM::SavedGame profile;
|
||||||
for (std::vector<ESM::Header::MasterData>::const_iterator it = header.mMaster.begin();
|
for (const auto & master : header.mMaster)
|
||||||
it != header.mMaster.end(); ++it)
|
|
||||||
{
|
{
|
||||||
profile.mContentFiles.push_back(it->name);
|
profile.mContentFiles.push_back(master.name);
|
||||||
}
|
}
|
||||||
profile.mDescription = esm.getDesc();
|
profile.mDescription = esm.getDesc();
|
||||||
profile.mInGameTime.mDay = context.mDay;
|
profile.mInGameTime.mDay = context.mDay;
|
||||||
|
|
|
@ -63,7 +63,6 @@ namespace ESSImport
|
||||||
, mHour(0.f)
|
, mHour(0.f)
|
||||||
, mNextActorId(0)
|
, mNextActorId(0)
|
||||||
{
|
{
|
||||||
mPlayer.mAutoMove = 0;
|
|
||||||
ESM::CellId playerCellId;
|
ESM::CellId playerCellId;
|
||||||
playerCellId.mPaged = true;
|
playerCellId.mPaged = true;
|
||||||
playerCellId.mIndex.mX = playerCellId.mIndex.mY = 0;
|
playerCellId.mIndex.mX = playerCellId.mIndex.mY = 0;
|
||||||
|
|
|
@ -4,8 +4,6 @@
|
||||||
|
|
||||||
#include <components/esm/esmreader.hpp>
|
#include <components/esm/esmreader.hpp>
|
||||||
|
|
||||||
#include <components/esm/loadcont.hpp>
|
|
||||||
|
|
||||||
namespace ESSImport
|
namespace ESSImport
|
||||||
{
|
{
|
||||||
|
|
||||||
|
|
|
@ -15,17 +15,13 @@ set(GAME_HEADER
|
||||||
engine.hpp
|
engine.hpp
|
||||||
)
|
)
|
||||||
|
|
||||||
if (BULLET_USE_DOUBLES)
|
|
||||||
add_definitions(-DBT_USE_DOUBLE_PRECISION)
|
|
||||||
endif()
|
|
||||||
|
|
||||||
source_group(game FILES ${GAME} ${GAME_HEADER})
|
source_group(game FILES ${GAME} ${GAME_HEADER})
|
||||||
|
|
||||||
add_openmw_dir (mwrender
|
add_openmw_dir (mwrender
|
||||||
actors objects renderingmanager animation rotatecontroller sky npcanimation vismask
|
actors objects renderingmanager animation rotatecontroller sky npcanimation vismask
|
||||||
creatureanimation effectmanager util renderinginterface pathgrid rendermode weaponanimation
|
creatureanimation effectmanager util renderinginterface pathgrid rendermode weaponanimation
|
||||||
bulletdebugdraw globalmap characterpreview camera localmap water terrainstorage ripplesimulation
|
bulletdebugdraw globalmap characterpreview camera localmap water terrainstorage ripplesimulation
|
||||||
renderbin actoranimation landmanager navmesh actorspaths recastmesh
|
renderbin actoranimation landmanager navmesh actorspaths recastmesh fogmanager
|
||||||
)
|
)
|
||||||
|
|
||||||
add_openmw_dir (mwinput
|
add_openmw_dir (mwinput
|
||||||
|
@ -71,7 +67,7 @@ add_openmw_dir (mwworld
|
||||||
actionequip timestamp actionalchemy cellstore actionapply actioneat
|
actionequip timestamp actionalchemy cellstore actionapply actioneat
|
||||||
store esmstore recordcmp fallback actionrepair actionsoulgem livecellref actiondoor
|
store esmstore recordcmp fallback actionrepair actionsoulgem livecellref actiondoor
|
||||||
contentloader esmloader actiontrap cellreflist cellref physicssystem weather projectilemanager
|
contentloader esmloader actiontrap cellreflist cellref physicssystem weather projectilemanager
|
||||||
cellpreloader
|
cellpreloader datetimemanager
|
||||||
)
|
)
|
||||||
|
|
||||||
add_openmw_dir (mwphysics
|
add_openmw_dir (mwphysics
|
||||||
|
|
|
@ -311,6 +311,8 @@ namespace MWBase
|
||||||
virtual float getAngleToPlayer(const MWWorld::Ptr& ptr) const = 0;
|
virtual float getAngleToPlayer(const MWWorld::Ptr& ptr) const = 0;
|
||||||
virtual MWMechanics::GreetingState getGreetingState(const MWWorld::Ptr& ptr) const = 0;
|
virtual MWMechanics::GreetingState getGreetingState(const MWWorld::Ptr& ptr) const = 0;
|
||||||
virtual bool isTurningToPlayer(const MWWorld::Ptr& ptr) const = 0;
|
virtual bool isTurningToPlayer(const MWWorld::Ptr& ptr) const = 0;
|
||||||
|
|
||||||
|
virtual void restoreStatsAfterCorprus(const MWWorld::Ptr& actor, const std::string& sourceId) = 0;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -36,6 +36,7 @@ namespace ESM
|
||||||
struct Position;
|
struct Position;
|
||||||
struct Cell;
|
struct Cell;
|
||||||
struct Class;
|
struct Class;
|
||||||
|
struct Creature;
|
||||||
struct Potion;
|
struct Potion;
|
||||||
struct Spell;
|
struct Spell;
|
||||||
struct NPC;
|
struct NPC;
|
||||||
|
@ -47,7 +48,7 @@ namespace ESM
|
||||||
struct EffectList;
|
struct EffectList;
|
||||||
struct CreatureLevList;
|
struct CreatureLevList;
|
||||||
struct ItemLevList;
|
struct ItemLevList;
|
||||||
struct Creature;
|
struct TimeStamp;
|
||||||
}
|
}
|
||||||
|
|
||||||
namespace MWRender
|
namespace MWRender
|
||||||
|
@ -234,54 +235,14 @@ namespace MWBase
|
||||||
virtual void advanceTime (double hours, bool incremental = false) = 0;
|
virtual void advanceTime (double hours, bool incremental = false) = 0;
|
||||||
///< Advance in-game time.
|
///< Advance in-game time.
|
||||||
|
|
||||||
virtual void setHour (double hour) = 0;
|
|
||||||
///< Set in-game time hour.
|
|
||||||
|
|
||||||
virtual void setMonth (int month) = 0;
|
|
||||||
///< Set in-game time month.
|
|
||||||
|
|
||||||
virtual void setDay (int day) = 0;
|
|
||||||
///< Set in-game time day.
|
|
||||||
|
|
||||||
/*
|
|
||||||
Start of tes3mp addition
|
|
||||||
|
|
||||||
Make it possible to set the year from elsewhere
|
|
||||||
*/
|
|
||||||
virtual void setYear(int year) = 0;
|
|
||||||
/*
|
|
||||||
End of tes3mp addition
|
|
||||||
*/
|
|
||||||
|
|
||||||
/*
|
|
||||||
Start of tes3mp addition
|
|
||||||
|
|
||||||
Make it possible to set the number of days passed from elsewhere
|
|
||||||
*/
|
|
||||||
virtual void setDaysPassed(int daysPassed) = 0;
|
|
||||||
/*
|
|
||||||
End of tes3mp addition
|
|
||||||
*/
|
|
||||||
|
|
||||||
/*
|
|
||||||
Start of tes3mp addition
|
|
||||||
|
|
||||||
Make it possible to set a custom timeScale from elsewhere
|
|
||||||
*/
|
|
||||||
virtual void setTimeScale(float timeScale) = 0;
|
|
||||||
/*
|
|
||||||
End of tes3mp addition
|
|
||||||
*/
|
|
||||||
|
|
||||||
virtual int getDay() const = 0;
|
|
||||||
virtual int getMonth() const = 0;
|
|
||||||
virtual int getYear() const = 0;
|
|
||||||
|
|
||||||
virtual std::string getMonthName (int month = -1) const = 0;
|
virtual std::string getMonthName (int month = -1) const = 0;
|
||||||
///< Return name of month (-1: current month)
|
///< Return name of month (-1: current month)
|
||||||
|
|
||||||
virtual MWWorld::TimeStamp getTimeStamp() const = 0;
|
virtual MWWorld::TimeStamp getTimeStamp() const = 0;
|
||||||
///< Return current in-game time stamp.
|
///< Return current in-game time and number of day since new game start.
|
||||||
|
|
||||||
|
virtual ESM::EpochTimeStamp getEpochTimeStamp() const = 0;
|
||||||
|
///< Return current in-game date and time.
|
||||||
|
|
||||||
virtual bool toggleSky() = 0;
|
virtual bool toggleSky() = 0;
|
||||||
///< \return Resulting mode
|
///< \return Resulting mode
|
||||||
|
@ -530,6 +491,14 @@ namespace MWBase
|
||||||
///< Write this record to the ESM store, allowing it to override a pre-existing record with the same ID.
|
///< Write this record to the ESM store, allowing it to override a pre-existing record with the same ID.
|
||||||
/// \return pointer to created record
|
/// \return pointer to created record
|
||||||
|
|
||||||
|
virtual const ESM::Creature *createOverrideRecord (const ESM::Creature& record) = 0;
|
||||||
|
///< Write this record to the ESM store, allowing it to override a pre-existing record with the same ID.
|
||||||
|
/// \return pointer to created record
|
||||||
|
|
||||||
|
virtual const ESM::NPC *createOverrideRecord (const ESM::NPC& record) = 0;
|
||||||
|
///< Write this record to the ESM store, allowing it to override a pre-existing record with the same ID.
|
||||||
|
/// \return pointer to created record
|
||||||
|
|
||||||
virtual void update (float duration, bool paused) = 0;
|
virtual void update (float duration, bool paused) = 0;
|
||||||
virtual void updatePhysics (float duration, bool paused) = 0;
|
virtual void updatePhysics (float duration, bool paused) = 0;
|
||||||
|
|
||||||
|
|
|
@ -322,7 +322,7 @@ namespace MWClass
|
||||||
const MWWorld::LiveCellRef<ESM::Armor> *ref = ptr.get<ESM::Armor>();
|
const MWWorld::LiveCellRef<ESM::Armor> *ref = ptr.get<ESM::Armor>();
|
||||||
|
|
||||||
int armorSkillType = getEquipmentSkill(ptr);
|
int armorSkillType = getEquipmentSkill(ptr);
|
||||||
int armorSkill = actor.getClass().getSkill(actor, armorSkillType);
|
float armorSkill = actor.getClass().getSkill(actor, armorSkillType);
|
||||||
|
|
||||||
const MWBase::World *world = MWBase::Environment::get().getWorld();
|
const MWBase::World *world = MWBase::Environment::get().getWorld();
|
||||||
int iBaseArmorSkill = world->getStore().get<ESM::GameSetting>().find("iBaseArmorSkill")->mValue.getInteger();
|
int iBaseArmorSkill = world->getStore().get<ESM::GameSetting>().find("iBaseArmorSkill")->mValue.getInteger();
|
||||||
|
|
|
@ -793,7 +793,7 @@ namespace MWClass
|
||||||
float Creature::getCapacity (const MWWorld::Ptr& ptr) const
|
float Creature::getCapacity (const MWWorld::Ptr& ptr) const
|
||||||
{
|
{
|
||||||
const MWMechanics::CreatureStats& stats = getCreatureStats (ptr);
|
const MWMechanics::CreatureStats& stats = getCreatureStats (ptr);
|
||||||
return static_cast<float>(stats.getAttribute(ESM::Attribute::Strength).getModified() * 5);
|
return stats.getAttribute(ESM::Attribute::Strength).getModified() * 5;
|
||||||
}
|
}
|
||||||
|
|
||||||
int Creature::getServices(const MWWorld::ConstPtr &actor) const
|
int Creature::getServices(const MWWorld::ConstPtr &actor) const
|
||||||
|
@ -933,7 +933,7 @@ namespace MWClass
|
||||||
throw std::runtime_error(std::string("Unexpected soundgen type: ")+name);
|
throw std::runtime_error(std::string("Unexpected soundgen type: ")+name);
|
||||||
}
|
}
|
||||||
|
|
||||||
int Creature::getSkill(const MWWorld::Ptr &ptr, int skill) const
|
float Creature::getSkill(const MWWorld::Ptr &ptr, int skill) const
|
||||||
{
|
{
|
||||||
MWWorld::LiveCellRef<ESM::Creature> *ref =
|
MWWorld::LiveCellRef<ESM::Creature> *ref =
|
||||||
ptr.get<ESM::Creature>();
|
ptr.get<ESM::Creature>();
|
||||||
|
@ -997,6 +997,12 @@ namespace MWClass
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (ptr.getRefData().getCount() <= 0)
|
||||||
|
{
|
||||||
|
state.mHasCustomState = false;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
const CreatureCustomData& customData = ptr.getRefData().getCustomData()->asCreatureCustomData();
|
const CreatureCustomData& customData = ptr.getRefData().getCustomData()->asCreatureCustomData();
|
||||||
ESM::CreatureState& creatureState = state.asCreatureState();
|
ESM::CreatureState& creatureState = state.asCreatureState();
|
||||||
customData.mContainerStore->writeState (creatureState.mInventory);
|
customData.mContainerStore->writeState (creatureState.mInventory);
|
||||||
|
@ -1066,4 +1072,9 @@ namespace MWClass
|
||||||
const MWWorld::LiveCellRef<ESM::Creature> *ref = ptr.get<ESM::Creature>();
|
const MWWorld::LiveCellRef<ESM::Creature> *ref = ptr.get<ESM::Creature>();
|
||||||
scale *= ref->mBase->mScale;
|
scale *= ref->mBase->mScale;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Creature::setBaseAISetting(const std::string& id, MWMechanics::CreatureStats::AiSetting setting, int value) const
|
||||||
|
{
|
||||||
|
MWMechanics::setBaseAISetting<ESM::Creature>(id, setting, value);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -118,7 +118,7 @@ namespace MWClass
|
||||||
virtual bool canSwim (const MWWorld::ConstPtr &ptr) const;
|
virtual bool canSwim (const MWWorld::ConstPtr &ptr) const;
|
||||||
virtual bool canWalk (const MWWorld::ConstPtr &ptr) const;
|
virtual bool canWalk (const MWWorld::ConstPtr &ptr) const;
|
||||||
|
|
||||||
virtual int getSkill(const MWWorld::Ptr &ptr, int skill) const;
|
virtual float getSkill(const MWWorld::Ptr &ptr, int skill) const;
|
||||||
|
|
||||||
/// Get a blood texture suitable for \a ptr (see Blood Texture 0-2 in Morrowind.ini)
|
/// Get a blood texture suitable for \a ptr (see Blood Texture 0-2 in Morrowind.ini)
|
||||||
virtual int getBloodTexture (const MWWorld::ConstPtr& ptr) const;
|
virtual int getBloodTexture (const MWWorld::ConstPtr& ptr) const;
|
||||||
|
@ -139,6 +139,8 @@ namespace MWClass
|
||||||
|
|
||||||
virtual void adjustScale(const MWWorld::ConstPtr& ptr, osg::Vec3f& scale, bool rendering) const;
|
virtual void adjustScale(const MWWorld::ConstPtr& ptr, osg::Vec3f& scale, bool rendering) const;
|
||||||
/// @param rendering Indicates if the scale to adjust is for the rendering mesh, or for the collision mesh
|
/// @param rendering Indicates if the scale to adjust is for the rendering mesh, or for the collision mesh
|
||||||
|
|
||||||
|
virtual void setBaseAISetting(const std::string& id, MWMechanics::CreatureStats::AiSetting setting, int value) const;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -158,7 +158,7 @@ namespace MWClass
|
||||||
}
|
}
|
||||||
|
|
||||||
MWWorld::Ptr player = MWBase::Environment::get().getWorld ()->getPlayerPtr();
|
MWWorld::Ptr player = MWBase::Environment::get().getWorld ()->getPlayerPtr();
|
||||||
int alchemySkill = player.getClass().getSkill(player, ESM::Skill::Alchemy);
|
float alchemySkill = player.getClass().getSkill(player, ESM::Skill::Alchemy);
|
||||||
|
|
||||||
static const float fWortChanceValue =
|
static const float fWortChanceValue =
|
||||||
MWBase::Environment::get().getWorld()->getStore().get<ESM::GameSetting>().find("fWortChanceValue")->mValue.getFloat();
|
MWBase::Environment::get().getWorld()->getStore().get<ESM::GameSetting>().find("fWortChanceValue")->mValue.getFloat();
|
||||||
|
|
|
@ -144,8 +144,8 @@ namespace
|
||||||
}
|
}
|
||||||
|
|
||||||
// initial health
|
// initial health
|
||||||
int strength = creatureStats.getAttribute(ESM::Attribute::Strength).getBase();
|
float strength = creatureStats.getAttribute(ESM::Attribute::Strength).getBase();
|
||||||
int endurance = creatureStats.getAttribute(ESM::Attribute::Endurance).getBase();
|
float endurance = creatureStats.getAttribute(ESM::Attribute::Endurance).getBase();
|
||||||
|
|
||||||
int multiplier = 3;
|
int multiplier = 3;
|
||||||
|
|
||||||
|
@ -1234,7 +1234,7 @@ namespace MWClass
|
||||||
gmst.fJumpEncumbranceMultiplier->mValue.getFloat() *
|
gmst.fJumpEncumbranceMultiplier->mValue.getFloat() *
|
||||||
(1.0f - Npc::getNormalizedEncumbrance(ptr));
|
(1.0f - Npc::getNormalizedEncumbrance(ptr));
|
||||||
|
|
||||||
float a = static_cast<float>(getSkill(ptr, ESM::Skill::Acrobatics));
|
float a = getSkill(ptr, ESM::Skill::Acrobatics);
|
||||||
float b = 0.0f;
|
float b = 0.0f;
|
||||||
if(a > 50.0f)
|
if(a > 50.0f)
|
||||||
{
|
{
|
||||||
|
@ -1359,7 +1359,7 @@ namespace MWClass
|
||||||
|
|
||||||
float fUnarmoredBase1 = store.find("fUnarmoredBase1")->mValue.getFloat();
|
float fUnarmoredBase1 = store.find("fUnarmoredBase1")->mValue.getFloat();
|
||||||
float fUnarmoredBase2 = store.find("fUnarmoredBase2")->mValue.getFloat();
|
float fUnarmoredBase2 = store.find("fUnarmoredBase2")->mValue.getFloat();
|
||||||
int unarmoredSkill = getSkill(ptr, ESM::Skill::Unarmored);
|
float unarmoredSkill = getSkill(ptr, ESM::Skill::Unarmored);
|
||||||
|
|
||||||
float ratings[MWWorld::InventoryStore::Slots];
|
float ratings[MWWorld::InventoryStore::Slots];
|
||||||
for(int i = 0;i < MWWorld::InventoryStore::Slots;i++)
|
for(int i = 0;i < MWWorld::InventoryStore::Slots;i++)
|
||||||
|
@ -1506,7 +1506,7 @@ namespace MWClass
|
||||||
return MWWorld::Ptr(cell.insert(ref), &cell);
|
return MWWorld::Ptr(cell.insert(ref), &cell);
|
||||||
}
|
}
|
||||||
|
|
||||||
int Npc::getSkill(const MWWorld::Ptr& ptr, int skill) const
|
float Npc::getSkill(const MWWorld::Ptr& ptr, int skill) const
|
||||||
{
|
{
|
||||||
return getNpcStats(ptr).getSkill(skill).getModified();
|
return getNpcStats(ptr).getSkill(skill).getModified();
|
||||||
}
|
}
|
||||||
|
@ -1550,6 +1550,12 @@ namespace MWClass
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (ptr.getRefData().getCount() <= 0)
|
||||||
|
{
|
||||||
|
state.mHasCustomState = false;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
const NpcCustomData& customData = ptr.getRefData().getCustomData()->asNpcCustomData();
|
const NpcCustomData& customData = ptr.getRefData().getCustomData()->asNpcCustomData();
|
||||||
ESM::NpcState& npcState = state.asNpcState();
|
ESM::NpcState& npcState = state.asNpcState();
|
||||||
customData.mInventoryStore.writeState (npcState.mInventory);
|
customData.mInventoryStore.writeState (npcState.mInventory);
|
||||||
|
@ -1660,4 +1666,9 @@ namespace MWClass
|
||||||
const MWWorld::LiveCellRef<ESM::NPC> *ref = ptr.get<ESM::NPC>();
|
const MWWorld::LiveCellRef<ESM::NPC> *ref = ptr.get<ESM::NPC>();
|
||||||
return ref->mBase->getFactionRank();
|
return ref->mBase->getFactionRank();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Npc::setBaseAISetting(const std::string& id, MWMechanics::CreatureStats::AiSetting setting, int value) const
|
||||||
|
{
|
||||||
|
MWMechanics::setBaseAISetting<ESM::NPC>(id, setting, value);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -139,7 +139,7 @@ namespace MWClass
|
||||||
|
|
||||||
virtual std::string getModel(const MWWorld::ConstPtr &ptr) const;
|
virtual std::string getModel(const MWWorld::ConstPtr &ptr) const;
|
||||||
|
|
||||||
virtual int getSkill(const MWWorld::Ptr& ptr, int skill) const;
|
virtual float getSkill(const MWWorld::Ptr& ptr, int skill) const;
|
||||||
|
|
||||||
/// Get a blood texture suitable for \a ptr (see Blood Texture 0-2 in Morrowind.ini)
|
/// Get a blood texture suitable for \a ptr (see Blood Texture 0-2 in Morrowind.ini)
|
||||||
virtual int getBloodTexture (const MWWorld::ConstPtr& ptr) const;
|
virtual int getBloodTexture (const MWWorld::ConstPtr& ptr) const;
|
||||||
|
@ -174,6 +174,8 @@ namespace MWClass
|
||||||
|
|
||||||
virtual std::string getPrimaryFaction(const MWWorld::ConstPtr &ptr) const;
|
virtual std::string getPrimaryFaction(const MWWorld::ConstPtr &ptr) const;
|
||||||
virtual int getPrimaryFactionRank(const MWWorld::ConstPtr &ptr) const;
|
virtual int getPrimaryFactionRank(const MWWorld::ConstPtr &ptr) const;
|
||||||
|
|
||||||
|
virtual void setBaseAISetting(const std::string& id, MWMechanics::CreatureStats::AiSetting setting, int value) const;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -134,6 +134,12 @@ namespace MWGui
|
||||||
End of tes3mp change (major)
|
End of tes3mp change (major)
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
// We should not worsen corprus when in prison
|
||||||
|
for (auto& spell : player.getClass().getCreatureStats(player).getCorprusSpells())
|
||||||
|
{
|
||||||
|
spell.second.mNextWorsening += mDays * 24;
|
||||||
|
}
|
||||||
|
|
||||||
std::set<int> skills;
|
std::set<int> skills;
|
||||||
for (int day=0; day<mDays; ++day)
|
for (int day=0; day<mDays; ++day)
|
||||||
{
|
{
|
||||||
|
@ -148,14 +154,14 @@ namespace MWGui
|
||||||
Disable increases for Security and Sneak when using ignoreJailSkillIncreases
|
Disable increases for Security and Sneak when using ignoreJailSkillIncreases
|
||||||
*/
|
*/
|
||||||
if (localPlayer->ignoreJailSkillIncreases)
|
if (localPlayer->ignoreJailSkillIncreases)
|
||||||
value.setBase(std::max(0, value.getBase()-1));
|
value.setBase(std::max(0.f, value.getBase()-1));
|
||||||
else if (skill == ESM::Skill::Security || skill == ESM::Skill::Sneak)
|
else if (skill == ESM::Skill::Security || skill == ESM::Skill::Sneak)
|
||||||
/*
|
/*
|
||||||
End of tes3mp change (minor)
|
End of tes3mp change (minor)
|
||||||
*/
|
*/
|
||||||
value.setBase(std::min(100, value.getBase()+1));
|
value.setBase(std::min(100.f, value.getBase() + 1));
|
||||||
else
|
else
|
||||||
value.setBase(std::max(0, value.getBase()-1));
|
value.setBase(std::max(0.f, value.getBase()-1));
|
||||||
}
|
}
|
||||||
|
|
||||||
const MWWorld::Store<ESM::GameSetting>& gmst = MWBase::Environment::get().getWorld()->getStore().get<ESM::GameSetting>();
|
const MWWorld::Store<ESM::GameSetting>& gmst = MWBase::Environment::get().getWorld()->getStore().get<ESM::GameSetting>();
|
||||||
|
|
|
@ -157,7 +157,7 @@ namespace MWGui
|
||||||
mAttributeValues[i]->setEnabled(true);
|
mAttributeValues[i]->setEnabled(true);
|
||||||
availableAttributes++;
|
availableAttributes++;
|
||||||
|
|
||||||
int mult = pcStats.getLevelupAttributeMultiplier (i);
|
float mult = pcStats.getLevelupAttributeMultiplier (i);
|
||||||
mult = std::min(mult, 100-pcStats.getAttribute(i).getBase());
|
mult = std::min(mult, 100-pcStats.getAttribute(i).getBase());
|
||||||
text->setCaption(mult <= 1 ? "" : "x" + MyGUI::utility::toString(mult));
|
text->setCaption(mult <= 1 ? "" : "x" + MyGUI::utility::toString(mult));
|
||||||
}
|
}
|
||||||
|
|
|
@ -22,7 +22,7 @@ namespace MWGui
|
||||||
{
|
{
|
||||||
MWWorld::Ptr player = MWMechanics::getPlayer();
|
MWWorld::Ptr player = MWMechanics::getPlayer();
|
||||||
mSourceModel = sourceModel;
|
mSourceModel = sourceModel;
|
||||||
int chance = player.getClass().getSkill(player, ESM::Skill::Sneak);
|
float chance = player.getClass().getSkill(player, ESM::Skill::Sneak);
|
||||||
|
|
||||||
mSourceModel->update();
|
mSourceModel->update();
|
||||||
|
|
||||||
|
|
|
@ -159,7 +159,7 @@ namespace MWGui
|
||||||
for (int i=0; ids[i]; ++i)
|
for (int i=0; ids[i]; ++i)
|
||||||
if (ids[i]==id)
|
if (ids[i]==id)
|
||||||
{
|
{
|
||||||
setText (id, std::to_string(value.getModified()));
|
setText (id, std::to_string(static_cast<int>(value.getModified())));
|
||||||
|
|
||||||
MyGUI::TextBox* box;
|
MyGUI::TextBox* box;
|
||||||
getWidget(box, id);
|
getWidget(box, id);
|
||||||
|
|
|
@ -86,11 +86,11 @@ namespace MWGui
|
||||||
mPlayerGold->setCaptionWithReplacing("#{sGold}: " + MyGUI::utility::toString(playerGold));
|
mPlayerGold->setCaptionWithReplacing("#{sGold}: " + MyGUI::utility::toString(playerGold));
|
||||||
|
|
||||||
// NPC can train you in his best 3 skills
|
// NPC can train you in his best 3 skills
|
||||||
std::vector< std::pair<int, int> > skills;
|
std::vector< std::pair<int, float> > skills;
|
||||||
|
|
||||||
for (int i=0; i<ESM::Skill::Length; ++i)
|
for (int i=0; i<ESM::Skill::Length; ++i)
|
||||||
{
|
{
|
||||||
int value = actor.getClass().getSkill(actor, i);
|
float value = actor.getClass().getSkill(actor, i);
|
||||||
|
|
||||||
skills.push_back(std::make_pair(i, value));
|
skills.push_back(std::make_pair(i, value));
|
||||||
}
|
}
|
||||||
|
|
|
@ -180,11 +180,10 @@ namespace MWGui
|
||||||
if (hour >= 13) hour -= 12;
|
if (hour >= 13) hour -= 12;
|
||||||
if (hour == 0) hour = 12;
|
if (hour == 0) hour = 12;
|
||||||
|
|
||||||
std::string dateTimeText =
|
ESM::EpochTimeStamp currentDate = MWBase::Environment::get().getWorld()->getEpochTimeStamp();
|
||||||
MyGUI::utility::toString(MWBase::Environment::get().getWorld ()->getDay ()) + " "
|
int daysPassed = MWBase::Environment::get().getWorld()->getTimeStamp().getDay();
|
||||||
+ month + " (#{sDay} " + MyGUI::utility::toString(MWBase::Environment::get().getWorld ()->getTimeStamp ().getDay())
|
std::string formattedHour = pm ? "#{sSaveMenuHelp05}" : "#{sSaveMenuHelp04}";
|
||||||
+ ") " + MyGUI::utility::toString(hour) + " " + (pm ? "#{sSaveMenuHelp05}" : "#{sSaveMenuHelp04}");
|
std::string dateTimeText = Misc::StringUtils::format("%i %s (#{sDay} %i) %i %s", currentDate.mDay, month, daysPassed, hour, formattedHour);
|
||||||
|
|
||||||
mDateTimeText->setCaptionWithReplacing (dateTimeText);
|
mDateTimeText->setCaptionWithReplacing (dateTimeText);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -29,13 +29,23 @@ namespace MWMechanics
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
bool interrupt = false;
|
||||||
std::vector<ActiveEffect>& effects = iter->second.mEffects;
|
std::vector<ActiveEffect>& effects = iter->second.mEffects;
|
||||||
for (std::vector<ActiveEffect>::iterator effectIt = effects.begin(); effectIt != effects.end();)
|
for (std::vector<ActiveEffect>::iterator effectIt = effects.begin(); effectIt != effects.end();)
|
||||||
{
|
{
|
||||||
if (effectIt->mTimeLeft <= 0)
|
if (effectIt->mTimeLeft <= 0)
|
||||||
{
|
{
|
||||||
effectIt = effects.erase(effectIt);
|
|
||||||
rebuild = true;
|
rebuild = true;
|
||||||
|
|
||||||
|
// Note: it we expire a Corprus effect, we should remove the whole spell.
|
||||||
|
if (effectIt->mEffectId == ESM::MagicEffect::Corprus)
|
||||||
|
{
|
||||||
|
iter = mSpells.erase (iter);
|
||||||
|
interrupt = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
effectIt = effects.erase(effectIt);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -43,6 +53,8 @@ namespace MWMechanics
|
||||||
++effectIt;
|
++effectIt;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!interrupt)
|
||||||
++iter;
|
++iter;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -327,6 +339,31 @@ namespace MWMechanics
|
||||||
End of tes3mp addition
|
End of tes3mp addition
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
void ActiveSpells::purgeCorprusDisease()
|
||||||
|
{
|
||||||
|
for (TContainer::iterator iter = mSpells.begin(); iter!=mSpells.end();)
|
||||||
|
{
|
||||||
|
bool hasCorprusEffect = false;
|
||||||
|
for (std::vector<ActiveEffect>::iterator effectIt = iter->second.mEffects.begin();
|
||||||
|
effectIt != iter->second.mEffects.end();++effectIt)
|
||||||
|
{
|
||||||
|
if (effectIt->mEffectId == ESM::MagicEffect::Corprus)
|
||||||
|
{
|
||||||
|
hasCorprusEffect = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (hasCorprusEffect)
|
||||||
|
{
|
||||||
|
mSpells.erase(iter++);
|
||||||
|
mSpellsChanged = true;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
++iter;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void ActiveSpells::clear()
|
void ActiveSpells::clear()
|
||||||
{
|
{
|
||||||
mSpells.clear();
|
mSpells.clear();
|
||||||
|
|
|
@ -119,6 +119,8 @@ namespace MWMechanics
|
||||||
bool isSpellActive (const std::string& id) const;
|
bool isSpellActive (const std::string& id) const;
|
||||||
///< case insensitive
|
///< case insensitive
|
||||||
|
|
||||||
|
void purgeCorprusDisease();
|
||||||
|
|
||||||
const MagicEffects& getMagicEffects() const;
|
const MagicEffects& getMagicEffects() const;
|
||||||
|
|
||||||
void visitEffectSources (MWMechanics::EffectSourceVisitor& visitor) const;
|
void visitEffectSources (MWMechanics::EffectSourceVisitor& visitor) const;
|
||||||
|
|
|
@ -131,11 +131,11 @@ void adjustCommandedActor (const MWWorld::Ptr& actor)
|
||||||
|
|
||||||
bool hasCommandPackage = false;
|
bool hasCommandPackage = false;
|
||||||
|
|
||||||
std::list<MWMechanics::AiPackage*>::const_iterator it;
|
auto it = stats.getAiSequence().begin();
|
||||||
for (it = stats.getAiSequence().begin(); it != stats.getAiSequence().end(); ++it)
|
for (; it != stats.getAiSequence().end(); ++it)
|
||||||
{
|
{
|
||||||
if ((*it)->getTypeId() == MWMechanics::AiPackage::TypeIdFollow &&
|
if ((*it)->getTypeId() == MWMechanics::AiPackage::TypeIdFollow &&
|
||||||
static_cast<MWMechanics::AiFollow*>(*it)->isCommanded())
|
static_cast<const MWMechanics::AiFollow*>(it->get())->isCommanded())
|
||||||
{
|
{
|
||||||
hasCommandPackage = true;
|
hasCommandPackage = true;
|
||||||
break;
|
break;
|
||||||
|
@ -151,7 +151,7 @@ void getRestorationPerHourOfSleep (const MWWorld::Ptr& ptr, float& health, float
|
||||||
MWMechanics::CreatureStats& stats = ptr.getClass().getCreatureStats (ptr);
|
MWMechanics::CreatureStats& stats = ptr.getClass().getCreatureStats (ptr);
|
||||||
const MWWorld::Store<ESM::GameSetting>& settings = MWBase::Environment::get().getWorld()->getStore().get<ESM::GameSetting>();
|
const MWWorld::Store<ESM::GameSetting>& settings = MWBase::Environment::get().getWorld()->getStore().get<ESM::GameSetting>();
|
||||||
|
|
||||||
int endurance = stats.getAttribute (ESM::Attribute::Endurance).getModified ();
|
float endurance = stats.getAttribute (ESM::Attribute::Endurance).getModified ();
|
||||||
health = 0.1f * endurance;
|
health = 0.1f * endurance;
|
||||||
|
|
||||||
float fRestMagicMult = settings.find("fRestMagicMult")->mValue.getFloat ();
|
float fRestMagicMult = settings.find("fRestMagicMult")->mValue.getFloat ();
|
||||||
|
@ -195,6 +195,49 @@ namespace MWMechanics
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
class GetCurrentMagnitudes : public MWMechanics::EffectSourceVisitor
|
||||||
|
{
|
||||||
|
std::string mSpellId;
|
||||||
|
|
||||||
|
public:
|
||||||
|
GetCurrentMagnitudes(const std::string& spellId)
|
||||||
|
: mSpellId(spellId)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual void visit (MWMechanics::EffectKey key,
|
||||||
|
const std::string& sourceName, const std::string& sourceId, int casterActorId,
|
||||||
|
float magnitude, float remainingTime = -1, float totalTime = -1)
|
||||||
|
{
|
||||||
|
if (magnitude <= 0)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (sourceId != mSpellId)
|
||||||
|
return;
|
||||||
|
|
||||||
|
mMagnitudes.push_back(std::make_pair(key, magnitude));
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<std::pair<MWMechanics::EffectKey, float>> mMagnitudes;
|
||||||
|
};
|
||||||
|
|
||||||
|
class GetCorprusSpells : public MWMechanics::EffectSourceVisitor
|
||||||
|
{
|
||||||
|
|
||||||
|
public:
|
||||||
|
virtual void visit (MWMechanics::EffectKey key,
|
||||||
|
const std::string& sourceName, const std::string& sourceId, int casterActorId,
|
||||||
|
float magnitude, float remainingTime = -1, float totalTime = -1)
|
||||||
|
{
|
||||||
|
if (key.mId != ESM::MagicEffect::Corprus)
|
||||||
|
return;
|
||||||
|
|
||||||
|
mSpells.push_back(sourceId);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<std::string> mSpells;
|
||||||
|
};
|
||||||
|
|
||||||
class SoulTrap : public MWMechanics::EffectSourceVisitor
|
class SoulTrap : public MWMechanics::EffectSourceVisitor
|
||||||
{
|
{
|
||||||
MWWorld::Ptr mCreature;
|
MWWorld::Ptr mCreature;
|
||||||
|
@ -468,9 +511,9 @@ namespace MWMechanics
|
||||||
CreatureStats &stats = actor.getClass().getCreatureStats(actor);
|
CreatureStats &stats = actor.getClass().getCreatureStats(actor);
|
||||||
MWMechanics::AiSequence& seq = stats.getAiSequence();
|
MWMechanics::AiSequence& seq = stats.getAiSequence();
|
||||||
|
|
||||||
if (!seq.isEmpty() && seq.getActivePackage()->useVariableSpeed())
|
if (!seq.isEmpty() && seq.getActivePackage().useVariableSpeed())
|
||||||
{
|
{
|
||||||
osg::Vec3f targetPos = seq.getActivePackage()->getDestination();
|
osg::Vec3f targetPos = seq.getActivePackage().getDestination();
|
||||||
osg::Vec3f actorPos = actor.getRefData().getPosition().asVec3();
|
osg::Vec3f actorPos = actor.getRefData().getPosition().asVec3();
|
||||||
float distance = (targetPos - actorPos).length();
|
float distance = (targetPos - actorPos).length();
|
||||||
if (distance < DECELERATE_DISTANCE)
|
if (distance < DECELERATE_DISTANCE)
|
||||||
|
@ -718,7 +761,7 @@ namespace MWMechanics
|
||||||
return;
|
return;
|
||||||
|
|
||||||
bool followerOrEscorter = false;
|
bool followerOrEscorter = false;
|
||||||
for (const AiPackage* package : creatureStats2.getAiSequence())
|
for (const auto& package : creatureStats2.getAiSequence())
|
||||||
{
|
{
|
||||||
// The follow package must be first or have nothing but combat before it
|
// The follow package must be first or have nothing but combat before it
|
||||||
if (package->sideWithTarget())
|
if (package->sideWithTarget())
|
||||||
|
@ -767,7 +810,7 @@ namespace MWMechanics
|
||||||
{
|
{
|
||||||
CreatureStats& creatureStats = ptr.getClass().getCreatureStats (ptr);
|
CreatureStats& creatureStats = ptr.getClass().getCreatureStats (ptr);
|
||||||
|
|
||||||
int intelligence = creatureStats.getAttribute(ESM::Attribute::Intelligence).getModified();
|
float intelligence = creatureStats.getAttribute(ESM::Attribute::Intelligence).getModified();
|
||||||
|
|
||||||
float base = 1.f;
|
float base = 1.f;
|
||||||
if (ptr == getPlayer())
|
if (ptr == getPlayer())
|
||||||
|
@ -846,7 +889,7 @@ namespace MWMechanics
|
||||||
float fFatigueReturnMult = settings.find("fFatigueReturnMult")->mValue.getFloat ();
|
float fFatigueReturnMult = settings.find("fFatigueReturnMult")->mValue.getFloat ();
|
||||||
float fEndFatigueMult = settings.find("fEndFatigueMult")->mValue.getFloat ();
|
float fEndFatigueMult = settings.find("fEndFatigueMult")->mValue.getFloat ();
|
||||||
|
|
||||||
int endurance = stats.getAttribute (ESM::Attribute::Endurance).getModified ();
|
float endurance = stats.getAttribute (ESM::Attribute::Endurance).getModified ();
|
||||||
|
|
||||||
float normalizedEncumbrance = ptr.getClass().getNormalizedEncumbrance(ptr);
|
float normalizedEncumbrance = ptr.getClass().getNormalizedEncumbrance(ptr);
|
||||||
if (normalizedEncumbrance > 1)
|
if (normalizedEncumbrance > 1)
|
||||||
|
@ -873,7 +916,7 @@ namespace MWMechanics
|
||||||
return;
|
return;
|
||||||
|
|
||||||
// Restore fatigue
|
// Restore fatigue
|
||||||
int endurance = stats.getAttribute(ESM::Attribute::Endurance).getModified();
|
float endurance = stats.getAttribute(ESM::Attribute::Endurance).getModified();
|
||||||
const MWWorld::Store<ESM::GameSetting>& settings = MWBase::Environment::get().getWorld()->getStore().get<ESM::GameSetting>();
|
const MWWorld::Store<ESM::GameSetting>& settings = MWBase::Environment::get().getWorld()->getStore().get<ESM::GameSetting>();
|
||||||
static const float fFatigueReturnBase = settings.find("fFatigueReturnBase")->mValue.getFloat ();
|
static const float fFatigueReturnBase = settings.find("fFatigueReturnBase")->mValue.getFloat ();
|
||||||
static const float fFatigueReturnMult = settings.find("fFatigueReturnMult")->mValue.getFloat ();
|
static const float fFatigueReturnMult = settings.find("fFatigueReturnMult")->mValue.getFloat ();
|
||||||
|
@ -987,20 +1030,74 @@ namespace MWMechanics
|
||||||
if (creatureStats.needToRecalcDynamicStats())
|
if (creatureStats.needToRecalcDynamicStats())
|
||||||
calculateDynamicStats(ptr);
|
calculateDynamicStats(ptr);
|
||||||
|
|
||||||
{
|
|
||||||
Spells & spells = creatureStats.getSpells();
|
|
||||||
for (Spells::TIterator it = spells.begin(); it != spells.end(); ++it)
|
|
||||||
{
|
|
||||||
if (spells.getCorprusSpells().find(it->first) != spells.getCorprusSpells().end())
|
|
||||||
{
|
|
||||||
if (MWBase::Environment::get().getWorld()->getTimeStamp() >= spells.getCorprusSpells().at(it->first).mNextWorsening)
|
|
||||||
{
|
|
||||||
spells.worsenCorprus(it->first);
|
|
||||||
|
|
||||||
if (ptr == getPlayer())
|
if (ptr == getPlayer())
|
||||||
|
{
|
||||||
|
GetCorprusSpells getCorprusSpellsVisitor;
|
||||||
|
creatureStats.getSpells().visitEffectSources(getCorprusSpellsVisitor);
|
||||||
|
creatureStats.getActiveSpells().visitEffectSources(getCorprusSpellsVisitor);
|
||||||
|
ptr.getClass().getInventoryStore(ptr).visitEffectSources(getCorprusSpellsVisitor);
|
||||||
|
std::vector<std::string> corprusSpells = getCorprusSpellsVisitor.mSpells;
|
||||||
|
std::vector<std::string> corprusSpellsToRemove;
|
||||||
|
|
||||||
|
for (auto it = creatureStats.getCorprusSpells().begin(); it != creatureStats.getCorprusSpells().end(); ++it)
|
||||||
|
{
|
||||||
|
if(std::find(corprusSpells.begin(), corprusSpells.end(), it->first) == corprusSpells.end())
|
||||||
|
{
|
||||||
|
// Corprus effect expired, remove entry and restore stats.
|
||||||
|
MWBase::Environment::get().getMechanicsManager()->restoreStatsAfterCorprus(ptr, it->first);
|
||||||
|
corprusSpellsToRemove.push_back(it->first);
|
||||||
|
corprusSpells.erase(std::remove(corprusSpells.begin(), corprusSpells.end(), it->first), corprusSpells.end());
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
corprusSpells.erase(std::remove(corprusSpells.begin(), corprusSpells.end(), it->first), corprusSpells.end());
|
||||||
|
|
||||||
|
if (MWBase::Environment::get().getWorld()->getTimeStamp() >= it->second.mNextWorsening)
|
||||||
|
{
|
||||||
|
it->second.mNextWorsening += CorprusStats::sWorseningPeriod;
|
||||||
|
GetCurrentMagnitudes getMagnitudesVisitor (it->first);
|
||||||
|
creatureStats.getSpells().visitEffectSources(getMagnitudesVisitor);
|
||||||
|
creatureStats.getActiveSpells().visitEffectSources(getMagnitudesVisitor);
|
||||||
|
ptr.getClass().getInventoryStore(ptr).visitEffectSources(getMagnitudesVisitor);
|
||||||
|
for (auto& effectMagnitude : getMagnitudesVisitor.mMagnitudes)
|
||||||
|
{
|
||||||
|
if (effectMagnitude.first.mId == ESM::MagicEffect::FortifyAttribute)
|
||||||
|
{
|
||||||
|
AttributeValue attr = creatureStats.getAttribute(effectMagnitude.first.mArg);
|
||||||
|
attr.damage(-effectMagnitude.second);
|
||||||
|
creatureStats.setAttribute(effectMagnitude.first.mArg, attr);
|
||||||
|
it->second.mWorsenings[effectMagnitude.first.mArg] = 0;
|
||||||
|
}
|
||||||
|
else if (effectMagnitude.first.mId == ESM::MagicEffect::DrainAttribute)
|
||||||
|
{
|
||||||
|
AttributeValue attr = creatureStats.getAttribute(effectMagnitude.first.mArg);
|
||||||
|
int currentDamage = attr.getDamage();
|
||||||
|
if (currentDamage >= 0)
|
||||||
|
it->second.mWorsenings[effectMagnitude.first.mArg] = std::min(it->second.mWorsenings[effectMagnitude.first.mArg], currentDamage);
|
||||||
|
|
||||||
|
it->second.mWorsenings[effectMagnitude.first.mArg] += effectMagnitude.second;
|
||||||
|
attr.damage(effectMagnitude.second);
|
||||||
|
creatureStats.setAttribute(effectMagnitude.first.mArg, attr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
MWBase::Environment::get().getWindowManager()->messageBox("#{sMagicCorprusWorsens}");
|
MWBase::Environment::get().getWindowManager()->messageBox("#{sMagicCorprusWorsens}");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
for (std::string& oldCorprusSpell : corprusSpellsToRemove)
|
||||||
|
{
|
||||||
|
creatureStats.removeCorprusSpell(oldCorprusSpell);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (std::string& newCorprusSpell : corprusSpells)
|
||||||
|
{
|
||||||
|
CorprusStats corprus;
|
||||||
|
for (int i=0; i<ESM::Attribute::Length; ++i)
|
||||||
|
corprus.mWorsenings[i] = 0;
|
||||||
|
corprus.mNextWorsening = MWBase::Environment::get().getWorld()->getTimeStamp() + CorprusStats::sWorseningPeriod;
|
||||||
|
|
||||||
|
creatureStats.addCorprusSpell(newCorprusSpell, corprus);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1786,9 +1883,14 @@ namespace MWMechanics
|
||||||
|
|
||||||
iter->first.getClass().getCreatureStats(iter->first).getActiveSpells().update(duration);
|
iter->first.getClass().getCreatureStats(iter->first).getActiveSpells().update(duration);
|
||||||
|
|
||||||
// For dead actors we need to remove looping spell particles
|
// For dead actors we need to update looping spell particles
|
||||||
if (iter->first.getClass().getCreatureStats(iter->first).isDead())
|
if (iter->first.getClass().getCreatureStats(iter->first).isDead())
|
||||||
|
{
|
||||||
|
// They can be added during the death animation
|
||||||
|
if (!iter->first.getClass().getCreatureStats(iter->first).isDeathAnimationFinished())
|
||||||
|
adjustMagicEffects(iter->first);
|
||||||
ctrl->updateContinuousVfx();
|
ctrl->updateContinuousVfx();
|
||||||
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
bool cellChanged = world->hasCellChanged();
|
bool cellChanged = world->hasCellChanged();
|
||||||
|
@ -1913,7 +2015,7 @@ namespace MWMechanics
|
||||||
if (!isPlayer && isConscious(iter->first) && !stats.isParalyzed())
|
if (!isPlayer && isConscious(iter->first) && !stats.isParalyzed())
|
||||||
{
|
{
|
||||||
MWMechanics::AiSequence& seq = stats.getAiSequence();
|
MWMechanics::AiSequence& seq = stats.getAiSequence();
|
||||||
alwaysActive = !seq.isEmpty() && seq.getActivePackage()->alwaysActive();
|
alwaysActive = !seq.isEmpty() && seq.getActivePackage().alwaysActive();
|
||||||
}
|
}
|
||||||
bool inRange = isPlayer || dist <= mActorsProcessingRange || alwaysActive;
|
bool inRange = isPlayer || dist <= mActorsProcessingRange || alwaysActive;
|
||||||
int activeFlag = 1; // Can be changed back to '2' to keep updating bounding boxes off screen (more accurate, but slower)
|
int activeFlag = 1; // Can be changed back to '2' to keep updating bounding boxes off screen (more accurate, but slower)
|
||||||
|
@ -2179,6 +2281,8 @@ namespace MWMechanics
|
||||||
|
|
||||||
for(PtrActorMap::iterator iter(mActors.begin()); iter != mActors.end(); ++iter)
|
for(PtrActorMap::iterator iter(mActors.begin()); iter != mActors.end(); ++iter)
|
||||||
{
|
{
|
||||||
|
iter->first.getClass().getCreatureStats(iter->first).getActiveSpells().update(duration);
|
||||||
|
|
||||||
if (iter->first.getClass().getCreatureStats(iter->first).isDead())
|
if (iter->first.getClass().getCreatureStats(iter->first).isDead())
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
|
@ -2434,7 +2538,7 @@ namespace MWMechanics
|
||||||
|
|
||||||
// An actor counts as siding with this actor if Follow or Escort is the current AI package, or there are only Combat and Wander packages before the Follow/Escort package
|
// An actor counts as siding with this actor if Follow or Escort is the current AI package, or there are only Combat and Wander packages before the Follow/Escort package
|
||||||
// Actors that are targeted by this actor's Follow or Escort packages also side with them
|
// Actors that are targeted by this actor's Follow or Escort packages also side with them
|
||||||
for (const AiPackage* package : stats.getAiSequence())
|
for (const auto& package : stats.getAiSequence())
|
||||||
{
|
{
|
||||||
if (package->sideWithTarget() && !package->getTarget().isEmpty())
|
if (package->sideWithTarget() && !package->getTarget().isEmpty())
|
||||||
{
|
{
|
||||||
|
@ -2470,7 +2574,7 @@ namespace MWMechanics
|
||||||
|
|
||||||
// An actor counts as following if AiFollow is the current AiPackage,
|
// An actor counts as following if AiFollow is the current AiPackage,
|
||||||
// or there are only Combat and Wander packages before the AiFollow package
|
// or there are only Combat and Wander packages before the AiFollow package
|
||||||
for (const AiPackage* package : stats.getAiSequence())
|
for (const auto& package : stats.getAiSequence())
|
||||||
{
|
{
|
||||||
if (package->followTargetThroughDoors() && package->getTarget() == actor)
|
if (package->followTargetThroughDoors() && package->getTarget() == actor)
|
||||||
list.push_back(iteratedActor);
|
list.push_back(iteratedActor);
|
||||||
|
@ -2533,11 +2637,11 @@ namespace MWMechanics
|
||||||
|
|
||||||
// An actor counts as following if AiFollow is the current AiPackage,
|
// An actor counts as following if AiFollow is the current AiPackage,
|
||||||
// or there are only Combat and Wander packages before the AiFollow package
|
// or there are only Combat and Wander packages before the AiFollow package
|
||||||
for (AiPackage* package : stats.getAiSequence())
|
for (const auto& package : stats.getAiSequence())
|
||||||
{
|
{
|
||||||
if (package->followTargetThroughDoors() && package->getTarget() == actor)
|
if (package->followTargetThroughDoors() && package->getTarget() == actor)
|
||||||
{
|
{
|
||||||
list.push_back(static_cast<AiFollow*>(package)->getFollowIndex());
|
list.push_back(static_cast<const AiFollow*>(package.get())->getFollowIndex());
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
else if (package->getTypeId() != AiPackage::TypeIdCombat && package->getTypeId() != AiPackage::TypeIdWander)
|
else if (package->getTypeId() != AiPackage::TypeIdCombat && package->getTypeId() != AiPackage::TypeIdWander)
|
||||||
|
|
|
@ -1,6 +1,16 @@
|
||||||
#ifndef OPENMW_MWMECHANICS_ACTORUTIL_H
|
#ifndef OPENMW_MWMECHANICS_ACTORUTIL_H
|
||||||
#define OPENMW_MWMECHANICS_ACTORUTIL_H
|
#define OPENMW_MWMECHANICS_ACTORUTIL_H
|
||||||
|
|
||||||
|
#include <components/esm/loadcrea.hpp>
|
||||||
|
#include <components/esm/loadnpc.hpp>
|
||||||
|
|
||||||
|
#include "../mwbase/environment.hpp"
|
||||||
|
#include "../mwbase/world.hpp"
|
||||||
|
|
||||||
|
#include "../mwworld/esmstore.hpp"
|
||||||
|
|
||||||
|
#include "./creaturestats.hpp"
|
||||||
|
|
||||||
namespace MWWorld
|
namespace MWWorld
|
||||||
{
|
{
|
||||||
class Ptr;
|
class Ptr;
|
||||||
|
@ -18,6 +28,33 @@ namespace MWMechanics
|
||||||
MWWorld::Ptr getPlayer();
|
MWWorld::Ptr getPlayer();
|
||||||
bool isPlayerInCombat();
|
bool isPlayerInCombat();
|
||||||
bool canActorMoveByZAxis(const MWWorld::Ptr& actor);
|
bool canActorMoveByZAxis(const MWWorld::Ptr& actor);
|
||||||
|
|
||||||
|
template<class T>
|
||||||
|
void setBaseAISetting(const std::string& id, MWMechanics::CreatureStats::AiSetting setting, int value)
|
||||||
|
{
|
||||||
|
T copy = *MWBase::Environment::get().getWorld()->getStore().get<T>().find(id);
|
||||||
|
switch(setting)
|
||||||
|
{
|
||||||
|
case MWMechanics::CreatureStats::AiSetting::AI_Hello:
|
||||||
|
copy.mAiData.mHello = value;
|
||||||
|
break;
|
||||||
|
case MWMechanics::CreatureStats::AiSetting::AI_Fight:
|
||||||
|
copy.mAiData.mFight = value;
|
||||||
|
break;
|
||||||
|
case MWMechanics::CreatureStats::AiSetting::AI_Flee:
|
||||||
|
copy.mAiData.mFlee = value;
|
||||||
|
break;
|
||||||
|
case MWMechanics::CreatureStats::AiSetting::AI_Alarm:
|
||||||
|
copy.mAiData.mAlarm = value;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
assert(0);
|
||||||
|
}
|
||||||
|
MWBase::Environment::get().getWorld()->createOverrideRecord(copy);
|
||||||
|
}
|
||||||
|
|
||||||
|
template void setBaseAISetting<ESM::Creature>(const std::string& id, MWMechanics::CreatureStats::AiSetting setting, int value);
|
||||||
|
template void setBaseAISetting<ESM::NPC>(const std::string& id, MWMechanics::CreatureStats::AiSetting setting, int value);
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -44,11 +44,6 @@ namespace MWMechanics
|
||||||
End of tes3mp addition
|
End of tes3mp addition
|
||||||
*/
|
*/
|
||||||
|
|
||||||
AiActivate *MWMechanics::AiActivate::clone() const
|
|
||||||
{
|
|
||||||
return new AiActivate(*this);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool AiActivate::execute(const MWWorld::Ptr& actor, CharacterController& characterController, AiState& state, float duration)
|
bool AiActivate::execute(const MWWorld::Ptr& actor, CharacterController& characterController, AiState& state, float duration)
|
||||||
{
|
{
|
||||||
/*
|
/*
|
||||||
|
@ -109,11 +104,6 @@ namespace MWMechanics
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
int AiActivate::getTypeId() const
|
|
||||||
{
|
|
||||||
return TypeIdActivate;
|
|
||||||
}
|
|
||||||
|
|
||||||
void AiActivate::writeState(ESM::AiSequence::AiSequence &sequence) const
|
void AiActivate::writeState(ESM::AiSequence::AiSequence &sequence) const
|
||||||
{
|
{
|
||||||
std::unique_ptr<ESM::AiSequence::AiActivate> activate(new ESM::AiSequence::AiActivate());
|
std::unique_ptr<ESM::AiSequence::AiActivate> activate(new ESM::AiSequence::AiActivate());
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
#ifndef GAME_MWMECHANICS_AIACTIVATE_H
|
#ifndef GAME_MWMECHANICS_AIACTIVATE_H
|
||||||
#define GAME_MWMECHANICS_AIACTIVATE_H
|
#define GAME_MWMECHANICS_AIACTIVATE_H
|
||||||
|
|
||||||
#include "aipackage.hpp"
|
#include "typedaipackage.hpp"
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Start of tes3mp addition
|
Start of tes3mp addition
|
||||||
|
@ -29,7 +29,7 @@ namespace MWMechanics
|
||||||
{
|
{
|
||||||
/// \brief Causes actor to walk to activatable object and activate it
|
/// \brief Causes actor to walk to activatable object and activate it
|
||||||
/** Will activate when close to object **/
|
/** Will activate when close to object **/
|
||||||
class AiActivate final : public AiPackage
|
class AiActivate final : public TypedAiPackage<AiActivate>
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
/// Constructor
|
/// Constructor
|
||||||
|
@ -49,14 +49,14 @@ namespace MWMechanics
|
||||||
|
|
||||||
AiActivate(const ESM::AiSequence::AiActivate* activate);
|
AiActivate(const ESM::AiSequence::AiActivate* activate);
|
||||||
|
|
||||||
AiActivate *clone() const final;
|
|
||||||
bool execute (const MWWorld::Ptr& actor, CharacterController& characterController, AiState& state, float duration) final;
|
bool execute (const MWWorld::Ptr& actor, CharacterController& characterController, AiState& state, float duration) final;
|
||||||
int getTypeId() const final;
|
|
||||||
|
static constexpr TypeId getTypeId() { return TypeIdActivate; }
|
||||||
|
|
||||||
void writeState(ESM::AiSequence::AiSequence& sequence) const final;
|
void writeState(ESM::AiSequence::AiSequence& sequence) const final;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
std::string mObjectId;
|
const std::string mObjectId;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Start of tes3mp addition
|
Start of tes3mp addition
|
||||||
|
|
|
@ -16,7 +16,7 @@
|
||||||
static const int MAX_DIRECTIONS = 4;
|
static const int MAX_DIRECTIONS = 4;
|
||||||
|
|
||||||
MWMechanics::AiAvoidDoor::AiAvoidDoor(const MWWorld::ConstPtr& doorPtr)
|
MWMechanics::AiAvoidDoor::AiAvoidDoor(const MWWorld::ConstPtr& doorPtr)
|
||||||
: AiPackage(), mDuration(1), mDoorPtr(doorPtr), mDirection(0)
|
: mDuration(1), mDoorPtr(doorPtr), mDirection(0)
|
||||||
{
|
{
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -72,21 +72,6 @@ bool MWMechanics::AiAvoidDoor::execute (const MWWorld::Ptr& actor, CharacterCont
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
MWMechanics::AiAvoidDoor *MWMechanics::AiAvoidDoor::clone() const
|
|
||||||
{
|
|
||||||
return new AiAvoidDoor(*this);
|
|
||||||
}
|
|
||||||
|
|
||||||
int MWMechanics::AiAvoidDoor::getTypeId() const
|
|
||||||
{
|
|
||||||
return TypeIdAvoidDoor;
|
|
||||||
}
|
|
||||||
|
|
||||||
unsigned int MWMechanics::AiAvoidDoor::getPriority() const
|
|
||||||
{
|
|
||||||
return 2;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool MWMechanics::AiAvoidDoor::isStuck(const osg::Vec3f& actorPos) const
|
bool MWMechanics::AiAvoidDoor::isStuck(const osg::Vec3f& actorPos) const
|
||||||
{
|
{
|
||||||
return (actorPos - mLastPos).length2() < 10 * 10;
|
return (actorPos - mLastPos).length2() < 10 * 10;
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
#ifndef GAME_MWMECHANICS_AIAVOIDDOOR_H
|
#ifndef GAME_MWMECHANICS_AIAVOIDDOOR_H
|
||||||
#define GAME_MWMECHANICS_AIAVOIDDOOR_H
|
#define GAME_MWMECHANICS_AIAVOIDDOOR_H
|
||||||
|
|
||||||
#include "aipackage.hpp"
|
#include "typedaipackage.hpp"
|
||||||
|
|
||||||
#include <string>
|
#include <string>
|
||||||
|
|
||||||
|
@ -16,26 +16,28 @@ namespace MWMechanics
|
||||||
/// \brief AiPackage to have an actor avoid an opening door
|
/// \brief AiPackage to have an actor avoid an opening door
|
||||||
/** The AI will retreat from the door until it has finished opening, walked far away from it, or one second has passed, in an attempt to avoid it
|
/** The AI will retreat from the door until it has finished opening, walked far away from it, or one second has passed, in an attempt to avoid it
|
||||||
**/
|
**/
|
||||||
class AiAvoidDoor final : public AiPackage
|
class AiAvoidDoor final : public TypedAiPackage<AiAvoidDoor>
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
/// Avoid door until the door is fully open
|
/// Avoid door until the door is fully open
|
||||||
AiAvoidDoor(const MWWorld::ConstPtr& doorPtr);
|
AiAvoidDoor(const MWWorld::ConstPtr& doorPtr);
|
||||||
|
|
||||||
AiAvoidDoor *clone() const final;
|
|
||||||
|
|
||||||
bool execute (const MWWorld::Ptr& actor, CharacterController& characterController, AiState& state, float duration) final;
|
bool execute (const MWWorld::Ptr& actor, CharacterController& characterController, AiState& state, float duration) final;
|
||||||
|
|
||||||
int getTypeId() const final;
|
static constexpr TypeId getTypeId() { return TypeIdAvoidDoor; }
|
||||||
|
|
||||||
unsigned int getPriority() const final;
|
static constexpr Options makeDefaultOptions()
|
||||||
|
{
|
||||||
bool canCancel() const final { return false; }
|
AiPackage::Options options;
|
||||||
bool shouldCancelPreviousAi() const final { return false; }
|
options.mPriority = 2;
|
||||||
|
options.mCanCancel = false;
|
||||||
|
options.mShouldCancelPreviousAi = false;
|
||||||
|
return options;
|
||||||
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
float mDuration;
|
float mDuration;
|
||||||
MWWorld::ConstPtr mDoorPtr;
|
const MWWorld::ConstPtr mDoorPtr;
|
||||||
osg::Vec3f mLastPos;
|
osg::Vec3f mLastPos;
|
||||||
int mDirection;
|
int mDirection;
|
||||||
|
|
||||||
|
|
|
@ -11,12 +11,6 @@
|
||||||
#include "movement.hpp"
|
#include "movement.hpp"
|
||||||
#include "steering.hpp"
|
#include "steering.hpp"
|
||||||
|
|
||||||
MWMechanics::AiBreathe::AiBreathe()
|
|
||||||
: AiPackage()
|
|
||||||
{
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
bool MWMechanics::AiBreathe::execute (const MWWorld::Ptr& actor, CharacterController& characterController, AiState& state, float duration)
|
bool MWMechanics::AiBreathe::execute (const MWWorld::Ptr& actor, CharacterController& characterController, AiState& state, float duration)
|
||||||
{
|
{
|
||||||
static const float fHoldBreathTime = MWBase::Environment::get().getWorld()->getStore().get<ESM::GameSetting>().find("fHoldBreathTime")->mValue.getFloat();
|
static const float fHoldBreathTime = MWBase::Environment::get().getWorld()->getStore().get<ESM::GameSetting>().find("fHoldBreathTime")->mValue.getFloat();
|
||||||
|
@ -37,18 +31,3 @@ bool MWMechanics::AiBreathe::execute (const MWWorld::Ptr& actor, CharacterContro
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
MWMechanics::AiBreathe *MWMechanics::AiBreathe::clone() const
|
|
||||||
{
|
|
||||||
return new AiBreathe(*this);
|
|
||||||
}
|
|
||||||
|
|
||||||
int MWMechanics::AiBreathe::getTypeId() const
|
|
||||||
{
|
|
||||||
return TypeIdBreathe;
|
|
||||||
}
|
|
||||||
|
|
||||||
unsigned int MWMechanics::AiBreathe::getPriority() const
|
|
||||||
{
|
|
||||||
return 2;
|
|
||||||
}
|
|
||||||
|
|
|
@ -1,28 +1,27 @@
|
||||||
#ifndef GAME_MWMECHANICS_AIBREATHE_H
|
#ifndef GAME_MWMECHANICS_AIBREATHE_H
|
||||||
#define GAME_MWMECHANICS_AIBREATHE_H
|
#define GAME_MWMECHANICS_AIBREATHE_H
|
||||||
|
|
||||||
#include "aipackage.hpp"
|
#include "typedaipackage.hpp"
|
||||||
|
|
||||||
namespace MWMechanics
|
namespace MWMechanics
|
||||||
{
|
{
|
||||||
/// \brief AiPackage to have an actor resurface to breathe
|
/// \brief AiPackage to have an actor resurface to breathe
|
||||||
// The AI will go up if lesser than half breath left
|
// The AI will go up if lesser than half breath left
|
||||||
class AiBreathe final : public AiPackage
|
class AiBreathe final : public TypedAiPackage<AiBreathe>
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
AiBreathe();
|
|
||||||
|
|
||||||
AiBreathe *clone() const final;
|
|
||||||
|
|
||||||
bool execute (const MWWorld::Ptr& actor, CharacterController& characterController, AiState& state, float duration) final;
|
bool execute (const MWWorld::Ptr& actor, CharacterController& characterController, AiState& state, float duration) final;
|
||||||
|
|
||||||
int getTypeId() const final;
|
static constexpr TypeId getTypeId() { return TypeIdBreathe; }
|
||||||
|
|
||||||
unsigned int getPriority() const final;
|
static constexpr Options makeDefaultOptions()
|
||||||
|
{
|
||||||
bool canCancel() const final { return false; }
|
AiPackage::Options options;
|
||||||
bool shouldCancelPreviousAi() const final { return false; }
|
options.mPriority = 2;
|
||||||
|
options.mCanCancel = false;
|
||||||
|
options.mShouldCancelPreviousAi = false;
|
||||||
|
return options;
|
||||||
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
|
@ -10,17 +10,22 @@
|
||||||
#include "creaturestats.hpp"
|
#include "creaturestats.hpp"
|
||||||
#include "steering.hpp"
|
#include "steering.hpp"
|
||||||
|
|
||||||
MWMechanics::AiCast::AiCast(const std::string& targetId, const std::string& spellId, bool manualSpell)
|
namespace MWMechanics
|
||||||
: mTargetId(targetId), mSpellId(spellId), mCasting(false), mManual(manualSpell), mDistance(0)
|
{
|
||||||
|
namespace
|
||||||
|
{
|
||||||
|
float getInitialDistance(const std::string& spellId)
|
||||||
{
|
{
|
||||||
ActionSpell action = ActionSpell(spellId);
|
ActionSpell action = ActionSpell(spellId);
|
||||||
bool isRanged;
|
bool isRanged;
|
||||||
mDistance = action.getCombatRange(isRanged);
|
return action.getCombatRange(isRanged);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
MWMechanics::AiPackage *MWMechanics::AiCast::clone() const
|
MWMechanics::AiCast::AiCast(const std::string& targetId, const std::string& spellId, bool manualSpell)
|
||||||
|
: mTargetId(targetId), mSpellId(spellId), mCasting(false), mManual(manualSpell), mDistance(getInitialDistance(spellId))
|
||||||
{
|
{
|
||||||
return new AiCast(*this);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool MWMechanics::AiCast::execute(const MWWorld::Ptr& actor, MWMechanics::CharacterController& characterController, MWMechanics::AiState& state, float duration)
|
bool MWMechanics::AiCast::execute(const MWWorld::Ptr& actor, MWMechanics::CharacterController& characterController, MWMechanics::AiState& state, float duration)
|
||||||
|
@ -84,13 +89,3 @@ MWWorld::Ptr MWMechanics::AiCast::getTarget() const
|
||||||
|
|
||||||
return target;
|
return target;
|
||||||
}
|
}
|
||||||
|
|
||||||
int MWMechanics::AiCast::getTypeId() const
|
|
||||||
{
|
|
||||||
return AiPackage::TypeIdCast;
|
|
||||||
}
|
|
||||||
|
|
||||||
unsigned int MWMechanics::AiCast::getPriority() const
|
|
||||||
{
|
|
||||||
return 3;
|
|
||||||
}
|
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
#ifndef GAME_MWMECHANICS_AICAST_H
|
#ifndef GAME_MWMECHANICS_AICAST_H
|
||||||
#define GAME_MWMECHANICS_AICAST_H
|
#define GAME_MWMECHANICS_AICAST_H
|
||||||
|
|
||||||
#include "aipackage.hpp"
|
#include "typedaipackage.hpp"
|
||||||
|
|
||||||
namespace MWWorld
|
namespace MWWorld
|
||||||
{
|
{
|
||||||
|
@ -11,29 +11,31 @@ namespace MWWorld
|
||||||
namespace MWMechanics
|
namespace MWMechanics
|
||||||
{
|
{
|
||||||
/// AiPackage which makes an actor to cast given spell.
|
/// AiPackage which makes an actor to cast given spell.
|
||||||
class AiCast final : public AiPackage {
|
class AiCast final : public TypedAiPackage<AiCast> {
|
||||||
public:
|
public:
|
||||||
AiCast(const std::string& targetId, const std::string& spellId, bool manualSpell=false);
|
AiCast(const std::string& targetId, const std::string& spellId, bool manualSpell=false);
|
||||||
|
|
||||||
AiPackage *clone() const final;
|
|
||||||
|
|
||||||
bool execute (const MWWorld::Ptr& actor, CharacterController& characterController, AiState& state, float duration) final;
|
bool execute (const MWWorld::Ptr& actor, CharacterController& characterController, AiState& state, float duration) final;
|
||||||
|
|
||||||
int getTypeId() const final;
|
static constexpr TypeId getTypeId() { return TypeIdCast; }
|
||||||
|
|
||||||
MWWorld::Ptr getTarget() const final;
|
MWWorld::Ptr getTarget() const final;
|
||||||
|
|
||||||
unsigned int getPriority() const final;
|
static constexpr Options makeDefaultOptions()
|
||||||
|
{
|
||||||
bool canCancel() const final { return false; }
|
AiPackage::Options options;
|
||||||
bool shouldCancelPreviousAi() const final { return false; }
|
options.mPriority = 3;
|
||||||
|
options.mCanCancel = false;
|
||||||
|
options.mShouldCancelPreviousAi = false;
|
||||||
|
return options;
|
||||||
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
std::string mTargetId;
|
const std::string mTargetId;
|
||||||
std::string mSpellId;
|
const std::string mSpellId;
|
||||||
bool mCasting;
|
bool mCasting;
|
||||||
bool mManual;
|
const bool mManual;
|
||||||
float mDistance;
|
const float mDistance;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -474,26 +474,11 @@ namespace MWMechanics
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
int AiCombat::getTypeId() const
|
|
||||||
{
|
|
||||||
return TypeIdCombat;
|
|
||||||
}
|
|
||||||
|
|
||||||
unsigned int AiCombat::getPriority() const
|
|
||||||
{
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
MWWorld::Ptr AiCombat::getTarget() const
|
MWWorld::Ptr AiCombat::getTarget() const
|
||||||
{
|
{
|
||||||
return MWBase::Environment::get().getWorld()->searchPtrViaActorId(mTargetActorId);
|
return MWBase::Environment::get().getWorld()->searchPtrViaActorId(mTargetActorId);
|
||||||
}
|
}
|
||||||
|
|
||||||
AiCombat *MWMechanics::AiCombat::clone() const
|
|
||||||
{
|
|
||||||
return new AiCombat(*this);
|
|
||||||
}
|
|
||||||
|
|
||||||
void AiCombat::writeState(ESM::AiSequence::AiSequence &sequence) const
|
void AiCombat::writeState(ESM::AiSequence::AiSequence &sequence) const
|
||||||
{
|
{
|
||||||
std::unique_ptr<ESM::AiSequence::AiCombat> combat(new ESM::AiSequence::AiCombat());
|
std::unique_ptr<ESM::AiSequence::AiCombat> combat(new ESM::AiSequence::AiCombat());
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
#ifndef GAME_MWMECHANICS_AICOMBAT_H
|
#ifndef GAME_MWMECHANICS_AICOMBAT_H
|
||||||
#define GAME_MWMECHANICS_AICOMBAT_H
|
#define GAME_MWMECHANICS_AICOMBAT_H
|
||||||
|
|
||||||
#include "aipackage.hpp"
|
#include "typedaipackage.hpp"
|
||||||
|
|
||||||
#include "../mwworld/cellstore.hpp" // for Doors
|
#include "../mwworld/cellstore.hpp" // for Doors
|
||||||
|
|
||||||
|
@ -91,7 +91,7 @@ namespace MWMechanics
|
||||||
};
|
};
|
||||||
|
|
||||||
/// \brief Causes the actor to fight another actor
|
/// \brief Causes the actor to fight another actor
|
||||||
class AiCombat final : public AiPackage
|
class AiCombat final : public TypedAiPackage<AiCombat>
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
///Constructor
|
///Constructor
|
||||||
|
@ -102,22 +102,24 @@ namespace MWMechanics
|
||||||
|
|
||||||
void init();
|
void init();
|
||||||
|
|
||||||
AiCombat *clone() const final;
|
|
||||||
|
|
||||||
bool execute (const MWWorld::Ptr& actor, CharacterController& characterController, AiState& state, float duration) final;
|
bool execute (const MWWorld::Ptr& actor, CharacterController& characterController, AiState& state, float duration) final;
|
||||||
|
|
||||||
int getTypeId() const final;
|
static constexpr TypeId getTypeId() { return TypeIdCombat; }
|
||||||
|
|
||||||
unsigned int getPriority() const final;
|
static constexpr Options makeDefaultOptions()
|
||||||
|
{
|
||||||
|
AiPackage::Options options;
|
||||||
|
options.mPriority = 1;
|
||||||
|
options.mCanCancel = false;
|
||||||
|
options.mShouldCancelPreviousAi = false;
|
||||||
|
return options;
|
||||||
|
}
|
||||||
|
|
||||||
///Returns target ID
|
///Returns target ID
|
||||||
MWWorld::Ptr getTarget() const final;
|
MWWorld::Ptr getTarget() const final;
|
||||||
|
|
||||||
void writeState(ESM::AiSequence::AiSequence &sequence) const final;
|
void writeState(ESM::AiSequence::AiSequence &sequence) const final;
|
||||||
|
|
||||||
bool canCancel() const final { return false; }
|
|
||||||
bool shouldCancelPreviousAi() const final { return false; }
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
/// Returns true if combat should end
|
/// Returns true if combat should end
|
||||||
bool attack(const MWWorld::Ptr& actor, const MWWorld::Ptr& target, AiCombatStorage& storage, CharacterController& characterController);
|
bool attack(const MWWorld::Ptr& actor, const MWWorld::Ptr& target, AiCombatStorage& storage, CharacterController& characterController);
|
||||||
|
|
|
@ -26,7 +26,6 @@ namespace MWMechanics
|
||||||
, mCellY(std::numeric_limits<int>::max())
|
, mCellY(std::numeric_limits<int>::max())
|
||||||
{
|
{
|
||||||
mTargetActorRefId = actorId;
|
mTargetActorRefId = actorId;
|
||||||
mMaxDist = 450;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
AiEscort::AiEscort(const std::string &actorId, const std::string &cellId, int duration, float x, float y, float z)
|
AiEscort::AiEscort(const std::string &actorId, const std::string &cellId, int duration, float x, float y, float z)
|
||||||
|
@ -35,30 +34,20 @@ namespace MWMechanics
|
||||||
, mCellY(std::numeric_limits<int>::max())
|
, mCellY(std::numeric_limits<int>::max())
|
||||||
{
|
{
|
||||||
mTargetActorRefId = actorId;
|
mTargetActorRefId = actorId;
|
||||||
mMaxDist = 450;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
AiEscort::AiEscort(const ESM::AiSequence::AiEscort *escort)
|
AiEscort::AiEscort(const ESM::AiSequence::AiEscort *escort)
|
||||||
: mCellId(escort->mCellId), mX(escort->mData.mX), mY(escort->mData.mY), mZ(escort->mData.mZ)
|
: mCellId(escort->mCellId), mX(escort->mData.mX), mY(escort->mData.mY), mZ(escort->mData.mZ)
|
||||||
, mMaxDist(450)
|
// mDuration isn't saved in the save file, so just giving it "1" for now if the package has a duration.
|
||||||
|
// The exact value of mDuration only matters for repeating packages.
|
||||||
|
// Previously mRemainingDuration could be negative even when mDuration was 0. Checking for > 0 should fix old saves.
|
||||||
|
, mDuration(escort->mRemainingDuration > 0)
|
||||||
, mRemainingDuration(escort->mRemainingDuration)
|
, mRemainingDuration(escort->mRemainingDuration)
|
||||||
, mCellX(std::numeric_limits<int>::max())
|
, mCellX(std::numeric_limits<int>::max())
|
||||||
, mCellY(std::numeric_limits<int>::max())
|
, mCellY(std::numeric_limits<int>::max())
|
||||||
{
|
{
|
||||||
mTargetActorRefId = escort->mTargetId;
|
mTargetActorRefId = escort->mTargetId;
|
||||||
mTargetActorId = escort->mTargetActorId;
|
mTargetActorId = escort->mTargetActorId;
|
||||||
// mDuration isn't saved in the save file, so just giving it "1" for now if the package has a duration.
|
|
||||||
// The exact value of mDuration only matters for repeating packages.
|
|
||||||
if (mRemainingDuration > 0) // Previously mRemainingDuration could be negative even when mDuration was 0. Checking for > 0 should fix old saves.
|
|
||||||
mDuration = 1;
|
|
||||||
else
|
|
||||||
mDuration = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
AiEscort *MWMechanics::AiEscort::clone() const
|
|
||||||
{
|
|
||||||
return new AiEscort(*this);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool AiEscort::execute (const MWWorld::Ptr& actor, CharacterController& characterController, AiState& state, float duration)
|
bool AiEscort::execute (const MWWorld::Ptr& actor, CharacterController& characterController, AiState& state, float duration)
|
||||||
|
@ -106,11 +95,6 @@ namespace MWMechanics
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
int AiEscort::getTypeId() const
|
|
||||||
{
|
|
||||||
return TypeIdEscort;
|
|
||||||
}
|
|
||||||
|
|
||||||
void AiEscort::writeState(ESM::AiSequence::AiSequence &sequence) const
|
void AiEscort::writeState(ESM::AiSequence::AiSequence &sequence) const
|
||||||
{
|
{
|
||||||
std::unique_ptr<ESM::AiSequence::AiEscort> escort(new ESM::AiSequence::AiEscort());
|
std::unique_ptr<ESM::AiSequence::AiEscort> escort(new ESM::AiSequence::AiEscort());
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
#ifndef GAME_MWMECHANICS_AIESCORT_H
|
#ifndef GAME_MWMECHANICS_AIESCORT_H
|
||||||
#define GAME_MWMECHANICS_AIESCORT_H
|
#define GAME_MWMECHANICS_AIESCORT_H
|
||||||
|
|
||||||
#include "aipackage.hpp"
|
#include "typedaipackage.hpp"
|
||||||
|
|
||||||
#include <string>
|
#include <string>
|
||||||
|
|
||||||
|
@ -16,7 +16,7 @@ namespace AiSequence
|
||||||
namespace MWMechanics
|
namespace MWMechanics
|
||||||
{
|
{
|
||||||
/// \brief AI Package to have an NPC lead the player to a specific point
|
/// \brief AI Package to have an NPC lead the player to a specific point
|
||||||
class AiEscort final : public AiPackage
|
class AiEscort final : public TypedAiPackage<AiEscort>
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
/// Implementation of AiEscort
|
/// Implementation of AiEscort
|
||||||
|
@ -30,15 +30,17 @@ namespace MWMechanics
|
||||||
|
|
||||||
AiEscort(const ESM::AiSequence::AiEscort* escort);
|
AiEscort(const ESM::AiSequence::AiEscort* escort);
|
||||||
|
|
||||||
AiEscort *clone() const final;
|
|
||||||
|
|
||||||
bool execute (const MWWorld::Ptr& actor, CharacterController& characterController, AiState& state, float duration) final;
|
bool execute (const MWWorld::Ptr& actor, CharacterController& characterController, AiState& state, float duration) final;
|
||||||
|
|
||||||
int getTypeId() const final;
|
static constexpr TypeId getTypeId() { return TypeIdEscort; }
|
||||||
|
|
||||||
bool useVariableSpeed() const final { return true; }
|
static constexpr Options makeDefaultOptions()
|
||||||
|
{
|
||||||
bool sideWithTarget() const final { return true; }
|
AiPackage::Options options;
|
||||||
|
options.mUseVariableSpeed = true;
|
||||||
|
options.mSideWithTarget = true;
|
||||||
|
return options;
|
||||||
|
}
|
||||||
|
|
||||||
void writeState(ESM::AiSequence::AiSequence &sequence) const final;
|
void writeState(ESM::AiSequence::AiSequence &sequence) const final;
|
||||||
|
|
||||||
|
@ -47,16 +49,16 @@ namespace MWMechanics
|
||||||
osg::Vec3f getDestination() const final { return osg::Vec3f(mX, mY, mZ); }
|
osg::Vec3f getDestination() const final { return osg::Vec3f(mX, mY, mZ); }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
std::string mCellId;
|
const std::string mCellId;
|
||||||
float mX;
|
const float mX;
|
||||||
float mY;
|
const float mY;
|
||||||
float mZ;
|
const float mZ;
|
||||||
float mMaxDist;
|
float mMaxDist = 450;
|
||||||
float mDuration; // In hours
|
const float mDuration; // In hours
|
||||||
float mRemainingDuration; // In hours
|
float mRemainingDuration; // In hours
|
||||||
|
|
||||||
int mCellX;
|
const int mCellX;
|
||||||
int mCellY;
|
const int mCellY;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -9,23 +9,8 @@ MWMechanics::AiFace::AiFace(float targetX, float targetY)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
MWMechanics::AiPackage *MWMechanics::AiFace::clone() const
|
|
||||||
{
|
|
||||||
return new AiFace(*this);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool MWMechanics::AiFace::execute(const MWWorld::Ptr& actor, MWMechanics::CharacterController& /*characterController*/, MWMechanics::AiState& /*state*/, float /*duration*/)
|
bool MWMechanics::AiFace::execute(const MWWorld::Ptr& actor, MWMechanics::CharacterController& /*characterController*/, MWMechanics::AiState& /*state*/, float /*duration*/)
|
||||||
{
|
{
|
||||||
osg::Vec3f dir = osg::Vec3f(mTargetX, mTargetY, 0) - actor.getRefData().getPosition().asVec3();
|
osg::Vec3f dir = osg::Vec3f(mTargetX, mTargetY, 0) - actor.getRefData().getPosition().asVec3();
|
||||||
return zTurn(actor, std::atan2(dir.x(), dir.y()), osg::DegreesToRadians(3.f));
|
return zTurn(actor, std::atan2(dir.x(), dir.y()), osg::DegreesToRadians(3.f));
|
||||||
}
|
}
|
||||||
|
|
||||||
int MWMechanics::AiFace::getTypeId() const
|
|
||||||
{
|
|
||||||
return AiPackage::TypeIdFace;
|
|
||||||
}
|
|
||||||
|
|
||||||
unsigned int MWMechanics::AiFace::getPriority() const
|
|
||||||
{
|
|
||||||
return 2;
|
|
||||||
}
|
|
||||||
|
|
|
@ -1,28 +1,31 @@
|
||||||
#ifndef GAME_MWMECHANICS_AIFACE_H
|
#ifndef GAME_MWMECHANICS_AIFACE_H
|
||||||
#define GAME_MWMECHANICS_AIFACE_H
|
#define GAME_MWMECHANICS_AIFACE_H
|
||||||
|
|
||||||
#include "aipackage.hpp"
|
#include "typedaipackage.hpp"
|
||||||
|
|
||||||
namespace MWMechanics
|
namespace MWMechanics
|
||||||
{
|
{
|
||||||
/// AiPackage which makes an actor face a certain direction.
|
/// AiPackage which makes an actor face a certain direction.
|
||||||
class AiFace final : public AiPackage {
|
class AiFace final : public TypedAiPackage<AiFace> {
|
||||||
public:
|
public:
|
||||||
AiFace(float targetX, float targetY);
|
AiFace(float targetX, float targetY);
|
||||||
|
|
||||||
AiPackage *clone() const final;
|
|
||||||
|
|
||||||
bool execute (const MWWorld::Ptr& actor, CharacterController& characterController, AiState& state, float duration) final;
|
bool execute (const MWWorld::Ptr& actor, CharacterController& characterController, AiState& state, float duration) final;
|
||||||
|
|
||||||
int getTypeId() const final;
|
static constexpr TypeId getTypeId() { return TypeIdFace; }
|
||||||
|
|
||||||
unsigned int getPriority() const final;
|
static constexpr Options makeDefaultOptions()
|
||||||
|
{
|
||||||
bool canCancel() const final { return false; }
|
AiPackage::Options options;
|
||||||
bool shouldCancelPreviousAi() const final { return false; }
|
options.mPriority = 2;
|
||||||
|
options.mCanCancel = false;
|
||||||
|
options.mShouldCancelPreviousAi = false;
|
||||||
|
return options;
|
||||||
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
float mTargetX, mTargetY;
|
const float mTargetX;
|
||||||
|
const float mTargetY;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -16,25 +16,24 @@
|
||||||
|
|
||||||
namespace MWMechanics
|
namespace MWMechanics
|
||||||
{
|
{
|
||||||
|
|
||||||
int AiFollow::mFollowIndexCounter = 0;
|
int AiFollow::mFollowIndexCounter = 0;
|
||||||
|
|
||||||
AiFollow::AiFollow(const std::string &actorId, float duration, float x, float y, float z)
|
AiFollow::AiFollow(const std::string &actorId, float duration, float x, float y, float z)
|
||||||
: mAlwaysFollow(false), mCommanded(false), mDuration(duration), mRemainingDuration(duration), mX(x), mY(y), mZ(z)
|
: mAlwaysFollow(false), mDuration(duration), mRemainingDuration(duration), mX(x), mY(y), mZ(z)
|
||||||
, mCellId(""), mActive(false), mFollowIndex(mFollowIndexCounter++)
|
, mCellId(""), mActive(false), mFollowIndex(mFollowIndexCounter++)
|
||||||
{
|
{
|
||||||
mTargetActorRefId = actorId;
|
mTargetActorRefId = actorId;
|
||||||
}
|
}
|
||||||
|
|
||||||
AiFollow::AiFollow(const std::string &actorId, const std::string &cellId, float duration, float x, float y, float z)
|
AiFollow::AiFollow(const std::string &actorId, const std::string &cellId, float duration, float x, float y, float z)
|
||||||
: mAlwaysFollow(false), mCommanded(false), mDuration(duration), mRemainingDuration(duration), mX(x), mY(y), mZ(z)
|
: mAlwaysFollow(false), mDuration(duration), mRemainingDuration(duration), mX(x), mY(y), mZ(z)
|
||||||
, mCellId(cellId), mActive(false), mFollowIndex(mFollowIndexCounter++)
|
, mCellId(cellId), mActive(false), mFollowIndex(mFollowIndexCounter++)
|
||||||
{
|
{
|
||||||
mTargetActorRefId = actorId;
|
mTargetActorRefId = actorId;
|
||||||
}
|
}
|
||||||
|
|
||||||
AiFollow::AiFollow(const MWWorld::Ptr& actor, float duration, float x, float y, float z)
|
AiFollow::AiFollow(const MWWorld::Ptr& actor, float duration, float x, float y, float z)
|
||||||
: mAlwaysFollow(false), mCommanded(false), mDuration(duration), mRemainingDuration(duration), mX(x), mY(y), mZ(z)
|
: mAlwaysFollow(false), mDuration(duration), mRemainingDuration(duration), mX(x), mY(y), mZ(z)
|
||||||
, mCellId(""), mActive(false), mFollowIndex(mFollowIndexCounter++)
|
, mCellId(""), mActive(false), mFollowIndex(mFollowIndexCounter++)
|
||||||
{
|
{
|
||||||
mTargetActorRefId = actor.getCellRef().getRefId();
|
mTargetActorRefId = actor.getCellRef().getRefId();
|
||||||
|
@ -42,7 +41,7 @@ AiFollow::AiFollow(const MWWorld::Ptr& actor, float duration, float x, float y,
|
||||||
}
|
}
|
||||||
|
|
||||||
AiFollow::AiFollow(const MWWorld::Ptr& actor, const std::string &cellId, float duration, float x, float y, float z)
|
AiFollow::AiFollow(const MWWorld::Ptr& actor, const std::string &cellId, float duration, float x, float y, float z)
|
||||||
: mAlwaysFollow(false), mCommanded(false), mDuration(duration), mRemainingDuration(duration), mX(x), mY(y), mZ(z)
|
: mAlwaysFollow(false), mDuration(duration), mRemainingDuration(duration), mX(x), mY(y), mZ(z)
|
||||||
, mCellId(cellId), mActive(false), mFollowIndex(mFollowIndexCounter++)
|
, mCellId(cellId), mActive(false), mFollowIndex(mFollowIndexCounter++)
|
||||||
{
|
{
|
||||||
mTargetActorRefId = actor.getCellRef().getRefId();
|
mTargetActorRefId = actor.getCellRef().getRefId();
|
||||||
|
@ -50,7 +49,8 @@ AiFollow::AiFollow(const MWWorld::Ptr& actor, const std::string &cellId, float d
|
||||||
}
|
}
|
||||||
|
|
||||||
AiFollow::AiFollow(const MWWorld::Ptr& actor, bool commanded)
|
AiFollow::AiFollow(const MWWorld::Ptr& actor, bool commanded)
|
||||||
: mAlwaysFollow(true), mCommanded(commanded), mDuration(0), mRemainingDuration(0), mX(0), mY(0), mZ(0)
|
: TypedAiPackage<AiFollow>(makeDefaultOptions().withShouldCancelPreviousAi(!commanded))
|
||||||
|
, mAlwaysFollow(true), mDuration(0), mRemainingDuration(0), mX(0), mY(0), mZ(0)
|
||||||
, mCellId(""), mActive(false), mFollowIndex(mFollowIndexCounter++)
|
, mCellId(""), mActive(false), mFollowIndex(mFollowIndexCounter++)
|
||||||
{
|
{
|
||||||
mTargetActorRefId = actor.getCellRef().getRefId();
|
mTargetActorRefId = actor.getCellRef().getRefId();
|
||||||
|
@ -58,18 +58,18 @@ AiFollow::AiFollow(const MWWorld::Ptr& actor, bool commanded)
|
||||||
}
|
}
|
||||||
|
|
||||||
AiFollow::AiFollow(const ESM::AiSequence::AiFollow *follow)
|
AiFollow::AiFollow(const ESM::AiSequence::AiFollow *follow)
|
||||||
: mAlwaysFollow(follow->mAlwaysFollow), mCommanded(follow->mCommanded), mRemainingDuration(follow->mRemainingDuration)
|
: TypedAiPackage<AiFollow>(makeDefaultOptions().withShouldCancelPreviousAi(!follow->mCommanded))
|
||||||
|
, mAlwaysFollow(follow->mAlwaysFollow)
|
||||||
|
// mDuration isn't saved in the save file, so just giving it "1" for now if the package had a duration.
|
||||||
|
// The exact value of mDuration only matters for repeating packages.
|
||||||
|
// Previously mRemainingDuration could be negative even when mDuration was 0. Checking for > 0 should fix old saves.
|
||||||
|
, mDuration(follow->mRemainingDuration)
|
||||||
|
, mRemainingDuration(follow->mRemainingDuration)
|
||||||
, mX(follow->mData.mX), mY(follow->mData.mY), mZ(follow->mData.mZ)
|
, mX(follow->mData.mX), mY(follow->mData.mY), mZ(follow->mData.mZ)
|
||||||
, mCellId(follow->mCellId), mActive(follow->mActive), mFollowIndex(mFollowIndexCounter++)
|
, mCellId(follow->mCellId), mActive(follow->mActive), mFollowIndex(mFollowIndexCounter++)
|
||||||
{
|
{
|
||||||
mTargetActorRefId = follow->mTargetId;
|
mTargetActorRefId = follow->mTargetId;
|
||||||
mTargetActorId = follow->mTargetActorId;
|
mTargetActorId = follow->mTargetActorId;
|
||||||
// mDuration isn't saved in the save file, so just giving it "1" for now if the package had a duration.
|
|
||||||
// The exact value of mDuration only matters for repeating packages.
|
|
||||||
if (mRemainingDuration > 0) // Previously mRemainingDuration could be negative even when mDuration was 0. Checking for > 0 should fix old saves.
|
|
||||||
mDuration = 1;
|
|
||||||
else
|
|
||||||
mDuration = 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool AiFollow::execute (const MWWorld::Ptr& actor, CharacterController& characterController, AiState& state, float duration)
|
bool AiFollow::execute (const MWWorld::Ptr& actor, CharacterController& characterController, AiState& state, float duration)
|
||||||
|
@ -212,19 +212,9 @@ std::string AiFollow::getFollowedActor()
|
||||||
return mTargetActorRefId;
|
return mTargetActorRefId;
|
||||||
}
|
}
|
||||||
|
|
||||||
AiFollow *MWMechanics::AiFollow::clone() const
|
|
||||||
{
|
|
||||||
return new AiFollow(*this);
|
|
||||||
}
|
|
||||||
|
|
||||||
int AiFollow::getTypeId() const
|
|
||||||
{
|
|
||||||
return TypeIdFollow;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool AiFollow::isCommanded() const
|
bool AiFollow::isCommanded() const
|
||||||
{
|
{
|
||||||
return mCommanded;
|
return !mOptions.mShouldCancelPreviousAi;
|
||||||
}
|
}
|
||||||
|
|
||||||
void AiFollow::writeState(ESM::AiSequence::AiSequence &sequence) const
|
void AiFollow::writeState(ESM::AiSequence::AiSequence &sequence) const
|
||||||
|
@ -238,7 +228,7 @@ void AiFollow::writeState(ESM::AiSequence::AiSequence &sequence) const
|
||||||
follow->mRemainingDuration = mRemainingDuration;
|
follow->mRemainingDuration = mRemainingDuration;
|
||||||
follow->mCellId = mCellId;
|
follow->mCellId = mCellId;
|
||||||
follow->mAlwaysFollow = mAlwaysFollow;
|
follow->mAlwaysFollow = mAlwaysFollow;
|
||||||
follow->mCommanded = mCommanded;
|
follow->mCommanded = isCommanded();
|
||||||
follow->mActive = mActive;
|
follow->mActive = mActive;
|
||||||
|
|
||||||
ESM::AiSequence::AiPackageContainer package;
|
ESM::AiSequence::AiPackageContainer package;
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
#ifndef GAME_MWMECHANICS_AIFOLLOW_H
|
#ifndef GAME_MWMECHANICS_AIFOLLOW_H
|
||||||
#define GAME_MWMECHANICS_AIFOLLOW_H
|
#define GAME_MWMECHANICS_AIFOLLOW_H
|
||||||
|
|
||||||
#include "aipackage.hpp"
|
#include "typedaipackage.hpp"
|
||||||
|
|
||||||
#include <string>
|
#include <string>
|
||||||
|
|
||||||
|
@ -39,7 +39,7 @@ namespace MWMechanics
|
||||||
/// \brief AiPackage for an actor to follow another actor/the PC
|
/// \brief AiPackage for an actor to follow another actor/the PC
|
||||||
/** The AI will follow the target until a condition (time, or position) are set. Both can be disabled to cause the actor to follow the other indefinitely
|
/** The AI will follow the target until a condition (time, or position) are set. Both can be disabled to cause the actor to follow the other indefinitely
|
||||||
**/
|
**/
|
||||||
class AiFollow final : public AiPackage
|
class AiFollow final : public TypedAiPackage<AiFollow>
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
AiFollow(const std::string &actorId, float duration, float x, float y, float z);
|
AiFollow(const std::string &actorId, float duration, float x, float y, float z);
|
||||||
|
@ -53,17 +53,18 @@ namespace MWMechanics
|
||||||
|
|
||||||
AiFollow(const ESM::AiSequence::AiFollow* follow);
|
AiFollow(const ESM::AiSequence::AiFollow* follow);
|
||||||
|
|
||||||
bool sideWithTarget() const final { return true; }
|
|
||||||
bool followTargetThroughDoors() const final { return true; }
|
|
||||||
bool shouldCancelPreviousAi() const final { return !mCommanded; }
|
|
||||||
|
|
||||||
AiFollow *clone() const final;
|
|
||||||
|
|
||||||
bool execute (const MWWorld::Ptr& actor, CharacterController& characterController, AiState& state, float duration) final;
|
bool execute (const MWWorld::Ptr& actor, CharacterController& characterController, AiState& state, float duration) final;
|
||||||
|
|
||||||
int getTypeId() const final;
|
static constexpr TypeId getTypeId() { return TypeIdFollow; }
|
||||||
|
|
||||||
bool useVariableSpeed() const final { return true; }
|
static constexpr Options makeDefaultOptions()
|
||||||
|
{
|
||||||
|
AiPackage::Options options;
|
||||||
|
options.mUseVariableSpeed = true;
|
||||||
|
options.mSideWithTarget = true;
|
||||||
|
options.mFollowTargetThroughDoors = true;
|
||||||
|
return options;
|
||||||
|
}
|
||||||
|
|
||||||
/// Returns the actor being followed
|
/// Returns the actor being followed
|
||||||
std::string getFollowedActor();
|
std::string getFollowedActor();
|
||||||
|
@ -98,16 +99,15 @@ namespace MWMechanics
|
||||||
private:
|
private:
|
||||||
/// This will make the actor always follow.
|
/// This will make the actor always follow.
|
||||||
/** Thus ignoring mDuration and mX,mY,mZ (used for summoned creatures). **/
|
/** Thus ignoring mDuration and mX,mY,mZ (used for summoned creatures). **/
|
||||||
bool mAlwaysFollow;
|
const bool mAlwaysFollow;
|
||||||
bool mCommanded;
|
const float mDuration; // Hours
|
||||||
float mDuration; // Hours
|
|
||||||
float mRemainingDuration; // Hours
|
float mRemainingDuration; // Hours
|
||||||
float mX;
|
const float mX;
|
||||||
float mY;
|
const float mY;
|
||||||
float mZ;
|
const float mZ;
|
||||||
std::string mCellId;
|
const std::string mCellId;
|
||||||
bool mActive; // have we spotted the target?
|
bool mActive; // have we spotted the target?
|
||||||
int mFollowIndex;
|
const int mFollowIndex;
|
||||||
|
|
||||||
static int mFollowIndexCounter;
|
static int mFollowIndexCounter;
|
||||||
|
|
||||||
|
|
|
@ -24,7 +24,9 @@
|
||||||
|
|
||||||
#include <osg/Quat>
|
#include <osg/Quat>
|
||||||
|
|
||||||
MWMechanics::AiPackage::AiPackage() :
|
MWMechanics::AiPackage::AiPackage(TypeId typeId, const Options& options) :
|
||||||
|
mTypeId(typeId),
|
||||||
|
mOptions(options),
|
||||||
mTimer(AI_REACTION_TIME + 1.0f), // to force initial pathbuild
|
mTimer(AI_REACTION_TIME + 1.0f), // to force initial pathbuild
|
||||||
mTargetActorRefId(""),
|
mTargetActorRefId(""),
|
||||||
mTargetActorId(-1),
|
mTargetActorId(-1),
|
||||||
|
@ -58,31 +60,6 @@ MWWorld::Ptr MWMechanics::AiPackage::getTarget() const
|
||||||
return MWWorld::Ptr();
|
return MWWorld::Ptr();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool MWMechanics::AiPackage::sideWithTarget() const
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool MWMechanics::AiPackage::followTargetThroughDoors() const
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool MWMechanics::AiPackage::canCancel() const
|
|
||||||
{
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool MWMechanics::AiPackage::shouldCancelPreviousAi() const
|
|
||||||
{
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool MWMechanics::AiPackage::getRepeat() const
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
void MWMechanics::AiPackage::reset()
|
void MWMechanics::AiPackage::reset()
|
||||||
{
|
{
|
||||||
// reset all members
|
// reset all members
|
||||||
|
|
|
@ -1,6 +1,8 @@
|
||||||
#ifndef GAME_MWMECHANICS_AIPACKAGE_H
|
#ifndef GAME_MWMECHANICS_AIPACKAGE_H
|
||||||
#define GAME_MWMECHANICS_AIPACKAGE_H
|
#define GAME_MWMECHANICS_AIPACKAGE_H
|
||||||
|
|
||||||
|
#include <memory>
|
||||||
|
|
||||||
#include <components/esm/defs.hpp>
|
#include <components/esm/defs.hpp>
|
||||||
|
|
||||||
#include "pathfinding.hpp"
|
#include "pathfinding.hpp"
|
||||||
|
@ -53,13 +55,41 @@ namespace MWMechanics
|
||||||
TypeIdCast = 11
|
TypeIdCast = 11
|
||||||
};
|
};
|
||||||
|
|
||||||
///Default constructor
|
struct Options
|
||||||
AiPackage();
|
{
|
||||||
|
unsigned int mPriority = 0;
|
||||||
|
bool mUseVariableSpeed = false;
|
||||||
|
bool mSideWithTarget = false;
|
||||||
|
bool mFollowTargetThroughDoors = false;
|
||||||
|
bool mCanCancel = true;
|
||||||
|
bool mShouldCancelPreviousAi = true;
|
||||||
|
bool mRepeat = false;
|
||||||
|
bool mAlwaysActive = false;
|
||||||
|
|
||||||
|
constexpr Options withRepeat(bool value)
|
||||||
|
{
|
||||||
|
mRepeat = value;
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
constexpr Options withShouldCancelPreviousAi(bool value)
|
||||||
|
{
|
||||||
|
mShouldCancelPreviousAi = value;
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
AiPackage(TypeId typeId, const Options& options);
|
||||||
|
|
||||||
virtual ~AiPackage() = default;
|
virtual ~AiPackage() = default;
|
||||||
|
|
||||||
|
static constexpr Options makeDefaultOptions()
|
||||||
|
{
|
||||||
|
return Options{};
|
||||||
|
}
|
||||||
|
|
||||||
///Clones the package
|
///Clones the package
|
||||||
virtual AiPackage *clone() const = 0;
|
virtual std::unique_ptr<AiPackage> clone() const = 0;
|
||||||
|
|
||||||
/// Updates and runs the package (Should run every frame)
|
/// Updates and runs the package (Should run every frame)
|
||||||
/// \return Package completed?
|
/// \return Package completed?
|
||||||
|
@ -67,13 +97,13 @@ namespace MWMechanics
|
||||||
|
|
||||||
/// Returns the TypeID of the AiPackage
|
/// Returns the TypeID of the AiPackage
|
||||||
/// \see enum TypeId
|
/// \see enum TypeId
|
||||||
virtual int getTypeId() const = 0;
|
TypeId getTypeId() const { return mTypeId; }
|
||||||
|
|
||||||
/// Higher number is higher priority (0 being the lowest)
|
/// Higher number is higher priority (0 being the lowest)
|
||||||
virtual unsigned int getPriority() const {return 0;}
|
unsigned int getPriority() const { return mOptions.mPriority; }
|
||||||
|
|
||||||
/// Check if package use movement with variable speed
|
/// Check if package use movement with variable speed
|
||||||
virtual bool useVariableSpeed() const { return false;}
|
bool useVariableSpeed() const { return mOptions.mUseVariableSpeed; }
|
||||||
|
|
||||||
virtual void writeState (ESM::AiSequence::AiSequence& sequence) const {}
|
virtual void writeState (ESM::AiSequence::AiSequence& sequence) const {}
|
||||||
|
|
||||||
|
@ -87,24 +117,24 @@ namespace MWMechanics
|
||||||
virtual osg::Vec3f getDestination(const MWWorld::Ptr& actor) const { return osg::Vec3f(0, 0, 0); };
|
virtual osg::Vec3f getDestination(const MWWorld::Ptr& actor) const { return osg::Vec3f(0, 0, 0); };
|
||||||
|
|
||||||
/// Return true if having this AiPackage makes the actor side with the target in fights (default false)
|
/// Return true if having this AiPackage makes the actor side with the target in fights (default false)
|
||||||
virtual bool sideWithTarget() const;
|
bool sideWithTarget() const { return mOptions.mSideWithTarget; }
|
||||||
|
|
||||||
/// Return true if the actor should follow the target through teleport doors (default false)
|
/// Return true if the actor should follow the target through teleport doors (default false)
|
||||||
virtual bool followTargetThroughDoors() const;
|
bool followTargetThroughDoors() const { return mOptions.mFollowTargetThroughDoors; }
|
||||||
|
|
||||||
/// Can this Ai package be canceled? (default true)
|
/// Can this Ai package be canceled? (default true)
|
||||||
virtual bool canCancel() const;
|
bool canCancel() const { return mOptions.mCanCancel; }
|
||||||
|
|
||||||
/// Upon adding this Ai package, should the Ai Sequence attempt to cancel previous Ai packages (default true)?
|
/// Upon adding this Ai package, should the Ai Sequence attempt to cancel previous Ai packages (default true)?
|
||||||
virtual bool shouldCancelPreviousAi() const;
|
bool shouldCancelPreviousAi() const { return mOptions.mShouldCancelPreviousAi; }
|
||||||
|
|
||||||
/// Return true if this package should repeat. Currently only used for Wander packages.
|
/// Return true if this package should repeat. Currently only used for Wander packages.
|
||||||
virtual bool getRepeat() const;
|
bool getRepeat() const { return mOptions.mRepeat; }
|
||||||
|
|
||||||
virtual osg::Vec3f getDestination() const { return osg::Vec3f(0, 0, 0); }
|
virtual osg::Vec3f getDestination() const { return osg::Vec3f(0, 0, 0); }
|
||||||
|
|
||||||
// Return true if any loaded actor with this AI package must be active.
|
/// Return true if any loaded actor with this AI package must be active.
|
||||||
virtual bool alwaysActive() const { return false; }
|
bool alwaysActive() const { return mOptions.mAlwaysActive; }
|
||||||
|
|
||||||
/// Reset pathfinding state
|
/// Reset pathfinding state
|
||||||
void reset();
|
void reset();
|
||||||
|
@ -137,6 +167,9 @@ namespace MWMechanics
|
||||||
|
|
||||||
DetourNavigator::Flags getNavigatorFlags(const MWWorld::Ptr& actor) const;
|
DetourNavigator::Flags getNavigatorFlags(const MWWorld::Ptr& actor) const;
|
||||||
|
|
||||||
|
const TypeId mTypeId;
|
||||||
|
const Options mOptions;
|
||||||
|
|
||||||
// TODO: all this does not belong here, move into temporary storage
|
// TODO: all this does not belong here, move into temporary storage
|
||||||
PathFinder mPathFinder;
|
PathFinder mPathFinder;
|
||||||
ObstacleCheck mObstacleCheck;
|
ObstacleCheck mObstacleCheck;
|
||||||
|
|
|
@ -40,10 +40,6 @@ AiPursue::AiPursue(const ESM::AiSequence::AiPursue *pursue)
|
||||||
mTargetActorId = pursue->mTargetActorId;
|
mTargetActorId = pursue->mTargetActorId;
|
||||||
}
|
}
|
||||||
|
|
||||||
AiPursue *MWMechanics::AiPursue::clone() const
|
|
||||||
{
|
|
||||||
return new AiPursue(*this);
|
|
||||||
}
|
|
||||||
bool AiPursue::execute (const MWWorld::Ptr& actor, CharacterController& characterController, AiState& state, float duration)
|
bool AiPursue::execute (const MWWorld::Ptr& actor, CharacterController& characterController, AiState& state, float duration)
|
||||||
{
|
{
|
||||||
if(actor.getClass().getCreatureStats(actor).isDead())
|
if(actor.getClass().getCreatureStats(actor).isDead())
|
||||||
|
@ -116,11 +112,6 @@ bool AiPursue::execute (const MWWorld::Ptr& actor, CharacterController& characte
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
int AiPursue::getTypeId() const
|
|
||||||
{
|
|
||||||
return TypeIdPursue;
|
|
||||||
}
|
|
||||||
|
|
||||||
MWWorld::Ptr AiPursue::getTarget() const
|
MWWorld::Ptr AiPursue::getTarget() const
|
||||||
{
|
{
|
||||||
return MWBase::Environment::get().getWorld()->searchPtrViaActorId(mTargetActorId);
|
return MWBase::Environment::get().getWorld()->searchPtrViaActorId(mTargetActorId);
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
#ifndef GAME_MWMECHANICS_AIPURSUE_H
|
#ifndef GAME_MWMECHANICS_AIPURSUE_H
|
||||||
#define GAME_MWMECHANICS_AIPURSUE_H
|
#define GAME_MWMECHANICS_AIPURSUE_H
|
||||||
|
|
||||||
#include "aipackage.hpp"
|
#include "typedaipackage.hpp"
|
||||||
|
|
||||||
namespace ESM
|
namespace ESM
|
||||||
{
|
{
|
||||||
|
@ -17,7 +17,7 @@ namespace MWMechanics
|
||||||
/** Used for arresting players. Causes the actor to run to the pursued actor and activate them, to arrest them.
|
/** Used for arresting players. Causes the actor to run to the pursued actor and activate them, to arrest them.
|
||||||
Note that while very similar to AiActivate, it will ONLY activate when evry close to target (Not also when the
|
Note that while very similar to AiActivate, it will ONLY activate when evry close to target (Not also when the
|
||||||
path is completed). **/
|
path is completed). **/
|
||||||
class AiPursue final : public AiPackage
|
class AiPursue final : public TypedAiPackage<AiPursue>
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
///Constructor
|
///Constructor
|
||||||
|
@ -26,16 +26,21 @@ namespace MWMechanics
|
||||||
|
|
||||||
AiPursue(const ESM::AiSequence::AiPursue* pursue);
|
AiPursue(const ESM::AiSequence::AiPursue* pursue);
|
||||||
|
|
||||||
AiPursue *clone() const final;
|
|
||||||
bool execute (const MWWorld::Ptr& actor, CharacterController& characterController, AiState& state, float duration) final;
|
bool execute (const MWWorld::Ptr& actor, CharacterController& characterController, AiState& state, float duration) final;
|
||||||
int getTypeId() const final;
|
|
||||||
|
static constexpr TypeId getTypeId() { return TypeIdPursue; }
|
||||||
|
|
||||||
|
static constexpr Options makeDefaultOptions()
|
||||||
|
{
|
||||||
|
AiPackage::Options options;
|
||||||
|
options.mCanCancel = false;
|
||||||
|
options.mShouldCancelPreviousAi = false;
|
||||||
|
return options;
|
||||||
|
}
|
||||||
|
|
||||||
MWWorld::Ptr getTarget() const final;
|
MWWorld::Ptr getTarget() const final;
|
||||||
|
|
||||||
void writeState (ESM::AiSequence::AiSequence& sequence) const final;
|
void writeState (ESM::AiSequence::AiSequence& sequence) const final;
|
||||||
|
|
||||||
bool canCancel() const final { return false; }
|
|
||||||
bool shouldCancelPreviousAi() const final { return false; }
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -25,9 +25,8 @@ namespace MWMechanics
|
||||||
|
|
||||||
void AiSequence::copy (const AiSequence& sequence)
|
void AiSequence::copy (const AiSequence& sequence)
|
||||||
{
|
{
|
||||||
for (std::list<AiPackage *>::const_iterator iter (sequence.mPackages.begin());
|
for (const auto& package : sequence.mPackages)
|
||||||
iter!=sequence.mPackages.end(); ++iter)
|
mPackages.push_back(package->clone());
|
||||||
mPackages.push_back ((*iter)->clone());
|
|
||||||
|
|
||||||
// We need to keep an AiWander storage, if present - it has a state machine.
|
// We need to keep an AiWander storage, if present - it has a state machine.
|
||||||
// Not sure about another temporary storages
|
// Not sure about another temporary storages
|
||||||
|
@ -82,7 +81,7 @@ bool AiSequence::getCombatTarget(MWWorld::Ptr &targetActor) const
|
||||||
|
|
||||||
bool AiSequence::getCombatTargets(std::vector<MWWorld::Ptr> &targetActors) const
|
bool AiSequence::getCombatTargets(std::vector<MWWorld::Ptr> &targetActors) const
|
||||||
{
|
{
|
||||||
for (std::list<AiPackage*>::const_iterator it = mPackages.begin(); it != mPackages.end(); ++it)
|
for (auto it = mPackages.begin(); it != mPackages.end(); ++it)
|
||||||
{
|
{
|
||||||
if ((*it)->getTypeId() == MWMechanics::AiPackage::TypeIdCombat)
|
if ((*it)->getTypeId() == MWMechanics::AiPackage::TypeIdCombat)
|
||||||
targetActors.push_back((*it)->getTarget());
|
targetActors.push_back((*it)->getTarget());
|
||||||
|
@ -91,24 +90,23 @@ bool AiSequence::getCombatTargets(std::vector<MWWorld::Ptr> &targetActors) const
|
||||||
return !targetActors.empty();
|
return !targetActors.empty();
|
||||||
}
|
}
|
||||||
|
|
||||||
std::list<AiPackage*>::const_iterator AiSequence::begin() const
|
std::list<std::unique_ptr<AiPackage>>::const_iterator AiSequence::begin() const
|
||||||
{
|
{
|
||||||
return mPackages.begin();
|
return mPackages.begin();
|
||||||
}
|
}
|
||||||
|
|
||||||
std::list<AiPackage*>::const_iterator AiSequence::end() const
|
std::list<std::unique_ptr<AiPackage>>::const_iterator AiSequence::end() const
|
||||||
{
|
{
|
||||||
return mPackages.end();
|
return mPackages.end();
|
||||||
}
|
}
|
||||||
|
|
||||||
void AiSequence::erase(std::list<AiPackage*>::const_iterator package)
|
void AiSequence::erase(std::list<std::unique_ptr<AiPackage>>::const_iterator package)
|
||||||
{
|
{
|
||||||
// Not sure if manually terminated packages should trigger mDone, probably not?
|
// Not sure if manually terminated packages should trigger mDone, probably not?
|
||||||
for(std::list<AiPackage*>::iterator it = mPackages.begin(); it != mPackages.end(); ++it)
|
for(auto it = mPackages.begin(); it != mPackages.end(); ++it)
|
||||||
{
|
{
|
||||||
if (package == it)
|
if (package == it)
|
||||||
{
|
{
|
||||||
delete *it;
|
|
||||||
mPackages.erase(it);
|
mPackages.erase(it);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -118,7 +116,7 @@ void AiSequence::erase(std::list<AiPackage*>::const_iterator package)
|
||||||
|
|
||||||
bool AiSequence::isInCombat() const
|
bool AiSequence::isInCombat() const
|
||||||
{
|
{
|
||||||
for(std::list<AiPackage*>::const_iterator it = mPackages.begin(); it != mPackages.end(); ++it)
|
for (auto it = mPackages.begin(); it != mPackages.end(); ++it)
|
||||||
{
|
{
|
||||||
if ((*it)->getTypeId() == AiPackage::TypeIdCombat)
|
if ((*it)->getTypeId() == AiPackage::TypeIdCombat)
|
||||||
return true;
|
return true;
|
||||||
|
@ -128,7 +126,7 @@ bool AiSequence::isInCombat() const
|
||||||
|
|
||||||
bool AiSequence::isEngagedWithActor() const
|
bool AiSequence::isEngagedWithActor() const
|
||||||
{
|
{
|
||||||
for (std::list<AiPackage *>::const_iterator it = mPackages.begin(); it != mPackages.end(); ++it)
|
for (auto it = mPackages.begin(); it != mPackages.end(); ++it)
|
||||||
{
|
{
|
||||||
if ((*it)->getTypeId() == AiPackage::TypeIdCombat)
|
if ((*it)->getTypeId() == AiPackage::TypeIdCombat)
|
||||||
{
|
{
|
||||||
|
@ -142,7 +140,7 @@ bool AiSequence::isEngagedWithActor() const
|
||||||
|
|
||||||
bool AiSequence::hasPackage(int typeId) const
|
bool AiSequence::hasPackage(int typeId) const
|
||||||
{
|
{
|
||||||
for (std::list<AiPackage*>::const_iterator it = mPackages.begin(); it != mPackages.end(); ++it)
|
for (auto it = mPackages.begin(); it != mPackages.end(); ++it)
|
||||||
{
|
{
|
||||||
if ((*it)->getTypeId() == typeId)
|
if ((*it)->getTypeId() == typeId)
|
||||||
return true;
|
return true;
|
||||||
|
@ -152,7 +150,7 @@ bool AiSequence::hasPackage(int typeId) const
|
||||||
|
|
||||||
bool AiSequence::isInCombat(const MWWorld::Ptr &actor) const
|
bool AiSequence::isInCombat(const MWWorld::Ptr &actor) const
|
||||||
{
|
{
|
||||||
for(std::list<AiPackage*>::const_iterator it = mPackages.begin(); it != mPackages.end(); ++it)
|
for (auto it = mPackages.begin(); it != mPackages.end(); ++it)
|
||||||
{
|
{
|
||||||
if ((*it)->getTypeId() == AiPackage::TypeIdCombat)
|
if ((*it)->getTypeId() == AiPackage::TypeIdCombat)
|
||||||
{
|
{
|
||||||
|
@ -165,11 +163,10 @@ bool AiSequence::isInCombat(const MWWorld::Ptr &actor) const
|
||||||
|
|
||||||
void AiSequence::stopCombat()
|
void AiSequence::stopCombat()
|
||||||
{
|
{
|
||||||
for(std::list<AiPackage*>::iterator it = mPackages.begin(); it != mPackages.end(); )
|
for(auto it = mPackages.begin(); it != mPackages.end(); )
|
||||||
{
|
{
|
||||||
if ((*it)->getTypeId() == AiPackage::TypeIdCombat)
|
if ((*it)->getTypeId() == AiPackage::TypeIdCombat)
|
||||||
{
|
{
|
||||||
delete *it;
|
|
||||||
it = mPackages.erase(it);
|
it = mPackages.erase(it);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
@ -179,11 +176,10 @@ void AiSequence::stopCombat()
|
||||||
|
|
||||||
void AiSequence::stopPursuit()
|
void AiSequence::stopPursuit()
|
||||||
{
|
{
|
||||||
for(std::list<AiPackage*>::iterator it = mPackages.begin(); it != mPackages.end(); )
|
for(auto it = mPackages.begin(); it != mPackages.end(); )
|
||||||
{
|
{
|
||||||
if ((*it)->getTypeId() == AiPackage::TypeIdPursue)
|
if ((*it)->getTypeId() == AiPackage::TypeIdPursue)
|
||||||
{
|
{
|
||||||
delete *it;
|
|
||||||
it = mPackages.erase(it);
|
it = mPackages.erase(it);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
@ -213,7 +209,7 @@ void AiSequence::execute (const MWWorld::Ptr& actor, CharacterController& charac
|
||||||
}
|
}
|
||||||
|
|
||||||
auto packageIt = mPackages.begin();
|
auto packageIt = mPackages.begin();
|
||||||
MWMechanics::AiPackage* package = *packageIt;
|
MWMechanics::AiPackage* package = packageIt->get();
|
||||||
if (!package->alwaysActive() && outOfRange)
|
if (!package->alwaysActive() && outOfRange)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
@ -231,7 +227,7 @@ void AiSequence::execute (const MWWorld::Ptr& actor, CharacterController& charac
|
||||||
|
|
||||||
float bestRating = 0.f;
|
float bestRating = 0.f;
|
||||||
|
|
||||||
for(std::list<AiPackage *>::iterator it = mPackages.begin(); it != mPackages.end();)
|
for (auto it = mPackages.begin(); it != mPackages.end();)
|
||||||
{
|
{
|
||||||
if ((*it)->getTypeId() != AiPackage::TypeIdCombat) break;
|
if ((*it)->getTypeId() != AiPackage::TypeIdCombat) break;
|
||||||
|
|
||||||
|
@ -240,7 +236,6 @@ void AiSequence::execute (const MWWorld::Ptr& actor, CharacterController& charac
|
||||||
// target disappeared (e.g. summoned creatures)
|
// target disappeared (e.g. summoned creatures)
|
||||||
if (target.isEmpty())
|
if (target.isEmpty())
|
||||||
{
|
{
|
||||||
delete *it;
|
|
||||||
it = mPackages.erase(it);
|
it = mPackages.erase(it);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
@ -276,7 +271,7 @@ void AiSequence::execute (const MWWorld::Ptr& actor, CharacterController& charac
|
||||||
}
|
}
|
||||||
|
|
||||||
packageIt = mPackages.begin();
|
packageIt = mPackages.begin();
|
||||||
package = *packageIt;
|
package = packageIt->get();
|
||||||
packageTypeId = package->getTypeId();
|
packageTypeId = package->getTypeId();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -293,7 +288,6 @@ void AiSequence::execute (const MWWorld::Ptr& actor, CharacterController& charac
|
||||||
// To account for the rare case where AiPackage::execute() queued another AI package
|
// To account for the rare case where AiPackage::execute() queued another AI package
|
||||||
// (e.g. AiPursue executing a dialogue script that uses startCombat)
|
// (e.g. AiPursue executing a dialogue script that uses startCombat)
|
||||||
mPackages.erase(packageIt);
|
mPackages.erase(packageIt);
|
||||||
delete package;
|
|
||||||
if (isActualAiPackage(packageTypeId))
|
if (isActualAiPackage(packageTypeId))
|
||||||
mDone = true;
|
mDone = true;
|
||||||
}
|
}
|
||||||
|
@ -311,9 +305,6 @@ void AiSequence::execute (const MWWorld::Ptr& actor, CharacterController& charac
|
||||||
|
|
||||||
void AiSequence::clear()
|
void AiSequence::clear()
|
||||||
{
|
{
|
||||||
for (std::list<AiPackage *>::const_iterator iter (mPackages.begin()); iter!=mPackages.end(); ++iter)
|
|
||||||
delete *iter;
|
|
||||||
|
|
||||||
mPackages.clear();
|
mPackages.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -340,26 +331,24 @@ void AiSequence::stack (const AiPackage& package, const MWWorld::Ptr& actor, boo
|
||||||
osg::Vec3f dest;
|
osg::Vec3f dest;
|
||||||
if (currentTypeId == MWMechanics::AiPackage::TypeIdWander)
|
if (currentTypeId == MWMechanics::AiPackage::TypeIdWander)
|
||||||
{
|
{
|
||||||
AiPackage* activePackage = getActivePackage();
|
dest = getActivePackage().getDestination(actor);
|
||||||
dest = activePackage->getDestination(actor);
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
dest = actor.getRefData().getPosition().asVec3();
|
dest = actor.getRefData().getPosition().asVec3();
|
||||||
}
|
}
|
||||||
|
|
||||||
MWMechanics::AiTravel travelPackage(dest.x(), dest.y(), dest.z(), true);
|
MWMechanics::AiInternalTravel travelPackage(dest.x(), dest.y(), dest.z());
|
||||||
stack(travelPackage, actor, false);
|
stack(travelPackage, actor, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
// remove previous packages if required
|
// remove previous packages if required
|
||||||
if (cancelOther && package.shouldCancelPreviousAi())
|
if (cancelOther && package.shouldCancelPreviousAi())
|
||||||
{
|
{
|
||||||
for(std::list<AiPackage *>::iterator it = mPackages.begin(); it != mPackages.end();)
|
for (auto it = mPackages.begin(); it != mPackages.end();)
|
||||||
{
|
{
|
||||||
if((*it)->canCancel())
|
if((*it)->canCancel())
|
||||||
{
|
{
|
||||||
delete *it;
|
|
||||||
it = mPackages.erase(it);
|
it = mPackages.erase(it);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
@ -369,7 +358,7 @@ void AiSequence::stack (const AiPackage& package, const MWWorld::Ptr& actor, boo
|
||||||
}
|
}
|
||||||
|
|
||||||
// insert new package in correct place depending on priority
|
// insert new package in correct place depending on priority
|
||||||
for(std::list<AiPackage *>::iterator it = mPackages.begin(); it != mPackages.end(); ++it)
|
for (auto it = mPackages.begin(); it != mPackages.end(); ++it)
|
||||||
{
|
{
|
||||||
// We should keep current AiCast package, if we try to add a new one.
|
// We should keep current AiCast package, if we try to add a new one.
|
||||||
if ((*it)->getTypeId() == MWMechanics::AiPackage::TypeIdCast &&
|
if ((*it)->getTypeId() == MWMechanics::AiPackage::TypeIdCast &&
|
||||||
|
@ -401,12 +390,11 @@ bool MWMechanics::AiSequence::isEmpty() const
|
||||||
return mPackages.empty();
|
return mPackages.empty();
|
||||||
}
|
}
|
||||||
|
|
||||||
AiPackage* MWMechanics::AiSequence::getActivePackage()
|
const AiPackage& MWMechanics::AiSequence::getActivePackage()
|
||||||
{
|
{
|
||||||
if(mPackages.empty())
|
if(mPackages.empty())
|
||||||
throw std::runtime_error(std::string("No AI Package!"));
|
throw std::runtime_error(std::string("No AI Package!"));
|
||||||
else
|
return *mPackages.front();
|
||||||
return mPackages.front();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void AiSequence::fill(const ESM::AIPackageList &list)
|
void AiSequence::fill(const ESM::AIPackageList &list)
|
||||||
|
@ -417,7 +405,7 @@ void AiSequence::fill(const ESM::AIPackageList &list)
|
||||||
|
|
||||||
for (std::vector<ESM::AIPackage>::const_iterator it = list.mList.begin(); it != list.mList.end(); ++it)
|
for (std::vector<ESM::AIPackage>::const_iterator it = list.mList.begin(); it != list.mList.end(); ++it)
|
||||||
{
|
{
|
||||||
MWMechanics::AiPackage* package;
|
std::unique_ptr<MWMechanics::AiPackage> package;
|
||||||
if (it->mType == ESM::AI_Wander)
|
if (it->mType == ESM::AI_Wander)
|
||||||
{
|
{
|
||||||
ESM::AIWander data = it->mWander;
|
ESM::AIWander data = it->mWander;
|
||||||
|
@ -425,38 +413,36 @@ void AiSequence::fill(const ESM::AIPackageList &list)
|
||||||
idles.reserve(8);
|
idles.reserve(8);
|
||||||
for (int i=0; i<8; ++i)
|
for (int i=0; i<8; ++i)
|
||||||
idles.push_back(data.mIdle[i]);
|
idles.push_back(data.mIdle[i]);
|
||||||
package = new MWMechanics::AiWander(data.mDistance, data.mDuration, data.mTimeOfDay, idles, data.mShouldRepeat != 0);
|
package = std::make_unique<MWMechanics::AiWander>(data.mDistance, data.mDuration, data.mTimeOfDay, idles, data.mShouldRepeat != 0);
|
||||||
}
|
}
|
||||||
else if (it->mType == ESM::AI_Escort)
|
else if (it->mType == ESM::AI_Escort)
|
||||||
{
|
{
|
||||||
ESM::AITarget data = it->mTarget;
|
ESM::AITarget data = it->mTarget;
|
||||||
package = new MWMechanics::AiEscort(data.mId.toString(), data.mDuration, data.mX, data.mY, data.mZ);
|
package = std::make_unique<MWMechanics::AiEscort>(data.mId.toString(), data.mDuration, data.mX, data.mY, data.mZ);
|
||||||
}
|
}
|
||||||
else if (it->mType == ESM::AI_Travel)
|
else if (it->mType == ESM::AI_Travel)
|
||||||
{
|
{
|
||||||
ESM::AITravel data = it->mTravel;
|
ESM::AITravel data = it->mTravel;
|
||||||
package = new MWMechanics::AiTravel(data.mX, data.mY, data.mZ);
|
package = std::make_unique<MWMechanics::AiTravel>(data.mX, data.mY, data.mZ);
|
||||||
}
|
}
|
||||||
else if (it->mType == ESM::AI_Activate)
|
else if (it->mType == ESM::AI_Activate)
|
||||||
{
|
{
|
||||||
ESM::AIActivate data = it->mActivate;
|
ESM::AIActivate data = it->mActivate;
|
||||||
package = new MWMechanics::AiActivate(data.mName.toString());
|
package = std::make_unique<MWMechanics::AiActivate>(data.mName.toString());
|
||||||
}
|
}
|
||||||
else //if (it->mType == ESM::AI_Follow)
|
else //if (it->mType == ESM::AI_Follow)
|
||||||
{
|
{
|
||||||
ESM::AITarget data = it->mTarget;
|
ESM::AITarget data = it->mTarget;
|
||||||
package = new MWMechanics::AiFollow(data.mId.toString(), data.mDuration, data.mX, data.mY, data.mZ);
|
package = std::make_unique<MWMechanics::AiFollow>(data.mId.toString(), data.mDuration, data.mX, data.mY, data.mZ);
|
||||||
}
|
}
|
||||||
mPackages.push_back(package);
|
mPackages.push_back(std::move(package));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void AiSequence::writeState(ESM::AiSequence::AiSequence &sequence) const
|
void AiSequence::writeState(ESM::AiSequence::AiSequence &sequence) const
|
||||||
{
|
{
|
||||||
for (std::list<AiPackage *>::const_iterator iter (mPackages.begin()); iter!=mPackages.end(); ++iter)
|
for (const auto& package : mPackages)
|
||||||
{
|
package->writeState(sequence);
|
||||||
(*iter)->writeState(sequence);
|
|
||||||
}
|
|
||||||
|
|
||||||
sequence.mLastAiPackage = mLastAiPackage;
|
sequence.mLastAiPackage = mLastAiPackage;
|
||||||
}
|
}
|
||||||
|
@ -492,7 +478,11 @@ void AiSequence::readState(const ESM::AiSequence::AiSequence &sequence)
|
||||||
}
|
}
|
||||||
case ESM::AiSequence::Ai_Travel:
|
case ESM::AiSequence::Ai_Travel:
|
||||||
{
|
{
|
||||||
package.reset(new AiTravel(static_cast<ESM::AiSequence::AiTravel*>(it->mPackage)));
|
const auto source = static_cast<const ESM::AiSequence::AiTravel*>(it->mPackage);
|
||||||
|
if (source->mHidden)
|
||||||
|
package.reset(new AiInternalTravel(source));
|
||||||
|
else
|
||||||
|
package.reset(new AiTravel(source));
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case ESM::AiSequence::Ai_Escort:
|
case ESM::AiSequence::Ai_Escort:
|
||||||
|
@ -527,7 +517,7 @@ void AiSequence::readState(const ESM::AiSequence::AiSequence &sequence)
|
||||||
if (!package.get())
|
if (!package.get())
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
mPackages.push_back(package.release());
|
mPackages.push_back(std::move(package));
|
||||||
}
|
}
|
||||||
|
|
||||||
mLastAiPackage = sequence.mLastAiPackage;
|
mLastAiPackage = sequence.mLastAiPackage;
|
||||||
|
@ -537,8 +527,7 @@ void AiSequence::fastForward(const MWWorld::Ptr& actor)
|
||||||
{
|
{
|
||||||
if (!mPackages.empty())
|
if (!mPackages.empty())
|
||||||
{
|
{
|
||||||
MWMechanics::AiPackage* package = mPackages.front();
|
mPackages.front()->fastForward(actor, mAiState);
|
||||||
package->fastForward(actor, mAiState);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -2,6 +2,7 @@
|
||||||
#define GAME_MWMECHANICS_AISEQUENCE_H
|
#define GAME_MWMECHANICS_AISEQUENCE_H
|
||||||
|
|
||||||
#include <list>
|
#include <list>
|
||||||
|
#include <memory>
|
||||||
|
|
||||||
#include "aistate.hpp"
|
#include "aistate.hpp"
|
||||||
|
|
||||||
|
@ -36,7 +37,7 @@ namespace MWMechanics
|
||||||
class AiSequence
|
class AiSequence
|
||||||
{
|
{
|
||||||
///AiPackages to run though
|
///AiPackages to run though
|
||||||
std::list<AiPackage *> mPackages;
|
std::list<std::unique_ptr<AiPackage>> mPackages;
|
||||||
|
|
||||||
///Finished with top AIPackage, set for one frame
|
///Finished with top AIPackage, set for one frame
|
||||||
bool mDone;
|
bool mDone;
|
||||||
|
@ -64,10 +65,10 @@ namespace MWMechanics
|
||||||
virtual ~AiSequence();
|
virtual ~AiSequence();
|
||||||
|
|
||||||
/// Iterator may be invalidated by any function calls other than begin() or end().
|
/// Iterator may be invalidated by any function calls other than begin() or end().
|
||||||
std::list<AiPackage*>::const_iterator begin() const;
|
std::list<std::unique_ptr<AiPackage>>::const_iterator begin() const;
|
||||||
std::list<AiPackage*>::const_iterator end() const;
|
std::list<std::unique_ptr<AiPackage>>::const_iterator end() const;
|
||||||
|
|
||||||
void erase (std::list<AiPackage*>::const_iterator package);
|
void erase(std::list<std::unique_ptr<AiPackage>>::const_iterator package);
|
||||||
|
|
||||||
/// Returns currently executing AiPackage type
|
/// Returns currently executing AiPackage type
|
||||||
/** \see enum AiPackage::TypeId **/
|
/** \see enum AiPackage::TypeId **/
|
||||||
|
@ -125,7 +126,7 @@ namespace MWMechanics
|
||||||
|
|
||||||
/// Return the current active package.
|
/// Return the current active package.
|
||||||
/** If there is no active package, it will throw an exception **/
|
/** If there is no active package, it will throw an exception **/
|
||||||
AiPackage* getActivePackage();
|
const AiPackage& getActivePackage();
|
||||||
|
|
||||||
/// Fills the AiSequence with packages
|
/// Fills the AiSequence with packages
|
||||||
/** Typically used for loading from the ESM
|
/** Typically used for loading from the ESM
|
||||||
|
|
|
@ -27,19 +27,26 @@ bool isWithinMaxRange(const osg::Vec3f& pos1, const osg::Vec3f& pos2)
|
||||||
|
|
||||||
namespace MWMechanics
|
namespace MWMechanics
|
||||||
{
|
{
|
||||||
AiTravel::AiTravel(float x, float y, float z, bool hidden)
|
AiTravel::AiTravel(float x, float y, float z, AiTravel*)
|
||||||
: mX(x),mY(y),mZ(z),mHidden(hidden)
|
: mX(x), mY(y), mZ(z), mHidden(false)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
AiTravel::AiTravel(float x, float y, float z, AiInternalTravel* derived)
|
||||||
|
: TypedAiPackage<AiTravel>(derived), mX(x), mY(y), mZ(z), mHidden(true)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
AiTravel::AiTravel(float x, float y, float z)
|
||||||
|
: AiTravel(x, y, z, this)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
AiTravel::AiTravel(const ESM::AiSequence::AiTravel *travel)
|
AiTravel::AiTravel(const ESM::AiSequence::AiTravel *travel)
|
||||||
: mX(travel->mData.mX), mY(travel->mData.mY), mZ(travel->mData.mZ), mHidden(travel->mHidden)
|
: mX(travel->mData.mX), mY(travel->mData.mY), mZ(travel->mData.mZ), mHidden(false)
|
||||||
{
|
{
|
||||||
}
|
// Hidden ESM::AiSequence::AiTravel package should be converted into MWMechanics::AiInternalTravel type
|
||||||
|
assert(!travel->mHidden);
|
||||||
AiTravel *MWMechanics::AiTravel::clone() const
|
|
||||||
{
|
|
||||||
return new AiTravel(*this);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool AiTravel::execute (const MWWorld::Ptr& actor, CharacterController& characterController, AiState& state, float duration)
|
bool AiTravel::execute (const MWWorld::Ptr& actor, CharacterController& characterController, AiState& state, float duration)
|
||||||
|
@ -83,11 +90,6 @@ namespace MWMechanics
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
int AiTravel::getTypeId() const
|
|
||||||
{
|
|
||||||
return mHidden ? TypeIdInternalTravel : TypeIdTravel;
|
|
||||||
}
|
|
||||||
|
|
||||||
void AiTravel::fastForward(const MWWorld::Ptr& actor, AiState& state)
|
void AiTravel::fastForward(const MWWorld::Ptr& actor, AiState& state)
|
||||||
{
|
{
|
||||||
if (!isWithinMaxRange(osg::Vec3f(mX, mY, mZ), actor.getRefData().getPosition().asVec3()))
|
if (!isWithinMaxRange(osg::Vec3f(mX, mY, mZ), actor.getRefData().getPosition().asVec3()))
|
||||||
|
@ -112,5 +114,20 @@ namespace MWMechanics
|
||||||
package.mPackage = travel.release();
|
package.mPackage = travel.release();
|
||||||
sequence.mPackages.push_back(package);
|
sequence.mPackages.push_back(package);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
AiInternalTravel::AiInternalTravel(float x, float y, float z)
|
||||||
|
: AiTravel(x, y, z, this)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
AiInternalTravel::AiInternalTravel(const ESM::AiSequence::AiTravel* travel)
|
||||||
|
: AiTravel(travel->mData.mX, travel->mData.mY, travel->mData.mZ, this)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
std::unique_ptr<AiPackage> AiInternalTravel::clone() const
|
||||||
|
{
|
||||||
|
return std::make_unique<AiInternalTravel>(*this);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
#ifndef GAME_MWMECHANICS_AITRAVEL_H
|
#ifndef GAME_MWMECHANICS_AITRAVEL_H
|
||||||
#define GAME_MWMECHANICS_AITRAVEL_H
|
#define GAME_MWMECHANICS_AITRAVEL_H
|
||||||
|
|
||||||
#include "aipackage.hpp"
|
#include "typedaipackage.hpp"
|
||||||
|
|
||||||
namespace ESM
|
namespace ESM
|
||||||
{
|
{
|
||||||
|
@ -13,12 +13,18 @@ namespace AiSequence
|
||||||
|
|
||||||
namespace MWMechanics
|
namespace MWMechanics
|
||||||
{
|
{
|
||||||
|
struct AiInternalTravel;
|
||||||
|
|
||||||
/// \brief Causes the AI to travel to the specified point
|
/// \brief Causes the AI to travel to the specified point
|
||||||
class AiTravel final : public AiPackage
|
class AiTravel : public TypedAiPackage<AiTravel>
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
/// Default constructor
|
AiTravel(float x, float y, float z, AiTravel* derived);
|
||||||
AiTravel(float x, float y, float z, bool hidden = false);
|
|
||||||
|
AiTravel(float x, float y, float z, AiInternalTravel* derived);
|
||||||
|
|
||||||
|
AiTravel(float x, float y, float z);
|
||||||
|
|
||||||
AiTravel(const ESM::AiSequence::AiTravel* travel);
|
AiTravel(const ESM::AiSequence::AiTravel* travel);
|
||||||
|
|
||||||
/// Simulates the passing of time
|
/// Simulates the passing of time
|
||||||
|
@ -26,24 +32,37 @@ namespace MWMechanics
|
||||||
|
|
||||||
void writeState(ESM::AiSequence::AiSequence &sequence) const final;
|
void writeState(ESM::AiSequence::AiSequence &sequence) const final;
|
||||||
|
|
||||||
AiTravel *clone() const final;
|
|
||||||
|
|
||||||
bool execute (const MWWorld::Ptr& actor, CharacterController& characterController, AiState& state, float duration) final;
|
bool execute (const MWWorld::Ptr& actor, CharacterController& characterController, AiState& state, float duration) final;
|
||||||
|
|
||||||
int getTypeId() const final;
|
static constexpr TypeId getTypeId() { return TypeIdTravel; }
|
||||||
|
|
||||||
bool useVariableSpeed() const final { return true; }
|
static constexpr Options makeDefaultOptions()
|
||||||
|
{
|
||||||
bool alwaysActive() const final { return true; }
|
AiPackage::Options options;
|
||||||
|
options.mUseVariableSpeed = true;
|
||||||
|
options.mAlwaysActive = true;
|
||||||
|
return options;
|
||||||
|
}
|
||||||
|
|
||||||
osg::Vec3f getDestination() const final { return osg::Vec3f(mX, mY, mZ); }
|
osg::Vec3f getDestination() const final { return osg::Vec3f(mX, mY, mZ); }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
float mX;
|
const float mX;
|
||||||
float mY;
|
const float mY;
|
||||||
float mZ;
|
const float mZ;
|
||||||
|
|
||||||
bool mHidden;
|
const bool mHidden;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct AiInternalTravel final : public AiTravel
|
||||||
|
{
|
||||||
|
AiInternalTravel(float x, float y, float z);
|
||||||
|
|
||||||
|
explicit AiInternalTravel(const ESM::AiSequence::AiTravel* travel);
|
||||||
|
|
||||||
|
static constexpr TypeId getTypeId() { return TypeIdInternalTravel; }
|
||||||
|
|
||||||
|
std::unique_ptr<AiPackage> clone() const final;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,7 @@
|
||||||
#include "aiwander.hpp"
|
#include "aiwander.hpp"
|
||||||
|
|
||||||
|
#include <algorithm>
|
||||||
|
|
||||||
#include <components/debug/debuglog.hpp>
|
#include <components/debug/debuglog.hpp>
|
||||||
#include <components/misc/rng.hpp>
|
#include <components/misc/rng.hpp>
|
||||||
#include <components/esm/aisequence.hpp>
|
#include <components/esm/aisequence.hpp>
|
||||||
|
@ -33,6 +35,8 @@ namespace MWMechanics
|
||||||
// distance must be long enough that NPC will need to move to get there.
|
// distance must be long enough that NPC will need to move to get there.
|
||||||
static const int MINIMUM_WANDER_DISTANCE = DESTINATION_TOLERANCE * 2;
|
static const int MINIMUM_WANDER_DISTANCE = DESTINATION_TOLERANCE * 2;
|
||||||
|
|
||||||
|
static const std::size_t MAX_IDLE_SIZE = 8;
|
||||||
|
|
||||||
const std::string AiWander::sIdleSelectToGroupName[GroupIndex_MaxIdle - GroupIndex_MinIdle + 1] =
|
const std::string AiWander::sIdleSelectToGroupName[GroupIndex_MaxIdle - GroupIndex_MinIdle + 1] =
|
||||||
{
|
{
|
||||||
std::string("idle2"),
|
std::string("idle2"),
|
||||||
|
@ -94,30 +98,29 @@ namespace MWMechanics
|
||||||
{
|
{
|
||||||
actor.getClass().getMovementSettings(actor).mPosition[1] = 0;
|
actor.getClass().getMovementSettings(actor).mPosition[1] = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::vector<unsigned char> getInitialIdle(const std::vector<unsigned char>& idle)
|
||||||
|
{
|
||||||
|
std::vector<unsigned char> result(MAX_IDLE_SIZE, 0);
|
||||||
|
std::copy_n(idle.begin(), std::min(MAX_IDLE_SIZE, idle.size()), result.begin());
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<unsigned char> getInitialIdle(const unsigned char (&idle)[MAX_IDLE_SIZE])
|
||||||
|
{
|
||||||
|
return std::vector<unsigned char>(std::begin(idle), std::end(idle));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
AiWander::AiWander(int distance, int duration, int timeOfDay, const std::vector<unsigned char>& idle, bool repeat):
|
AiWander::AiWander(int distance, int duration, int timeOfDay, const std::vector<unsigned char>& idle, bool repeat):
|
||||||
mDistance(distance), mDuration(duration), mRemainingDuration(duration), mTimeOfDay(timeOfDay), mIdle(idle),
|
TypedAiPackage<AiWander>(makeDefaultOptions().withRepeat(repeat)),
|
||||||
mRepeat(repeat), mStoredInitialActorPosition(false), mInitialActorPosition(osg::Vec3f(0, 0, 0)),
|
mDistance(std::max(0, distance)),
|
||||||
|
mDuration(std::max(0, duration)),
|
||||||
|
mRemainingDuration(duration), mTimeOfDay(timeOfDay),
|
||||||
|
mIdle(getInitialIdle(idle)),
|
||||||
|
mStoredInitialActorPosition(false), mInitialActorPosition(osg::Vec3f(0, 0, 0)),
|
||||||
mHasDestination(false), mDestination(osg::Vec3f(0, 0, 0)), mUsePathgrid(false)
|
mHasDestination(false), mDestination(osg::Vec3f(0, 0, 0)), mUsePathgrid(false)
|
||||||
{
|
{
|
||||||
mIdle.resize(8, 0);
|
|
||||||
init();
|
|
||||||
}
|
|
||||||
|
|
||||||
void AiWander::init()
|
|
||||||
{
|
|
||||||
// NOTE: mDistance and mDuration must be set already
|
|
||||||
|
|
||||||
if(mDistance < 0)
|
|
||||||
mDistance = 0;
|
|
||||||
if(mDuration < 0)
|
|
||||||
mDuration = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
AiPackage * MWMechanics::AiWander::clone() const
|
|
||||||
{
|
|
||||||
return new AiWander(*this);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -240,7 +243,6 @@ namespace MWMechanics
|
||||||
stopWalking(actor);
|
stopWalking(actor);
|
||||||
// Reset package so it can be used again
|
// Reset package so it can be used again
|
||||||
mRemainingDuration=mDuration;
|
mRemainingDuration=mDuration;
|
||||||
init();
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -308,11 +310,6 @@ namespace MWMechanics
|
||||||
return false; // AiWander package not yet completed
|
return false; // AiWander package not yet completed
|
||||||
}
|
}
|
||||||
|
|
||||||
bool AiWander::getRepeat() const
|
|
||||||
{
|
|
||||||
return mRepeat;
|
|
||||||
}
|
|
||||||
|
|
||||||
osg::Vec3f AiWander::getDestination(const MWWorld::Ptr& actor) const
|
osg::Vec3f AiWander::getDestination(const MWWorld::Ptr& actor) const
|
||||||
{
|
{
|
||||||
if (mHasDestination)
|
if (mHasDestination)
|
||||||
|
@ -598,11 +595,6 @@ namespace MWMechanics
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
int AiWander::getTypeId() const
|
|
||||||
{
|
|
||||||
return TypeIdWander;
|
|
||||||
}
|
|
||||||
|
|
||||||
void AiWander::stopWalking(const MWWorld::Ptr& actor)
|
void AiWander::stopWalking(const MWWorld::Ptr& actor)
|
||||||
{
|
{
|
||||||
mPathFinder.clearPath();
|
mPathFinder.clearPath();
|
||||||
|
@ -872,7 +864,7 @@ namespace MWMechanics
|
||||||
assert (mIdle.size() == 8);
|
assert (mIdle.size() == 8);
|
||||||
for (int i=0; i<8; ++i)
|
for (int i=0; i<8; ++i)
|
||||||
wander->mData.mIdle[i] = mIdle[i];
|
wander->mData.mIdle[i] = mIdle[i];
|
||||||
wander->mData.mShouldRepeat = mRepeat;
|
wander->mData.mShouldRepeat = mOptions.mRepeat;
|
||||||
wander->mStoredInitialActorPosition = mStoredInitialActorPosition;
|
wander->mStoredInitialActorPosition = mStoredInitialActorPosition;
|
||||||
if (mStoredInitialActorPosition)
|
if (mStoredInitialActorPosition)
|
||||||
wander->mInitialActorPosition = mInitialActorPosition;
|
wander->mInitialActorPosition = mInitialActorPosition;
|
||||||
|
@ -884,11 +876,12 @@ namespace MWMechanics
|
||||||
}
|
}
|
||||||
|
|
||||||
AiWander::AiWander (const ESM::AiSequence::AiWander* wander)
|
AiWander::AiWander (const ESM::AiSequence::AiWander* wander)
|
||||||
: mDistance(wander->mData.mDistance)
|
: TypedAiPackage<AiWander>(makeDefaultOptions().withRepeat(wander->mData.mShouldRepeat != 0))
|
||||||
, mDuration(wander->mData.mDuration)
|
, mDistance(std::max(static_cast<short>(0), wander->mData.mDistance))
|
||||||
|
, mDuration(std::max(static_cast<short>(0), wander->mData.mDuration))
|
||||||
, mRemainingDuration(wander->mDurationData.mRemainingDuration)
|
, mRemainingDuration(wander->mDurationData.mRemainingDuration)
|
||||||
, mTimeOfDay(wander->mData.mTimeOfDay)
|
, mTimeOfDay(wander->mData.mTimeOfDay)
|
||||||
, mRepeat(wander->mData.mShouldRepeat != 0)
|
, mIdle(getInitialIdle(wander->mData.mIdle))
|
||||||
, mStoredInitialActorPosition(wander->mStoredInitialActorPosition)
|
, mStoredInitialActorPosition(wander->mStoredInitialActorPosition)
|
||||||
, mHasDestination(false)
|
, mHasDestination(false)
|
||||||
, mDestination(osg::Vec3f(0, 0, 0))
|
, mDestination(osg::Vec3f(0, 0, 0))
|
||||||
|
@ -896,11 +889,7 @@ namespace MWMechanics
|
||||||
{
|
{
|
||||||
if (mStoredInitialActorPosition)
|
if (mStoredInitialActorPosition)
|
||||||
mInitialActorPosition = wander->mInitialActorPosition;
|
mInitialActorPosition = wander->mInitialActorPosition;
|
||||||
for (int i=0; i<8; ++i)
|
|
||||||
mIdle.push_back(wander->mData.mIdle[i]);
|
|
||||||
if (mRemainingDuration <= 0 || mRemainingDuration >= 24)
|
if (mRemainingDuration <= 0 || mRemainingDuration >= 24)
|
||||||
mRemainingDuration = mDuration;
|
mRemainingDuration = mDuration;
|
||||||
|
|
||||||
init();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
#ifndef GAME_MWMECHANICS_AIWANDER_H
|
#ifndef GAME_MWMECHANICS_AIWANDER_H
|
||||||
#define GAME_MWMECHANICS_AIWANDER_H
|
#define GAME_MWMECHANICS_AIWANDER_H
|
||||||
|
|
||||||
#include "aipackage.hpp"
|
#include "typedaipackage.hpp"
|
||||||
|
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
|
@ -78,7 +78,7 @@ namespace MWMechanics
|
||||||
};
|
};
|
||||||
|
|
||||||
/// \brief Causes the Actor to wander within a specified range
|
/// \brief Causes the Actor to wander within a specified range
|
||||||
class AiWander final : public AiPackage
|
class AiWander final : public TypedAiPackage<AiWander>
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
/// Constructor
|
/// Constructor
|
||||||
|
@ -91,20 +91,22 @@ namespace MWMechanics
|
||||||
|
|
||||||
AiWander (const ESM::AiSequence::AiWander* wander);
|
AiWander (const ESM::AiSequence::AiWander* wander);
|
||||||
|
|
||||||
AiPackage *clone() const final;
|
|
||||||
|
|
||||||
bool execute(const MWWorld::Ptr& actor, CharacterController& characterController, AiState& state, float duration) final;
|
bool execute(const MWWorld::Ptr& actor, CharacterController& characterController, AiState& state, float duration) final;
|
||||||
|
|
||||||
int getTypeId() const final;
|
static constexpr TypeId getTypeId() { return TypeIdWander; }
|
||||||
|
|
||||||
bool useVariableSpeed() const final { return true; }
|
static constexpr Options makeDefaultOptions()
|
||||||
|
{
|
||||||
|
AiPackage::Options options;
|
||||||
|
options.mUseVariableSpeed = true;
|
||||||
|
options.mRepeat = false;
|
||||||
|
return options;
|
||||||
|
}
|
||||||
|
|
||||||
void writeState(ESM::AiSequence::AiSequence &sequence) const final;
|
void writeState(ESM::AiSequence::AiSequence &sequence) const final;
|
||||||
|
|
||||||
void fastForward(const MWWorld::Ptr& actor, AiState& state) final;
|
void fastForward(const MWWorld::Ptr& actor, AiState& state) final;
|
||||||
|
|
||||||
bool getRepeat() const final;
|
|
||||||
|
|
||||||
osg::Vec3f getDestination(const MWWorld::Ptr& actor) const final;
|
osg::Vec3f getDestination(const MWWorld::Ptr& actor) const final;
|
||||||
|
|
||||||
osg::Vec3f getDestination() const final
|
osg::Vec3f getDestination() const final
|
||||||
|
@ -116,8 +118,6 @@ namespace MWMechanics
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
// NOTE: mDistance and mDuration must be set already
|
|
||||||
void init();
|
|
||||||
void stopWalking(const MWWorld::Ptr& actor);
|
void stopWalking(const MWWorld::Ptr& actor);
|
||||||
|
|
||||||
/// Have the given actor play an idle animation
|
/// Have the given actor play an idle animation
|
||||||
|
@ -138,12 +138,11 @@ namespace MWMechanics
|
||||||
bool destinationIsAtWater(const MWWorld::Ptr &actor, const osg::Vec3f& destination);
|
bool destinationIsAtWater(const MWWorld::Ptr &actor, const osg::Vec3f& destination);
|
||||||
void completeManualWalking(const MWWorld::Ptr &actor, AiWanderStorage &storage);
|
void completeManualWalking(const MWWorld::Ptr &actor, AiWanderStorage &storage);
|
||||||
|
|
||||||
int mDistance; // how far the actor can wander from the spawn point
|
const int mDistance; // how far the actor can wander from the spawn point
|
||||||
int mDuration;
|
const int mDuration;
|
||||||
float mRemainingDuration;
|
float mRemainingDuration;
|
||||||
int mTimeOfDay;
|
const int mTimeOfDay;
|
||||||
std::vector<unsigned char> mIdle;
|
const std::vector<unsigned char> mIdle;
|
||||||
bool mRepeat;
|
|
||||||
|
|
||||||
bool mStoredInitialActorPosition;
|
bool mStoredInitialActorPosition;
|
||||||
osg::Vec3f mInitialActorPosition; // Note: an original engine does not reset coordinates even when actor changes a cell
|
osg::Vec3f mInitialActorPosition; // Note: an original engine does not reset coordinates even when actor changes a cell
|
||||||
|
|
|
@ -507,7 +507,7 @@ MWMechanics::Alchemy::TEffectsIterator MWMechanics::Alchemy::endEffects() const
|
||||||
|
|
||||||
bool MWMechanics::Alchemy::knownEffect(unsigned int potionEffectIndex, const MWWorld::Ptr &npc)
|
bool MWMechanics::Alchemy::knownEffect(unsigned int potionEffectIndex, const MWWorld::Ptr &npc)
|
||||||
{
|
{
|
||||||
int alchemySkill = npc.getClass().getSkill (npc, ESM::Skill::Alchemy);
|
float alchemySkill = npc.getClass().getSkill (npc, ESM::Skill::Alchemy);
|
||||||
static const float fWortChanceValue =
|
static const float fWortChanceValue =
|
||||||
MWBase::Environment::get().getWorld()->getStore().get<ESM::GameSetting>().find("fWortChanceValue")->mValue.getFloat();
|
MWBase::Environment::get().getWorld()->getStore().get<ESM::GameSetting>().find("fWortChanceValue")->mValue.getFloat();
|
||||||
return (potionEffectIndex <= 1 && alchemySkill >= fWortChanceValue)
|
return (potionEffectIndex <= 1 && alchemySkill >= fWortChanceValue)
|
||||||
|
|
|
@ -2319,7 +2319,7 @@ void CharacterController::update(float duration, bool animationOnly)
|
||||||
cls.onHit(mPtr, realHealthLost, true, MWWorld::Ptr(), MWWorld::Ptr(), osg::Vec3f(), true);
|
cls.onHit(mPtr, realHealthLost, true, MWWorld::Ptr(), MWWorld::Ptr(), osg::Vec3f(), true);
|
||||||
}
|
}
|
||||||
|
|
||||||
const int acrobaticsSkill = cls.getSkill(mPtr, ESM::Skill::Acrobatics);
|
const float acrobaticsSkill = cls.getSkill(mPtr, ESM::Skill::Acrobatics);
|
||||||
if (healthLost > (acrobaticsSkill * fatigueTerm))
|
if (healthLost > (acrobaticsSkill * fatigueTerm))
|
||||||
{
|
{
|
||||||
if (!godmode)
|
if (!godmode)
|
||||||
|
|
|
@ -116,7 +116,7 @@ namespace MWMechanics
|
||||||
blockerTerm *= gmst.find("fBlockStillBonus")->mValue.getFloat();
|
blockerTerm *= gmst.find("fBlockStillBonus")->mValue.getFloat();
|
||||||
blockerTerm *= blockerStats.getFatigueTerm();
|
blockerTerm *= blockerStats.getFatigueTerm();
|
||||||
|
|
||||||
int attackerSkill = 0;
|
float attackerSkill = 0;
|
||||||
if (weapon.isEmpty())
|
if (weapon.isEmpty())
|
||||||
attackerSkill = attacker.getClass().getSkill(attacker, ESM::Skill::HandToHand);
|
attackerSkill = attacker.getClass().getSkill(attacker, ESM::Skill::HandToHand);
|
||||||
else
|
else
|
||||||
|
|
|
@ -137,7 +137,7 @@ namespace MWMechanics
|
||||||
return mMagicEffects;
|
return mMagicEffects;
|
||||||
}
|
}
|
||||||
|
|
||||||
void CreatureStats::setAttribute(int index, int base)
|
void CreatureStats::setAttribute(int index, float base)
|
||||||
{
|
{
|
||||||
AttributeValue current = getAttribute(index);
|
AttributeValue current = getAttribute(index);
|
||||||
current.setBase(base);
|
current.setBase(base);
|
||||||
|
@ -163,10 +163,10 @@ namespace MWMechanics
|
||||||
index == ESM::Attribute::Agility ||
|
index == ESM::Attribute::Agility ||
|
||||||
index == ESM::Attribute::Endurance)
|
index == ESM::Attribute::Endurance)
|
||||||
{
|
{
|
||||||
int strength = getAttribute(ESM::Attribute::Strength).getModified();
|
float strength = getAttribute(ESM::Attribute::Strength).getModified();
|
||||||
int willpower = getAttribute(ESM::Attribute::Willpower).getModified();
|
float willpower = getAttribute(ESM::Attribute::Willpower).getModified();
|
||||||
int agility = getAttribute(ESM::Attribute::Agility).getModified();
|
float agility = getAttribute(ESM::Attribute::Agility).getModified();
|
||||||
int endurance = getAttribute(ESM::Attribute::Endurance).getModified();
|
float endurance = getAttribute(ESM::Attribute::Endurance).getModified();
|
||||||
DynamicStat<float> fatigue = getFatigue();
|
DynamicStat<float> fatigue = getFatigue();
|
||||||
float diff = (strength+willpower+agility+endurance) - fatigue.getBase();
|
float diff = (strength+willpower+agility+endurance) - fatigue.getBase();
|
||||||
float currentToBaseRatio = fatigue.getBase() > 0 ? (fatigue.getCurrent() / fatigue.getBase()) : 0;
|
float currentToBaseRatio = fatigue.getBase() > 0 ? (fatigue.getCurrent() / fatigue.getBase()) : 0;
|
||||||
|
@ -575,6 +575,14 @@ namespace MWMechanics
|
||||||
state.mHasAiSettings = true;
|
state.mHasAiSettings = true;
|
||||||
for (int i=0; i<4; ++i)
|
for (int i=0; i<4; ++i)
|
||||||
mAiSettings[i].writeState (state.mAiSettings[i]);
|
mAiSettings[i].writeState (state.mAiSettings[i]);
|
||||||
|
|
||||||
|
for (auto it = mCorprusSpells.begin(); it != mCorprusSpells.end(); ++it)
|
||||||
|
{
|
||||||
|
for (int i=0; i<ESM::Attribute::Length; ++i)
|
||||||
|
state.mCorprusSpells[it->first].mWorsenings[i] = mCorprusSpells.at(it->first).mWorsenings[i];
|
||||||
|
|
||||||
|
state.mCorprusSpells[it->first].mNextWorsening = mCorprusSpells.at(it->first).mNextWorsening.toEsm();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void CreatureStats::readState (const ESM::CreatureStats& state)
|
void CreatureStats::readState (const ESM::CreatureStats& state)
|
||||||
|
@ -613,7 +621,7 @@ namespace MWMechanics
|
||||||
mTimeOfDeath = MWWorld::TimeStamp(state.mTimeOfDeath);
|
mTimeOfDeath = MWWorld::TimeStamp(state.mTimeOfDeath);
|
||||||
//mHitAttemptActorId = state.mHitAttemptActorId;
|
//mHitAttemptActorId = state.mHitAttemptActorId;
|
||||||
|
|
||||||
mSpells.readState(state.mSpells);
|
mSpells.readState(state.mSpells, this);
|
||||||
mActiveSpells.readState(state.mActiveSpells);
|
mActiveSpells.readState(state.mActiveSpells);
|
||||||
mAiSequence.readState(state.mAiSequence);
|
mAiSequence.readState(state.mAiSequence);
|
||||||
mMagicEffects.readState(state.mMagicEffects);
|
mMagicEffects.readState(state.mMagicEffects);
|
||||||
|
@ -624,6 +632,15 @@ namespace MWMechanics
|
||||||
if (state.mHasAiSettings)
|
if (state.mHasAiSettings)
|
||||||
for (int i=0; i<4; ++i)
|
for (int i=0; i<4; ++i)
|
||||||
mAiSettings[i].readState(state.mAiSettings[i]);
|
mAiSettings[i].readState(state.mAiSettings[i]);
|
||||||
|
|
||||||
|
mCorprusSpells.clear();
|
||||||
|
for (auto it = state.mCorprusSpells.begin(); it != state.mCorprusSpells.end(); ++it)
|
||||||
|
{
|
||||||
|
for (int i=0; i<ESM::Attribute::Length; ++i)
|
||||||
|
mCorprusSpells[it->first].mWorsenings[i] = state.mCorprusSpells.at(it->first).mWorsenings[i];
|
||||||
|
|
||||||
|
mCorprusSpells[it->first].mNextWorsening = MWWorld::TimeStamp(state.mCorprusSpells.at(it->first).mNextWorsening);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void CreatureStats::setLastRestockTime(MWWorld::TimeStamp tradeTime)
|
void CreatureStats::setLastRestockTime(MWWorld::TimeStamp tradeTime)
|
||||||
|
@ -722,4 +739,23 @@ namespace MWMechanics
|
||||||
/*
|
/*
|
||||||
End of tes3mp addition
|
End of tes3mp addition
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
std::map<std::string, CorprusStats> &CreatureStats::getCorprusSpells()
|
||||||
|
{
|
||||||
|
return mCorprusSpells;
|
||||||
|
}
|
||||||
|
|
||||||
|
void CreatureStats::addCorprusSpell(const std::string& sourceId, CorprusStats& stats)
|
||||||
|
{
|
||||||
|
mCorprusSpells[sourceId] = stats;
|
||||||
|
}
|
||||||
|
|
||||||
|
void CreatureStats::removeCorprusSpell(const std::string& sourceId)
|
||||||
|
{
|
||||||
|
auto corprusIt = mCorprusSpells.find(sourceId);
|
||||||
|
if (corprusIt != mCorprusSpells.end())
|
||||||
|
{
|
||||||
|
mCorprusSpells.erase(corprusIt);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -12,6 +12,8 @@
|
||||||
#include "aisequence.hpp"
|
#include "aisequence.hpp"
|
||||||
#include "drawstate.hpp"
|
#include "drawstate.hpp"
|
||||||
|
|
||||||
|
#include <components/esm/attr.hpp>
|
||||||
|
|
||||||
namespace ESM
|
namespace ESM
|
||||||
{
|
{
|
||||||
struct CreatureStats;
|
struct CreatureStats;
|
||||||
|
@ -19,6 +21,14 @@ namespace ESM
|
||||||
|
|
||||||
namespace MWMechanics
|
namespace MWMechanics
|
||||||
{
|
{
|
||||||
|
struct CorprusStats
|
||||||
|
{
|
||||||
|
static const int sWorseningPeriod = 24;
|
||||||
|
|
||||||
|
int mWorsenings[ESM::Attribute::Length];
|
||||||
|
MWWorld::TimeStamp mNextWorsening;
|
||||||
|
};
|
||||||
|
|
||||||
/// \brief Common creature stats
|
/// \brief Common creature stats
|
||||||
///
|
///
|
||||||
///
|
///
|
||||||
|
@ -26,7 +36,7 @@ namespace MWMechanics
|
||||||
{
|
{
|
||||||
static int sActorId;
|
static int sActorId;
|
||||||
DrawState_ mDrawState;
|
DrawState_ mDrawState;
|
||||||
AttributeValue mAttributes[8];
|
AttributeValue mAttributes[ESM::Attribute::Length];
|
||||||
DynamicStat<float> mDynamic[3]; // health, magicka, fatigue
|
DynamicStat<float> mDynamic[3]; // health, magicka, fatigue
|
||||||
Spells mSpells;
|
Spells mSpells;
|
||||||
ActiveSpells mActiveSpells;
|
ActiveSpells mActiveSpells;
|
||||||
|
@ -79,6 +89,8 @@ namespace MWMechanics
|
||||||
// This may be necessary when the creature is in an inactive cell.
|
// This may be necessary when the creature is in an inactive cell.
|
||||||
std::vector<int> mSummonGraveyard;
|
std::vector<int> mSummonGraveyard;
|
||||||
|
|
||||||
|
std::map<std::string, CorprusStats> mCorprusSpells;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
int mLevel;
|
int mLevel;
|
||||||
|
|
||||||
|
@ -126,7 +138,7 @@ namespace MWMechanics
|
||||||
|
|
||||||
void setAttribute(int index, const AttributeValue &value);
|
void setAttribute(int index, const AttributeValue &value);
|
||||||
// Shortcut to set only the base
|
// Shortcut to set only the base
|
||||||
void setAttribute(int index, int base);
|
void setAttribute(int index, float base);
|
||||||
|
|
||||||
void setHealth(const DynamicStat<float> &value);
|
void setHealth(const DynamicStat<float> &value);
|
||||||
|
|
||||||
|
@ -301,6 +313,12 @@ namespace MWMechanics
|
||||||
/// assigned this function will return false).
|
/// assigned this function will return false).
|
||||||
|
|
||||||
static void cleanup();
|
static void cleanup();
|
||||||
|
|
||||||
|
std::map<std::string, CorprusStats> & getCorprusSpells();
|
||||||
|
|
||||||
|
void addCorprusSpell(const std::string& sourceId, CorprusStats& stats);
|
||||||
|
|
||||||
|
void removeCorprusSpell(const std::string& sourceId);
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -303,6 +303,24 @@ namespace MWMechanics
|
||||||
mWatched = ptr;
|
mWatched = ptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void MechanicsManager::restoreStatsAfterCorprus(const MWWorld::Ptr& actor, const std::string& sourceId)
|
||||||
|
{
|
||||||
|
auto& stats = actor.getClass().getCreatureStats (actor);
|
||||||
|
auto& corprusSpells = stats.getCorprusSpells();
|
||||||
|
|
||||||
|
auto corprusIt = corprusSpells.find(sourceId);
|
||||||
|
|
||||||
|
if (corprusIt != corprusSpells.end())
|
||||||
|
{
|
||||||
|
for (int i = 0; i < ESM::Attribute::Length; ++i)
|
||||||
|
{
|
||||||
|
MWMechanics::AttributeValue attr = stats.getAttribute(i);
|
||||||
|
attr.restore(corprusIt->second.mWorsenings[i]);
|
||||||
|
actor.getClass().getCreatureStats(actor).setAttribute(i, attr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void MechanicsManager::update(float duration, bool paused)
|
void MechanicsManager::update(float duration, bool paused)
|
||||||
{
|
{
|
||||||
if(!mWatched.isEmpty())
|
if(!mWatched.isEmpty())
|
||||||
|
@ -684,10 +702,10 @@ namespace MWMechanics
|
||||||
// I suppose the temporary disposition change (second param to getDerivedDisposition()) _has_ to be considered here,
|
// I suppose the temporary disposition change (second param to getDerivedDisposition()) _has_ to be considered here,
|
||||||
// otherwise one would get different prices when exiting and re-entering the dialogue window...
|
// otherwise one would get different prices when exiting and re-entering the dialogue window...
|
||||||
int clampedDisposition = getDerivedDisposition(ptr);
|
int clampedDisposition = getDerivedDisposition(ptr);
|
||||||
float a = static_cast<float>(std::min(playerPtr.getClass().getSkill(playerPtr, ESM::Skill::Mercantile), 100));
|
float a = std::min(playerPtr.getClass().getSkill(playerPtr, ESM::Skill::Mercantile), 100.f);
|
||||||
float b = std::min(0.1f * playerStats.getAttribute(ESM::Attribute::Luck).getModified(), 10.f);
|
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);
|
float c = std::min(0.2f * playerStats.getAttribute(ESM::Attribute::Personality).getModified(), 10.f);
|
||||||
float d = static_cast<float>(std::min(ptr.getClass().getSkill(ptr, ESM::Skill::Mercantile), 100));
|
float d = std::min(ptr.getClass().getSkill(ptr, ESM::Skill::Mercantile), 100.f);
|
||||||
float e = std::min(0.1f * sellerStats.getAttribute(ESM::Attribute::Luck).getModified(), 10.f);
|
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);
|
float f = std::min(0.2f * sellerStats.getAttribute(ESM::Attribute::Personality).getModified(), 10.f);
|
||||||
float pcTerm = (clampedDisposition - 50 + a + b + c) * playerStats.getFatigueTerm();
|
float pcTerm = (clampedDisposition - 50 + a + b + c) * playerStats.getFatigueTerm();
|
||||||
|
@ -1262,7 +1280,7 @@ namespace MWMechanics
|
||||||
|
|
||||||
if (!Misc::StringUtils::ciEqual(item.getCellRef().getRefId(), MWWorld::ContainerStore::sGoldId))
|
if (!Misc::StringUtils::ciEqual(item.getCellRef().getRefId(), MWWorld::ContainerStore::sGoldId))
|
||||||
{
|
{
|
||||||
if (victim.isEmpty() || (victim.getClass().isActor() && !victim.getClass().getCreatureStats(victim).isDead()))
|
if (victim.isEmpty() || (victim.getClass().isActor() && victim.getRefData().getCount() > 0 && !victim.getClass().getCreatureStats(victim).isDead()))
|
||||||
mStolenItems[Misc::StringUtils::lowerCase(item.getCellRef().getRefId())][owner] += count;
|
mStolenItems[Misc::StringUtils::lowerCase(item.getCellRef().getRefId())][owner] += count;
|
||||||
}
|
}
|
||||||
if (alarm)
|
if (alarm)
|
||||||
|
@ -1743,8 +1761,8 @@ namespace MWMechanics
|
||||||
static float fSneakSkillMult = store.find("fSneakSkillMult")->mValue.getFloat();
|
static float fSneakSkillMult = store.find("fSneakSkillMult")->mValue.getFloat();
|
||||||
static float fSneakBootMult = store.find("fSneakBootMult")->mValue.getFloat();
|
static float fSneakBootMult = store.find("fSneakBootMult")->mValue.getFloat();
|
||||||
float sneak = static_cast<float>(ptr.getClass().getSkill(ptr, ESM::Skill::Sneak));
|
float sneak = static_cast<float>(ptr.getClass().getSkill(ptr, ESM::Skill::Sneak));
|
||||||
int agility = stats.getAttribute(ESM::Attribute::Agility).getModified();
|
float agility = stats.getAttribute(ESM::Attribute::Agility).getModified();
|
||||||
int luck = stats.getAttribute(ESM::Attribute::Luck).getModified();
|
float luck = stats.getAttribute(ESM::Attribute::Luck).getModified();
|
||||||
float bootWeight = 0;
|
float bootWeight = 0;
|
||||||
if (ptr.getClass().isNpc() && MWBase::Environment::get().getWorld()->isOnGround(ptr))
|
if (ptr.getClass().isNpc() && MWBase::Environment::get().getWorld()->isOnGround(ptr))
|
||||||
{
|
{
|
||||||
|
@ -1767,10 +1785,10 @@ namespace MWMechanics
|
||||||
float x = sneakTerm * distTerm * stats.getFatigueTerm() + chameleon + invisibility;
|
float x = sneakTerm * distTerm * stats.getFatigueTerm() + chameleon + invisibility;
|
||||||
|
|
||||||
CreatureStats& observerStats = observer.getClass().getCreatureStats(observer);
|
CreatureStats& observerStats = observer.getClass().getCreatureStats(observer);
|
||||||
int obsAgility = observerStats.getAttribute(ESM::Attribute::Agility).getModified();
|
float obsAgility = observerStats.getAttribute(ESM::Attribute::Agility).getModified();
|
||||||
int obsLuck = observerStats.getAttribute(ESM::Attribute::Luck).getModified();
|
float obsLuck = observerStats.getAttribute(ESM::Attribute::Luck).getModified();
|
||||||
float obsBlind = observerStats.getMagicEffects().get(ESM::MagicEffect::Blind).getMagnitude();
|
float obsBlind = observerStats.getMagicEffects().get(ESM::MagicEffect::Blind).getMagnitude();
|
||||||
int obsSneak = observer.getClass().getSkill(observer, ESM::Skill::Sneak);
|
float obsSneak = observer.getClass().getSkill(observer, ESM::Skill::Sneak);
|
||||||
|
|
||||||
float obsTerm = obsSneak + 0.2f * obsAgility + 0.1f * obsLuck - obsBlind;
|
float obsTerm = obsSneak + 0.2f * obsAgility + 0.1f * obsLuck - obsBlind;
|
||||||
|
|
||||||
|
|
|
@ -277,6 +277,8 @@ namespace MWMechanics
|
||||||
virtual GreetingState getGreetingState(const MWWorld::Ptr& ptr) const override;
|
virtual GreetingState getGreetingState(const MWWorld::Ptr& ptr) const override;
|
||||||
virtual bool isTurningToPlayer(const MWWorld::Ptr& ptr) const override;
|
virtual bool isTurningToPlayer(const MWWorld::Ptr& ptr) const override;
|
||||||
|
|
||||||
|
virtual void restoreStatsAfterCorprus(const MWWorld::Ptr& actor, const std::string& sourceId) override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
bool canCommitCrimeAgainst(const MWWorld::Ptr& victim, const MWWorld::Ptr& attacker);
|
bool canCommitCrimeAgainst(const MWWorld::Ptr& victim, const MWWorld::Ptr& attacker);
|
||||||
bool canReportCrime(const MWWorld::Ptr &actor, const MWWorld::Ptr &victim, std::set<MWWorld::Ptr> &playerFollowers);
|
bool canReportCrime(const MWWorld::Ptr &actor, const MWWorld::Ptr &victim, std::set<MWWorld::Ptr> &playerFollowers);
|
||||||
|
|
|
@ -226,9 +226,9 @@ void MWMechanics::NpcStats::useSkill (int skillIndex, const ESM::Class& class_,
|
||||||
|
|
||||||
void MWMechanics::NpcStats::increaseSkill(int skillIndex, const ESM::Class &class_, bool preserveProgress, bool readBook)
|
void MWMechanics::NpcStats::increaseSkill(int skillIndex, const ESM::Class &class_, bool preserveProgress, bool readBook)
|
||||||
{
|
{
|
||||||
int base = getSkill (skillIndex).getBase();
|
float base = getSkill (skillIndex).getBase();
|
||||||
|
|
||||||
if (base >= 100)
|
if (base >= 100.f)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
base += 1;
|
base += 1;
|
||||||
|
@ -265,7 +265,7 @@ void MWMechanics::NpcStats::increaseSkill(int skillIndex, const ESM::Class &clas
|
||||||
MWBase::Environment::get().getWindowManager()->playSound("skillraise");
|
MWBase::Environment::get().getWindowManager()->playSound("skillraise");
|
||||||
|
|
||||||
std::string message = MWBase::Environment::get().getWindowManager ()->getGameSettingString ("sNotifyMessage39", "");
|
std::string message = MWBase::Environment::get().getWindowManager ()->getGameSettingString ("sNotifyMessage39", "");
|
||||||
message = Misc::StringUtils::format(message, ("#{" + ESM::Skill::sSkillNameIds[skillIndex] + "}"), base);
|
message = Misc::StringUtils::format(message, ("#{" + ESM::Skill::sSkillNameIds[skillIndex] + "}"), static_cast<int>(base));
|
||||||
|
|
||||||
if (readBook)
|
if (readBook)
|
||||||
message = "#{sBookSkillMessage}\n" + message;
|
message = "#{sBookSkillMessage}\n" + message;
|
||||||
|
@ -360,7 +360,7 @@ void MWMechanics::NpcStats::levelUp()
|
||||||
for (int i=0; i<ESM::Attribute::Length; ++i)
|
for (int i=0; i<ESM::Attribute::Length; ++i)
|
||||||
mSkillIncreases[i] = 0;
|
mSkillIncreases[i] = 0;
|
||||||
|
|
||||||
const int endurance = getAttribute(ESM::Attribute::Endurance).getBase();
|
const float endurance = getAttribute(ESM::Attribute::Endurance).getBase();
|
||||||
|
|
||||||
// "When you gain a level, in addition to increasing three primary attributes, your Health
|
// "When you gain a level, in addition to increasing three primary attributes, your Health
|
||||||
// will automatically increase by 10% of your Endurance attribute. If you increased Endurance this level,
|
// will automatically increase by 10% of your Endurance attribute. If you increased Endurance this level,
|
||||||
|
@ -377,8 +377,8 @@ void MWMechanics::NpcStats::levelUp()
|
||||||
|
|
||||||
void MWMechanics::NpcStats::updateHealth()
|
void MWMechanics::NpcStats::updateHealth()
|
||||||
{
|
{
|
||||||
const int endurance = getAttribute(ESM::Attribute::Endurance).getBase();
|
const float endurance = getAttribute(ESM::Attribute::Endurance).getBase();
|
||||||
const int strength = getAttribute(ESM::Attribute::Strength).getBase();
|
const float strength = getAttribute(ESM::Attribute::Strength).getBase();
|
||||||
|
|
||||||
setHealth(floor(0.5f * (strength + endurance)));
|
setHealth(floor(0.5f * (strength + endurance)));
|
||||||
}
|
}
|
||||||
|
|
|
@ -22,8 +22,8 @@ namespace MWMechanics
|
||||||
float Pickpocket::getChanceModifier(const MWWorld::Ptr &ptr, float add)
|
float Pickpocket::getChanceModifier(const MWWorld::Ptr &ptr, float add)
|
||||||
{
|
{
|
||||||
NpcStats& stats = ptr.getClass().getNpcStats(ptr);
|
NpcStats& stats = ptr.getClass().getNpcStats(ptr);
|
||||||
float agility = static_cast<float>(stats.getAttribute(ESM::Attribute::Agility).getModified());
|
float agility = stats.getAttribute(ESM::Attribute::Agility).getModified();
|
||||||
float luck = static_cast<float>(stats.getAttribute(ESM::Attribute::Luck).getModified());
|
float luck = stats.getAttribute(ESM::Attribute::Luck).getModified();
|
||||||
float sneak = static_cast<float>(ptr.getClass().getSkill(ptr, ESM::Skill::Sneak));
|
float sneak = static_cast<float>(ptr.getClass().getSkill(ptr, ESM::Skill::Sneak));
|
||||||
return (add + 0.2f * agility + 0.1f * luck + sneak) * stats.getFatigueTerm();
|
return (add + 0.2f * agility + 0.1f * luck + sneak) * stats.getFatigueTerm();
|
||||||
}
|
}
|
||||||
|
|
|
@ -45,9 +45,9 @@ void Repair::repair(const MWWorld::Ptr &itemToRepair)
|
||||||
MWMechanics::CreatureStats& stats = player.getClass().getCreatureStats(player);
|
MWMechanics::CreatureStats& stats = player.getClass().getCreatureStats(player);
|
||||||
|
|
||||||
float fatigueTerm = stats.getFatigueTerm();
|
float fatigueTerm = stats.getFatigueTerm();
|
||||||
int pcStrength = stats.getAttribute(ESM::Attribute::Strength).getModified();
|
float pcStrength = stats.getAttribute(ESM::Attribute::Strength).getModified();
|
||||||
int pcLuck = stats.getAttribute(ESM::Attribute::Luck).getModified();
|
float pcLuck = stats.getAttribute(ESM::Attribute::Luck).getModified();
|
||||||
int armorerSkill = player.getClass().getSkill(player, ESM::Skill::Armorer);
|
float armorerSkill = player.getClass().getSkill(player, ESM::Skill::Armorer);
|
||||||
|
|
||||||
float fRepairAmountMult = MWBase::Environment::get().getWorld()->getStore().get<ESM::GameSetting>()
|
float fRepairAmountMult = MWBase::Environment::get().getWorld()->getStore().get<ESM::GameSetting>()
|
||||||
.find("fRepairAmountMult")->mValue.getFloat();
|
.find("fRepairAmountMult")->mValue.getFloat();
|
||||||
|
|
|
@ -33,8 +33,8 @@ namespace MWMechanics
|
||||||
: mActor(actor)
|
: mActor(actor)
|
||||||
{
|
{
|
||||||
CreatureStats& creatureStats = actor.getClass().getCreatureStats(actor);
|
CreatureStats& creatureStats = actor.getClass().getCreatureStats(actor);
|
||||||
mAgility = static_cast<float>(creatureStats.getAttribute(ESM::Attribute::Agility).getModified());
|
mAgility = creatureStats.getAttribute(ESM::Attribute::Agility).getModified();
|
||||||
mLuck = static_cast<float>(creatureStats.getAttribute(ESM::Attribute::Luck).getModified());
|
mLuck = creatureStats.getAttribute(ESM::Attribute::Luck).getModified();
|
||||||
mSecuritySkill = static_cast<float>(actor.getClass().getSkill(actor, ESM::Skill::Security));
|
mSecuritySkill = static_cast<float>(actor.getClass().getSkill(actor, ESM::Skill::Security));
|
||||||
mFatigueTerm = creatureStats.getFatigueTerm();
|
mFatigueTerm = creatureStats.getFatigueTerm();
|
||||||
}
|
}
|
||||||
|
|
|
@ -77,8 +77,13 @@ namespace MWMechanics
|
||||||
void CastSpell::inflict(const MWWorld::Ptr &target, const MWWorld::Ptr &caster,
|
void CastSpell::inflict(const MWWorld::Ptr &target, const MWWorld::Ptr &caster,
|
||||||
const ESM::EffectList &effects, ESM::RangeType range, bool reflected, bool exploded)
|
const ESM::EffectList &effects, ESM::RangeType range, bool reflected, bool exploded)
|
||||||
{
|
{
|
||||||
if (!target.isEmpty() && target.getClass().isActor() && target.getClass().getCreatureStats(target).isDead())
|
if (!target.isEmpty() && target.getClass().isActor())
|
||||||
|
{
|
||||||
|
// Early-out for characters that have departed.
|
||||||
|
const auto& stats = target.getClass().getCreatureStats(target);
|
||||||
|
if (stats.isDead() && stats.isDeathAnimationFinished())
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
// If none of the effects need to apply, we can early-out
|
// If none of the effects need to apply, we can early-out
|
||||||
bool found = false;
|
bool found = false;
|
||||||
|
@ -218,9 +223,9 @@ namespace MWMechanics
|
||||||
}
|
}
|
||||||
|
|
||||||
bool effectAffectsHealth = isHarmful || effectIt->mEffectID == ESM::MagicEffect::RestoreHealth;
|
bool effectAffectsHealth = isHarmful || effectIt->mEffectID == ESM::MagicEffect::RestoreHealth;
|
||||||
if (castByPlayer && target != caster && effectAffectsHealth)
|
if (castByPlayer && target != caster && !target.getClass().getCreatureStats(target).isDead() && effectAffectsHealth)
|
||||||
{
|
{
|
||||||
// If player is attempting to cast a harmful spell or is healing someone, show the target's HP bar.
|
// If player is attempting to cast a harmful spell on or is healing a living target, show the target's HP bar.
|
||||||
MWBase::Environment::get().getWindowManager()->setEnemy(target);
|
MWBase::Environment::get().getWindowManager()->setEnemy(target);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -40,8 +40,8 @@ namespace MWMechanics
|
||||||
|
|
||||||
float resistance = getEffectResistanceAttribute(effectId, magicEffects);
|
float resistance = getEffectResistanceAttribute(effectId, magicEffects);
|
||||||
|
|
||||||
int willpower = stats.getAttribute(ESM::Attribute::Willpower).getModified();
|
float willpower = stats.getAttribute(ESM::Attribute::Willpower).getModified();
|
||||||
float luck = static_cast<float>(stats.getAttribute(ESM::Attribute::Luck).getModified());
|
float luck = stats.getAttribute(ESM::Attribute::Luck).getModified();
|
||||||
float x = (willpower + 0.1f * luck) * stats.getFatigueTerm();
|
float x = (willpower + 0.1f * luck) * stats.getFatigueTerm();
|
||||||
|
|
||||||
// This makes spells that are easy to cast harder to resist and vice versa
|
// This makes spells that are easy to cast harder to resist and vice versa
|
||||||
|
|
|
@ -18,9 +18,13 @@
|
||||||
#include "../mwbase/environment.hpp"
|
#include "../mwbase/environment.hpp"
|
||||||
#include "../mwbase/world.hpp"
|
#include "../mwbase/world.hpp"
|
||||||
|
|
||||||
|
#include "../mwworld/class.hpp"
|
||||||
#include "../mwworld/esmstore.hpp"
|
#include "../mwworld/esmstore.hpp"
|
||||||
|
|
||||||
|
#include "actorutil.hpp"
|
||||||
|
#include "creaturestats.hpp"
|
||||||
#include "magiceffects.hpp"
|
#include "magiceffects.hpp"
|
||||||
|
#include "stat.hpp"
|
||||||
|
|
||||||
namespace MWMechanics
|
namespace MWMechanics
|
||||||
{
|
{
|
||||||
|
@ -74,12 +78,6 @@ namespace MWMechanics
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for (std::map<SpellKey, MagicEffects>::const_iterator it = mPermanentSpellEffects.begin(); it != mPermanentSpellEffects.end(); ++it)
|
|
||||||
{
|
|
||||||
mEffects += it->second;
|
|
||||||
mSourcedEffects[it->first] += it->second;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Spells::hasSpell(const std::string &spell) const
|
bool Spells::hasSpell(const std::string &spell) const
|
||||||
|
@ -112,15 +110,6 @@ namespace MWMechanics
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (hasCorprusEffect(spell))
|
|
||||||
{
|
|
||||||
CorprusStats corprus;
|
|
||||||
corprus.mWorsenings = 0;
|
|
||||||
corprus.mNextWorsening = MWBase::Environment::get().getWorld()->getTimeStamp() + CorprusStats::sWorseningPeriod;
|
|
||||||
|
|
||||||
mCorprusSpells[spell] = corprus;
|
|
||||||
}
|
|
||||||
|
|
||||||
SpellParams params;
|
SpellParams params;
|
||||||
params.mEffectRands = random;
|
params.mEffectRands = random;
|
||||||
mSpells.insert (std::make_pair (spell, params));
|
mSpells.insert (std::make_pair (spell, params));
|
||||||
|
@ -138,27 +127,6 @@ namespace MWMechanics
|
||||||
const ESM::Spell* spell = getSpell(spellId);
|
const ESM::Spell* spell = getSpell(spellId);
|
||||||
TContainer::iterator iter = mSpells.find (spell);
|
TContainer::iterator iter = mSpells.find (spell);
|
||||||
|
|
||||||
std::map<SpellKey, CorprusStats>::iterator corprusIt = mCorprusSpells.find(spell);
|
|
||||||
|
|
||||||
// if it's corprus, remove negative and keep positive effects
|
|
||||||
if (corprusIt != mCorprusSpells.end())
|
|
||||||
{
|
|
||||||
worsenCorprus(spell);
|
|
||||||
if (mPermanentSpellEffects.find(spell) != mPermanentSpellEffects.end())
|
|
||||||
{
|
|
||||||
MagicEffects & effects = mPermanentSpellEffects[spell];
|
|
||||||
for (MagicEffects::Collection::const_iterator effectIt = effects.begin(); effectIt != effects.end();)
|
|
||||||
{
|
|
||||||
const ESM::MagicEffect * magicEffect = MWBase::Environment::get().getWorld()->getStore().get<ESM::MagicEffect>().find(effectIt->first.mId);
|
|
||||||
if (magicEffect->mData.mFlags & ESM::MagicEffect::Harmful)
|
|
||||||
effects.remove((effectIt++)->first);
|
|
||||||
else
|
|
||||||
++effectIt;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
mCorprusSpells.erase(corprusIt);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (iter!=mSpells.end())
|
if (iter!=mSpells.end())
|
||||||
{
|
{
|
||||||
mSpells.erase (iter);
|
mSpells.erase (iter);
|
||||||
|
@ -371,31 +339,6 @@ namespace MWMechanics
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Spells::worsenCorprus(const ESM::Spell* spell)
|
|
||||||
{
|
|
||||||
mCorprusSpells[spell].mNextWorsening = MWBase::Environment::get().getWorld()->getTimeStamp() + CorprusStats::sWorseningPeriod;
|
|
||||||
mCorprusSpells[spell].mWorsenings++;
|
|
||||||
|
|
||||||
// update worsened effects
|
|
||||||
mPermanentSpellEffects[spell] = MagicEffects();
|
|
||||||
int i=0;
|
|
||||||
for (std::vector<ESM::ENAMstruct>::const_iterator effectIt = spell->mEffects.mList.begin(); effectIt != spell->mEffects.mList.end(); ++effectIt, ++i)
|
|
||||||
{
|
|
||||||
const ESM::MagicEffect * magicEffect = MWBase::Environment::get().getWorld()->getStore().get<ESM::MagicEffect>().find(effectIt->mEffectID);
|
|
||||||
if ((effectIt->mEffectID != ESM::MagicEffect::Corprus) && (magicEffect->mData.mFlags & ESM::MagicEffect::AppliedOnce))
|
|
||||||
{
|
|
||||||
float random = 1.f;
|
|
||||||
if (mSpells[spell].mEffectRands.find(i) != mSpells[spell].mEffectRands.end())
|
|
||||||
random = mSpells[spell].mEffectRands.at(i);
|
|
||||||
|
|
||||||
float magnitude = effectIt->mMagnMin + (effectIt->mMagnMax - effectIt->mMagnMin) * random;
|
|
||||||
magnitude *= std::max(1, mCorprusSpells[spell].mWorsenings);
|
|
||||||
mPermanentSpellEffects[spell].add(MWMechanics::EffectKey(*effectIt), MWMechanics::EffectParam(magnitude));
|
|
||||||
mSpellsChanged = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
bool Spells::hasCorprusEffect(const ESM::Spell *spell)
|
bool Spells::hasCorprusEffect(const ESM::Spell *spell)
|
||||||
{
|
{
|
||||||
for (std::vector<ESM::ENAMstruct>::const_iterator effectIt = spell->mEffects.mList.begin(); effectIt != spell->mEffects.mList.end(); ++effectIt)
|
for (std::vector<ESM::ENAMstruct>::const_iterator effectIt = spell->mEffects.mList.begin(); effectIt != spell->mEffects.mList.end(); ++effectIt)
|
||||||
|
@ -408,11 +351,6 @@ namespace MWMechanics
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
const std::map<Spells::SpellKey, Spells::CorprusStats> &Spells::getCorprusSpells() const
|
|
||||||
{
|
|
||||||
return mCorprusSpells;
|
|
||||||
}
|
|
||||||
|
|
||||||
void Spells::purgeEffect(int effectId)
|
void Spells::purgeEffect(int effectId)
|
||||||
{
|
{
|
||||||
for (TContainer::iterator spellIt = mSpells.begin(); spellIt != mSpells.end(); ++spellIt)
|
for (TContainer::iterator spellIt = mSpells.begin(); spellIt != mSpells.end(); ++spellIt)
|
||||||
|
@ -463,7 +401,7 @@ namespace MWMechanics
|
||||||
mUsedPowers[spell] = MWBase::Environment::get().getWorld()->getTimeStamp();
|
mUsedPowers[spell] = MWBase::Environment::get().getWorld()->getTimeStamp();
|
||||||
}
|
}
|
||||||
|
|
||||||
void Spells::readState(const ESM::SpellState &state)
|
void Spells::readState(const ESM::SpellState &state, CreatureStats* creatureStats)
|
||||||
{
|
{
|
||||||
for (ESM::SpellState::TContainer::const_iterator it = state.mSpells.begin(); it != state.mSpells.end(); ++it)
|
for (ESM::SpellState::TContainer::const_iterator it = state.mSpells.begin(); it != state.mSpells.end(); ++it)
|
||||||
{
|
{
|
||||||
|
@ -487,6 +425,32 @@ namespace MWMechanics
|
||||||
mUsedPowers[spell] = MWWorld::TimeStamp(it->second);
|
mUsedPowers[spell] = MWWorld::TimeStamp(it->second);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
for (std::map<std::string, ESM::SpellState::CorprusStats>::const_iterator it = state.mCorprusSpells.begin(); it != state.mCorprusSpells.end(); ++it)
|
||||||
|
{
|
||||||
|
const ESM::Spell * spell = MWBase::Environment::get().getWorld()->getStore().get<ESM::Spell>().search(it->first);
|
||||||
|
if (!spell)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
CorprusStats stats;
|
||||||
|
|
||||||
|
int worsening = state.mCorprusSpells.at(it->first).mWorsenings;
|
||||||
|
|
||||||
|
for (int i=0; i<ESM::Attribute::Length; ++i)
|
||||||
|
stats.mWorsenings[i] = 0;
|
||||||
|
|
||||||
|
for (auto& effect : spell->mEffects.mList)
|
||||||
|
{
|
||||||
|
if (effect.mEffectID == ESM::MagicEffect::DrainAttribute)
|
||||||
|
stats.mWorsenings[effect.mAttribute] = worsening;
|
||||||
|
}
|
||||||
|
stats.mNextWorsening = MWWorld::TimeStamp(state.mCorprusSpells.at(it->first).mNextWorsening);
|
||||||
|
|
||||||
|
creatureStats->addCorprusSpell(it->first, stats);
|
||||||
|
}
|
||||||
|
|
||||||
|
mSpellsChanged = true;
|
||||||
|
|
||||||
|
// Permanent effects are used only to keep the custom magnitude of corprus spells effects (after cure too), and only in old saves. Convert data to the new approach.
|
||||||
for (std::map<std::string, std::vector<ESM::SpellState::PermanentSpellEffectInfo> >::const_iterator it =
|
for (std::map<std::string, std::vector<ESM::SpellState::PermanentSpellEffectInfo> >::const_iterator it =
|
||||||
state.mPermanentSpellEffects.begin(); it != state.mPermanentSpellEffects.end(); ++it)
|
state.mPermanentSpellEffects.begin(); it != state.mPermanentSpellEffects.end(); ++it)
|
||||||
{
|
{
|
||||||
|
@ -494,24 +458,31 @@ namespace MWMechanics
|
||||||
if (!spell)
|
if (!spell)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
mPermanentSpellEffects[spell] = MagicEffects();
|
// Import data only for player, other actors should not suffer from corprus worsening.
|
||||||
|
MWWorld::Ptr player = getPlayer();
|
||||||
|
if (creatureStats->getActorId() != player.getClass().getCreatureStats(player).getActorId())
|
||||||
|
return;
|
||||||
|
|
||||||
|
// Note: if target actor has the Restore attirbute effects, stats will be restored.
|
||||||
for (std::vector<ESM::SpellState::PermanentSpellEffectInfo>::const_iterator effectIt = it->second.begin(); effectIt != it->second.end(); ++effectIt)
|
for (std::vector<ESM::SpellState::PermanentSpellEffectInfo>::const_iterator effectIt = it->second.begin(); effectIt != it->second.end(); ++effectIt)
|
||||||
{
|
{
|
||||||
mPermanentSpellEffects[spell].add(EffectKey(effectIt->mId, effectIt->mArg), effectIt->mMagnitude);
|
// Applied corprus effects are already in loaded stats modifiers
|
||||||
}
|
if (effectIt->mId == ESM::MagicEffect::FortifyAttribute)
|
||||||
}
|
|
||||||
|
|
||||||
mCorprusSpells.clear();
|
|
||||||
for (std::map<std::string, ESM::SpellState::CorprusStats>::const_iterator it = state.mCorprusSpells.begin(); it != state.mCorprusSpells.end(); ++it)
|
|
||||||
{
|
{
|
||||||
const ESM::Spell* spell = MWBase::Environment::get().getWorld()->getStore().get<ESM::Spell>().search(it->first);
|
AttributeValue attr = creatureStats->getAttribute(effectIt->mArg);
|
||||||
if (!spell) // Discard unavailable corprus spells
|
attr.setModifier(attr.getModifier() - effectIt->mMagnitude);
|
||||||
continue;
|
attr.damage(-effectIt->mMagnitude);
|
||||||
mCorprusSpells[spell].mWorsenings = state.mCorprusSpells.at(it->first).mWorsenings;
|
creatureStats->setAttribute(effectIt->mArg, attr);
|
||||||
mCorprusSpells[spell].mNextWorsening = MWWorld::TimeStamp(state.mCorprusSpells.at(it->first).mNextWorsening);
|
}
|
||||||
|
else if (effectIt->mId == ESM::MagicEffect::DrainAttribute)
|
||||||
|
{
|
||||||
|
AttributeValue attr = creatureStats->getAttribute(effectIt->mArg);
|
||||||
|
attr.setModifier(attr.getModifier() + effectIt->mMagnitude);
|
||||||
|
attr.damage(effectIt->mMagnitude);
|
||||||
|
creatureStats->setAttribute(effectIt->mArg, attr);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
mSpellsChanged = true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Spells::writeState(ESM::SpellState &state) const
|
void Spells::writeState(ESM::SpellState &state) const
|
||||||
|
@ -528,26 +499,5 @@ namespace MWMechanics
|
||||||
|
|
||||||
for (std::map<SpellKey, MWWorld::TimeStamp>::const_iterator it = mUsedPowers.begin(); it != mUsedPowers.end(); ++it)
|
for (std::map<SpellKey, MWWorld::TimeStamp>::const_iterator it = mUsedPowers.begin(); it != mUsedPowers.end(); ++it)
|
||||||
state.mUsedPowers[it->first->mId] = it->second.toEsm();
|
state.mUsedPowers[it->first->mId] = it->second.toEsm();
|
||||||
|
|
||||||
for (std::map<SpellKey, MagicEffects>::const_iterator it = mPermanentSpellEffects.begin(); it != mPermanentSpellEffects.end(); ++it)
|
|
||||||
{
|
|
||||||
std::vector<ESM::SpellState::PermanentSpellEffectInfo> effectList;
|
|
||||||
for (MagicEffects::Collection::const_iterator effectIt = it->second.begin(); effectIt != it->second.end(); ++effectIt)
|
|
||||||
{
|
|
||||||
ESM::SpellState::PermanentSpellEffectInfo info;
|
|
||||||
info.mId = effectIt->first.mId;
|
|
||||||
info.mArg = effectIt->first.mArg;
|
|
||||||
info.mMagnitude = effectIt->second.getModifier();
|
|
||||||
|
|
||||||
effectList.push_back(info);
|
|
||||||
}
|
|
||||||
state.mPermanentSpellEffects[it->first->mId] = effectList;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (std::map<SpellKey, CorprusStats>::const_iterator it = mCorprusSpells.begin(); it != mCorprusSpells.end(); ++it)
|
|
||||||
{
|
|
||||||
state.mCorprusSpells[it->first->mId].mWorsenings = mCorprusSpells.at(it->first).mWorsenings;
|
|
||||||
state.mCorprusSpells[it->first->mId].mNextWorsening = mCorprusSpells.at(it->first).mNextWorsening.toEsm();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -22,6 +22,8 @@ namespace ESM
|
||||||
|
|
||||||
namespace MWMechanics
|
namespace MWMechanics
|
||||||
{
|
{
|
||||||
|
class CreatureStats;
|
||||||
|
|
||||||
class MagicEffects;
|
class MagicEffects;
|
||||||
|
|
||||||
/// \brief Spell list
|
/// \brief Spell list
|
||||||
|
@ -33,7 +35,8 @@ namespace MWMechanics
|
||||||
public:
|
public:
|
||||||
|
|
||||||
typedef const ESM::Spell* SpellKey;
|
typedef const ESM::Spell* SpellKey;
|
||||||
struct SpellParams {
|
struct SpellParams
|
||||||
|
{
|
||||||
std::map<int, float> mEffectRands; // <effect index, normalised random magnitude>
|
std::map<int, float> mEffectRands; // <effect index, normalised random magnitude>
|
||||||
std::set<int> mPurgedEffects; // indices of purged effects
|
std::set<int> mPurgedEffects; // indices of purged effects
|
||||||
};
|
};
|
||||||
|
@ -41,27 +44,14 @@ namespace MWMechanics
|
||||||
typedef std::map<SpellKey, SpellParams> TContainer;
|
typedef std::map<SpellKey, SpellParams> TContainer;
|
||||||
typedef TContainer::const_iterator TIterator;
|
typedef TContainer::const_iterator TIterator;
|
||||||
|
|
||||||
struct CorprusStats
|
|
||||||
{
|
|
||||||
static const int sWorseningPeriod = 24;
|
|
||||||
|
|
||||||
int mWorsenings;
|
|
||||||
MWWorld::TimeStamp mNextWorsening;
|
|
||||||
};
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
TContainer mSpells;
|
TContainer mSpells;
|
||||||
|
|
||||||
// spell-tied effects that will be applied even after removing the spell (currently used to keep positive effects when corprus is removed)
|
|
||||||
std::map<SpellKey, MagicEffects> mPermanentSpellEffects;
|
|
||||||
|
|
||||||
// Note: this is the spell that's about to be cast, *not* the spell selected in the GUI (which may be different)
|
// Note: this is the spell that's about to be cast, *not* the spell selected in the GUI (which may be different)
|
||||||
std::string mSelectedSpell;
|
std::string mSelectedSpell;
|
||||||
|
|
||||||
std::map<SpellKey, MWWorld::TimeStamp> mUsedPowers;
|
std::map<SpellKey, MWWorld::TimeStamp> mUsedPowers;
|
||||||
|
|
||||||
std::map<SpellKey, CorprusStats> mCorprusSpells;
|
|
||||||
|
|
||||||
mutable bool mSpellsChanged;
|
mutable bool mSpellsChanged;
|
||||||
mutable MagicEffects mEffects;
|
mutable MagicEffects mEffects;
|
||||||
mutable std::map<SpellKey, MagicEffects> mSourcedEffects;
|
mutable std::map<SpellKey, MagicEffects> mSourcedEffects;
|
||||||
|
@ -73,9 +63,7 @@ namespace MWMechanics
|
||||||
public:
|
public:
|
||||||
Spells();
|
Spells();
|
||||||
|
|
||||||
void worsenCorprus(const ESM::Spell* spell);
|
|
||||||
static bool hasCorprusEffect(const ESM::Spell *spell);
|
static bool hasCorprusEffect(const ESM::Spell *spell);
|
||||||
const std::map<SpellKey, CorprusStats> & getCorprusSpells() const;
|
|
||||||
|
|
||||||
void purgeEffect(int effectId);
|
void purgeEffect(int effectId);
|
||||||
void purgeEffect(int effectId, const std::string & sourceId);
|
void purgeEffect(int effectId, const std::string & sourceId);
|
||||||
|
@ -128,7 +116,7 @@ namespace MWMechanics
|
||||||
|
|
||||||
void visitEffectSources (MWMechanics::EffectSourceVisitor& visitor) const;
|
void visitEffectSources (MWMechanics::EffectSourceVisitor& visitor) const;
|
||||||
|
|
||||||
void readState (const ESM::SpellState& state);
|
void readState (const ESM::SpellState& state, CreatureStats* creatureStats);
|
||||||
void writeState (ESM::SpellState& state) const;
|
void writeState (ESM::SpellState& state) const;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
|
@ -94,8 +94,8 @@ namespace MWMechanics
|
||||||
|
|
||||||
CreatureStats& stats = actor.getClass().getCreatureStats(actor);
|
CreatureStats& stats = actor.getClass().getCreatureStats(actor);
|
||||||
|
|
||||||
int actorWillpower = stats.getAttribute(ESM::Attribute::Willpower).getModified();
|
float actorWillpower = stats.getAttribute(ESM::Attribute::Willpower).getModified();
|
||||||
int actorLuck = stats.getAttribute(ESM::Attribute::Luck).getModified();
|
float actorLuck = stats.getAttribute(ESM::Attribute::Luck).getModified();
|
||||||
|
|
||||||
float castChance = (lowestSkill - spell->mData.mCost + 0.2f * actorWillpower + 0.1f * actorLuck);
|
float castChance = (lowestSkill - spell->mData.mCost + 0.2f * actorWillpower + 0.1f * actorLuck);
|
||||||
|
|
||||||
|
|
|
@ -227,39 +227,46 @@ namespace MWMechanics
|
||||||
}
|
}
|
||||||
|
|
||||||
AttributeValue::AttributeValue() :
|
AttributeValue::AttributeValue() :
|
||||||
mBase(0), mModifier(0), mDamage(0)
|
mBase(0.f), mModifier(0.f), mDamage(0.f)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
int AttributeValue::getModified() const
|
float AttributeValue::getModified() const
|
||||||
{
|
{
|
||||||
return std::max(0, mBase - (int) mDamage + mModifier);
|
return std::max(0.f, mBase - mDamage + mModifier);
|
||||||
}
|
}
|
||||||
int AttributeValue::getBase() const
|
float AttributeValue::getBase() const
|
||||||
{
|
{
|
||||||
return mBase;
|
return mBase;
|
||||||
}
|
}
|
||||||
int AttributeValue::getModifier() const
|
float AttributeValue::getModifier() const
|
||||||
{
|
{
|
||||||
return mModifier;
|
return mModifier;
|
||||||
}
|
}
|
||||||
|
|
||||||
void AttributeValue::setBase(int base)
|
void AttributeValue::setBase(float base)
|
||||||
{
|
{
|
||||||
mBase = base;
|
mBase = base;
|
||||||
}
|
}
|
||||||
|
|
||||||
void AttributeValue::setModifier(int mod)
|
void AttributeValue::setModifier(float mod)
|
||||||
{
|
{
|
||||||
mModifier = mod;
|
mModifier = mod;
|
||||||
}
|
}
|
||||||
|
|
||||||
void AttributeValue::damage(float damage)
|
void AttributeValue::damage(float damage)
|
||||||
{
|
{
|
||||||
mDamage += std::min(damage, (float)getModified());
|
float threshold = mBase + mModifier;
|
||||||
|
|
||||||
|
if (mDamage + damage > threshold)
|
||||||
|
mDamage = threshold;
|
||||||
|
else
|
||||||
|
mDamage += damage;
|
||||||
}
|
}
|
||||||
void AttributeValue::restore(float amount)
|
void AttributeValue::restore(float amount)
|
||||||
{
|
{
|
||||||
|
if (mDamage <= 0) return;
|
||||||
|
|
||||||
mDamage -= std::min(mDamage, amount);
|
mDamage -= std::min(mDamage, amount);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -268,14 +275,14 @@ namespace MWMechanics
|
||||||
return mDamage;
|
return mDamage;
|
||||||
}
|
}
|
||||||
|
|
||||||
void AttributeValue::writeState (ESM::StatState<int>& state) const
|
void AttributeValue::writeState (ESM::StatState<float>& state) const
|
||||||
{
|
{
|
||||||
state.mBase = mBase;
|
state.mBase = mBase;
|
||||||
state.mMod = mModifier;
|
state.mMod = mModifier;
|
||||||
state.mDamage = mDamage;
|
state.mDamage = mDamage;
|
||||||
}
|
}
|
||||||
|
|
||||||
void AttributeValue::readState (const ESM::StatState<int>& state)
|
void AttributeValue::readState (const ESM::StatState<float>& state)
|
||||||
{
|
{
|
||||||
mBase = state.mBase;
|
mBase = state.mBase;
|
||||||
mModifier = state.mMod;
|
mModifier = state.mMod;
|
||||||
|
@ -296,13 +303,13 @@ namespace MWMechanics
|
||||||
mProgress = progress;
|
mProgress = progress;
|
||||||
}
|
}
|
||||||
|
|
||||||
void SkillValue::writeState (ESM::StatState<int>& state) const
|
void SkillValue::writeState (ESM::StatState<float>& state) const
|
||||||
{
|
{
|
||||||
AttributeValue::writeState (state);
|
AttributeValue::writeState (state);
|
||||||
state.mProgress = mProgress;
|
state.mProgress = mProgress;
|
||||||
}
|
}
|
||||||
|
|
||||||
void SkillValue::readState (const ESM::StatState<int>& state)
|
void SkillValue::readState (const ESM::StatState<float>& state)
|
||||||
{
|
{
|
||||||
AttributeValue::readState (state);
|
AttributeValue::readState (state);
|
||||||
mProgress = state.mProgress;
|
mProgress = state.mProgress;
|
||||||
|
|
|
@ -122,20 +122,20 @@ namespace MWMechanics
|
||||||
|
|
||||||
class AttributeValue
|
class AttributeValue
|
||||||
{
|
{
|
||||||
int mBase;
|
float mBase;
|
||||||
int mModifier;
|
float mModifier;
|
||||||
float mDamage; // needs to be float to allow continuous damage
|
float mDamage; // needs to be float to allow continuous damage
|
||||||
|
|
||||||
public:
|
public:
|
||||||
AttributeValue();
|
AttributeValue();
|
||||||
|
|
||||||
int getModified() const;
|
float getModified() const;
|
||||||
int getBase() const;
|
float getBase() const;
|
||||||
int getModifier() const;
|
float getModifier() const;
|
||||||
|
|
||||||
void setBase(int base);
|
void setBase(float base);
|
||||||
|
|
||||||
void setModifier(int mod);
|
void setModifier(float mod);
|
||||||
|
|
||||||
// Maximum attribute damage is limited to the modified value.
|
// Maximum attribute damage is limited to the modified value.
|
||||||
// Note: I think MW applies damage directly to mModified, since you can also
|
// Note: I think MW applies damage directly to mModified, since you can also
|
||||||
|
@ -145,8 +145,8 @@ namespace MWMechanics
|
||||||
|
|
||||||
float getDamage() const;
|
float getDamage() const;
|
||||||
|
|
||||||
void writeState (ESM::StatState<int>& state) const;
|
void writeState (ESM::StatState<float>& state) const;
|
||||||
void readState (const ESM::StatState<int>& state);
|
void readState (const ESM::StatState<float>& state);
|
||||||
};
|
};
|
||||||
|
|
||||||
class SkillValue : public AttributeValue
|
class SkillValue : public AttributeValue
|
||||||
|
@ -157,8 +157,8 @@ namespace MWMechanics
|
||||||
float getProgress() const;
|
float getProgress() const;
|
||||||
void setProgress(float progress);
|
void setProgress(float progress);
|
||||||
|
|
||||||
void writeState (ESM::StatState<int>& state) const;
|
void writeState (ESM::StatState<float>& state) const;
|
||||||
void readState (const ESM::StatState<int>& state);
|
void readState (const ESM::StatState<float>& state);
|
||||||
};
|
};
|
||||||
|
|
||||||
inline bool operator== (const AttributeValue& left, const AttributeValue& right)
|
inline bool operator== (const AttributeValue& left, const AttributeValue& right)
|
||||||
|
|
28
apps/openmw/mwmechanics/typedaipackage.hpp
Normal file
28
apps/openmw/mwmechanics/typedaipackage.hpp
Normal file
|
@ -0,0 +1,28 @@
|
||||||
|
#ifndef GAME_MWMECHANICS_TYPEDAIPACKAGE_H
|
||||||
|
#define GAME_MWMECHANICS_TYPEDAIPACKAGE_H
|
||||||
|
|
||||||
|
#include "aipackage.hpp"
|
||||||
|
|
||||||
|
namespace MWMechanics
|
||||||
|
{
|
||||||
|
template <class T>
|
||||||
|
struct TypedAiPackage : public AiPackage
|
||||||
|
{
|
||||||
|
TypedAiPackage() :
|
||||||
|
AiPackage(T::getTypeId(), T::makeDefaultOptions()) {}
|
||||||
|
|
||||||
|
TypedAiPackage(const Options& options) :
|
||||||
|
AiPackage(T::getTypeId(), options) {}
|
||||||
|
|
||||||
|
template <class Derived>
|
||||||
|
TypedAiPackage(Derived*) :
|
||||||
|
AiPackage(Derived::getTypeId(), Derived::makeDefaultOptions()) {}
|
||||||
|
|
||||||
|
virtual std::unique_ptr<AiPackage> clone() const override
|
||||||
|
{
|
||||||
|
return std::make_unique<T>(*static_cast<const T*>(this));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
|
@ -20,6 +20,7 @@ namespace mwmp
|
||||||
{
|
{
|
||||||
MWBase::World *world = MWBase::Environment::get().getWorld();
|
MWBase::World *world = MWBase::Environment::get().getWorld();
|
||||||
|
|
||||||
|
/*
|
||||||
if (worldstate.time.hour != -1)
|
if (worldstate.time.hour != -1)
|
||||||
world->setHour(worldstate.time.hour);
|
world->setHour(worldstate.time.hour);
|
||||||
|
|
||||||
|
@ -37,6 +38,7 @@ namespace mwmp
|
||||||
|
|
||||||
if (worldstate.time.timeScale != -1)
|
if (worldstate.time.timeScale != -1)
|
||||||
world->setTimeScale(worldstate.time.timeScale);
|
world->setTimeScale(worldstate.time.timeScale);
|
||||||
|
*/
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
104
apps/openmw/mwrender/fogmanager.cpp
Normal file
104
apps/openmw/mwrender/fogmanager.cpp
Normal file
|
@ -0,0 +1,104 @@
|
||||||
|
#include "fogmanager.hpp"
|
||||||
|
|
||||||
|
#include <algorithm>
|
||||||
|
|
||||||
|
#include <components/esm/loadcell.hpp>
|
||||||
|
#include <components/fallback/fallback.hpp>
|
||||||
|
#include <components/sceneutil/util.hpp>
|
||||||
|
#include <components/settings/settings.hpp>
|
||||||
|
|
||||||
|
namespace
|
||||||
|
{
|
||||||
|
float DLLandFogStart;
|
||||||
|
float DLLandFogEnd;
|
||||||
|
float DLUnderwaterFogStart;
|
||||||
|
float DLUnderwaterFogEnd;
|
||||||
|
float DLInteriorFogStart;
|
||||||
|
float DLInteriorFogEnd;
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace MWRender
|
||||||
|
{
|
||||||
|
FogManager::FogManager()
|
||||||
|
: mLandFogStart(0.f)
|
||||||
|
, mLandFogEnd(std::numeric_limits<float>::max())
|
||||||
|
, mUnderwaterFogStart(0.f)
|
||||||
|
, mUnderwaterFogEnd(std::numeric_limits<float>::max())
|
||||||
|
, mFogColor(osg::Vec4f())
|
||||||
|
, mDistantFog(Settings::Manager::getBool("use distant fog", "Fog"))
|
||||||
|
, mUnderwaterColor(Fallback::Map::getColour("Water_UnderwaterColor"))
|
||||||
|
, mUnderwaterWeight(Fallback::Map::getFloat("Water_UnderwaterColorWeight"))
|
||||||
|
, mUnderwaterIndoorFog(Fallback::Map::getFloat("Water_UnderwaterIndoorFog"))
|
||||||
|
{
|
||||||
|
DLLandFogStart = Settings::Manager::getFloat("distant land fog start", "Fog");
|
||||||
|
DLLandFogEnd = Settings::Manager::getFloat("distant land fog end", "Fog");
|
||||||
|
DLUnderwaterFogStart = Settings::Manager::getFloat("distant underwater fog start", "Fog");
|
||||||
|
DLUnderwaterFogEnd = Settings::Manager::getFloat("distant underwater fog end", "Fog");
|
||||||
|
DLInteriorFogStart = Settings::Manager::getFloat("distant interior fog start", "Fog");
|
||||||
|
DLInteriorFogEnd = Settings::Manager::getFloat("distant interior fog end", "Fog");
|
||||||
|
}
|
||||||
|
|
||||||
|
void FogManager::configure(float viewDistance, const ESM::Cell *cell)
|
||||||
|
{
|
||||||
|
osg::Vec4f color = SceneUtil::colourFromRGB(cell->mAmbi.mFog);
|
||||||
|
|
||||||
|
if (mDistantFog)
|
||||||
|
{
|
||||||
|
float density = std::max(0.2f, cell->mAmbi.mFogDensity);
|
||||||
|
mLandFogStart = DLInteriorFogEnd * (1.0f - density) + DLInteriorFogStart*density;
|
||||||
|
mLandFogEnd = DLInteriorFogEnd;
|
||||||
|
mUnderwaterFogStart = DLUnderwaterFogStart;
|
||||||
|
mUnderwaterFogEnd = DLUnderwaterFogEnd;
|
||||||
|
mFogColor = color;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
configure(viewDistance, cell->mAmbi.mFogDensity, mUnderwaterIndoorFog, 1.0f, 0.0f, color);
|
||||||
|
}
|
||||||
|
|
||||||
|
void FogManager::configure(float viewDistance, float fogDepth, float underwaterFog, float dlFactor, float dlOffset, const osg::Vec4f &color)
|
||||||
|
{
|
||||||
|
if (mDistantFog)
|
||||||
|
{
|
||||||
|
mLandFogStart = dlFactor * (DLLandFogStart - dlOffset * DLLandFogEnd);
|
||||||
|
mLandFogEnd = dlFactor * (1.0f - dlOffset) * DLLandFogEnd;
|
||||||
|
mUnderwaterFogStart = DLUnderwaterFogStart;
|
||||||
|
mUnderwaterFogEnd = DLUnderwaterFogEnd;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (fogDepth == 0.0)
|
||||||
|
{
|
||||||
|
mLandFogStart = 0.0f;
|
||||||
|
mLandFogEnd = std::numeric_limits<float>::max();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
mLandFogStart = viewDistance * (1 - fogDepth);
|
||||||
|
mLandFogEnd = viewDistance;
|
||||||
|
}
|
||||||
|
mUnderwaterFogStart = std::min(viewDistance, 6666.f) * (1 - underwaterFog);
|
||||||
|
mUnderwaterFogEnd = std::min(viewDistance, 6666.f);
|
||||||
|
}
|
||||||
|
mFogColor = color;
|
||||||
|
}
|
||||||
|
|
||||||
|
float FogManager::getFogStart(bool isUnderwater) const
|
||||||
|
{
|
||||||
|
return isUnderwater ? mUnderwaterFogStart : mLandFogStart;
|
||||||
|
}
|
||||||
|
|
||||||
|
float FogManager::getFogEnd(bool isUnderwater) const
|
||||||
|
{
|
||||||
|
return isUnderwater ? mUnderwaterFogEnd : mLandFogEnd;
|
||||||
|
}
|
||||||
|
|
||||||
|
osg::Vec4f FogManager::getFogColor(bool isUnderwater) const
|
||||||
|
{
|
||||||
|
if (isUnderwater)
|
||||||
|
{
|
||||||
|
return mUnderwaterColor * mUnderwaterWeight + mFogColor * (1.f-mUnderwaterWeight);
|
||||||
|
}
|
||||||
|
|
||||||
|
return mFogColor;
|
||||||
|
}
|
||||||
|
}
|
39
apps/openmw/mwrender/fogmanager.hpp
Normal file
39
apps/openmw/mwrender/fogmanager.hpp
Normal file
|
@ -0,0 +1,39 @@
|
||||||
|
#ifndef OPENMW_MWRENDER_FOGMANAGER_H
|
||||||
|
#define OPENMW_MWRENDER_FOGMANAGER_H
|
||||||
|
|
||||||
|
#include <osg/Vec4f>
|
||||||
|
|
||||||
|
namespace ESM
|
||||||
|
{
|
||||||
|
struct Cell;
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace MWRender
|
||||||
|
{
|
||||||
|
class FogManager
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
FogManager();
|
||||||
|
|
||||||
|
void configure(float viewDistance, const ESM::Cell *cell);
|
||||||
|
void configure(float viewDistance, float fogDepth, float underwaterFog, float dlFactor, float dlOffset, const osg::Vec4f &color);
|
||||||
|
|
||||||
|
osg::Vec4f getFogColor(bool isUnderwater) const;
|
||||||
|
float getFogStart(bool isUnderwater) const;
|
||||||
|
float getFogEnd(bool isUnderwater) const;
|
||||||
|
|
||||||
|
private:
|
||||||
|
float mLandFogStart;
|
||||||
|
float mLandFogEnd;
|
||||||
|
float mUnderwaterFogStart;
|
||||||
|
float mUnderwaterFogEnd;
|
||||||
|
osg::Vec4f mFogColor;
|
||||||
|
bool mDistantFog;
|
||||||
|
|
||||||
|
osg::Vec4f mUnderwaterColor;
|
||||||
|
float mUnderwaterWeight;
|
||||||
|
float mUnderwaterIndoorFog;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
|
@ -69,16 +69,7 @@
|
||||||
#include "navmesh.hpp"
|
#include "navmesh.hpp"
|
||||||
#include "actorspaths.hpp"
|
#include "actorspaths.hpp"
|
||||||
#include "recastmesh.hpp"
|
#include "recastmesh.hpp"
|
||||||
|
#include "fogmanager.hpp"
|
||||||
namespace
|
|
||||||
{
|
|
||||||
float DLLandFogStart;
|
|
||||||
float DLLandFogEnd;
|
|
||||||
float DLUnderwaterFogStart;
|
|
||||||
float DLUnderwaterFogEnd;
|
|
||||||
float DLInteriorFogStart;
|
|
||||||
float DLInteriorFogEnd;
|
|
||||||
}
|
|
||||||
|
|
||||||
namespace MWRender
|
namespace MWRender
|
||||||
{
|
{
|
||||||
|
@ -204,19 +195,9 @@ namespace MWRender
|
||||||
, mWorkQueue(workQueue)
|
, mWorkQueue(workQueue)
|
||||||
, mUnrefQueue(new SceneUtil::UnrefQueue)
|
, mUnrefQueue(new SceneUtil::UnrefQueue)
|
||||||
, mNavigator(navigator)
|
, mNavigator(navigator)
|
||||||
, mLandFogStart(0.f)
|
|
||||||
, mLandFogEnd(std::numeric_limits<float>::max())
|
|
||||||
, mUnderwaterFogStart(0.f)
|
|
||||||
, mUnderwaterFogEnd(std::numeric_limits<float>::max())
|
|
||||||
, mUnderwaterColor(Fallback::Map::getColour("Water_UnderwaterColor"))
|
|
||||||
, mUnderwaterWeight(Fallback::Map::getFloat("Water_UnderwaterColorWeight"))
|
|
||||||
, mUnderwaterIndoorFog(Fallback::Map::getFloat("Water_UnderwaterIndoorFog"))
|
|
||||||
, mNightEyeFactor(0.f)
|
, mNightEyeFactor(0.f)
|
||||||
, mDistantFog(false)
|
|
||||||
, mDistantTerrain(false)
|
|
||||||
, mFieldOfViewOverridden(false)
|
, mFieldOfViewOverridden(false)
|
||||||
, mFieldOfViewOverride(0.f)
|
, mFieldOfViewOverride(0.f)
|
||||||
, mBorders(false)
|
|
||||||
{
|
{
|
||||||
resourceSystem->getSceneManager()->setParticleSystemMask(MWRender::Mask_ParticleSystem);
|
resourceSystem->getSceneManager()->setParticleSystemMask(MWRender::Mask_ParticleSystem);
|
||||||
resourceSystem->getSceneManager()->setShaderPath(resourcePath + "/shaders");
|
resourceSystem->getSceneManager()->setShaderPath(resourcePath + "/shaders");
|
||||||
|
@ -284,16 +265,6 @@ namespace MWRender
|
||||||
|
|
||||||
mEffectManager.reset(new EffectManager(sceneRoot, mResourceSystem));
|
mEffectManager.reset(new EffectManager(sceneRoot, mResourceSystem));
|
||||||
|
|
||||||
DLLandFogStart = Settings::Manager::getFloat("distant land fog start", "Fog");
|
|
||||||
DLLandFogEnd = Settings::Manager::getFloat("distant land fog end", "Fog");
|
|
||||||
DLUnderwaterFogStart = Settings::Manager::getFloat("distant underwater fog start", "Fog");
|
|
||||||
DLUnderwaterFogEnd = Settings::Manager::getFloat("distant underwater fog end", "Fog");
|
|
||||||
DLInteriorFogStart = Settings::Manager::getFloat("distant interior fog start", "Fog");
|
|
||||||
DLInteriorFogEnd = Settings::Manager::getFloat("distant interior fog end", "Fog");
|
|
||||||
|
|
||||||
mDistantFog = Settings::Manager::getBool("use distant fog", "Fog");
|
|
||||||
mDistantTerrain = Settings::Manager::getBool("distant terrain", "Terrain");
|
|
||||||
|
|
||||||
const std::string normalMapPattern = Settings::Manager::getString("normal map pattern", "Shaders");
|
const std::string normalMapPattern = Settings::Manager::getString("normal map pattern", "Shaders");
|
||||||
const std::string heightMapPattern = Settings::Manager::getString("normal height map pattern", "Shaders");
|
const std::string heightMapPattern = Settings::Manager::getString("normal height map pattern", "Shaders");
|
||||||
const std::string specularMapPattern = Settings::Manager::getString("terrain specular map pattern", "Shaders");
|
const std::string specularMapPattern = Settings::Manager::getString("terrain specular map pattern", "Shaders");
|
||||||
|
@ -302,7 +273,7 @@ namespace MWRender
|
||||||
|
|
||||||
mTerrainStorage = new TerrainStorage(mResourceSystem, normalMapPattern, heightMapPattern, useTerrainNormalMaps, specularMapPattern, useTerrainSpecularMaps);
|
mTerrainStorage = new TerrainStorage(mResourceSystem, normalMapPattern, heightMapPattern, useTerrainNormalMaps, specularMapPattern, useTerrainSpecularMaps);
|
||||||
|
|
||||||
if (mDistantTerrain)
|
if (Settings::Manager::getBool("distant terrain", "Terrain"))
|
||||||
{
|
{
|
||||||
const int compMapResolution = Settings::Manager::getInt("composite map resolution", "Terrain");
|
const int compMapResolution = Settings::Manager::getInt("composite map resolution", "Terrain");
|
||||||
int compMapPower = Settings::Manager::getInt("composite map level", "Terrain");
|
int compMapPower = Settings::Manager::getInt("composite map level", "Terrain");
|
||||||
|
@ -349,8 +320,9 @@ namespace MWRender
|
||||||
defaultMat->setSpecular(osg::Material::FRONT_AND_BACK, osg::Vec4f(0.f, 0.f, 0.f, 0.f));
|
defaultMat->setSpecular(osg::Material::FRONT_AND_BACK, osg::Vec4f(0.f, 0.f, 0.f, 0.f));
|
||||||
sceneRoot->getOrCreateStateSet()->setAttribute(defaultMat);
|
sceneRoot->getOrCreateStateSet()->setAttribute(defaultMat);
|
||||||
|
|
||||||
mSky.reset(new SkyManager(sceneRoot, resourceSystem->getSceneManager()));
|
mFog.reset(new FogManager());
|
||||||
|
|
||||||
|
mSky.reset(new SkyManager(sceneRoot, resourceSystem->getSceneManager()));
|
||||||
mSky->setCamera(mViewer->getCamera());
|
mSky->setCamera(mViewer->getCamera());
|
||||||
mSky->setRainIntensityUniform(mWater->getRainIntensityUniform());
|
mSky->setRainIntensityUniform(mWater->getRainIntensityUniform());
|
||||||
|
|
||||||
|
@ -558,9 +530,9 @@ namespace MWRender
|
||||||
|
|
||||||
bool RenderingManager::toggleBorders()
|
bool RenderingManager::toggleBorders()
|
||||||
{
|
{
|
||||||
mBorders = !mBorders;
|
bool borders = !mTerrain->getBordersVisible();
|
||||||
mTerrain->setBordersVisible(mBorders);
|
mTerrain->setBordersVisible(borders);
|
||||||
return mBorders;
|
return borders;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool RenderingManager::toggleRenderMode(RenderMode mode)
|
bool RenderingManager::toggleRenderMode(RenderMode mode)
|
||||||
|
@ -606,46 +578,12 @@ namespace MWRender
|
||||||
|
|
||||||
void RenderingManager::configureFog(const ESM::Cell *cell)
|
void RenderingManager::configureFog(const ESM::Cell *cell)
|
||||||
{
|
{
|
||||||
osg::Vec4f color = SceneUtil::colourFromRGB(cell->mAmbi.mFog);
|
mFog->configure(mViewDistance, cell);
|
||||||
|
|
||||||
if(mDistantFog)
|
|
||||||
{
|
|
||||||
float density = std::max(0.2f, cell->mAmbi.mFogDensity);
|
|
||||||
mLandFogStart = (DLInteriorFogEnd*(1.0f-density) + DLInteriorFogStart*density);
|
|
||||||
mLandFogEnd = DLInteriorFogEnd;
|
|
||||||
mUnderwaterFogStart = DLUnderwaterFogStart;
|
|
||||||
mUnderwaterFogEnd = DLUnderwaterFogEnd;
|
|
||||||
mFogColor = color;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
configureFog(cell->mAmbi.mFogDensity, mUnderwaterIndoorFog, 1.0f, 0.0f, color);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void RenderingManager::configureFog(float fogDepth, float underwaterFog, float dlFactor, float dlOffset, const osg::Vec4f &color)
|
void RenderingManager::configureFog(float fogDepth, float underwaterFog, float dlFactor, float dlOffset, const osg::Vec4f &color)
|
||||||
{
|
{
|
||||||
if(mDistantFog)
|
mFog->configure(mViewDistance, fogDepth, underwaterFog, dlFactor, dlOffset, color);
|
||||||
{
|
|
||||||
mLandFogStart = dlFactor * (DLLandFogStart - dlOffset*DLLandFogEnd);
|
|
||||||
mLandFogEnd = dlFactor * (1.0f-dlOffset) * DLLandFogEnd;
|
|
||||||
mUnderwaterFogStart = DLUnderwaterFogStart;
|
|
||||||
mUnderwaterFogEnd = DLUnderwaterFogEnd;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
if(fogDepth == 0.0)
|
|
||||||
{
|
|
||||||
mLandFogStart = 0.0f;
|
|
||||||
mLandFogEnd = std::numeric_limits<float>::max();
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
mLandFogStart = mViewDistance * (1 - fogDepth);
|
|
||||||
mLandFogEnd = mViewDistance;
|
|
||||||
}
|
|
||||||
mUnderwaterFogStart = std::min(mViewDistance, 6666.f) * (1 - underwaterFog);
|
|
||||||
mUnderwaterFogEnd = std::min(mViewDistance, 6666.f);
|
|
||||||
}
|
|
||||||
mFogColor = color;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
SkyManager* RenderingManager::getSkyManager()
|
SkyManager* RenderingManager::getSkyManager()
|
||||||
|
@ -674,19 +612,11 @@ namespace MWRender
|
||||||
osg::Vec3f focal, cameraPos;
|
osg::Vec3f focal, cameraPos;
|
||||||
mCamera->getPosition(focal, cameraPos);
|
mCamera->getPosition(focal, cameraPos);
|
||||||
mCurrentCameraPos = cameraPos;
|
mCurrentCameraPos = cameraPos;
|
||||||
if (mWater->isUnderwater(cameraPos))
|
|
||||||
{
|
|
||||||
setFogColor(mUnderwaterColor * mUnderwaterWeight + mFogColor * (1.f-mUnderwaterWeight));
|
|
||||||
mStateUpdater->setFogStart(mUnderwaterFogStart);
|
|
||||||
mStateUpdater->setFogEnd(mUnderwaterFogEnd);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
setFogColor(mFogColor);
|
|
||||||
|
|
||||||
mStateUpdater->setFogStart(mLandFogStart);
|
bool isUnderwater = mWater->isUnderwater(cameraPos);
|
||||||
mStateUpdater->setFogEnd(mLandFogEnd);
|
mStateUpdater->setFogStart(mFog->getFogStart(isUnderwater));
|
||||||
}
|
mStateUpdater->setFogEnd(mFog->getFogEnd(isUnderwater));
|
||||||
|
setFogColor(mFog->getFogColor(isUnderwater));
|
||||||
}
|
}
|
||||||
|
|
||||||
void RenderingManager::updatePlayerPtr(const MWWorld::Ptr &ptr)
|
void RenderingManager::updatePlayerPtr(const MWWorld::Ptr &ptr)
|
||||||
|
@ -1335,7 +1265,7 @@ namespace MWRender
|
||||||
else if (it->first == "Camera" && it->second == "viewing distance")
|
else if (it->first == "Camera" && it->second == "viewing distance")
|
||||||
{
|
{
|
||||||
mViewDistance = Settings::Manager::getFloat("viewing distance", "Camera");
|
mViewDistance = Settings::Manager::getFloat("viewing distance", "Camera");
|
||||||
if(!mDistantFog)
|
if(!Settings::Manager::getBool("use distant fog", "Fog"))
|
||||||
mStateUpdater->setFogEnd(mViewDistance);
|
mStateUpdater->setFogEnd(mViewDistance);
|
||||||
updateProjectionMatrix();
|
updateProjectionMatrix();
|
||||||
}
|
}
|
||||||
|
|
|
@ -73,6 +73,7 @@ namespace MWRender
|
||||||
class StateUpdater;
|
class StateUpdater;
|
||||||
|
|
||||||
class EffectManager;
|
class EffectManager;
|
||||||
|
class FogManager;
|
||||||
class SkyManager;
|
class SkyManager;
|
||||||
class NpcAnimation;
|
class NpcAnimation;
|
||||||
class Pathgrid;
|
class Pathgrid;
|
||||||
|
@ -275,6 +276,7 @@ namespace MWRender
|
||||||
std::unique_ptr<Terrain::World> mTerrain;
|
std::unique_ptr<Terrain::World> mTerrain;
|
||||||
TerrainStorage* mTerrainStorage;
|
TerrainStorage* mTerrainStorage;
|
||||||
std::unique_ptr<SkyManager> mSky;
|
std::unique_ptr<SkyManager> mSky;
|
||||||
|
std::unique_ptr<FogManager> mFog;
|
||||||
std::unique_ptr<EffectManager> mEffectManager;
|
std::unique_ptr<EffectManager> mEffectManager;
|
||||||
std::unique_ptr<SceneUtil::ShadowManager> mShadowManager;
|
std::unique_ptr<SceneUtil::ShadowManager> mShadowManager;
|
||||||
osg::ref_ptr<NpcAnimation> mPlayerAnimation;
|
osg::ref_ptr<NpcAnimation> mPlayerAnimation;
|
||||||
|
@ -284,27 +286,15 @@ namespace MWRender
|
||||||
|
|
||||||
osg::ref_ptr<StateUpdater> mStateUpdater;
|
osg::ref_ptr<StateUpdater> mStateUpdater;
|
||||||
|
|
||||||
float mLandFogStart;
|
|
||||||
float mLandFogEnd;
|
|
||||||
float mUnderwaterFogStart;
|
|
||||||
float mUnderwaterFogEnd;
|
|
||||||
osg::Vec4f mUnderwaterColor;
|
|
||||||
float mUnderwaterWeight;
|
|
||||||
float mUnderwaterIndoorFog;
|
|
||||||
osg::Vec4f mFogColor;
|
|
||||||
|
|
||||||
osg::Vec4f mAmbientColor;
|
osg::Vec4f mAmbientColor;
|
||||||
float mNightEyeFactor;
|
float mNightEyeFactor;
|
||||||
|
|
||||||
float mNearClip;
|
float mNearClip;
|
||||||
float mViewDistance;
|
float mViewDistance;
|
||||||
bool mDistantFog : 1;
|
bool mFieldOfViewOverridden;
|
||||||
bool mDistantTerrain : 1;
|
|
||||||
bool mFieldOfViewOverridden : 1;
|
|
||||||
float mFieldOfViewOverride;
|
float mFieldOfViewOverride;
|
||||||
float mFieldOfView;
|
float mFieldOfView;
|
||||||
float mFirstPersonFieldOfView;
|
float mFirstPersonFieldOfView;
|
||||||
bool mBorders;
|
|
||||||
|
|
||||||
void operator = (const RenderingManager&);
|
void operator = (const RenderingManager&);
|
||||||
RenderingManager(const RenderingManager&);
|
RenderingManager(const RenderingManager&);
|
||||||
|
|
|
@ -271,8 +271,10 @@ namespace MWScript
|
||||||
Interpreter::Type_Integer value = runtime[0].mInteger;
|
Interpreter::Type_Integer value = runtime[0].mInteger;
|
||||||
runtime.pop();
|
runtime.pop();
|
||||||
|
|
||||||
ptr.getClass().getCreatureStats (ptr).setAiSetting (mIndex,
|
int modified = ptr.getClass().getCreatureStats (ptr).getAiSetting (mIndex).getBase() + value;
|
||||||
ptr.getClass().getCreatureStats (ptr).getAiSetting (mIndex).getBase() + value);
|
|
||||||
|
ptr.getClass().getCreatureStats (ptr).setAiSetting (mIndex, modified);
|
||||||
|
ptr.getClass().setBaseAISetting(ptr.getCellRef().getRefId(), mIndex, modified);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
template<class R>
|
template<class R>
|
||||||
|
@ -302,7 +304,7 @@ namespace MWScript
|
||||||
*/
|
*/
|
||||||
|
|
||||||
stat.setModified(value, 0);
|
stat.setModified(value, 0);
|
||||||
ptr.getClass().getCreatureStats(ptr).setAiSetting(mIndex, stat);
|
ptr.getClass().setBaseAISetting(ptr.getCellRef().getRefId(), mIndex, value);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Start of tes3mp addition
|
Start of tes3mp addition
|
||||||
|
|
|
@ -106,7 +106,7 @@ namespace MWScript
|
||||||
{
|
{
|
||||||
MWWorld::Ptr ptr = R()(runtime);
|
MWWorld::Ptr ptr = R()(runtime);
|
||||||
|
|
||||||
Interpreter::Type_Integer value =
|
Interpreter::Type_Float value =
|
||||||
ptr.getClass()
|
ptr.getClass()
|
||||||
.getCreatureStats (ptr)
|
.getCreatureStats (ptr)
|
||||||
.getAttribute(mIndex)
|
.getAttribute(mIndex)
|
||||||
|
@ -129,7 +129,7 @@ namespace MWScript
|
||||||
{
|
{
|
||||||
MWWorld::Ptr ptr = R()(runtime);
|
MWWorld::Ptr ptr = R()(runtime);
|
||||||
|
|
||||||
Interpreter::Type_Integer value = runtime[0].mInteger;
|
Interpreter::Type_Float value = runtime[0].mFloat;
|
||||||
runtime.pop();
|
runtime.pop();
|
||||||
|
|
||||||
MWMechanics::AttributeValue attribute = ptr.getClass().getCreatureStats(ptr).getAttribute(mIndex);
|
MWMechanics::AttributeValue attribute = ptr.getClass().getCreatureStats(ptr).getAttribute(mIndex);
|
||||||
|
@ -151,7 +151,7 @@ namespace MWScript
|
||||||
{
|
{
|
||||||
MWWorld::Ptr ptr = R()(runtime);
|
MWWorld::Ptr ptr = R()(runtime);
|
||||||
|
|
||||||
Interpreter::Type_Integer value = runtime[0].mInteger;
|
Interpreter::Type_Float value = runtime[0].mFloat;
|
||||||
runtime.pop();
|
runtime.pop();
|
||||||
|
|
||||||
MWMechanics::AttributeValue attribute = ptr.getClass()
|
MWMechanics::AttributeValue attribute = ptr.getClass()
|
||||||
|
@ -166,9 +166,9 @@ namespace MWScript
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (value < 0)
|
if (value < 0)
|
||||||
attribute.setBase(std::max(0, attribute.getBase() + value));
|
attribute.setBase(std::max(0.f, attribute.getBase() + value));
|
||||||
else
|
else
|
||||||
attribute.setBase(std::min(100, attribute.getBase() + value));
|
attribute.setBase(std::min(100.f, attribute.getBase() + value));
|
||||||
|
|
||||||
ptr.getClass().getCreatureStats(ptr).setAttribute(mIndex, attribute);
|
ptr.getClass().getCreatureStats(ptr).setAttribute(mIndex, attribute);
|
||||||
}
|
}
|
||||||
|
@ -356,7 +356,7 @@ namespace MWScript
|
||||||
{
|
{
|
||||||
MWWorld::Ptr ptr = R()(runtime);
|
MWWorld::Ptr ptr = R()(runtime);
|
||||||
|
|
||||||
Interpreter::Type_Integer value = ptr.getClass().getSkill(ptr, mIndex);
|
Interpreter::Type_Float value = ptr.getClass().getSkill(ptr, mIndex);
|
||||||
|
|
||||||
runtime.push (value);
|
runtime.push (value);
|
||||||
}
|
}
|
||||||
|
@ -375,7 +375,7 @@ namespace MWScript
|
||||||
{
|
{
|
||||||
MWWorld::Ptr ptr = R()(runtime);
|
MWWorld::Ptr ptr = R()(runtime);
|
||||||
|
|
||||||
Interpreter::Type_Integer value = runtime[0].mInteger;
|
Interpreter::Type_Float value = runtime[0].mFloat;
|
||||||
runtime.pop();
|
runtime.pop();
|
||||||
|
|
||||||
MWMechanics::NpcStats& stats = ptr.getClass().getNpcStats (ptr);
|
MWMechanics::NpcStats& stats = ptr.getClass().getNpcStats (ptr);
|
||||||
|
@ -397,7 +397,7 @@ namespace MWScript
|
||||||
{
|
{
|
||||||
MWWorld::Ptr ptr = R()(runtime);
|
MWWorld::Ptr ptr = R()(runtime);
|
||||||
|
|
||||||
Interpreter::Type_Integer value = runtime[0].mInteger;
|
Interpreter::Type_Float value = runtime[0].mFloat;
|
||||||
runtime.pop();
|
runtime.pop();
|
||||||
|
|
||||||
MWMechanics::SkillValue &skill = ptr.getClass()
|
MWMechanics::SkillValue &skill = ptr.getClass()
|
||||||
|
@ -407,14 +407,14 @@ namespace MWScript
|
||||||
if (value == 0)
|
if (value == 0)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (((skill.getBase() <= 0) && (value < 0))
|
if (((skill.getBase() <= 0.f) && (value < 0.f))
|
||||||
|| ((skill.getBase() >= 100) && (value > 0)))
|
|| ((skill.getBase() >= 100.f) && (value > 0.f)))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (value < 0)
|
if (value < 0)
|
||||||
skill.setBase(std::max(0, skill.getBase() + value));
|
skill.setBase(std::max(0.f, skill.getBase() + value));
|
||||||
else
|
else
|
||||||
skill.setBase(std::min(100, skill.getBase() + value));
|
skill.setBase(std::min(100.f, skill.getBase() + value));
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -519,18 +519,20 @@ namespace MWScript
|
||||||
std::string id = runtime.getStringLiteral (runtime[0].mInteger);
|
std::string id = runtime.getStringLiteral (runtime[0].mInteger);
|
||||||
runtime.pop();
|
runtime.pop();
|
||||||
|
|
||||||
|
MWMechanics::CreatureStats& creatureStats = ptr.getClass().getCreatureStats(ptr);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Start of tes3mp change (major)
|
Start of tes3mp change (major)
|
||||||
|
|
||||||
Only remove the spell if the target has it
|
Only remove the spell if the target has it
|
||||||
|
|
||||||
Send an ID_PLAYER_SPELLBOOK packet every time a player loses a spell here
|
|
||||||
*/
|
*/
|
||||||
MWMechanics::CreatureStats& creatureStats = ptr.getClass().getCreatureStats(ptr);
|
|
||||||
MWMechanics::Spells& spells = creatureStats.getSpells();
|
MWMechanics::Spells& spells = creatureStats.getSpells();
|
||||||
|
|
||||||
if (spells.hasSpell(id))
|
if (!spells.hasSpell(id)) return;
|
||||||
{
|
/*
|
||||||
|
End of tes3mp change (major)
|
||||||
|
*/
|
||||||
|
|
||||||
// The spell may have an instant effect which must be handled before the spell's removal.
|
// The spell may have an instant effect which must be handled before the spell's removal.
|
||||||
for (const auto& effect : creatureStats.getSpells().getMagicEffects())
|
for (const auto& effect : creatureStats.getSpells().getMagicEffects())
|
||||||
{
|
{
|
||||||
|
@ -541,19 +543,24 @@ namespace MWScript
|
||||||
creatureStats.getSpells().purgeEffect(effect.first.mId);
|
creatureStats.getSpells().purgeEffect(effect.first.mId);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
MWBase::Environment::get().getMechanicsManager()->restoreStatsAfterCorprus(ptr, id);
|
||||||
creatureStats.getSpells().remove (id);
|
creatureStats.getSpells().remove (id);
|
||||||
|
|
||||||
if (ptr == MWMechanics::getPlayer())
|
|
||||||
{
|
|
||||||
MWBase::WindowManager* wm = MWBase::Environment::get().getWindowManager();
|
MWBase::WindowManager* wm = MWBase::Environment::get().getWindowManager();
|
||||||
|
|
||||||
if (id == wm->getSelectedSpell())
|
if (ptr == MWMechanics::getPlayer() &&
|
||||||
|
id == wm->getSelectedSpell())
|
||||||
|
{
|
||||||
wm->unsetSelectedSpell();
|
wm->unsetSelectedSpell();
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
Start of tes3mp change (major)
|
||||||
|
|
||||||
|
Send an ID_PLAYER_SPELLBOOK packet every time a player loses a spell here
|
||||||
|
*/
|
||||||
if (mwmp::Main::get().getLocalPlayer()->isLoggedIn())
|
if (mwmp::Main::get().getLocalPlayer()->isLoggedIn())
|
||||||
mwmp::Main::get().getLocalPlayer()->sendSpellChange(id, mwmp::SpellbookChanges::REMOVE);
|
mwmp::Main::get().getLocalPlayer()->sendSpellChange(id, mwmp::SpellbookChanges::REMOVE);
|
||||||
}
|
|
||||||
}
|
|
||||||
/*
|
/*
|
||||||
End of tes3mp change (major)
|
End of tes3mp change (major)
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -147,10 +147,11 @@ namespace MWSound
|
||||||
volume = static_cast<float>(pow(10.0, (sound->mData.mVolume / 255.0*3348.0 - 3348.0) / 2000.0));
|
volume = static_cast<float>(pow(10.0, (sound->mData.mVolume / 255.0*3348.0 - 3348.0) / 2000.0));
|
||||||
min = sound->mData.mMinRange;
|
min = sound->mData.mMinRange;
|
||||||
max = sound->mData.mMaxRange;
|
max = sound->mData.mMaxRange;
|
||||||
if (min == 0)
|
if (min == 0 && max == 0)
|
||||||
|
{
|
||||||
min = fAudioDefaultMinDistance;
|
min = fAudioDefaultMinDistance;
|
||||||
if (max == 0)
|
|
||||||
max = fAudioDefaultMaxDistance;
|
max = fAudioDefaultMaxDistance;
|
||||||
|
}
|
||||||
|
|
||||||
min *= fAudioMinDistanceMult;
|
min *= fAudioMinDistanceMult;
|
||||||
max *= fAudioMaxDistanceMult;
|
max *= fAudioMaxDistanceMult;
|
||||||
|
|
|
@ -213,11 +213,7 @@ void MWState::StateManager::saveGame (const std::string& description, const Slot
|
||||||
profile.mPlayerClassId = classId;
|
profile.mPlayerClassId = classId;
|
||||||
|
|
||||||
profile.mPlayerCell = world.getCellName();
|
profile.mPlayerCell = world.getCellName();
|
||||||
|
profile.mInGameTime = world.getEpochTimeStamp();
|
||||||
profile.mInGameTime.mGameHour = world.getTimeStamp().getHour();
|
|
||||||
profile.mInGameTime.mDay = world.getDay();
|
|
||||||
profile.mInGameTime.mMonth = world.getMonth();
|
|
||||||
profile.mInGameTime.mYear = world.getYear();
|
|
||||||
profile.mTimePlayed = mTimePlayed;
|
profile.mTimePlayed = mTimePlayed;
|
||||||
profile.mDescription = description;
|
profile.mDescription = description;
|
||||||
|
|
||||||
|
@ -464,6 +460,7 @@ void MWState::StateManager::loadGame (const Character *character, const std::str
|
||||||
case ESM::REC_ENAB:
|
case ESM::REC_ENAB:
|
||||||
case ESM::REC_LEVC:
|
case ESM::REC_LEVC:
|
||||||
case ESM::REC_LEVI:
|
case ESM::REC_LEVI:
|
||||||
|
case ESM::REC_CREA:
|
||||||
MWBase::Environment::get().getWorld()->readRecord(reader, n.intval, contentFileMap);
|
MWBase::Environment::get().getWorld()->readRecord(reader, n.intval, contentFileMap);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
|
|
@ -434,7 +434,7 @@ namespace MWWorld
|
||||||
return canSwim(ptr) || canWalk(ptr) || canFly(ptr);
|
return canSwim(ptr) || canWalk(ptr) || canFly(ptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
int Class::getSkill(const MWWorld::Ptr& ptr, int skill) const
|
float Class::getSkill(const MWWorld::Ptr& ptr, int skill) const
|
||||||
{
|
{
|
||||||
throw std::runtime_error("class does not support skills");
|
throw std::runtime_error("class does not support skills");
|
||||||
}
|
}
|
||||||
|
@ -529,4 +529,9 @@ namespace MWWorld
|
||||||
result.z() = magicEffect->mData.mBlue / 255.f;
|
result.z() = magicEffect->mData.mBlue / 255.f;
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Class::setBaseAISetting(const std::string& id, MWMechanics::CreatureStats::AiSetting setting, int value) const
|
||||||
|
{
|
||||||
|
throw std::runtime_error ("class does not have creature stats");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,6 +10,7 @@
|
||||||
|
|
||||||
#include "ptr.hpp"
|
#include "ptr.hpp"
|
||||||
#include "doorstate.hpp"
|
#include "doorstate.hpp"
|
||||||
|
#include "../mwmechanics/creaturestats.hpp"
|
||||||
|
|
||||||
namespace ESM
|
namespace ESM
|
||||||
{
|
{
|
||||||
|
@ -28,7 +29,6 @@ namespace MWPhysics
|
||||||
|
|
||||||
namespace MWMechanics
|
namespace MWMechanics
|
||||||
{
|
{
|
||||||
class CreatureStats;
|
|
||||||
class NpcStats;
|
class NpcStats;
|
||||||
struct Movement;
|
struct Movement;
|
||||||
}
|
}
|
||||||
|
@ -332,7 +332,7 @@ namespace MWWorld
|
||||||
bool isPureLandCreature(const MWWorld::Ptr& ptr) const;
|
bool isPureLandCreature(const MWWorld::Ptr& ptr) const;
|
||||||
bool isMobile(const MWWorld::Ptr& ptr) const;
|
bool isMobile(const MWWorld::Ptr& ptr) const;
|
||||||
|
|
||||||
virtual int getSkill(const MWWorld::Ptr& ptr, int skill) const;
|
virtual float getSkill(const MWWorld::Ptr& ptr, int skill) const;
|
||||||
|
|
||||||
virtual void readAdditionalState (const MWWorld::Ptr& ptr, const ESM::ObjectState& state)
|
virtual void readAdditionalState (const MWWorld::Ptr& ptr, const ESM::ObjectState& state)
|
||||||
const;
|
const;
|
||||||
|
@ -371,6 +371,8 @@ namespace MWWorld
|
||||||
virtual float getEffectiveArmorRating(const MWWorld::ConstPtr& armor, const MWWorld::Ptr& actor) const;
|
virtual float getEffectiveArmorRating(const MWWorld::ConstPtr& armor, const MWWorld::Ptr& actor) const;
|
||||||
|
|
||||||
virtual osg::Vec4f getEnchantmentColor(const MWWorld::ConstPtr& item) const;
|
virtual osg::Vec4f getEnchantmentColor(const MWWorld::ConstPtr& item) const;
|
||||||
|
|
||||||
|
virtual void setBaseAISetting(const std::string& id, MWMechanics::CreatureStats::AiSetting setting, int value) const;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
266
apps/openmw/mwworld/datetimemanager.cpp
Normal file
266
apps/openmw/mwworld/datetimemanager.cpp
Normal file
|
@ -0,0 +1,266 @@
|
||||||
|
#include "datetimemanager.hpp"
|
||||||
|
|
||||||
|
#include "../mwbase/environment.hpp"
|
||||||
|
#include "../mwbase/world.hpp"
|
||||||
|
|
||||||
|
#include "esmstore.hpp"
|
||||||
|
#include "globals.hpp"
|
||||||
|
#include "timestamp.hpp"
|
||||||
|
|
||||||
|
namespace
|
||||||
|
{
|
||||||
|
static int getDaysPerMonth(int month)
|
||||||
|
{
|
||||||
|
switch (month)
|
||||||
|
{
|
||||||
|
case 0: return 31;
|
||||||
|
case 1: return 28;
|
||||||
|
case 2: return 31;
|
||||||
|
case 3: return 30;
|
||||||
|
case 4: return 31;
|
||||||
|
case 5: return 30;
|
||||||
|
case 6: return 31;
|
||||||
|
case 7: return 31;
|
||||||
|
case 8: return 30;
|
||||||
|
case 9: return 31;
|
||||||
|
case 10: return 30;
|
||||||
|
case 11: return 31;
|
||||||
|
}
|
||||||
|
|
||||||
|
throw std::runtime_error ("month out of range");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace MWWorld
|
||||||
|
{
|
||||||
|
void DateTimeManager::setup(Globals& globalVariables)
|
||||||
|
{
|
||||||
|
mGameHour = globalVariables["gamehour"].getFloat();
|
||||||
|
mDaysPassed = globalVariables["dayspassed"].getInteger();
|
||||||
|
mDay = globalVariables["day"].getInteger();
|
||||||
|
mMonth = globalVariables["month"].getInteger();
|
||||||
|
mYear = globalVariables["year"].getInteger();
|
||||||
|
mTimeScale = globalVariables["timescale"].getFloat();
|
||||||
|
}
|
||||||
|
|
||||||
|
void DateTimeManager::setHour(double hour)
|
||||||
|
{
|
||||||
|
if (hour < 0)
|
||||||
|
hour = 0;
|
||||||
|
|
||||||
|
int days = static_cast<int>(hour / 24);
|
||||||
|
hour = std::fmod(hour, 24);
|
||||||
|
mGameHour = static_cast<float>(hour);
|
||||||
|
|
||||||
|
if (days > 0)
|
||||||
|
setDay(days + mDay);
|
||||||
|
}
|
||||||
|
|
||||||
|
void DateTimeManager::setDay(int day)
|
||||||
|
{
|
||||||
|
if (day < 1)
|
||||||
|
day = 1;
|
||||||
|
|
||||||
|
int month = mMonth;
|
||||||
|
while (true)
|
||||||
|
{
|
||||||
|
int days = getDaysPerMonth(month);
|
||||||
|
if (day <= days)
|
||||||
|
break;
|
||||||
|
|
||||||
|
if (month < 11)
|
||||||
|
{
|
||||||
|
++month;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
month = 0;
|
||||||
|
mYear++;
|
||||||
|
}
|
||||||
|
|
||||||
|
day -= days;
|
||||||
|
}
|
||||||
|
|
||||||
|
mDay = day;
|
||||||
|
mMonth = month;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
Start of tes3mp addition
|
||||||
|
|
||||||
|
Make it possible to set the year from elsewhere
|
||||||
|
*/
|
||||||
|
void DateTimeManager::setYear(int year)
|
||||||
|
{
|
||||||
|
mYear = year;
|
||||||
|
}
|
||||||
|
/*
|
||||||
|
End of tes3mp addition
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
Start of tes3mp addition
|
||||||
|
|
||||||
|
Make it possible to set the number of days passed from elsewhere
|
||||||
|
*/
|
||||||
|
void DateTimeManager::setDaysPassed(int days)
|
||||||
|
{
|
||||||
|
mDaysPassed = days;
|
||||||
|
}
|
||||||
|
/*
|
||||||
|
End of tes3mp addition
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
Start of tes3mp addition
|
||||||
|
|
||||||
|
Make it possible to set a custom timeScale from elsewhere
|
||||||
|
*/
|
||||||
|
void DateTimeManager::setTimeScale(float timeScale)
|
||||||
|
{
|
||||||
|
mTimeScale = timeScale;
|
||||||
|
}
|
||||||
|
/*
|
||||||
|
End of tes3mp addition
|
||||||
|
*/
|
||||||
|
|
||||||
|
TimeStamp DateTimeManager::getTimeStamp() const
|
||||||
|
{
|
||||||
|
return TimeStamp(mGameHour, mDaysPassed);
|
||||||
|
}
|
||||||
|
|
||||||
|
float DateTimeManager::getTimeScaleFactor() const
|
||||||
|
{
|
||||||
|
return mTimeScale;
|
||||||
|
}
|
||||||
|
|
||||||
|
ESM::EpochTimeStamp DateTimeManager::getEpochTimeStamp() const
|
||||||
|
{
|
||||||
|
ESM::EpochTimeStamp timeStamp;
|
||||||
|
timeStamp.mGameHour = mGameHour;
|
||||||
|
timeStamp.mDay = mDay;
|
||||||
|
timeStamp.mMonth = mMonth;
|
||||||
|
timeStamp.mYear = mYear;
|
||||||
|
return timeStamp;
|
||||||
|
}
|
||||||
|
|
||||||
|
void DateTimeManager::setMonth(int month)
|
||||||
|
{
|
||||||
|
if (month < 0)
|
||||||
|
month = 0;
|
||||||
|
|
||||||
|
int years = month / 12;
|
||||||
|
month = month % 12;
|
||||||
|
|
||||||
|
int days = getDaysPerMonth(month);
|
||||||
|
if (mDay > days)
|
||||||
|
mDay = days;
|
||||||
|
|
||||||
|
mMonth = month;
|
||||||
|
|
||||||
|
if (years > 0)
|
||||||
|
mYear += years;
|
||||||
|
}
|
||||||
|
|
||||||
|
void DateTimeManager::advanceTime(double hours, Globals& globalVariables)
|
||||||
|
{
|
||||||
|
hours += mGameHour;
|
||||||
|
setHour(hours);
|
||||||
|
|
||||||
|
int days = static_cast<int>(hours / 24);
|
||||||
|
if (days > 0)
|
||||||
|
mDaysPassed += days;
|
||||||
|
|
||||||
|
globalVariables["gamehour"].setFloat(mGameHour);
|
||||||
|
globalVariables["dayspassed"].setInteger(mDaysPassed);
|
||||||
|
globalVariables["day"].setInteger(mDay);
|
||||||
|
globalVariables["month"].setInteger(mMonth);
|
||||||
|
globalVariables["year"].setInteger(mYear);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string DateTimeManager::getMonthName(int month) const
|
||||||
|
{
|
||||||
|
if (month == -1)
|
||||||
|
month = mMonth;
|
||||||
|
|
||||||
|
const int months = 12;
|
||||||
|
if (month < 0 || month >= months)
|
||||||
|
return std::string();
|
||||||
|
|
||||||
|
static const char *monthNames[months] =
|
||||||
|
{
|
||||||
|
"sMonthMorningstar", "sMonthSunsdawn", "sMonthFirstseed", "sMonthRainshand",
|
||||||
|
"sMonthSecondseed", "sMonthMidyear", "sMonthSunsheight", "sMonthLastseed",
|
||||||
|
"sMonthHeartfire", "sMonthFrostfall", "sMonthSunsdusk", "sMonthEveningstar"
|
||||||
|
};
|
||||||
|
|
||||||
|
const ESM::GameSetting *setting = MWBase::Environment::get().getWorld()->getStore().get<ESM::GameSetting>().find(monthNames[month]);
|
||||||
|
return setting->mValue.getString();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool DateTimeManager::updateGlobalFloat(const std::string& name, float value)
|
||||||
|
{
|
||||||
|
if (name=="gamehour")
|
||||||
|
{
|
||||||
|
setHour(value);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
else if (name=="day")
|
||||||
|
{
|
||||||
|
setDay(static_cast<int>(value));
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
else if (name=="month")
|
||||||
|
{
|
||||||
|
setMonth(static_cast<int>(value));
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
else if (name=="year")
|
||||||
|
{
|
||||||
|
mYear = static_cast<int>(value);
|
||||||
|
}
|
||||||
|
else if (name=="timescale")
|
||||||
|
{
|
||||||
|
mTimeScale = value;
|
||||||
|
}
|
||||||
|
else if (name=="dayspassed")
|
||||||
|
{
|
||||||
|
mDaysPassed = static_cast<int>(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool DateTimeManager::updateGlobalInt(const std::string& name, int value)
|
||||||
|
{
|
||||||
|
if (name=="gamehour")
|
||||||
|
{
|
||||||
|
setHour(static_cast<float>(value));
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
else if (name=="day")
|
||||||
|
{
|
||||||
|
setDay(value);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
else if (name=="month")
|
||||||
|
{
|
||||||
|
setMonth(value);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
else if (name=="year")
|
||||||
|
{
|
||||||
|
mYear = value;
|
||||||
|
}
|
||||||
|
else if (name=="timescale")
|
||||||
|
{
|
||||||
|
mTimeScale = static_cast<float>(value);
|
||||||
|
}
|
||||||
|
else if (name=="dayspassed")
|
||||||
|
{
|
||||||
|
mDaysPassed = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
73
apps/openmw/mwworld/datetimemanager.hpp
Normal file
73
apps/openmw/mwworld/datetimemanager.hpp
Normal file
|
@ -0,0 +1,73 @@
|
||||||
|
#ifndef GAME_MWWORLD_DATETIMEMANAGER_H
|
||||||
|
#define GAME_MWWORLD_DATETIMEMANAGER_H
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
namespace ESM
|
||||||
|
{
|
||||||
|
struct EpochTimeStamp;
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace MWWorld
|
||||||
|
{
|
||||||
|
class Globals;
|
||||||
|
class TimeStamp;
|
||||||
|
|
||||||
|
class DateTimeManager
|
||||||
|
{
|
||||||
|
int mDaysPassed = 0;
|
||||||
|
int mDay = 0;
|
||||||
|
int mMonth = 0;
|
||||||
|
int mYear = 0;
|
||||||
|
float mGameHour = 0.f;
|
||||||
|
float mTimeScale = 0.f;
|
||||||
|
|
||||||
|
void setHour(double hour);
|
||||||
|
void setDay(int day);
|
||||||
|
void setMonth(int month);
|
||||||
|
|
||||||
|
/*
|
||||||
|
Start of tes3mp addition
|
||||||
|
|
||||||
|
Make it possible to set the year from elsewhere
|
||||||
|
*/
|
||||||
|
void setYear(int year);
|
||||||
|
/*
|
||||||
|
End of tes3mp addition
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
Start of tes3mp addition
|
||||||
|
|
||||||
|
Make it possible to set the number of days passed from elsewhere
|
||||||
|
*/
|
||||||
|
void setDaysPassed(int daysPassed);
|
||||||
|
/*
|
||||||
|
End of tes3mp addition
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
Start of tes3mp addition
|
||||||
|
|
||||||
|
Make it possible to set a custom timeScale from elsewhere
|
||||||
|
*/
|
||||||
|
void setTimeScale(float timeScale);
|
||||||
|
/*
|
||||||
|
End of tes3mp addition
|
||||||
|
*/
|
||||||
|
|
||||||
|
public:
|
||||||
|
std::string getMonthName(int month) const;
|
||||||
|
TimeStamp getTimeStamp() const;
|
||||||
|
ESM::EpochTimeStamp getEpochTimeStamp() const;
|
||||||
|
float getTimeScaleFactor() const;
|
||||||
|
|
||||||
|
void advanceTime(double hours, Globals& globalVariables);
|
||||||
|
|
||||||
|
void setup(Globals& globalVariables);
|
||||||
|
bool updateGlobalInt(const std::string& name, int value);
|
||||||
|
bool updateGlobalFloat(const std::string& name, float value);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
|
@ -273,7 +273,8 @@ void ESMStore::validate()
|
||||||
+mSpells.getDynamicSize()
|
+mSpells.getDynamicSize()
|
||||||
+mWeapons.getDynamicSize()
|
+mWeapons.getDynamicSize()
|
||||||
+mCreatureLists.getDynamicSize()
|
+mCreatureLists.getDynamicSize()
|
||||||
+mItemLists.getDynamicSize();
|
+mItemLists.getDynamicSize()
|
||||||
|
+mCreatures.getDynamicSize();
|
||||||
}
|
}
|
||||||
|
|
||||||
void ESMStore::write (ESM::ESMWriter& writer, Loading::Listener& progress) const
|
void ESMStore::write (ESM::ESMWriter& writer, Loading::Listener& progress) const
|
||||||
|
@ -295,6 +296,7 @@ void ESMStore::validate()
|
||||||
mNpcs.write (writer, progress);
|
mNpcs.write (writer, progress);
|
||||||
mItemLists.write (writer, progress);
|
mItemLists.write (writer, progress);
|
||||||
mCreatureLists.write (writer, progress);
|
mCreatureLists.write (writer, progress);
|
||||||
|
mCreatures.write (writer, progress);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool ESMStore::readRecord (ESM::ESMReader& reader, uint32_t type)
|
bool ESMStore::readRecord (ESM::ESMReader& reader, uint32_t type)
|
||||||
|
@ -312,24 +314,8 @@ void ESMStore::validate()
|
||||||
case ESM::REC_NPC_:
|
case ESM::REC_NPC_:
|
||||||
case ESM::REC_LEVI:
|
case ESM::REC_LEVI:
|
||||||
case ESM::REC_LEVC:
|
case ESM::REC_LEVC:
|
||||||
|
case ESM::REC_CREA:
|
||||||
{
|
|
||||||
mStores[type]->read (reader);
|
mStores[type]->read (reader);
|
||||||
}
|
|
||||||
|
|
||||||
if (type==ESM::REC_NPC_)
|
|
||||||
{
|
|
||||||
// NPC record will always be last and we know that there can be only one
|
|
||||||
// dynamic NPC record (player) -> We are done here with dynamic record loading
|
|
||||||
setUp();
|
|
||||||
|
|
||||||
const ESM::NPC *player = mNpcs.find ("player");
|
|
||||||
|
|
||||||
if (!mRaces.find (player->mRace) ||
|
|
||||||
!mClasses.find (player->mClass))
|
|
||||||
throw std::runtime_error ("Invalid player record (race or class unavailable");
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
case ESM::REC_DYNA:
|
case ESM::REC_DYNA:
|
||||||
|
@ -343,4 +329,15 @@ void ESMStore::validate()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void ESMStore::checkPlayer()
|
||||||
|
{
|
||||||
|
setUp();
|
||||||
|
|
||||||
|
const ESM::NPC *player = mNpcs.find ("player");
|
||||||
|
|
||||||
|
if (!mRaces.find (player->mRace) ||
|
||||||
|
!mClasses.find (player->mClass))
|
||||||
|
throw std::runtime_error ("Invalid player record (race or class unavailable");
|
||||||
|
}
|
||||||
|
|
||||||
} // end namespace
|
} // end namespace
|
||||||
|
|
|
@ -239,6 +239,9 @@ namespace MWWorld
|
||||||
|
|
||||||
bool readRecord (ESM::ESMReader& reader, uint32_t type);
|
bool readRecord (ESM::ESMReader& reader, uint32_t type);
|
||||||
///< \return Known type?
|
///< \return Known type?
|
||||||
|
|
||||||
|
// To be called when we are done with dynamic record loading
|
||||||
|
void checkPlayer();
|
||||||
};
|
};
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
|
@ -2,10 +2,9 @@
|
||||||
|
|
||||||
#include <stdexcept>
|
#include <stdexcept>
|
||||||
|
|
||||||
#include <components/misc/stringops.hpp>
|
|
||||||
|
|
||||||
#include <components/esm/esmwriter.hpp>
|
#include <components/esm/esmwriter.hpp>
|
||||||
#include <components/esm/esmreader.hpp>
|
#include <components/esm/esmreader.hpp>
|
||||||
|
#include <components/misc/stringops.hpp>
|
||||||
|
|
||||||
#include "esmstore.hpp"
|
#include "esmstore.hpp"
|
||||||
|
|
||||||
|
|
|
@ -317,12 +317,12 @@ void MWWorld::InventoryStore::autoEquipWeapon (const MWWorld::Ptr& actor, TSlots
|
||||||
// rate weapon
|
// rate weapon
|
||||||
for (int i = 0; i < static_cast<int>(weaponSkillsLength); ++i)
|
for (int i = 0; i < static_cast<int>(weaponSkillsLength); ++i)
|
||||||
{
|
{
|
||||||
int max = 0;
|
float max = 0;
|
||||||
int maxWeaponSkill = -1;
|
int maxWeaponSkill = -1;
|
||||||
|
|
||||||
for (int j = 0; j < static_cast<int>(weaponSkillsLength); ++j)
|
for (int j = 0; j < static_cast<int>(weaponSkillsLength); ++j)
|
||||||
{
|
{
|
||||||
int skillValue = actor.getClass().getSkill(actor, static_cast<int>(weaponSkills[j]));
|
float skillValue = actor.getClass().getSkill(actor, static_cast<int>(weaponSkills[j]));
|
||||||
if (skillValue > max && !weaponSkillVisited[j])
|
if (skillValue > max && !weaponSkillVisited[j])
|
||||||
{
|
{
|
||||||
max = skillValue;
|
max = skillValue;
|
||||||
|
@ -432,7 +432,7 @@ void MWWorld::InventoryStore::autoEquipArmor (const MWWorld::Ptr& actor, TSlots&
|
||||||
static float fUnarmoredBase1 = store.find("fUnarmoredBase1")->mValue.getFloat();
|
static float fUnarmoredBase1 = store.find("fUnarmoredBase1")->mValue.getFloat();
|
||||||
static float fUnarmoredBase2 = store.find("fUnarmoredBase2")->mValue.getFloat();
|
static float fUnarmoredBase2 = store.find("fUnarmoredBase2")->mValue.getFloat();
|
||||||
|
|
||||||
int unarmoredSkill = actor.getClass().getSkill(actor, ESM::Skill::Unarmored);
|
float unarmoredSkill = actor.getClass().getSkill(actor, ESM::Skill::Unarmored);
|
||||||
float unarmoredRating = (fUnarmoredBase1 * unarmoredSkill) * (fUnarmoredBase2 * unarmoredSkill);
|
float unarmoredRating = (fUnarmoredBase1 * unarmoredSkill) * (fUnarmoredBase2 * unarmoredSkill);
|
||||||
|
|
||||||
for (ContainerStoreIterator iter (begin(ContainerStore::Type_Clothing | ContainerStore::Type_Armor)); iter!=end(); ++iter)
|
for (ContainerStoreIterator iter (begin(ContainerStore::Type_Clothing | ContainerStore::Type_Armor)); iter!=end(); ++iter)
|
||||||
|
@ -617,7 +617,8 @@ void MWWorld::InventoryStore::updateMagicEffects(const Ptr& actor)
|
||||||
|
|
||||||
mMagicEffects = MWMechanics::MagicEffects();
|
mMagicEffects = MWMechanics::MagicEffects();
|
||||||
|
|
||||||
if (actor.getClass().getCreatureStats(actor).isDead())
|
const auto& stats = actor.getClass().getCreatureStats(actor);
|
||||||
|
if (stats.isDead() && stats.isDeathAnimationFinished())
|
||||||
return;
|
return;
|
||||||
|
|
||||||
for (TSlots::const_iterator iter (mSlots.begin()); iter!=mSlots.end(); ++iter)
|
for (TSlots::const_iterator iter (mSlots.begin()); iter!=mSlots.end(); ++iter)
|
||||||
|
@ -982,16 +983,16 @@ void MWWorld::InventoryStore::visitEffectSources(MWMechanics::EffectSourceVisito
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void MWWorld::InventoryStore::purgeEffect(short effectId)
|
void MWWorld::InventoryStore::purgeEffect(short effectId, bool wholeSpell)
|
||||||
{
|
{
|
||||||
for (TSlots::const_iterator it = mSlots.begin(); it != mSlots.end(); ++it)
|
for (TSlots::const_iterator it = mSlots.begin(); it != mSlots.end(); ++it)
|
||||||
{
|
{
|
||||||
if (*it != end())
|
if (*it != end())
|
||||||
purgeEffect(effectId, (*it)->getCellRef().getRefId());
|
purgeEffect(effectId, (*it)->getCellRef().getRefId(), wholeSpell);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void MWWorld::InventoryStore::purgeEffect(short effectId, const std::string &sourceId)
|
void MWWorld::InventoryStore::purgeEffect(short effectId, const std::string &sourceId, bool wholeSpell)
|
||||||
{
|
{
|
||||||
TEffectMagnitudes::iterator effectMagnitudeIt = mPermanentMagicEffectMagnitudes.find(sourceId);
|
TEffectMagnitudes::iterator effectMagnitudeIt = mPermanentMagicEffectMagnitudes.find(sourceId);
|
||||||
if (effectMagnitudeIt == mPermanentMagicEffectMagnitudes.end())
|
if (effectMagnitudeIt == mPermanentMagicEffectMagnitudes.end())
|
||||||
|
@ -1024,6 +1025,12 @@ void MWWorld::InventoryStore::purgeEffect(short effectId, const std::string &sou
|
||||||
if (effectIt->mEffectID != effectId)
|
if (effectIt->mEffectID != effectId)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
|
if (wholeSpell)
|
||||||
|
{
|
||||||
|
mPermanentMagicEffectMagnitudes.erase(sourceId);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
float magnitude = effectIt->mMagnMin + (effectIt->mMagnMax - effectIt->mMagnMin) * params[i].mRandom;
|
float magnitude = effectIt->mMagnMin + (effectIt->mMagnMax - effectIt->mMagnMin) * params[i].mRandom;
|
||||||
magnitude *= params[i].mMultiplier;
|
magnitude *= params[i].mMultiplier;
|
||||||
|
|
||||||
|
|
|
@ -203,10 +203,10 @@ namespace MWWorld
|
||||||
|
|
||||||
void visitEffectSources (MWMechanics::EffectSourceVisitor& visitor);
|
void visitEffectSources (MWMechanics::EffectSourceVisitor& visitor);
|
||||||
|
|
||||||
void purgeEffect (short effectId);
|
void purgeEffect (short effectId, bool wholeSpell = false);
|
||||||
///< Remove a magic effect
|
///< Remove a magic effect
|
||||||
|
|
||||||
void purgeEffect (short effectId, const std::string& sourceId);
|
void purgeEffect (short effectId, const std::string& sourceId, bool wholeSpell = false);
|
||||||
///< Remove a magic effect
|
///< Remove a magic effect
|
||||||
|
|
||||||
virtual void clear();
|
virtual void clear();
|
||||||
|
|
|
@ -391,8 +391,6 @@ namespace MWWorld
|
||||||
else
|
else
|
||||||
player.mHasMark = false;
|
player.mHasMark = false;
|
||||||
|
|
||||||
player.mAutoMove = mAutoMove ? 1 : 0;
|
|
||||||
|
|
||||||
for (int i=0; i<ESM::Attribute::Length; ++i)
|
for (int i=0; i<ESM::Attribute::Length; ++i)
|
||||||
mSaveAttributes[i].writeState(player.mSaveAttributes[i]);
|
mSaveAttributes[i].writeState(player.mSaveAttributes[i]);
|
||||||
for (int i=0; i<ESM::Skill::Length; ++i)
|
for (int i=0; i<ESM::Skill::Length; ++i)
|
||||||
|
@ -487,8 +485,6 @@ namespace MWWorld
|
||||||
mMarkedCell = 0;
|
mMarkedCell = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
mAutoMove = player.mAutoMove!=0;
|
|
||||||
|
|
||||||
mForwardBackward = 0;
|
mForwardBackward = 0;
|
||||||
mTeleported = false;
|
mTeleported = false;
|
||||||
|
|
||||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue