1
0
Fork 1
mirror of https://github.com/TES3MP/openmw-tes3mp.git synced 2025-07-01 15:21:34 +00:00

Add OpenMW commits up to 2 Jan 2020

# Conflicts:
#	apps/openmw/mwmechanics/enchanting.cpp
#	apps/openmw/mwworld/scene.cpp
This commit is contained in:
David Cernat 2020-01-02 22:09:54 +02:00
commit a58f09fd6c
29 changed files with 420 additions and 76 deletions

View file

@ -189,6 +189,7 @@
Feature #2229: Improve pathfinding AI
Feature #3025: Analogue gamepad movement controls
Feature #3442: Default values for fallbacks from ini file
Feature #3517: Multiple projectiles enchantment
Feature #3610: Option to invert X axis
Feature #3871: Editor: Terrain Selection
Feature #3893: Implicit target for "set" function in console
@ -235,6 +236,7 @@
Feature #5147: Show spell magicka cost in spell buying window
Feature #5170: Editor: Land shape editing, land selection
Feature #5193: Weapon sheathing
Feature #5219: Impelement TestCells console command
Feature #5224: Handle NiKeyframeController for NiTriShape
Task #4686: Upgrade media decoder to a more current FFmpeg API
Task #4695: Optimize Distant Terrain memory consumption

View file

@ -2,7 +2,6 @@
brew update
brew outdated pkgconfig || brew upgrade pkgconfig
brew install cmake
brew install qt
brew install ccache

View file

@ -375,7 +375,12 @@ void Launcher::DataFilesPage::reloadCells(QStringList selectedFiles)
// The following code will run only if there is not another thread currently running it
CellNameLoader cellNameLoader;
#if QT_VERSION >= QT_VERSION_CHECK(5,14,0)
QSet<QString> set = cellNameLoader.getCellNames(selectedFiles);
QStringList cellNamesList(set.begin(), set.end());
#else
QStringList cellNamesList = QStringList::fromSet(cellNameLoader.getCellNames(selectedFiles));
#endif
std::sort(cellNamesList.begin(), cellNamesList.end());
emit signalLoadedCellsChanged(cellNamesList);
}

View file

