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:
commit
a58f09fd6c
29 changed files with 420 additions and 76 deletions
|
@ -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
|
||||
|
|
|
@ -2,7 +2,6 @@
|
|||
|
||||
brew update
|
||||
brew outdated pkgconfig || brew upgrade pkgconfig
|
||||
brew install cmake
|
||||
brew install qt
|
||||
brew install ccache
|
||||
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
{
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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());
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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))
|
||||
{
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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); });
|
||||
|
|
|
@ -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();
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
@ -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());
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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() )
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -30,7 +30,7 @@ namespace DetourNavigator
|
|||
public:
|
||||
struct Water
|
||||
{
|
||||
int mCellSize;
|
||||
int mCellSize = 0;
|
||||
btTransform mTransform;
|
||||
};
|
||||
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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 ());
|
||||
}
|
||||
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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).
|
||||
|
|
Loading…
Reference in a new issue