@ -1054,7 +1054,11 @@ void CSVDoc::View::updateWidth(bool isGrowLimit, int minSubViewWidth)
if (isGrowLimit)
rect = dw->screenGeometry(this);
else
#if QT_VERSION >= QT_VERSION_CHECK(5,0,0)
rect = QGuiApplication::screens().at(dw->screenNumber(this))->geometry();
#else
rect = dw->screenGeometry(dw->screen(dw->screenNumber(this)));
#endif
if (!mScrollbarOnly && mScroll && mSubViews.size() > 1)
{

View file

@ -119,6 +119,9 @@ namespace MWBase
virtual MWWorld::CellStore *getCell (const ESM::CellId& id) = 0;
virtual void testExteriorCells() = 0;
virtual void testInteriorCells() = 0;
virtual void useDeathCamera() = 0;
virtual void setWaterHeight(const float height) = 0;

View file

@ -46,7 +46,7 @@ namespace MWClass
class DoorCustomData : public MWWorld::CustomData
{
public:
MWWorld::DoorState mDoorState;
MWWorld::DoorState mDoorState = MWWorld::DoorState::Idle;
virtual MWWorld::CustomData *clone() const;
@ -435,8 +435,6 @@ namespace MWClass
if (!ptr.getRefData().getCustomData())
{
std::unique_ptr<DoorCustomData> data(new DoorCustomData);
data->mDoorState = MWWorld::DoorState::Idle;
ptr.getRefData().setCustomData(data.release());
}
}

View file

@ -1,6 +1,7 @@
#include "enchanting.hpp"
#include <components/misc/rng.hpp>
#include <components/settings/settings.hpp>
/*
Start of tes3mp addition
@ -75,7 +76,6 @@ namespace MWMechanics
const MWWorld::Ptr& player = getPlayer();
MWWorld::ContainerStore& store = player.getClass().getContainerStore(player);
ESM::Enchantment enchantment;
enchantment.mData.mCharge = getGemCharge();
enchantment.mData.mAutocalc = 0;
enchantment.mData.mType = mCastStyle;
enchantment.mData.mCost = getBaseCastCost();
@ -94,14 +94,21 @@ namespace MWMechanics
mEnchanter.getClass().skillUsageSucceeded (mEnchanter, ESM::Skill::Enchant, 2);
}
if(mCastStyle==ESM::Enchantment::ConstantEffect)
{
enchantment.mData.mCharge=0;
}
enchantment.mEffects = mEffectList;
int count = getEnchantItemsCount();
if(mCastStyle==ESM::Enchantment::ConstantEffect)
enchantment.mData.mCharge = 0;
else
enchantment.mData.mCharge = getGemCharge() / count;
// Try to find a dynamic enchantment with the same stats, create a new one if not found.
const ESM::Enchantment* enchantmentPtr = getRecord(enchantment);
if (enchantmentPtr == nullptr)
enchantmentPtr = MWBase::Environment::get().getWorld()->createRecord (enchantment);
// Apply the enchantment
const ESM::Enchantment *enchantmentPtr = MWBase::Environment::get().getWorld()->createRecord (enchantment);
/*
Start of tes3mp change (major)
@ -117,7 +124,7 @@ namespace MWMechanics
*/
mwmp::Main::get().getNetworking()->getWorldstate()->sendEnchantmentRecord(enchantmentPtr);
store.remove(mOldItemPtr, 1, player);
store.remove(mOldItemPtr, count, player);
if(!mSelfEnchanting)
payForEnchantment();
@ -152,20 +159,22 @@ namespace MWMechanics
}
else if (mWeaponType != -1)
{ // Weapon
ESM::WeaponType::Class weapclass = MWMechanics::getWeaponType(mWeaponType)->mWeaponClass;
switch(mCastStyle)
{
case ESM::Enchantment::WhenStrikes:
mCastStyle = ESM::Enchantment::WhenUsed;
if (weapclass == ESM::WeaponType::Melee || weapclass == ESM::WeaponType::Ranged)
mCastStyle = ESM::Enchantment::WhenUsed;
return;
case ESM::Enchantment::WhenUsed:
if (powerfulSoul)
if (powerfulSoul && weapclass != ESM::WeaponType::Ammo && weapclass != ESM::WeaponType::Thrown)
mCastStyle = ESM::Enchantment::ConstantEffect;
else if (getWeaponType(mWeaponType)->mWeaponClass != ESM::WeaponType::Ranged)
else if (weapclass != ESM::WeaponType::Ranged)
mCastStyle = ESM::Enchantment::WhenStrikes;
return;
default: // takes care of Constant effect too
mCastStyle = ESM::Enchantment::WhenUsed;
if (getWeaponType(mWeaponType)->mWeaponClass != ESM::WeaponType::Ranged)
if (weapclass != ESM::WeaponType::Ranged)
mCastStyle = ESM::Enchantment::WhenStrikes;
return;
}
@ -229,6 +238,53 @@ namespace MWMechanics
return enchantmentCost;
}
const ESM::Enchantment* Enchanting::getRecord(const ESM::Enchantment& toFind) const
{
const MWWorld::Store<ESM::Enchantment>& enchantments = MWBase::Environment::get().getWorld()->getStore().get<ESM::Enchantment>();
MWWorld::Store<ESM::Enchantment>::iterator iter (enchantments.begin());
iter += (enchantments.getSize() - enchantments.getDynamicSize());
for (; iter != enchantments.end(); ++iter)
{
if (iter->mEffects.mList.size() != toFind.mEffects.mList.size())
continue;
if (iter->mData.mAutocalc != toFind.mData.mAutocalc
|| iter->mData.mType != toFind.mData.mType
|| iter->mData.mCost != toFind.mData.mCost
|| iter->mData.mCharge != toFind.mData.mCharge)
continue;
// Don't choose an ID that came from the content files, would have unintended side effects
if (!enchantments.isDynamic(iter->mId))
continue;
bool mismatch = false;
for (int i=0; i<static_cast<int> (iter->mEffects.mList.size()); ++i)
{
const ESM::ENAMstruct& first = iter->mEffects.mList[i];
const ESM::ENAMstruct& second = toFind.mEffects.mList[i];
if (first.mEffectID!=second.mEffectID ||
first.mArea!=second.mArea ||
first.mRange!=second.mRange ||
first.mSkill!=second.mSkill ||
first.mAttribute!=second.mAttribute ||
first.mMagnMin!=second.mMagnMin ||
first.mMagnMax!=second.mMagnMax ||
first.mDuration!=second.mDuration)
{
mismatch = true;
break;
}
}
if (!mismatch)
return &(*iter);
}
return nullptr;
}
int Enchanting::getBaseCastCost() const
{
@ -253,6 +309,7 @@ namespace MWMechanics
float priceMultipler = MWBase::Environment::get().getWorld()->getStore().get<ESM::GameSetting>().find ("fEnchantmentValueMult")->mValue.getFloat();
int price = MWBase::Environment::get().getMechanicsManager()->getBarterOffer(mEnchanter, static_cast<int>(getEnchantPoints() * priceMultipler), true);
price *= getEnchantItemsCount() * getTypeMultiplier();
return price;
}
@ -311,13 +368,45 @@ namespace MWMechanics
const float fEnchantmentChanceMult = gmst.find("fEnchantmentChanceMult")->mValue.getFloat();
const float fEnchantmentConstantChanceMult = gmst.find("fEnchantmentConstantChanceMult")->mValue.getFloat();
float x = (a - getEnchantPoints()*fEnchantmentChanceMult + 0.2f * b + 0.1f * c) * stats.getFatigueTerm();
float x = (a - getEnchantPoints() * fEnchantmentChanceMult * getTypeMultiplier() * getEnchantItemsCount() + 0.2f * b + 0.1f * c) * stats.getFatigueTerm();
if (mCastStyle == ESM::Enchantment::ConstantEffect)
x *= fEnchantmentConstantChanceMult;
return static_cast<int>(x);
}
int Enchanting::getEnchantItemsCount() const
{
int count = 1;
float enchantPoints = getEnchantPoints();
if (mWeaponType != -1 && enchantPoints > 0)
{
ESM::WeaponType::Class weapclass = MWMechanics::getWeaponType(mWeaponType)->mWeaponClass;
if (weapclass == ESM::WeaponType::Thrown || weapclass == ESM::WeaponType::Ammo)
{
static const float multiplier = std::max(0.f, std::min(1.0f, Settings::Manager::getFloat("projectiles enchant multiplier", "Game")));
MWWorld::Ptr player = getPlayer();
int itemsInInventoryCount = player.getClass().getContainerStore(player).count(mOldItemPtr.getCellRef().getRefId());
count = std::min(itemsInInventoryCount, std::max(1, int(getGemCharge() * multiplier / enchantPoints)));
}
}
return count;
}
float Enchanting::getTypeMultiplier() const
{
static const bool useMultiplier = Settings::Manager::getFloat("projectiles enchant multiplier", "Game") > 0;
if (useMultiplier && mWeaponType != -1 && getEnchantPoints() > 0)
{
ESM::WeaponType::Class weapclass = MWMechanics::getWeaponType(mWeaponType)->mWeaponClass;
if (weapclass == ESM::WeaponType::Thrown || weapclass == ESM::WeaponType::Ammo)
return 0.125f;
}
return 1.f;
}
void Enchanting::payForEnchantment() const
{
const MWWorld::Ptr& player = getPlayer();

View file

@ -4,6 +4,7 @@
#include <string>
#include <components/esm/effectlist.hpp>
#include <components/esm/loadench.hpp>
#include "../mwworld/ptr.hpp"
@ -25,6 +26,8 @@ namespace MWMechanics
std::string mObjectType;
int mWeaponType;
const ESM::Enchantment* getRecord(const ESM::Enchantment& newEnchantment) const;
public:
Enchanting();
void setEnchanter(const MWWorld::Ptr& enchanter);
@ -45,6 +48,8 @@ namespace MWMechanics
int getMaxEnchantValue() const;
int getGemCharge() const;
int getEnchantChance() const;
int getEnchantItemsCount() const;
float getTypeMultiplier() const;
bool soulEmpty() const; //Return true if empty
bool itemEmpty() const; //Return true if empty
void payForEnchantment() const;

View file

@ -15,7 +15,6 @@
#include <osg/TextureCubeMap>
#include <osgUtil/LineSegmentIntersector>
#include <osgUtil/IncrementalCompileOperation>
#include <osg/ImageUtils>
@ -391,6 +390,11 @@ namespace MWRender
mWorkQueue = nullptr;
}
osgUtil::IncrementalCompileOperation* RenderingManager::getIncrementalCompileOperation()
{
return mViewer->getIncrementalCompileOperation();
}
MWRender::Objects& RenderingManager::getObjects()
{
return *mObjects.get();

View file

@ -7,6 +7,8 @@
#include <components/settings/settings.hpp>
#include <osgUtil/IncrementalCompileOperation>
#include "objects.hpp"
#include "renderinginterface.hpp"
@ -89,6 +91,8 @@ namespace MWRender
const std::string& resourcePath, DetourNavigator::Navigator& navigator);
~RenderingManager();
osgUtil::IncrementalCompileOperation* getIncrementalCompileOperation();
MWRender::Objects& getObjects();
Resource::ResourceSystem* getResourceSystem();

View file

@ -23,7 +23,7 @@ class TextureOverrideVisitor : public osg::NodeVisitor
virtual void apply(osg::Node& node)
{
int index;
int index = 0;
osg::ref_ptr<osg::Node> nodePtr(&node);
if (node.getUserValue("overrideFx", index))
{

View file

@ -10,11 +10,13 @@
#include <components/interpreter/runtime.hpp>
#include <components/interpreter/opcodes.hpp>
#include "../mwbase/environment.hpp"
#include "../mwbase/world.hpp"
#include "../mwworld/player.hpp"
#include "../mwworld/cellstore.hpp"
#include "../mwworld/actionteleport.hpp"
#include "../mwworld/cellstore.hpp"
#include "../mwbase/environment.hpp"
#include "../mwworld/player.hpp"
#include "../mwbase/statemanager.hpp"
#include "../mwbase/windowmanager.hpp"
#include "../mwbase/world.hpp"
#include "../mwmechanics/actorutil.hpp"
@ -34,6 +36,52 @@ namespace MWScript
}
};
class OpTestCells : public Interpreter::Opcode0
{
public:
virtual void execute (Interpreter::Runtime& runtime)
{
if (MWBase::Environment::get().getStateManager()->getState() != MWBase::StateManager::State_NoGame)
{
runtime.getContext().report("Use TestCells from the main menu, when there is no active game session.");
return;
}
bool wasConsole = MWBase::Environment::get().getWindowManager()->isConsoleMode();
if (wasConsole)
MWBase::Environment::get().getWindowManager()->toggleConsole();
MWBase::Environment::get().getWorld()->testExteriorCells();
if (wasConsole)
MWBase::Environment::get().getWindowManager()->toggleConsole();
}
};
class OpTestInteriorCells : public Interpreter::Opcode0
{
public:
virtual void execute (Interpreter::Runtime& runtime)
{
if (MWBase::Environment::get().getStateManager()->getState() != MWBase::StateManager::State_NoGame)
{
runtime.getContext().report("Use TestInteriorCells from the main menu, when there is no active game session.");
return;
}
bool wasConsole = MWBase::Environment::get().getWindowManager()->isConsoleMode();
if (wasConsole)
MWBase::Environment::get().getWindowManager()->toggleConsole();
MWBase::Environment::get().getWorld()->testInteriorCells();
if (wasConsole)
MWBase::Environment::get().getWindowManager()->toggleConsole();
}
};
class OpCOC : public Interpreter::Opcode0
{
public:
@ -204,6 +252,8 @@ namespace MWScript
void installOpcodes (Interpreter::Interpreter& interpreter)
{
interpreter.installSegment5 (Compiler::Cell::opcodeCellChanged, new OpCellChanged);
interpreter.installSegment5 (Compiler::Cell::opcodeTestCells, new OpTestCells);
interpreter.installSegment5 (Compiler::Cell::opcodeTestInteriorCells, new OpTestInteriorCells);
interpreter.installSegment5 (Compiler::Cell::opcodeCOC, new OpCOC);
interpreter.installSegment5 (Compiler::Cell::opcodeCOE, new OpCOE);
interpreter.installSegment5 (Compiler::Cell::opcodeGetInterior, new OpGetInterior);

View file

@ -461,5 +461,7 @@ op 0x200030a: SetNavMeshNumber
op 0x200030b: Journal, explicit
op 0x200030c: RepairedOnMe
op 0x200030d: RepairedOnMe, explicit
op 0x200030e: TestCells
op 0x200030f: TestInteriorCells
opcodes 0x200030c-0x3ffffff unused
opcodes 0x2000310-0x3ffffff unused

View file

@ -12,6 +12,7 @@
#include <components/resource/resourcesystem.hpp>
#include <components/resource/scenemanager.hpp>
#include <components/resource/bulletshape.hpp>
#include <components/sceneutil/unrefqueue.hpp>
#include <components/detournavigator/navigator.hpp>
#include <components/detournavigator/debug.hpp>
#include <components/misc/convert.hpp>
@ -33,6 +34,8 @@
#include "../mwbase/mechanicsmanager.hpp"
#include "../mwbase/windowmanager.hpp"
#include "../mwmechanics/actorutil.hpp"
#include "../mwrender/renderingmanager.hpp"
#include "../mwrender/landmanager.hpp"
@ -216,10 +219,11 @@ namespace
{
MWWorld::CellStore& mCell;
Loading::Listener& mLoadingListener;
bool mTest;
std::vector<MWWorld::Ptr> mToInsert;
InsertVisitor (MWWorld::CellStore& cell, Loading::Listener& loadingListener);
InsertVisitor (MWWorld::CellStore& cell, Loading::Listener& loadingListener, bool test);
bool operator() (const MWWorld::Ptr& ptr);
@ -227,8 +231,8 @@ namespace
void insert(AddObject&& addObject);
};
InsertVisitor::InsertVisitor (MWWorld::CellStore& cell, Loading::Listener& loadingListener)
: mCell (cell), mLoadingListener (loadingListener)
InsertVisitor::InsertVisitor (MWWorld::CellStore& cell, Loading::Listener& loadingListener, bool test)
: mCell (cell), mLoadingListener (loadingListener), mTest(test)
{}
bool InsertVisitor::operator() (const MWWorld::Ptr& ptr)
@ -257,7 +261,8 @@ namespace
}
}
mLoadingListener.increaseProgress (1);
if (!mTest)
mLoadingListener.increaseProgress (1);
}
}
@ -328,9 +333,10 @@ namespace MWWorld
mPreloader->updateCache(mRendering.getReferenceTime());
}
void Scene::unloadCell (CellStoreCollection::iterator iter)
void Scene::unloadCell (CellStoreCollection::iterator iter, bool test)
{
Log(Debug::Info) << "Unloading cell " << (*iter)->getCell()->getDescription();
if (!test)
Log(Debug::Info) << "Unloading cell " << (*iter)->getCell()->getDescription();
const auto navigator = MWBase::Environment::get().getWorld()->getNavigator();
ListAndResetObjectsVisitor visitor;
@ -405,13 +411,16 @@ namespace MWWorld
*/
}
void Scene::loadCell (CellStore *cell, Loading::Listener* loadingListener, bool respawn)
void Scene::loadCell (CellStore *cell, Loading::Listener* loadingListener, bool respawn, bool test)
{
std::pair<CellStoreCollection::iterator, bool> result = mActiveCells.insert(cell);
if(result.second)
{
Log(Debug::Info) << "Loading cell " << cell->getCell()->getDescription();
if (test)
Log(Debug::Info) << "Testing cell " << cell->getCell()->getDescription();
else
Log(Debug::Info) << "Loading cell " << cell->getCell()->getDescription();
float verts = ESM::Land::LAND_SIZE;
float worldsize = ESM::Land::REAL_SIZE;
@ -422,7 +431,7 @@ namespace MWWorld
const int cellY = cell->getCell()->getGridY();
// Load terrain physics first...
if (cell->getCell()->isExterior())
if (!test && cell->getCell()->isExterior())
{
osg::ref_ptr<const ESMTerrain::LandObject> land = mRendering.getLandManager()->getLand(cellX, cellY);
const ESM::Land::LandData* data = land ? land->getData(ESM::Land::DATA_VHGT) : 0;
@ -450,48 +459,54 @@ namespace MWWorld
cell->respawn();
// ... then references. This is important for adjustPosition to work correctly.
insertCell (*cell, loadingListener);
insertCell (*cell, loadingListener, test);
mRendering.addCell(cell);
MWBase::Environment::get().getWindowManager()->addCell(cell);
bool waterEnabled = cell->getCell()->hasWater() || cell->isExterior();
float waterLevel = cell->getWaterLevel();
mRendering.setWaterEnabled(waterEnabled);
if (waterEnabled)
if (!test)
{
mPhysics->enableWater(waterLevel);
mRendering.setWaterHeight(waterLevel);
if (cell->getCell()->isExterior())
MWBase::Environment::get().getWindowManager()->addCell(cell);
bool waterEnabled = cell->getCell()->hasWater() || cell->isExterior();
float waterLevel = cell->getWaterLevel();
mRendering.setWaterEnabled(waterEnabled);
if (waterEnabled)
{
if (const auto heightField = mPhysics->getHeightField(cellX, cellY))
navigator->addWater(osg::Vec2i(cellX, cellY), ESM::Land::REAL_SIZE,
cell->getWaterLevel(), heightField->getCollisionObject()->getWorldTransform());
mPhysics->enableWater(waterLevel);
mRendering.setWaterHeight(waterLevel);
if (cell->getCell()->isExterior())
{
if (const auto heightField = mPhysics->getHeightField(cellX, cellY))
navigator->addWater(osg::Vec2i(cellX, cellY), ESM::Land::REAL_SIZE,
cell->getWaterLevel(), heightField->getCollisionObject()->getWorldTransform());
}
else
{
navigator->addWater(osg::Vec2i(cellX, cellY), std::numeric_limits<int>::max(),
cell->getWaterLevel(), btTransform::getIdentity());
}
}
else
mPhysics->disableWater();
const auto player = MWBase::Environment::get().getWorld()->getPlayerPtr();
navigator->update(player.getRefData().getPosition().asVec3());
if (!cell->isExterior() && !(cell->getCell()->mData.mFlags & ESM::Cell::QuasiEx))
{
navigator->addWater(osg::Vec2i(cellX, cellY), std::numeric_limits<int>::max(),
cell->getWaterLevel(), btTransform::getIdentity());
mRendering.configureAmbient(cell->getCell());
}
/*
Start of tes3mp addition
Store a cell load for the LocalPlayer
*/
mwmp::Main::get().getLocalPlayer()->storeCellState(*cell->getCell(), mwmp::CellState::LOAD);
/*
End of tes3mp addition
*/
}
else
mPhysics->disableWater();
const auto player = MWBase::Environment::get().getWorld()->getPlayerPtr();
navigator->update(player.getRefData().getPosition().asVec3());
if (!cell->isExterior() && !(cell->getCell()->mData.mFlags & ESM::Cell::QuasiEx))
mRendering.configureAmbient(cell->getCell());
/*
Start of tes3mp addition
Store a cell load for the LocalPlayer
*/
mwmp::Main::get().getLocalPlayer()->storeCellState(*cell->getCell(), mwmp::CellState::LOAD);
/*
End of tes3mp addition
*/
}
mPreloader->notifyLoaded(cell);
@ -651,6 +666,101 @@ namespace MWWorld
mCellChanged = true;
}
void Scene::testExteriorCells()
{
// Note: temporary disable ICO to decrease memory usage
mRendering.getResourceSystem()->getSceneManager()->setIncrementalCompileOperation(nullptr);
mRendering.getResourceSystem()->setExpiryDelay(1.f);
const MWWorld::Store<ESM::Cell> &cells = MWBase::Environment::get().getWorld()->getStore().get<ESM::Cell>();
Loading::Listener* loadingListener = MWBase::Environment::get().getWindowManager()->getLoadingScreen();
Loading::ScopedLoad load(loadingListener);
loadingListener->setProgressRange(cells.getExtSize());
MWWorld::Store<ESM::Cell>::iterator it = cells.extBegin();
int i = 1;
for (; it != cells.extEnd(); ++it)
{
loadingListener->setLabel("Testing exterior cells ("+std::to_string(i)+"/"+std::to_string(cells.getExtSize())+")...");
CellStoreCollection::iterator iter = mActiveCells.begin();
CellStore *cell = MWBase::Environment::get().getWorld()->getExterior(it->mData.mX, it->mData.mY);
loadCell (cell, loadingListener, false, true);
iter = mActiveCells.begin();
while (iter != mActiveCells.end())
{
if (it->isExterior() && it->mData.mX == (*iter)->getCell()->getGridX() &&
it->mData.mY == (*iter)->getCell()->getGridY())
{
unloadCell(iter, true);
break;
}
++iter;
}
mRendering.getResourceSystem()->updateCache(mRendering.getReferenceTime());
mRendering.getUnrefQueue()->flush(mRendering.getWorkQueue());
loadingListener->increaseProgress (1);
i++;
}
mRendering.getResourceSystem()->getSceneManager()->setIncrementalCompileOperation(mRendering.getIncrementalCompileOperation());
mRendering.getResourceSystem()->setExpiryDelay(Settings::Manager::getFloat("cache expiry delay", "Cells"));
}
void Scene::testInteriorCells()
{
// Note: temporary disable ICO to decrease memory usage
mRendering.getResourceSystem()->getSceneManager()->setIncrementalCompileOperation(nullptr);
mRendering.getResourceSystem()->setExpiryDelay(1.f);
const MWWorld::Store<ESM::Cell> &cells = MWBase::Environment::get().getWorld()->getStore().get<ESM::Cell>();
Loading::Listener* loadingListener = MWBase::Environment::get().getWindowManager()->getLoadingScreen();
Loading::ScopedLoad load(loadingListener);
loadingListener->setProgressRange(cells.getIntSize());
int i = 1;
MWWorld::Store<ESM::Cell>::iterator it = cells.intBegin();
for (; it != cells.intEnd(); ++it)
{
loadingListener->setLabel("Testing interior cells ("+std::to_string(i)+"/"+std::to_string(cells.getIntSize())+")...");
CellStore *cell = MWBase::Environment::get().getWorld()->getInterior(it->mName);
loadCell (cell, loadingListener, false, true);
CellStoreCollection::iterator iter = mActiveCells.begin();
while (iter != mActiveCells.end())
{
assert (!(*iter)->getCell()->isExterior());
if (it->mName == (*iter)->getCell()->mName)
{
unloadCell(iter, true);
break;
}
++iter;
}
mRendering.getResourceSystem()->updateCache(mRendering.getReferenceTime());
mRendering.getUnrefQueue()->flush(mRendering.getWorkQueue());
loadingListener->increaseProgress (1);
i++;
}
mRendering.getResourceSystem()->getSceneManager()->setIncrementalCompileOperation(mRendering.getIncrementalCompileOperation());
mRendering.getResourceSystem()->setExpiryDelay(Settings::Manager::getFloat("cache expiry delay", "Cells"));
}
void Scene::changePlayerCell(CellStore *cell, const ESM::Position &pos, bool adjustPlayerPos)
{
mCurrentCell = cell;
@ -831,9 +941,9 @@ namespace MWWorld
mCellChanged = false;
}
void Scene::insertCell (CellStore &cell, Loading::Listener* loadingListener)
void Scene::insertCell (CellStore &cell, Loading::Listener* loadingListener, bool test)
{
InsertVisitor insertVisitor (cell, *loadingListener);
InsertVisitor insertVisitor (cell, *loadingListener, test);
cell.forEach (insertVisitor);
insertVisitor.insert([&] (const MWWorld::Ptr& ptr) { addObject(ptr, *mPhysics, mRendering); });
insertVisitor.insert([&] (const MWWorld::Ptr& ptr) { addObject(ptr, *mPhysics, mNavigator); });

View file

@ -85,7 +85,7 @@ namespace MWWorld
osg::Vec3f mLastPlayerPos;
void insertCell (CellStore &cell, Loading::Listener* loadingListener);
void insertCell (CellStore &cell, Loading::Listener* loadingListener, bool test = false);
// Load and unload cells as necessary to create a cell grid with "X" and "Y" in the center
void changeCellGrid (int playerCellX, int playerCellY, bool changeEvent = true);
@ -107,9 +107,9 @@ namespace MWWorld
void preloadCell(MWWorld::CellStore* cell, bool preloadSurrounding=false);
void preloadTerrain(const osg::Vec3f& pos);
void unloadCell (CellStoreCollection::iterator iter);
void unloadCell (CellStoreCollection::iterator iter, bool test = false);
void loadCell (CellStore *cell, Loading::Listener* loadingListener, bool respawn);
void loadCell (CellStore *cell, Loading::Listener* loadingListener, bool respawn, bool test = false);
void playerMoved (const osg::Vec3f& pos);
@ -151,6 +151,9 @@ namespace MWWorld
Ptr searchPtrViaActorId (int actorId);
void preload(const std::string& mesh, bool useAnim=false);
void testExteriorCells();
void testInteriorCells();
};
}

View file

@ -792,6 +792,14 @@ namespace MWWorld
{
return mSharedInt.size() + mSharedExt.size();
}
size_t Store<ESM::Cell>::getExtSize() const
{
return mSharedExt.size();
}
size_t Store<ESM::Cell>::getIntSize() const
{
return mSharedInt.size();
}
void Store<ESM::Cell>::listIdentifier(std::vector<std::string> &list) const
{
list.reserve(list.size() + mSharedInt.size());

View file

@ -106,6 +106,11 @@ namespace MWWorld
return iter;
}
SharedIterator &operator+=(int advance) {
mIter += advance;
return *this;
}
SharedIterator &operator--() {
--mIter;
return *this;
@ -314,6 +319,8 @@ namespace MWWorld
const ESM::Cell *searchExtByRegion(const std::string &id) const;
size_t getSize() const;
size_t getExtSize() const;
size_t getIntSize() const;
void listIdentifier(std::vector<std::string> &list) const;

View file

@ -617,6 +617,16 @@ namespace MWWorld
return getInterior (id.mWorldspace);
}
void World::testExteriorCells()
{
mWorldScene->testExteriorCells();
}
void World::testInteriorCells()
{
mWorldScene->testInteriorCells();
}
void World::useDeathCamera()
{
if(mRendering->getCamera()->isVanityOrPreviewModeEnabled() )

View file

@ -232,6 +232,9 @@ namespace MWWorld
CellStore *getCell (const ESM::CellId& id) override;
void testExteriorCells() override;
void testInteriorCells() override;
//switch to POV before showing player's death animation
void useDeathCamera() override;

View file

@ -89,6 +89,8 @@ namespace Compiler
void registerExtensions (Extensions& extensions)
{
extensions.registerFunction ("cellchanged", 'l', "", opcodeCellChanged);
extensions.registerInstruction("testcells", "", opcodeTestCells);
extensions.registerInstruction("testinteriorcells", "", opcodeTestInteriorCells);
extensions.registerInstruction ("coc", "S", opcodeCOC);
extensions.registerInstruction ("centeroncell", "S", opcodeCOC);
extensions.registerInstruction ("coe", "ll", opcodeCOE);

View file

@ -75,6 +75,8 @@ namespace Compiler
namespace Cell
{
const int opcodeCellChanged = 0x2000000;
const int opcodeTestCells = 0x200030e;
const int opcodeTestInteriorCells = 0x200030f;
const int opcodeCOC = 0x2000026;
const int opcodeCOE = 0x2000226;
const int opcodeGetInterior = 0x2000131;

View file

@ -30,7 +30,7 @@ namespace DetourNavigator
public:
struct Water
{
int mCellSize;
int mCellSize = 0;
btTransform mTransform;
};

View file

@ -168,9 +168,8 @@ void ESM::CellRef::save (ESMWriter &esm, bool wideRefNum, bool inInventory, bool
if (mChargeInt != -1)
esm.writeHNT("INTV", mChargeInt);
if (mGoldValue != 1) {
if (mGoldValue > 1)
esm.writeHNT("NAM9", mGoldValue);
}
if (!inInventory && mTeleport)
{
@ -208,7 +207,7 @@ void ESM::CellRef::blank()
mChargeInt = -1;
mChargeIntRemainder = 0.0f;
mEnchantmentCharge = -1;
mGoldValue = 0;
mGoldValue = 1;
mDestCell.clear();
mLockLevel = 0;
mKey.clear();

View file

@ -3,6 +3,8 @@
#include "esmreader.hpp"
#include "esmwriter.hpp"
#include <components/debug/debuglog.hpp>
namespace ESM
{
@ -12,12 +14,20 @@ namespace ESM
mDoorState = 0;
esm.getHNOT (mDoorState, "ANIM");
if (mDoorState < 0 || mDoorState > 2)
Log(Debug::Warning) << "Dropping invalid door state (" << mDoorState << ") for door \"" << mRef.mRefID << "\"";
}
void DoorState::save(ESMWriter &esm, bool inInventory) const
{
ObjectState::save(esm, inInventory);
if (mDoorState < 0 || mDoorState > 2)
{
Log(Debug::Warning) << "Dropping invalid door state (" << mDoorState << ") for door \"" << mRef.mRefID << "\"";
return;
}
if (mDoorState != 0)
esm.writeHNT ("ANIM", mDoorState);
}

View file

@ -9,7 +9,7 @@ namespace ESM
struct DoorState : public ObjectState
{
int mDoorState;
int mDoorState = 0;
virtual void load (ESMReader &esm);
virtual void save (ESMWriter &esm, bool inInventory = false) const;

View file

@ -261,7 +261,7 @@ void LowLevelFile::open (char const * filename)
if (handle == INVALID_HANDLE_VALUE)
{
std::ostringstream os;
os << "Failed to open '" << filename << "' for reading.";
os << "Failed to open '" << filename << "' for reading: " << GetLastError();
throw std::runtime_error (os.str ());
}

View file

@ -282,3 +282,19 @@ equivalent to the one introduced by the equivalent Morrowind Code Patch feature.
This makes the movement speed behavior more fair between different races.
This setting can be controlled in Advanced tab of the launcher.
projectiles enchant multiplier
------------------------------
:Type: floating point
:Range: 0.0 to 1.0
:Default: 0.0
The value of this setting determines how many projectiles (thrown weapons, arrows and bolts) you can enchant at once according to the following formula:
count = (soul gem charge * projectiles enchant multiplier) / enchantment strength
A value of 0 means that you can only enchant one projectile.
If you want to have Morrowind Code Patch-like count of projectiles being enchanted at once, set this value to 0.25 (i.e. 25% of the charge).
This setting can only be configured by editing the settings configuration file.

View file

@ -306,6 +306,10 @@ struct dtMeshTile
int dataSize; ///< Size of the tile data.
int flags; ///< Tile flags. (See: #dtTileFlags)
dtMeshTile* next; ///< The next free tile, or the next tile in the spatial grid.
// OpenMW code - make dtMeshTile POD since R&D init it by memset
//private:
// dtMeshTile(const dtMeshTile&);
// dtMeshTile& operator=(const dtMeshTile&);
};
/// Get flags for edge in detail triangle.

View file

@ -267,6 +267,11 @@ use magic item animations = false
# Don't use race weight in NPC movement speed calculations
normalise race speed = false
# Adjusts the number of projectiles you can enchant at once:
# count = (soul gem charge * projectiles enchant multiplier) / enchantment strength
# A value of 0 means that you can only enchant one projectile.
projectiles enchant multiplier = 0
[General]
# Anisotropy reduces distortion in textures at low angles (e.g. 0 to 16).