diff --git a/CMakeLists.txt b/CMakeLists.txt index 47e50e769a..d1cc16b8b2 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -81,7 +81,7 @@ message(STATUS "Configuring OpenMW...") set(OPENMW_VERSION_MAJOR 0) set(OPENMW_VERSION_MINOR 49) set(OPENMW_VERSION_RELEASE 0) -set(OPENMW_LUA_API_REVISION 60) +set(OPENMW_LUA_API_REVISION 61) set(OPENMW_POSTPROCESSING_API_REVISION 1) set(OPENMW_VERSION_COMMITHASH "") diff --git a/apps/essimporter/importproj.h b/apps/essimporter/importproj.h index a2e03b5ba3..04c7b4003e 100644 --- a/apps/essimporter/importproj.h +++ b/apps/essimporter/importproj.h @@ -2,7 +2,8 @@ #define OPENMW_ESSIMPORT_IMPORTPROJ_H #include -#include +#include + #include #include diff --git a/apps/launcher/ui/mainwindow.ui b/apps/launcher/ui/mainwindow.ui index 862ae2430e..6a2502f466 100644 --- a/apps/launcher/ui/mainwindow.ui +++ b/apps/launcher/ui/mainwindow.ui @@ -6,13 +6,13 @@ 0 0 - 750 + 775 635 - 750 + 775 635 diff --git a/apps/opencs/view/world/scriptedit.cpp b/apps/opencs/view/world/scriptedit.cpp index c8505f007f..00acf71235 100644 --- a/apps/opencs/view/world/scriptedit.cpp +++ b/apps/opencs/view/world/scriptedit.cpp @@ -2,6 +2,7 @@ #include +#include #include #include #include @@ -424,6 +425,7 @@ void CSVWorld::ScriptEdit::lineNumberAreaPaintEvent(QPaintEvent* event) painter.setBackgroundMode(Qt::OpaqueMode); QFont font = painter.font(); QBrush background = painter.background(); + QColor textColor = QApplication::palette().text().color(); while (block.isValid() && top <= event->rect().bottom()) { @@ -440,7 +442,7 @@ void CSVWorld::ScriptEdit::lineNumberAreaPaintEvent(QPaintEvent* event) else { painter.setBackground(background); - painter.setPen(Qt::black); + painter.setPen(textColor); } painter.setFont(newFont); painter.drawText(0, top, mLineNumberArea->width(), fontMetrics().height(), Qt::AlignRight, number); diff --git a/apps/openmw/mwgui/loadingscreen.cpp b/apps/openmw/mwgui/loadingscreen.cpp index 3a9aba7828..3d9cfa5c44 100644 --- a/apps/openmw/mwgui/loadingscreen.cpp +++ b/apps/openmw/mwgui/loadingscreen.cpp @@ -343,7 +343,12 @@ namespace MWGui MWBase::Environment::get().getInputManager()->update(0, true, true); - mResourceSystem->reportStats(mViewer->getFrameStamp()->getFrameNumber(), mViewer->getViewerStats()); + osg::Stats* const stats = mViewer->getViewerStats(); + const unsigned frameNumber = mViewer->getFrameStamp()->getFrameNumber(); + + stats->setAttribute(frameNumber, "Loading", 1); + + mResourceSystem->reportStats(frameNumber, stats); if (osgUtil::IncrementalCompileOperation* ico = mViewer->getIncrementalCompileOperation()) { ico->setMinimumTimeAvailableForGLCompileAndDeletePerFrame(1.f / getTargetFrameRate()); diff --git a/apps/openmw/mwlua/localscripts.cpp b/apps/openmw/mwlua/localscripts.cpp index 8fa0571afc..3b0d44a984 100644 --- a/apps/openmw/mwlua/localscripts.cpp +++ b/apps/openmw/mwlua/localscripts.cpp @@ -104,7 +104,27 @@ namespace MWLua }); aiPackage["sideWithTarget"] = sol::readonly_property([](const AiPackage& p) { return p.sideWithTarget(); }); aiPackage["destPosition"] = sol::readonly_property([](const AiPackage& p) { return p.getDestination(); }); + aiPackage["distance"] = sol::readonly_property([](const AiPackage& p) { return p.getDistance(); }); + aiPackage["duration"] = sol::readonly_property([](const AiPackage& p) { return p.getDuration(); }); + aiPackage["idle"] = sol::readonly_property([context](const AiPackage& p) -> sol::optional { + if (p.getTypeId() == MWMechanics::AiPackageTypeId::Wander) + { + sol::table idles(context.mLua->sol(), sol::create); + const std::vector& idle = static_cast(p).getIdle(); + if (!idle.empty()) + { + for (size_t i = 0; i < idle.size(); ++i) + { + std::string_view groupName = MWMechanics::AiWander::getIdleGroupName(i); + idles[groupName] = idle[i]; + } + return idles; + } + } + return sol::nullopt; + }); + aiPackage["isRepeat"] = sol::readonly_property([](const AiPackage& p) { return p.getRepeat(); }); selfAPI["_getActiveAiPackage"] = [](SelfObject& self) -> sol::optional> { const MWWorld::Ptr& ptr = self.ptr(); MWMechanics::AiSequence& ai = ptr.getClass().getCreatureStats(ptr).getAiSequence(); @@ -132,13 +152,25 @@ namespace MWLua MWMechanics::AiSequence& ai = ptr.getClass().getCreatureStats(ptr).getAiSequence(); ai.stack(MWMechanics::AiPursue(target.ptr()), ptr, cancelOther); }; - selfAPI["_startAiFollow"] = [](SelfObject& self, const LObject& target, bool cancelOther) { + selfAPI["_startAiFollow"] = [](SelfObject& self, const LObject& target, sol::optional cell, + float duration, const osg::Vec3f& dest, bool repeat, bool cancelOther) { const MWWorld::Ptr& ptr = self.ptr(); MWMechanics::AiSequence& ai = ptr.getClass().getCreatureStats(ptr).getAiSequence(); - ai.stack(MWMechanics::AiFollow(target.ptr()), ptr, cancelOther); + if (cell) + { + ai.stack(MWMechanics::AiFollow(target.ptr().getCellRef().getRefId(), + cell->mStore->getCell()->getNameId(), duration, dest.x(), dest.y(), dest.z(), repeat), + ptr, cancelOther); + } + else + { + ai.stack(MWMechanics::AiFollow( + target.ptr().getCellRef().getRefId(), duration, dest.x(), dest.y(), dest.z(), repeat), + ptr, cancelOther); + } }; selfAPI["_startAiEscort"] = [](SelfObject& self, const LObject& target, LCell cell, float duration, - const osg::Vec3f& dest, bool cancelOther) { + const osg::Vec3f& dest, bool repeat, bool cancelOther) { const MWWorld::Ptr& ptr = self.ptr(); MWMechanics::AiSequence& ai = ptr.getClass().getCreatureStats(ptr).getAiSequence(); // TODO: change AiEscort implementation to accept ptr instead of a non-unique refId. @@ -146,23 +178,27 @@ namespace MWLua int gameHoursDuration = static_cast(std::ceil(duration / 3600.0)); auto* esmCell = cell.mStore->getCell(); if (esmCell->isExterior()) - ai.stack(MWMechanics::AiEscort(refId, gameHoursDuration, dest.x(), dest.y(), dest.z(), false), ptr, + ai.stack(MWMechanics::AiEscort(refId, gameHoursDuration, dest.x(), dest.y(), dest.z(), repeat), ptr, cancelOther); else ai.stack(MWMechanics::AiEscort( - refId, esmCell->getNameId(), gameHoursDuration, dest.x(), dest.y(), dest.z(), false), + refId, esmCell->getNameId(), gameHoursDuration, dest.x(), dest.y(), dest.z(), repeat), ptr, cancelOther); }; - selfAPI["_startAiWander"] = [](SelfObject& self, int distance, float duration, bool cancelOther) { + selfAPI["_startAiWander"] + = [](SelfObject& self, int distance, int duration, sol::table luaIdle, bool repeat, bool cancelOther) { + const MWWorld::Ptr& ptr = self.ptr(); + MWMechanics::AiSequence& ai = ptr.getClass().getCreatureStats(ptr).getAiSequence(); + std::vector idle; + // Lua index starts at 1 + for (size_t i = 1; i <= luaIdle.size(); i++) + idle.emplace_back(luaIdle.get(i)); + ai.stack(MWMechanics::AiWander(distance, duration, 0, idle, repeat), ptr, cancelOther); + }; + selfAPI["_startAiTravel"] = [](SelfObject& self, const osg::Vec3f& target, bool repeat, bool cancelOther) { const MWWorld::Ptr& ptr = self.ptr(); MWMechanics::AiSequence& ai = ptr.getClass().getCreatureStats(ptr).getAiSequence(); - int gameHoursDuration = static_cast(std::ceil(duration / 3600.0)); - ai.stack(MWMechanics::AiWander(distance, gameHoursDuration, 0, {}, false), ptr, cancelOther); - }; - selfAPI["_startAiTravel"] = [](SelfObject& self, const osg::Vec3f& target, bool cancelOther) { - const MWWorld::Ptr& ptr = self.ptr(); - MWMechanics::AiSequence& ai = ptr.getClass().getCreatureStats(ptr).getAiSequence(); - ai.stack(MWMechanics::AiTravel(target.x(), target.y(), target.z(), false), ptr, cancelOther); + ai.stack(MWMechanics::AiTravel(target.x(), target.y(), target.z(), repeat), ptr, cancelOther); }; selfAPI["_enableLuaAnimations"] = [](SelfObject& self, bool enable) { const MWWorld::Ptr& ptr = self.ptr(); diff --git a/apps/openmw/mwmechanics/aiescort.cpp b/apps/openmw/mwmechanics/aiescort.cpp index 380c0ace9f..9e6df46340 100644 --- a/apps/openmw/mwmechanics/aiescort.cpp +++ b/apps/openmw/mwmechanics/aiescort.cpp @@ -1,5 +1,6 @@ #include "aiescort.hpp" +#include #include #include #include diff --git a/apps/openmw/mwmechanics/aiescort.hpp b/apps/openmw/mwmechanics/aiescort.hpp index 709b2bee59..d88ecac6a5 100644 --- a/apps/openmw/mwmechanics/aiescort.hpp +++ b/apps/openmw/mwmechanics/aiescort.hpp @@ -51,6 +51,8 @@ namespace MWMechanics osg::Vec3f getDestination() const override { return osg::Vec3f(mX, mY, mZ); } + std::optional getDuration() const override { return mDuration; } + private: const std::string mCellId; const float mX; diff --git a/apps/openmw/mwmechanics/aipackage.hpp b/apps/openmw/mwmechanics/aipackage.hpp index 29a9f9c9ad..ca33f5dc90 100644 --- a/apps/openmw/mwmechanics/aipackage.hpp +++ b/apps/openmw/mwmechanics/aipackage.hpp @@ -110,6 +110,10 @@ namespace MWMechanics virtual osg::Vec3f getDestination() const { return osg::Vec3f(0, 0, 0); } + virtual std::optional getDistance() const { return std::nullopt; } + + virtual std::optional getDuration() const { return std::nullopt; } + /// Return true if any loaded actor with this AI package must be active. bool alwaysActive() const { return mOptions.mAlwaysActive; } diff --git a/apps/openmw/mwmechanics/aiwander.hpp b/apps/openmw/mwmechanics/aiwander.hpp index 6d5bd7f8cd..aed7214f4d 100644 --- a/apps/openmw/mwmechanics/aiwander.hpp +++ b/apps/openmw/mwmechanics/aiwander.hpp @@ -113,6 +113,14 @@ namespace MWMechanics bool isStationary() const { return mDistance == 0; } + std::optional getDistance() const override { return mDistance; } + + std::optional getDuration() const override { return static_cast(mDuration); } + + const std::vector& getIdle() const { return mIdle; } + + static std::string_view getIdleGroupName(size_t index) { return sIdleSelectToGroupName[index]; } + private: void stopWalking(const MWWorld::Ptr& actor); diff --git a/apps/openmw/mwphysics/mtphysics.hpp b/apps/openmw/mwphysics/mtphysics.hpp index 57f3711096..579211b489 100644 --- a/apps/openmw/mwphysics/mtphysics.hpp +++ b/apps/openmw/mwphysics/mtphysics.hpp @@ -3,7 +3,9 @@ #include #include +#include #include +#include #include #include #include diff --git a/apps/openmw/mwphysics/physicssystem.hpp b/apps/openmw/mwphysics/physicssystem.hpp index 9cc55fecc6..876f8e8164 100644 --- a/apps/openmw/mwphysics/physicssystem.hpp +++ b/apps/openmw/mwphysics/physicssystem.hpp @@ -6,7 +6,6 @@ #include #include #include -#include #include #include #include @@ -16,8 +15,6 @@ #include #include -#include - #include "../mwworld/ptr.hpp" #include "collisiontype.hpp" diff --git a/apps/openmw/mwrender/landmanager.hpp b/apps/openmw/mwrender/landmanager.hpp index 7166c4b111..1b82f32ce9 100644 --- a/apps/openmw/mwrender/landmanager.hpp +++ b/apps/openmw/mwrender/landmanager.hpp @@ -3,7 +3,7 @@ #include -#include +#include #include #include diff --git a/apps/openmw/mwrender/objectpaging.cpp b/apps/openmw/mwrender/objectpaging.cpp index f426672784..f3e9570aa4 100644 --- a/apps/openmw/mwrender/objectpaging.cpp +++ b/apps/openmw/mwrender/objectpaging.cpp @@ -555,11 +555,19 @@ namespace MWRender // TODO } - if (activeGrid) + if (activeGrid && !refs.empty()) { std::lock_guard lock(mRefTrackerMutex); - for (auto ref : getRefTracker().mBlacklist) - refs.erase(ref); + const std::set& blacklist = getRefTracker().mBlacklist; + if (blacklist.size() < refs.size()) + { + for (ESM::RefNum ref : blacklist) + refs.erase(ref); + } + else + { + std::erase_if(refs, [&](const auto& ref) { return blacklist.contains(ref.first); }); + } } osg::Vec2f minBound = (center - osg::Vec2f(size / 2.f, size / 2.f)); diff --git a/apps/openmw/mwscript/cellextensions.cpp b/apps/openmw/mwscript/cellextensions.cpp index 3a8318a7a3..d913eb0915 100644 --- a/apps/openmw/mwscript/cellextensions.cpp +++ b/apps/openmw/mwscript/cellextensions.cpp @@ -11,6 +11,8 @@ #include +#include + #include "../mwbase/environment.hpp" #include "../mwbase/statemanager.hpp" #include "../mwbase/windowmanager.hpp" @@ -123,7 +125,7 @@ namespace MWScript MWBase::World* world = MWBase::Environment::get().getWorld(); MWWorld::Ptr playerPtr = world->getPlayerPtr(); - osg::Vec2 posFromIndex + const osg::Vec2f posFromIndex = ESM::indexToPosition(ESM::ExteriorCellLocation(x, y, ESM::Cell::sDefaultWorldspaceId), true); pos.pos[0] = posFromIndex.x(); pos.pos[1] = posFromIndex.y(); diff --git a/apps/openmw/mwscript/transformationextensions.cpp b/apps/openmw/mwscript/transformationextensions.cpp index 614fbbe26f..7144147843 100644 --- a/apps/openmw/mwscript/transformationextensions.cpp +++ b/apps/openmw/mwscript/transformationextensions.cpp @@ -4,6 +4,8 @@ #include +#include + #include #include diff --git a/apps/openmw/mwstate/statemanagerimp.cpp b/apps/openmw/mwstate/statemanagerimp.cpp index 5b2ad010ea..3ced01d28f 100644 --- a/apps/openmw/mwstate/statemanagerimp.cpp +++ b/apps/openmw/mwstate/statemanagerimp.cpp @@ -624,7 +624,7 @@ void MWState::StateManager::loadGame(const Character* character, const std::file Log(Debug::Warning) << "Player character's cell no longer exists, changing to the default cell"; ESM::ExteriorCellLocation cellIndex(0, 0, ESM::Cell::sDefaultWorldspaceId); MWWorld::CellStore& cell = MWBase::Environment::get().getWorldModel()->getExterior(cellIndex); - osg::Vec2 posFromIndex = ESM::indexToPosition(cellIndex, false); + const osg::Vec2f posFromIndex = ESM::indexToPosition(cellIndex, false); ESM::Position pos; pos.pos[0] = posFromIndex.x(); pos.pos[1] = posFromIndex.y(); diff --git a/apps/openmw/mwworld/cell.hpp b/apps/openmw/mwworld/cell.hpp index 1fa088eac4..eab5024e12 100644 --- a/apps/openmw/mwworld/cell.hpp +++ b/apps/openmw/mwworld/cell.hpp @@ -4,8 +4,8 @@ #include #include +#include #include -#include namespace ESM { diff --git a/apps/openmw/mwworld/projectilemanager.cpp b/apps/openmw/mwworld/projectilemanager.cpp index d6715c5ad2..4daa85a450 100644 --- a/apps/openmw/mwworld/projectilemanager.cpp +++ b/apps/openmw/mwworld/projectilemanager.cpp @@ -15,6 +15,9 @@ #include #include +#include +#include + #include #include #include diff --git a/apps/openmw/mwworld/scene.cpp b/apps/openmw/mwworld/scene.cpp index b373bf416e..169e4bfd21 100644 --- a/apps/openmw/mwworld/scene.cpp +++ b/apps/openmw/mwworld/scene.cpp @@ -542,7 +542,7 @@ namespace MWWorld = mCurrentCell ? mCurrentCell->getCell()->getWorldSpace() : ESM::Cell::sDefaultWorldspaceId; if (currentGridCenter) { - osg::Vec2 center = ESM::indexToPosition( + const osg::Vec2f center = ESM::indexToPosition( ESM::ExteriorCellLocation(currentGridCenter->x(), currentGridCenter->y(), worldspace), true); float distance = std::max(std::abs(center.x() - pos.x()), std::abs(center.y() - pos.y())); float cellSize = ESM::getCellSize(worldspace); @@ -1171,7 +1171,7 @@ namespace MWWorld && dx != -halfGridSizePlusOne) continue; // only care about the outer (not yet loaded) part of the grid ESM::ExteriorCellLocation cellIndex(cellX + dx, cellY + dy, extWorldspace); - osg::Vec2 thisCellCenter = ESM::indexToPosition(cellIndex, true); + const osg::Vec2f thisCellCenter = ESM::indexToPosition(cellIndex, true); float dist = std::max( std::abs(thisCellCenter.x() - playerPos.x()), std::abs(thisCellCenter.y() - playerPos.y())); diff --git a/apps/openmw/mwworld/scene.hpp b/apps/openmw/mwworld/scene.hpp index 96050bad32..91feff8746 100644 --- a/apps/openmw/mwworld/scene.hpp +++ b/apps/openmw/mwworld/scene.hpp @@ -10,10 +10,9 @@ #include #include #include -#include #include -#include +#include #include namespace osg diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index 24731055ad..a4464d70ad 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -2784,7 +2784,7 @@ namespace MWWorld int x = ext->getGridX(); int y = ext->getGridY(); - osg::Vec2 posFromIndex = indexToPosition(ESM::ExteriorCellLocation(x, y, ext->getWorldSpace()), true); + const osg::Vec2f posFromIndex = indexToPosition(ESM::ExteriorCellLocation(x, y, ext->getWorldSpace()), true); pos.pos[0] = posFromIndex.x(); pos.pos[1] = posFromIndex.y(); diff --git a/apps/openmw/mwworld/worldmodel.hpp b/apps/openmw/mwworld/worldmodel.hpp index 324ff48023..c7b18671d3 100644 --- a/apps/openmw/mwworld/worldmodel.hpp +++ b/apps/openmw/mwworld/worldmodel.hpp @@ -7,7 +7,7 @@ #include #include -#include +#include #include #include "cellstore.hpp" diff --git a/components/CMakeLists.txt b/components/CMakeLists.txt index 0926f738af..a0695b9a5b 100644 --- a/components/CMakeLists.txt +++ b/components/CMakeLists.txt @@ -169,6 +169,9 @@ add_component_dir(esm attr common defs esmcommon records util luascripts format indexrefid serializerefid esm3exteriorcellrefid + quaternion + vector3 + exteriorcelllocation ) add_component_dir(fx pass technique lexer lexer_types parse_constants widgets stateupdater) @@ -186,6 +189,7 @@ add_component_dir (esm3 weatherstate quickkeys fogstate spellstate activespells creaturelevliststate doorstate projectilestate debugprofile aisequence magiceffects custommarkerstate stolenitems transport animationstate controlsstate mappings readerscache infoorder timestamp formatversion landrecorddata selectiongroup dialoguecondition + refnum ) add_component_dir (esmterrain diff --git a/components/contentselector/model/contentmodel.cpp b/components/contentselector/model/contentmodel.cpp index 8e7b77d308..e1973c7506 100644 --- a/components/contentselector/model/contentmodel.cpp +++ b/components/contentselector/model/contentmodel.cpp @@ -602,7 +602,8 @@ void ContentSelectorModel::ContentModel::sortFiles() emit layoutAboutToBeChanged(); int firstModifiable = 0; - while (mFiles.at(firstModifiable)->builtIn() || mFiles.at(firstModifiable)->fromAnotherConfigFile()) + while (firstModifiable < mFiles.size() + && (mFiles.at(firstModifiable)->builtIn() || mFiles.at(firstModifiable)->fromAnotherConfigFile())) ++firstModifiable; // Dependency sort diff --git a/components/esm/exteriorcelllocation.hpp b/components/esm/exteriorcelllocation.hpp new file mode 100644 index 0000000000..3b98bb7b03 --- /dev/null +++ b/components/esm/exteriorcelllocation.hpp @@ -0,0 +1,53 @@ +#ifndef OPENMW_COMPONENTS_ESM_EXTERIORCELLLOCATION_H +#define OPENMW_COMPONENTS_ESM_EXTERIORCELLLOCATION_H + +#include "refid.hpp" + +#include + +#include + +namespace ESM +{ + struct ExteriorCellLocation + { + int mX = 0; + int mY = 0; + ESM::RefId mWorldspace = ESM::Cell::sDefaultWorldspaceId; + + ExteriorCellLocation() = default; + + ExteriorCellLocation(int x, int y, ESM::RefId worldspace) + : mX(x) + , mY(y) + , mWorldspace(worldspace) + { + } + + friend bool operator==(const ExteriorCellLocation& lhs, const ExteriorCellLocation& rhs) = default; + + friend inline bool operator<(const ExteriorCellLocation& lhs, const ExteriorCellLocation& rhs) + { + return std::make_tuple(lhs.mX, lhs.mY, lhs.mWorldspace) < std::make_tuple(rhs.mX, rhs.mY, rhs.mWorldspace); + } + }; +} + +namespace std +{ + template <> + struct hash + { + std::size_t operator()(const ESM::ExteriorCellLocation& toHash) const + { + // Compute individual hash values for first, + // second and third and combine them using XOR + // and bit shifting: + + return ((hash()(toHash.mX) ^ (hash()(toHash.mY) << 1)) >> 1) + ^ (hash()(toHash.mWorldspace) << 1); + } + }; +} + +#endif diff --git a/components/esm/quaternion.hpp b/components/esm/quaternion.hpp new file mode 100644 index 0000000000..0f2f94a4e6 --- /dev/null +++ b/components/esm/quaternion.hpp @@ -0,0 +1,29 @@ +#ifndef OPENMW_COMPONENTS_ESM_QUATERNION_H +#define OPENMW_COMPONENTS_ESM_QUATERNION_H + +#include + +namespace ESM +{ + // format 0, savegames only + struct Quaternion + { + float mValues[4]; + + Quaternion() = default; + + Quaternion(const osg::Quat& q) + : mValues{ + static_cast(q.w()), + static_cast(q.x()), + static_cast(q.y()), + static_cast(q.z()), + } + { + } + + operator osg::Quat() const { return osg::Quat(mValues[1], mValues[2], mValues[3], mValues[0]); } + }; +} + +#endif diff --git a/components/esm/util.cpp b/components/esm/util.cpp index 0dc38d59aa..9a7faa6917 100644 --- a/components/esm/util.cpp +++ b/components/esm/util.cpp @@ -1,8 +1,9 @@ #include "util.hpp" + #include #include -osg::Vec2 ESM::indexToPosition(const ESM::ExteriorCellLocation& cellIndex, bool centre) +osg::Vec2f ESM::indexToPosition(const ESM::ExteriorCellLocation& cellIndex, bool centre) { const int cellSize = ESM::getCellSize(cellIndex.mWorldspace); @@ -14,7 +15,8 @@ osg::Vec2 ESM::indexToPosition(const ESM::ExteriorCellLocation& cellIndex, bool x += cellSize / 2; y += cellSize / 2; } - return osg::Vec2(x, y); + + return osg::Vec2f(x, y); } int ESM::getLandSize(ESM::RefId worldspaceId) diff --git a/components/esm/util.hpp b/components/esm/util.hpp index d7ebcf8f6f..ae756baf6a 100644 --- a/components/esm/util.hpp +++ b/components/esm/util.hpp @@ -1,79 +1,18 @@ -#ifndef OPENMW_ESM_UTIL_H -#define OPENMW_ESM_UTIL_H +#ifndef OPENMW_COMPONENTS_ESM_UTIL_H +#define OPENMW_COMPONENTS_ESM_UTIL_H + #include -#include -#include -#include -#include +#include -#include -#include -#include +#include "components/esm3/loadcell.hpp" +#include "components/misc/constants.hpp" + +#include "exteriorcelllocation.hpp" +#include "refid.hpp" namespace ESM { - - // format 0, savegames only - - struct Quaternion - { - float mValues[4]; - - Quaternion() = default; - - Quaternion(const osg::Quat& q) - { - mValues[0] = q.w(); - mValues[1] = q.x(); - mValues[2] = q.y(); - mValues[3] = q.z(); - } - - operator osg::Quat() const { return osg::Quat(mValues[1], mValues[2], mValues[3], mValues[0]); } - }; - - struct Vector3 - { - float mValues[3]; - - Vector3() = default; - - Vector3(const osg::Vec3f& v) - { - mValues[0] = v.x(); - mValues[1] = v.y(); - mValues[2] = v.z(); - } - - operator osg::Vec3f() const { return osg::Vec3f(mValues[0], mValues[1], mValues[2]); } - }; - - struct ExteriorCellLocation - { - int mX = 0; - int mY = 0; - ESM::RefId mWorldspace = ESM::Cell::sDefaultWorldspaceId; - ExteriorCellLocation() = default; - - ExteriorCellLocation(int x, int y, ESM::RefId worldspace) - : mX(x) - , mY(y) - , mWorldspace(worldspace) - { - } - - bool operator==(const ExteriorCellLocation& other) const - { - return mX == other.mX && mY == other.mY && mWorldspace == other.mWorldspace; - } - - bool operator<(const ExteriorCellLocation& other) const - { - return std::make_tuple(mX, mY, mWorldspace) < std::make_tuple(other.mX, other.mY, other.mWorldspace); - } - }; - inline bool isEsm4Ext(ESM::RefId worldspaceId) { return worldspaceId != ESM::Cell::sDefaultWorldspaceId; @@ -81,7 +20,6 @@ namespace ESM inline int getCellSize(ESM::RefId worldspaceId) { - return isEsm4Ext(worldspaceId) ? Constants::ESM4CellSizeInUnits : Constants::CellSizeInUnits; } @@ -95,25 +33,8 @@ namespace ESM return { static_cast(std::floor(x / cellSize)), static_cast(std::floor(y / cellSize)), worldspaceId }; } - osg::Vec2 indexToPosition(const ESM::ExteriorCellLocation& cellIndex, bool centre = false); - ///< Convert cell numbers to position. -} - -namespace std -{ - template <> - struct hash - { - std::size_t operator()(const ESM::ExteriorCellLocation& toHash) const - { - // Compute individual hash values for first, - // second and third and combine them using XOR - // and bit shifting: - - return ((hash()(toHash.mX) ^ (hash()(toHash.mY) << 1)) >> 1) - ^ (hash()(toHash.mWorldspace) << 1); - } - }; + // Convert exterior cell location to position. + osg::Vec2f indexToPosition(const ESM::ExteriorCellLocation& cellIndex, bool centre = false); } #endif diff --git a/components/esm/vector3.hpp b/components/esm/vector3.hpp new file mode 100644 index 0000000000..dd0262b78d --- /dev/null +++ b/components/esm/vector3.hpp @@ -0,0 +1,24 @@ +#ifndef OPENMW_COMPONENTS_ESM_VECTOR3_H +#define OPENMW_COMPONENTS_ESM_VECTOR3_H + +#include + +namespace ESM +{ + // format 0, savegames only + struct Vector3 + { + float mValues[3]; + + Vector3() = default; + + Vector3(const osg::Vec3f& v) + : mValues{ v.x(), v.y(), v.z() } + { + } + + operator osg::Vec3f() const { return osg::Vec3f(mValues[0], mValues[1], mValues[2]); } + }; +} + +#endif diff --git a/components/esm3/aisequence.hpp b/components/esm3/aisequence.hpp index d6d6259f6b..729a914544 100644 --- a/components/esm3/aisequence.hpp +++ b/components/esm3/aisequence.hpp @@ -6,8 +6,8 @@ #include #include -#include "components/esm/refid.hpp" -#include "components/esm/util.hpp" +#include +#include namespace ESM { diff --git a/components/esm3/cellref.hpp b/components/esm3/cellref.hpp index 5079095889..8b23cc5c34 100644 --- a/components/esm3/cellref.hpp +++ b/components/esm3/cellref.hpp @@ -8,13 +8,13 @@ #include #include +#include "refnum.hpp" + namespace ESM { class ESMWriter; class ESMReader; - using RefNum = ESM::FormId; - /* Cell reference. This represents ONE object (of many) inside the cell. The cell references are not loaded as part of the normal loading process, but are rather loaded later on demand when we are diff --git a/components/esm3/projectilestate.hpp b/components/esm3/projectilestate.hpp index cab550b114..c89d55c0e5 100644 --- a/components/esm3/projectilestate.hpp +++ b/components/esm3/projectilestate.hpp @@ -1,18 +1,19 @@ #ifndef OPENMW_ESM_PROJECTILESTATE_H #define OPENMW_ESM_PROJECTILESTATE_H -#include - #include #include -#include "effectlist.hpp" - +#include "components/esm/quaternion.hpp" #include "components/esm/refid.hpp" -#include "components/esm/util.hpp" +#include "components/esm/vector3.hpp" + +#include "refnum.hpp" namespace ESM { + class ESMReader; + class ESMWriter; // format 0, savegames only diff --git a/components/esm3/refnum.hpp b/components/esm3/refnum.hpp new file mode 100644 index 0000000000..6e21d6893e --- /dev/null +++ b/components/esm3/refnum.hpp @@ -0,0 +1,11 @@ +#ifndef OPENMW_COMPONENTS_ESM3_REFNUM_H +#define OPENMW_COMPONENTS_ESM3_REFNUM_H + +#include + +namespace ESM +{ + using RefNum = ESM::FormId; +} + +#endif diff --git a/components/esm4/loadcell.hpp b/components/esm4/loadcell.hpp index 58d1f0da43..7b874b4179 100644 --- a/components/esm4/loadcell.hpp +++ b/components/esm4/loadcell.hpp @@ -32,8 +32,8 @@ #include #include +#include #include -#include #include #include diff --git a/components/esmterrain/storage.cpp b/components/esmterrain/storage.cpp index a00cca0904..bb44d836de 100644 --- a/components/esmterrain/storage.cpp +++ b/components/esmterrain/storage.cpp @@ -9,6 +9,7 @@ #include #include +#include #include #include #include diff --git a/components/esmterrain/storage.hpp b/components/esmterrain/storage.hpp index 4858dfd544..5ebd0a9d37 100644 --- a/components/esmterrain/storage.hpp +++ b/components/esmterrain/storage.hpp @@ -7,7 +7,7 @@ #include #include -#include +#include #include namespace ESM4 diff --git a/components/resource/stats.cpp b/components/resource/stats.cpp index 6730ddb303..963a9cf45d 100644 --- a/components/resource/stats.cpp +++ b/components/resource/stats.cpp @@ -54,6 +54,7 @@ namespace Resource constexpr std::string_view firstPage[] = { "FrameNumber", "", + "Loading", "Compiling", "WorkQueue", "WorkThread", @@ -75,7 +76,6 @@ namespace Resource "", "", "", - "", }; static_assert(std::size(firstPage) == itemsPerPage); diff --git a/components/terrain/quadtreeworld.cpp b/components/terrain/quadtreeworld.cpp index bdf9f56790..63b55abb21 100644 --- a/components/terrain/quadtreeworld.cpp +++ b/components/terrain/quadtreeworld.cpp @@ -7,6 +7,7 @@ #include +#include #include #include #include diff --git a/components/terrain/storage.hpp b/components/terrain/storage.hpp index 7a99478929..b1007c13e6 100644 --- a/components/terrain/storage.hpp +++ b/components/terrain/storage.hpp @@ -8,8 +8,8 @@ #include #include +#include #include -#include #include "defs.hpp" diff --git a/docs/source/reference/lua-scripting/aipackages.rst b/docs/source/reference/lua-scripting/aipackages.rst index 4ef3149582..7a23d156f5 100644 --- a/docs/source/reference/lua-scripting/aipackages.rst +++ b/docs/source/reference/lua-scripting/aipackages.rst @@ -99,6 +99,18 @@ Follow another actor. * - target - `GameObject `_ [required] - the actor to follow + * - destCell + - Cell [optional] + - the destination cell + * - duration + - number [optional] + - duration in game time (will be rounded up to the next hour) + * - destPosition + - `3d vector `_ [optional] + - the destination point + * - isRepeat + - boolean [optional] + - Will the package repeat (true or false) Escort ------ @@ -126,6 +138,9 @@ Escort another actor to the given location. * - duration - number [optional] - duration in game time (will be rounded up to the next hour) + * - isRepeat + - boolean [optional] + - Will the package repeat (true or false) **Example** @@ -136,6 +151,7 @@ Escort another actor to the given location. target = object.self, destPosition = util.vector3(x, y, z), duration = 3 * time.hour, + isRepeat = true }) Wander @@ -158,6 +174,34 @@ Wander nearby current position. * - duration - number [optional] - duration in game time (will be rounded up to the next hour) + * - idle + - table [optional] + - Idle chance values, up to 8 + * - isRepeat + - boolean [optional] + - Will the package repeat (true or false) + +**Example** + +.. code-block:: Lua + + local idleTable = { + idle2 = 60, + idle3 = 50, + idle4 = 40, + idle5 = 30, + idle6 = 20, + idle7 = 10, + idle8 = 0, + idle9 = 25 + } + actor:sendEvent('StartAIPackage', { + type = 'Wander', + distance = 5000, + duration = 5 * time.hour, + idle = idleTable, + isRepeat = true + }) Travel ------ @@ -176,4 +220,6 @@ Go to given location. * - destPosition - `3d vector `_ [required] - the point to travel to - + * - isRepeat + - boolean [optional] + - Will the package repeat (true or false) diff --git a/files/data/scripts/omw/ai.lua b/files/data/scripts/omw/ai.lua index 0bf9e1bbec..59455dc8cb 100644 --- a/files/data/scripts/omw/ai.lua +++ b/files/data/scripts/omw/ai.lua @@ -1,5 +1,6 @@ local self = require('openmw.self') local interfaces = require('openmw.interfaces') +local util = require('openmw.util') local function startPackage(args) local cancelOther = args.cancelOther @@ -12,16 +13,36 @@ local function startPackage(args) self:_startAiPursue(args.target, cancelOther) elseif args.type == 'Follow' then if not args.target then error("target required") end - self:_startAiFollow(args.target, cancelOther) + self:_startAiFollow(args.target, args.cellId, args.duration or 0, args.destPosition or util.vector3(0, 0, 0), args.isRepeat or false, cancelOther) elseif args.type == 'Escort' then if not args.target then error("target required") end if not args.destPosition then error("destPosition required") end self:_startAiEscort(args.target, args.destCell or self.cell, args.duration or 0, args.destPosition, cancelOther) elseif args.type == 'Wander' then - self:_startAiWander(args.distance or 0, args.duration or 0, cancelOther) + local key = "idle" + local idle = {} + local duration = 0 + if args.idle then + for i = 2, 9 do + local val = args.idle[key .. i] + if val == nil then + idle[i-1] = 0 + else + local v = tonumber(val) or 0 + if v < 0 or v > 100 then + error("idle values cannot exceed 100") + end + idle[i-1] = v + end + end + end + if args.duration then + duration = args.duration / 3600 + end + self:_startAiWander(args.distance or 0, duration, idle, args.isRepeat or false, cancelOther) elseif args.type == 'Travel' then if not args.destPosition then error("destPosition required") end - self:_startAiTravel(args.destPosition, cancelOther) + self:_startAiTravel(args.destPosition, args.isRepeat or false, cancelOther) else error('Unsupported AI Package: ' .. args.type) end @@ -47,6 +68,10 @@ return { -- @field openmw.core#GameObject target Target (usually an actor) of the AI package (can be nil). -- @field #boolean sideWithTarget Whether to help the target in combat (true or false). -- @field openmw.util#Vector3 destPosition Destination point of the AI package. + -- @field #number distance Distance value (can be nil). + -- @field #number duration Duration value (can be nil). + -- @field #table idle Idle value (can be nil). + -- @field #boolean isRepeat Should this package be repeated (true or false). --- Return the currently active AI package (or `nil` if there are no AI packages). -- @function [parent=#AI] getActivePackage diff --git a/files/lang/components_en.ts b/files/lang/components_en.ts new file mode 100644 index 0000000000..fdc5b37d36 --- /dev/null +++ b/files/lang/components_en.ts @@ -0,0 +1,93 @@ + + + + + ContentSelector + + Select language used by ESM/ESP content files to allow OpenMW to detect their encoding. + + + + + ContentSelectorModel::ContentModel + + Unable to find dependent file: %1 + + + + Dependent file needs to be active: %1 + + + + This file needs to load after %1 + + + + + ContentSelectorModel::EsmFile + + <br/><b>This content file cannot be disabled because it is part of OpenMW.</b><br/> + + + + <br/><b>This content file cannot be disabled because it is enabled in a config file other than the user one.</b><br/> + + + + <b>Author:</b> %1<br/><b>Format version:</b> %2<br/><b>Modified:</b> %3<br/><b>Path:</b><br/>%4<br/><br/><b>Description:</b><br/>%5<br/><br/><b>Dependencies: </b>%6<br/> + + + + + ContentSelectorView::ContentSelector + + <No game file> + + + + &Check Selected + + + + &Uncheck Selected + + + + &Copy Path(s) to Clipboard + + + + + Process::ProcessInvoker + + Error starting executable + + + + <html><head/><body><p><b>Could not find %1</b></p><p>The application is not found.</p><p>Please make sure OpenMW is installed correctly and try again.</p></body></html> + + + + <html><head/><body><p><b>Could not start %1</b></p><p>The application is not executable.</p><p>Please make sure you have the right permissions and try again.</p></body></html> + + + + <html><head/><body><p><b>Could not start %1</b></p><p>An error occurred while starting %1.</p><p>Press "Show Details..." for more information.</p></body></html> + + + + Error running executable + + + + <html><head/><body><p><b>Executable %1 returned an error</b></p><p>An error occurred while running %1.</p><p>Press "Show Details..." for more information.</p></body></html> + + + + +Arguments: + + + + + diff --git a/files/lang/launcher_en.ts b/files/lang/launcher_en.ts new file mode 100644 index 0000000000..2d312ef8db --- /dev/null +++ b/files/lang/launcher_en.ts @@ -0,0 +1,1475 @@ + + + + + DataFilesPage + + Content Files + + + + <html><head/><body><p>Note: content files that are not part of current Content List are <span style=" font-style:italic;font-weight: bold">highlighted</span></p></body></html> + + + + Data Directories + + + + Scan directories for likely data directories and append them at the end of the list. + + + + Append + + + + Scan directories for likely data directories and insert them above the selected position + + + + Insert Above + + + + Move selected directory one position up + + + + Move Up + + + + Move selected directory one position down + + + + Move Down + + + + Remove selected directory + + + + Remove + + + + <html><head/><body><p>Note: directories that are not part of current Content List are <span style=" font-style:italic;font-weight: bold">highlighted</span></p></body></html> + + + + Archive Files + + + + Move selected archive one position up + + + + Move selected archive one position down + + + + <html><head/><body><p>Note: archives that are not part of current Content List are <span style=" font-style:italic;font-weight: bold">highlighted</span></p></body></html> + + + + Navigation Mesh Cache + + + + Generate navigation mesh cache for all content. Will be used by the engine to make cell loading faster. + + + + Update + + + + Cancel navigation mesh generation. Already processed data will be saved. + + + + Cancel + + + + Remove Unused Tiles + + + + Max Size + + + + MiB + + + + Content List + + + + Select a content list + + + + New Content List + + + + &New Content List + + + + Clone Content List + + + + Delete Content List + + + + Ctrl+N + + + + Ctrl+G + + + + Ctrl+D + + + + Check Selection + + + + Uncheck Selection + + + + Refresh Data Files + + + + Ctrl+R + + + + + GraphicsPage + + Screen + + + + Window Mode + + + + × + + + + Custom: + + + + Standard: + + + + 0 + + + + 2 + + + + 4 + + + + 8 + + + + 16 + + + + Framerate Limit + + + + Window Border + + + + Disabled + + + + Enabled + + + + Adaptive + + + + Fullscreen + + + + Windowed Fullscreen + + + + Windowed + + + + Resolution + + + + FPS + + + + Anti-Aliasing + + + + Vertical Synchronization + + + + + ImportPage + + Form + + + + Morrowind Installation Wizard + + + + Run &Installation Wizard + + + + Morrowind Settings Importer + + + + File to Import Settings From: + + + + Browse... + + + + Import Add-on and Plugin Selection + + + + Fonts shipped with the original engine are blurry with UI scaling and support only a small amount of characters, +so OpenMW provides another set of fonts to avoid these issues. These fonts use TrueType technology and are quite similar +to default Morrowind fonts. Check this box if you still prefer original fonts over OpenMW ones or if you use custom bitmap fonts. + + + + Import Bitmap Fonts + + + + Run &Settings Importer + + + + + Launcher::DataFilesPage + + English + + + + French + + + + German + + + + Italian + + + + Polish + + + + Russian + + + + Spanish + + + + New Content List + + + + Content List name: + + + + Clone Content List + + + + &Check Selected + + + + &Uncheck Selected + + + + Resolved as %1 + + + + Will be added to the current profile + + + + This is the data-local directory and cannot be disabled + + + + This directory is part of OpenMW and cannot be disabled + + + + This directory is enabled in an openmw.cfg other than the user one + + + + Contains content file(s) + + + + This archive is enabled in an openmw.cfg other than the user one + + + + Select Directory + + + + Delete Content List + + + + Are you sure you want to delete <b>%1</b>? + + + + Delete + + + + + Launcher::GraphicsPage + + Error receiving number of screens + + + + <br><b>SDL_GetNumVideoDisplays failed:</b><br><br> + + + + Screen + + + + Error receiving resolutions + + + + <br><b>SDL_GetNumDisplayModes failed:</b><br><br> + + + + <br><b>SDL_GetDisplayMode failed:</b><br><br> + + + + + Launcher::ImportPage + + Error writing OpenMW configuration file + + + + <html><head/><body><p><b>Could not open or create %1 for writing </b></p><p>Please make sure you have the right permissions and try again.</p></body></html> + + + + Morrowind configuration file (*.ini) + + + + Importer finished + + + + Failed to import settings from INI file. + + + + + Launcher::MainDialog + + Close + + + + Launch OpenMW + + + + Help + + + + Error creating OpenMW configuration directory: code %0 + + + + <br><b>Could not create directory %0</b><br><br>%1<br> + + + + First run + + + + <html><head/><body><p><b>Welcome to OpenMW!</b></p><p>It is recommended to run the Installation Wizard.</p><p>The Wizard will let you select an existing Morrowind installation, or install Morrowind for OpenMW to use.</p></body></html> + + + + Run &Installation Wizard + + + + Skip + + + + OpenMW %1 release + + + + OpenMW development (%1) + + + + Compiled on %1 %2 + + + + Error opening OpenMW configuration file + + + + <br><b>Could not open %0 for reading:</b><br><br>%1<br><br>Please make sure you have the right permissions and try again.<br> + + + + <br><b>Could not open %0 for reading</b><br><br>Please make sure you have the right permissions and try again.<br> + + + + Error detecting Morrowind installation + + + + <br><b>Could not find the Data Files location</b><br><br>The directory containing the data files was not found. + + + + Run &Installation Wizard... + + + + Error reading OpenMW configuration files + + + + <br>The problem may be due to an incomplete installation of OpenMW.<br>Reinstalling OpenMW may resolve the problem.<br> + + + + Error writing OpenMW configuration file + + + + <br><b>Could not open or create %0 for writing</b><br><br>Please make sure you have the right permissions and try again.<br> + + + + Error writing user settings file + + + + Error writing Launcher configuration file + + + + No game file selected + + + + <br><b>You do not have a game file selected.</b><br><br>OpenMW will not start without a game file selected.<br> + + + + + Launcher::SettingsPage + + Text file (*.txt) + + + + + MainWindow + + OpenMW Launcher + + + + OpenMW version + + + + toolBar + + + + Data Files + + + + Allows to setup data files and directories + + + + Display + + + + Allows to change display settings + + + + Settings + + + + Allows to tweak engine settings + + + + Import + + + + Allows to import data from original engine + + + + + QObject + + Select configuration file + + + + Select script file + + + + + SelectSubdirs + + Select directories you wish to add + + + + + SettingsPage + + Gameplay + + + + <html><head/><body><p>Make Damage Fatigue magic effect uncapped like Drain Fatigue effect.</p><p>This means that unlike Morrowind you will be able to knock down actors using this effect.</p></body></html> + + + + Uncapped Damage Fatigue + + + + <html><head/><body><p>Give actors an ability to swim over the water surface when they follow other actor independently from their ability to swim. Has effect only when nav mesh building is enabled.</p></body></html> + + + + Always Allow Actors to Follow over Water + + + + <html><head/><body><p>Make disposition change of merchants caused by trading permanent.</p></body></html> + + + + Permanent Barter Disposition Changes + + + + <html><head/><body><p>Don't use race weight in NPC movement speed calculations.</p></body></html> + + + + Racial Variation in Speed Fix + + + + <html><head/><body><p>Stops combat with NPCs affected by Calm spells every frame -- like in Morrowind without the MCP.</p></body></html> + + + + Classic Calm Spells Behavior + + + + <html><head/><body><p>If enabled NPCs apply evasion maneuver to avoid collisions with others.</p></body></html> + + + + NPCs Avoid Collisions + + + + <html><head/><body><p>Make the value of filled soul gems dependent only on soul magnitude.</p></body></html> + + + + Soulgem Values Rebalance + + + + <html><head/><body><p>If this setting is true, supporting models will make use of day night switch nodes.</p></body></html> + + + + Day Night Switch Nodes + + + + <html><head/><body><p>Make player followers and escorters start combat with enemies who have started combat with them or the player. Otherwise they wait for the enemies or the player to do an attack first.</p></body></html> + + + + Followers Defend Immediately + + + + <html><head/><body><p><a name="docs-internal-guid-f375b85a-7fff-02ff-a5af-c5cff63923c0"/>When enabled, a navigation mesh is built in the background for world geometry to be used for pathfinding. When disabled only the path grid is used to build paths. Single-core CPU systems may have a big performance impact on existing interior location and moving across the exterior world. May slightly affect performance on multi-core CPU systems. Multi-core CPU systems may have different latency for nav mesh update depending on other settings and system performance. Moving across external world, entering/exiting location produce nav mesh update. NPC and creatures may not be able to find path before nav mesh is built around them. Try to disable this if you want to have old fashioned AI which doesn't know where to go when you stand behind that stone and cast a firebolt.</p></body></html> + + + + Use Navigation Mesh for Pathfinding + + + + <html><head/><body><p>If enabled, a magical ammunition is required to bypass normal weapon resistance or weakness. If disabled, a magical ranged weapon or a magical ammunition is required.</p></body></html> + + + + Only Magical Ammo Bypass Resistance + + + + <html><head/><body><p>If this setting is true, containers supporting graphic herbalism will do so instead of opening the menu.</p></body></html> + + + + Graphic Herbalism + + + + <html><head/><body><p>Makes player swim a bit upward from the line of sight. Applies only in third person mode. Intended to make simpler swimming without diving.</p></body></html> + + + + Swim Upward Correction + + + + <html><head/><body><p>Make enchanted weapons without Magical flag bypass normal weapons resistance, like in Morrowind.</p></body></html> + + + + Enchanted Weapons Are Magical + + + + <html><head/><body><p>Prevents merchants from equipping items that are sold to them.</p></body></html> + + + + Merchant Equipping Fix + + + + <html><head/><body><p>Trainers now only choose which skills to train using their base skill points, allowing mercantile improving effects to be used without making mercantile an offered skill.</p></body></html> + + + + Trainers Choose Offered Skills by Base Value + + + + <html><head/><body><p>If this setting is true, the player is allowed to loot actors (e.g. summoned creatures) during death animation, if they are not in combat. In this case we have to increment death counter and run disposed actor's script instantly.</p><p>If this setting is false, player has to wait until end of death animation in all cases. Makes using of summoned creatures exploit (looting summoned Dremoras and Golden Saints for expensive weapons) a lot harder. Conflicts with mannequin mods, which use SkipAnim to prevent end of death animation.</p></body></html> + + + + Can Loot During Death Animation + + + + <html><head/><body><p>Make stealing items from NPCs that were knocked down possible during combat.</p></body></html> + + + + Steal from Knocked out Actors in Combat + + + + <html><head/><body><p>Effects of reflected Absorb spells are not mirrored - like in Morrowind.</p></body></html> + + + + Classic Reflected Absorb Spells Behavior + + + + <html><head/><body><p>Makes unarmed creature attacks able to reduce armor condition, just as attacks from NPCs and armed creatures.</p></body></html> + + + + Unarmed Creature Attacks Damage Armor + + + + Factor Strength into Hand-to-Hand Combat + + + + Off + + + + Affect Werewolves + + + + Do Not Affect Werewolves + + + + <html><head/><body><p>How many threads will be spawned to compute physics update in the background. A value of 0 means that the update will be performed in the main thread.</p><p>A value greater than 1 requires the Bullet library be compiled with multithreading support.</p></body></html> + + + + Background Physics Threads + + + + Actor Collision Shape Type + + + + Collision is used for both physics simulation and navigation mesh generation for pathfinding. Cylinder gives the best consistency between available navigation paths and ability to move by them. Changing this value affects navigation mesh generation therefore navigation mesh disk cache generated for one value will not be useful with another. + + + + Axis-Aligned Bounding Box + + + + Rotating Box + + + + Cylinder + + + + Visuals + + + + Animations + + + + <html><head/><body><p>Makes NPCs and player movement more smooth. Recommended to use with "turn to movement direction" enabled.</p></body></html> + + + + Smooth Movement + + + + <html><head/><body><p>Load per-group KF-files and skeleton files from Animations folder</p></body></html> + + + + Use Additional Animation Sources + + + + <html><head/><body><p>Affects side and diagonal movement. Enabling this setting makes movement more realistic.</p><p>If disabled then the whole character's body is pointed to the direction of view. Diagonal movement has no special animation and causes sliding.</p><p>If enabled then the character turns lower body to the direction of movement. Upper body is turned partially. Head is always pointed to the direction of view. In combat mode it works only for diagonal movement. In non-combat mode it changes straight right and straight left movement as well. Also turns the whole body up or down when swimming according to the movement direction.</p></body></html> + + + + Turn to Movement Direction + + + + <html><head/><body><p>Render holstered weapons (with quivers and scabbards), requires modded assets.</p></body></html> + + + + Weapon Sheathing + + + + <html><head/><body><p>Render holstered shield, requires modded assets.</p></body></html> + + + + Shield Sheathing + + + + <html><head/><body><p>In third person, the camera will sway along with the movement animations of the player. Enabling this option disables this swaying by having the player character move independently of its animation. This was the default behavior of OpenMW 0.48 and earlier.</p></body></html> + + + + Player Movement Ignores Animation + + + + <html><head/><body><p>Use casting animations for magic items, just as for spells.</p></body></html> + + + + Use Magic Item Animation + + + + Shaders + + + + <html><head/><body><p>If this option is enabled, normal maps are automatically recognized and used if they are named appropriately + (see 'normal map pattern', e.g. for a base texture foo.dds, the normal map texture would have to be named foo_n.dds). + If this option is disabled, normal maps are only used if they are explicitly listed within the mesh file (.nif or .osg file). Affects objects.</p></body></html> + + + + Auto Use Object Normal Maps + + + + <html><head/><body><p>Enables soft particles for particle effects. This technique softens the intersection between individual particles and other opaque geometry by blending between them.</p></body></html> + + + + Soft Particles + + + + <html><head/><body><p>If this option is enabled, specular maps are automatically recognized and used if they are named appropriately + (see 'specular map pattern', e.g. for a base texture foo.dds, + the specular map texture would have to be named foo_spec.dds). + If this option is disabled, normal maps are only used if they are explicitly listed within the mesh file + (.osg file, not supported in .nif files). Affects objects.</p></body></html> + + + + Auto Use Object Specular Maps + + + + <html><head/><body><p>See 'auto use object normal maps'. Affects terrain.</p></body></html> + + + + Auto Use Terrain Normal Maps + + + + <html><head/><body><p>If a file with pattern 'terrain specular map pattern' exists, use that file as a 'diffuse specular' map. The texture must contain the layer colour in the RGB channel (as usual), and a specular multiplier in the alpha channel.</p></body></html> + + + + Auto Use Terrain Specular Maps + + + + <html><head/><body><p>Simulate coverage-preserving mipmaps to prevent alpha-tested meshes shrinking as they get further away. Will cause meshes whose textures have coverage-preserving mipmaps to grow, though, so refer to mod installation instructions for how to set this.</p></body></html> + + + + Adjust Coverage for Alpha Test + + + + <html><head/><body><p>Allows MSAA to work with alpha-tested meshes, producing better-looking edges without pixelation. Can negatively impact performance.</p></body></html> + + + + Use Anti-Aliased Alpha Testing + + + + <html><head/><body><p>Normally environment map reflections aren't affected by lighting, which makes environment-mapped (and thus bump-mapped objects) glow in the dark. + Morrowind Code Patch includes an option to remedy that by doing environment-mapping before applying lighting, this is the equivalent of that option. + Affected objects will use shaders. + </p></body></html> + + + + Bump/Reflect Map Local Lighting + + + + <html><head/><body><p>EXPERIMENTAL: Stop rain and snow from falling through overhangs and roofs.</p></body></html> + + + + Weather Particle Occlusion + + + + Fog + + + + <html><head/><body><p>Use exponential fog formula. By default, linear fog is used.</p></body></html> + + + + Exponential Fog + + + + <html><head/><body><p>By default, the fog becomes thicker proportionally to your distance from the clipping plane set at the clipping distance, which causes distortion at the edges of the screen. + This setting makes the fog use the actual eye point distance (or so called Euclidean distance) to calculate the fog, which makes the fog look less artificial, especially if you have a wide FOV.</p></body></html> + + + + Radial Fog + + + + <html><head/><body><p>The fraction of the maximum distance at which blending with the sky starts.</p></body></html> + + + + Sky Blending Start + + + + <html><head/><body><p>Reduce visibility of clipping plane by blending objects with the sky.</p></body></html> + + + + Sky Blending + + + + Terrain + + + + <html><head/><body><p>Controls how large an object must be to be visible in the scene. The object’s size is divided by its distance to the camera and the result of the division is compared with this value. The smaller this value is, the more objects you will see in the scene.</p></body></html> + + + + Object Paging Min Size + + + + Viewing Distance + + + + cells + + + + <html><head/><body><p>If true, use paging and LOD algorithms to display the entire terrain. If false, only display terrain of the loaded cells.</p></body></html> + + + + Distant Land + + + + <html><head/><body><p>Use object paging for active cells grid.</p></body></html> + + + + Active Grid Object Paging + + + + Post Processing + + + + <html><head/><body><p>Re-render transparent objects with forced alpha clipping.</p></body></html> + + + + Transparent Postpass + + + + <html><head/><body><p>Controls how much eye adaptation can change from frame to frame. Smaller values makes for slower transitions.</p></body></html> + + + + Auto Exposure Speed + + + + <html><head/><body><p>If this setting is true, post processing will be enabled.</p></body></html> + + + + Enable Post Processing + + + + Shadows + + + + Bounds + + + + Primitives + + + + None + + + + <html><head/><body><p>Type of "compute scene bounds" computation method to be used. Bounds (default) for good balance between performance and shadow quality, primitives for better looking shadows or none for no computation.</p></body></html> + + + + Shadow Planes Computation Method + + + + <html><head/><body><p>64 game units is 1 real life yard or about 0.9 m</p></body></html> + + + + unit(s) + + + + <html><head/><body><p>Enable shadows for NPCs and creatures besides the player character. May have a minor performance impact.</p></body></html> + + + + Enable Actor Shadows + + + + 512 + + + + 1024 + + + + 2048 + + + + 4096 + + + + <html><head/><body><p>The fraction of the limit above at which shadows begin to gradually fade away.</p></body></html> + + + + Fade Start Multiplier + + + + <html><head/><body><p>Enable shadows exclusively for the player character. May have a very minor performance impact.</p></body></html> + + + + Enable Player Shadows + + + + <html><head/><body><p>The resolution of each individual shadow map. Increasing it significantly improves shadow quality but may have a minor performance impact.</p></body></html> + + + + Shadow Map Resolution + + + + <html><head/><body><p>The distance from the camera at which shadows completely disappear.</p></body></html> + + + + Shadow Distance Limit: + + + + <html><head/><body><p>Enable shadows for primarily inanimate objects. May have a significant performance impact.</p></body></html> + + + + Enable Object Shadows + + + + <html><head/><body><p>Due to limitations with Morrowind's data, only actors can cast shadows indoors, which some might feel is distracting.</p><p>Has no effect if actor/player shadows are not enabled.</p></body></html> + + + + Enable Indoor Shadows + + + + <html><head/><body><p>Enable shadows for the terrain including distant terrain. May have a significant performance and shadow quality impact.</p></body></html> + + + + Enable Terrain Shadows + + + + Lighting + + + + <html><head/><body><p>Maximum distance at which lights will appear (measured in units).</p><p>Set this to 0 to use an unlimited distance.</p></body></html> + + + + Maximum Light Distance + + + + <html><head/><body><p>Maximum number of lights per object.</p><p>A low number near default will cause light popping similar to what you would see with legacy lighting.</p></body></html> + + + + Max Lights + + + + <html><head/><body><p>Fraction of maximum distance at which lights will start to fade.</p><p>Set this to a low value for slower transitions or a high value for quicker transitions.</p></body></html> + + + + <html><head/><body><p>Set the internal handling of light sources.</p> +<p> "Legacy" always uses 8 lights per object and provides a lighting closest to an original game.</p> +<p>"Shaders (compatibility)" removes the 8 light limit. This mode also enables lighting on groundcover and a configurable light fade. It is recommended to use this with older hardware and a light limit closer to 8.</p> +<p> "Shaders" carries all of the benefits that "Shaders (compatibility)" does, but uses a modern approach that allows for a higher max lights count with little to no performance penalties on modern hardware.</p></body></html> + + + + Lighting Method + + + + Legacy + + + + Shaders (compatibility) + + + + <html><head/><body><p>Multipler for bounding sphere of lights.</p><p>Higher numbers allows for smooth falloff but require an increase in number of max lights.</p><p>Does not effect the illumination or strength of lights.</p></body></html> + + + + Bounding Sphere Multiplier + + + + <html><head/><body><p>Minimum ambient interior brightness.</p><p>Increase this if you feel interiors are too dark.</p></body></html> + + + + Minimum Interior Brightness + + + + Audio + + + + Select your preferred audio device. + + + + Audio Device + + + + Default + + + + This setting controls HRTF, which simulates 3D sound on stereo systems. + + + + HRTF + + + + Automatic + + + + On + + + + Select your preferred HRTF profile. + + + + HRTF Profile + + + + In third-person view, use the camera as the sound listener instead of the player character. + + + + Use the Camera as the Sound Listener + + + + Interface + + + + Tooltip + + + + Crosshair + + + + Tooltip and Crosshair + + + + <html><head/><body><p>This setting scales GUI windows. A value of 1.0 results in the normal scale.</p></body></html> + + + + GUI Scaling Factor + + + + <html><head/><body><p>Show the remaining duration of magic effects and lights if this setting is true. The remaining duration is displayed in the tooltip by hovering over the magical effect. </p><p>The default value is false.</p></body></html> + + + + Show Effect Duration + + + + <html><head/><body><p>If this setting is true, dialogue topics will have a different color if the topic is specific to the NPC you're talking to or the topic was previously seen. Color can be changed in settings.cfg.</p><p>The default value is false.</p></body></html> + + + + Change Dialogue Topic Color + + + + Size of characters in game texts. + + + + Font Size + + + + <html><head/><body><p>Enable zooming on local and global maps.</p></body></html> + + + + Can Zoom on Maps + + + + <html><head/><body><p>If this setting is true, damage bonus of arrows and bolts will be shown on item tooltip.</p><p>The default value is false.</p></body></html> + + + + Show Projectile Damage + + + + <html><head/><body><p>If this setting is true, melee weapons reach and speed will be shown on item tooltip.</p><p>The default value is false.</p></body></html> + + + + Show Melee Info + + + + <html><head/><body><p>Stretch menus, load screens, etc. to the window aspect ratio.</p></body></html> + + + + Stretch Menu Background + + + + Show Owned Objects + + + + <html><head/><body><p>Whether or not the chance of success will be displayed in the enchanting menu.</p><p>The default value is false.</p></body></html> + + + + Show Enchant Chance + + + + Miscellaneous + + + + Saves + + + + <html><head/><body><p>This setting determines whether the amount of the time the player has spent playing will be displayed for each saved game in the Load menu.</p></body></html> + + + + Add "Time Played" to Saves + + + + Maximum Quicksaves + + + + Screenshots + + + + Screenshot Format + + + + JPG + + + + PNG + + + + TGA + + + + Notify on Saved Screenshot + + + + Testing + + + + These settings are intended for testing mods and will cause issues if used for normal gameplay. + + + + <html><head/><body><p>OpenMW will capture control of the cursor if this setting is true.</p><p>In “look mode”, OpenMW will center the cursor regardless of the value of this setting (since the cursor/crosshair is always centered in the OpenMW window). However, in GUI mode, this setting determines the behavior when the cursor is moved outside the OpenMW window. If true, the cursor movement stops at the edge of the window preventing access to other applications. If false, the cursor is allowed to move freely on the desktop.</p><p>This setting does not apply to the screen where escape has been pressed, where the cursor is never captured. Regardless of this setting “Alt-Tab” or some other operating system dependent key sequence can be used to allow the operating system to regain control of the mouse cursor. This setting interacts with the minimize on focus loss setting by affecting what counts as a focus loss. Specifically on a two-screen configuration it may be more convenient to access the second screen with setting disabled.</p><p>Note for developers: it’s desirable to have this setting disabled when running the game in a debugger, to prevent the mouse cursor from becoming unusable when the game pauses on a breakpoint.</p></body></html> + + + + Grab Cursor + + + + Skip Menu and Generate Default Character + + + + Start Default Character at + + + + Default Cell + + + + Run Script After Startup: + + + + Browse… + + + + diff --git a/files/lang/launcher_ru.ts b/files/lang/launcher_ru.ts index 5c6719c11c..57a9c67f65 100644 --- a/files/lang/launcher_ru.ts +++ b/files/lang/launcher_ru.ts @@ -1226,11 +1226,11 @@ to default Morrowind fonts. Check this box if you still prefer original fonts ov <html><head/><body><p>If enabled, a magical ammunition is required to bypass normal weapon resistance or weakness. If disabled, a magical ranged weapon or a magical ammunition is required.</p></body></html> - <html><head/><body><p>Если настройка включена, требуются магические метательные снаряды, чтобы обойти сопротивление обычному оружию или уязвимость к нему. Если отключена, то требуются магические снаряды или магическое оружие дальнего боя.</p></body></html> + <html><head/><body><p>Если настройка включена, для обхода сопротивления или уязвимости к обычному оружию необходимо, чтобы снаряд был магическим. Если выключена, то магическим для этого может быть как снаряд, так и оружие дальнего боя.</p></body></html> Only Magical Ammo Bypass Resistance - Только снаряды обходят сопротивление + Обычные снаряды не обходят сопротивление Graphic Herbalism diff --git a/files/lang/wizard_en.ts b/files/lang/wizard_en.ts new file mode 100644 index 0000000000..790d8e0589 --- /dev/null +++ b/files/lang/wizard_en.ts @@ -0,0 +1,656 @@ + + + + + ComponentSelectionPage + + WizardPage + + + + Select Components + + + + Which components should be installed? + + + + <html><head/><body><p>Select which official Morrowind expansions should be installed. For best results, it is recommended to have both expansions installed.</p><p><span style=" font-weight:bold;">Note:</span> It is possible to install expansions later by re-running this Wizard.<br/></p></body></html> + + + + Selected components: + + + + + ConclusionPage + + WizardPage + + + + Completing the OpenMW Wizard + + + + Placeholder + + + + + ExistingInstallationPage + + WizardPage + + + + Select Existing Installation + + + + Select an existing installation for OpenMW to use or modify. + + + + Detected installations: + + + + Browse... + + + + + ImportPage + + WizardPage + + + + Import Settings + + + + Import settings from the Morrowind installation. + + + + <html><head/><body><p>OpenMW needs to import settings from the Morrowind configuration file in order to function properly.</p><p><span style=" font-weight:bold;">Note:</span> It is possible to import settings later by re-running this Wizard.</p><p/></body></html> + + + + Import Settings From Morrowind.ini + + + + Import Add-on and Plugin Selection + + + + Import Bitmap Fonts Setup From Morrowind.ini + + + + Fonts shipped with the original engine are blurry with UI scaling and support only a small amount of characters, +so OpenMW provides another set of fonts to avoid these issues. These fonts use TrueType technology and are quite similar +to default Morrowind fonts. Check this box if you still prefer original fonts over OpenMW ones or if you use custom bitmap fonts. + + + + + InstallationPage + + WizardPage + + + + Installing + + + + Please wait while Morrowind is installed on your computer. + + + + + InstallationTargetPage + + WizardPage + + + + Select Installation Destination + + + + Where should Morrowind be installed? + + + + Morrowind will be installed to the following location. + + + + Browse... + + + + + IntroPage + + WizardPage + + + + Welcome to the OpenMW Wizard + + + + This Wizard will help you install Morrowind and its add-ons for OpenMW to use. + + + + + LanguageSelectionPage + + WizardPage + + + + Select Morrowind Language + + + + What is the language of the Morrowind installation? + + + + Select the language of the Morrowind installation. + + + + + MethodSelectionPage + + WizardPage + + + + Select Installation Method + + + + <html><head/><body><p>Select how you would like to install <i>The Elder Scrolls III: Morrowind</i>.</p></body></html> + + + + Retail CD/DVD + + + + Install from a retail disc to a new location. + + + + Existing Installation + + + + Select an existing installation. + + + + Don't have a copy? + + + + Buy the game + + + + + QObject + + <br><b>Could not find Morrowind.ini</b><br><br>The Wizard needs to update settings in this file.<br><br>Press "Browse..." to specify the location manually.<br> + + + + B&rowse... + + + + Select configuration file + + + + <b>Morrowind.bsa</b> is missing!<br>Make sure your Morrowind installation is complete. + + + + Most recent Morrowind not detected + + + + <br><b>There may be a more recent version of Morrowind available.</b><br><br>Do you wish to continue anyway?<br> + + + + Select a valid %1 installation media.<br><b>Hint</b>: make sure that it contains at least one <b>.cab</b> file. + + + + There may be a more recent version of Morrowind available.<br><br>Do you wish to continue anyway? + + + + + Wizard::ComponentSelectionPage + + &Install + + + + &Skip + + + + Morrowind (installed) + + + + Morrowind + + + + Tribunal (installed) + + + + Tribunal + + + + Bloodmoon (installed) + + + + Bloodmoon + + + + About to install Tribunal after Bloodmoon + + + + <html><head/><body><p><b>You are about to install Tribunal</b></p><p>Bloodmoon is already installed on your computer.</p><p>However, it is recommended that you install Tribunal before Bloodmoon.</p><p>Would you like to re-install Bloodmoon?</p></body></html> + + + + Re-install &Bloodmoon + + + + + Wizard::ConclusionPage + + <html><head/><body><p>The OpenMW Wizard successfully installed Morrowind on your computer.</p></body></html> + + + + <html><head/><body><p>The OpenMW Wizard successfully modified your existing Morrowind installation.</body></html> + + + + <html><head/><body><p>The OpenMW Wizard failed to install Morrowind on your computer.</p><p>Please report any bugs you might have encountered to our <a href="https://gitlab.com/OpenMW/openmw/issues">bug tracker</a>.<br/>Make sure to include the installation log.</p><br/></body></html> + + + + + Wizard::ExistingInstallationPage + + No existing installations detected + + + + Error detecting Morrowind configuration + + + + Morrowind configuration file (*.ini) + + + + Select Morrowind.esm (located in Data Files) + + + + Morrowind master file (Morrowind.esm) + + + + Error detecting Morrowind files + + + + + Wizard::InstallationPage + + <p>Attempting to install component %1.</p> + + + + Attempting to install component %1. + + + + %1 Installation + + + + Select %1 installation media + + + + <p><br/><span style="color:red;"><b>Error: The installation was aborted by the user</b></span></p> + + + + <p>Detected old version of component Morrowind.</p> + + + + Detected old version of component Morrowind. + + + + Morrowind Installation + + + + Installation finished + + + + Installation completed successfully! + + + + Installation failed! + + + + <p><br/><span style="color:red;"><b>Error: %1</b></p> + + + + <p><span style="color:red;"><b>%1</b></p> + + + + An error occurred + + + + <html><head/><body><p><b>The Wizard has encountered an error</b></p><p>The error reported was:</p><p>%1</p><p>Press &quot;Show Details...&quot; for more information.</p></body></html> + + + + + Wizard::InstallationTargetPage + + Error creating destination + + + + <html><head/><body><p><b>Could not create the destination directory</b></p><p>Please make sure you have the right permissions and try again, or specify a different location.</p></body></html> + + + + Insufficient permissions + + + + <html><head/><body><p><b>Could not write to the destination directory</b></p><p>Please make sure you have the right permissions and try again, or specify a different location.</p></body></html> + + + + Destination not empty + + + + <html><head/><body><p><b>The destination directory is not empty</b></p><p>An existing Morrowind installation is present in the specified location.</p><p>Please specify a different location, or go back and select the location as an existing installation.</p></body></html> + + + + Select where to install Morrowind + + + + + Wizard::LanguageSelectionPage + + English + + + + French + + + + German + + + + Italian + + + + Polish + + + + Russian + + + + Spanish + + + + + Wizard::MainWizard + + OpenMW Wizard + + + + <html><head/><body><p><b>Could not open %1 for writing</b></p><p>Please make sure you have the right permissions and try again.</p></body></html> + + + + Error opening Wizard log file + + + + <html><head/><body><p><b>Could not open %1 for reading</b></p><p>Please make sure you have the right permissions and try again.</p></body></html> + + + + Error opening OpenMW configuration file + + + + Quit Wizard + + + + Are you sure you want to exit the Wizard? + + + + Error creating OpenMW configuration directory + + + + <html><head/><body><p><b>Could not create %1</b></p><p>Please make sure you have the right permissions and try again.</p></body></html> + + + + Error writing OpenMW configuration file + + + + + Wizard::UnshieldWorker + + Failed to open Morrowind configuration file! + + + + Opening %1 failed: %2. + + + + Failed to write Morrowind configuration file! + + + + Writing to %1 failed: %2. + + + + Installing: %1 + + + + Installing: %1 directory + + + + Installation finished! + + + + Component parameter is invalid! + + + + An invalid component parameter was supplied. + + + + Failed to find a valid archive containing %1.bsa! Retrying. + + + + Installing %1 + + + + Installation media path not set! + + + + The source path for %1 was not set. + + + + Cannot create temporary directory! + + + + Failed to create %1. + + + + Cannot move into temporary directory! + + + + Failed to move into %1. + + + + Moving installation files + + + + Could not install directory! + + + + Installing %1 to %2 failed. + + + + Could not install translation file! + + + + Failed to install *%1 files. + + + + Could not install Morrowind data file! + + + + Failed to install %1. + + + + Could not install Morrowind configuration file! + + + + Installing: Sound directory + + + + Could not find Tribunal data file! + + + + Failed to find %1. + + + + Could not find Tribunal patch file! + + + + Could not find Bloodmoon data file! + + + + Updating Morrowind configuration file + + + + %1 installation finished! + + + + Extracting: %1 + + + + Failed to open InstallShield Cabinet File. + + + + Opening %1 failed. + + + + Failed to extract %1. + + + + Complete path: %1 + + + + diff --git a/files/opencs/record-down.svg b/files/opencs/record-down.svg index 9febe57065..1f3d8a385d 100644 --- a/files/opencs/record-down.svg +++ b/files/opencs/record-down.svg @@ -117,7 +117,7 @@ xlink:href="#Main-3" id="linearGradient6786" gradientUnits="userSpaceOnUse" - gradientTransform="matrix(3.7795276,0,0,3.7795276,-5.9999999,-6.9999999)" + gradientTransform="matrix(0.95388135,0,0,1.0509393,2.6074109,-0.47696551)" x1="2.116667" y1="-3.7041662" x2="6.3499999" @@ -137,8 +137,7 @@ rx="2.8318619e-14" /> + style="font-variation-settings:normal;opacity:1;vector-effect:none;fill:url(#linearGradient6786);fill-opacity:1;stroke:none;stroke-width:0.26491px;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;paint-order:fill markers stroke;stop-color:#000000;stop-opacity:1" + d="m 51.120283,8.2042949 c -0.03261,-0.010163 -0.0557,0.014998 -0.0557,0.068972 v 2.4835411 c 0,0.09214 0.05209,0.118729 0.116333,0.05973 l 1.433536,-1.1996808 c 0.05017,-0.04607 0.05017,-0.1211999 0,-0.1672709 L 51.155284,8.2265564 c -0.01254,-0.011517 -0.02412,-0.01888 -0.035,-0.022267 z m 0.197668,0.5327694 0.992382,0.7967099 -0.992382,0.7939938 z" /> diff --git a/files/opencs/record-next.svg b/files/opencs/record-next.svg index bbc44e7459..d3fb40a720 100644 --- a/files/opencs/record-next.svg +++ b/files/opencs/record-next.svg @@ -117,7 +117,7 @@ xlink:href="#Main-3" id="linearGradient6770" gradientUnits="userSpaceOnUse" - gradientTransform="translate(0.39687235)" + gradientTransform="matrix(0.95393695,0,0,1.0509392,2.7307818,-0.47696343)" x1="2.116667" y1="-3.7041662" x2="6.3499999" @@ -137,7 +137,7 @@ rx="2.8318619e-14" /> + style="font-variation-settings:normal;opacity:1;vector-effect:none;fill:url(#linearGradient6770);fill-opacity:1;stroke:none;stroke-width:0.264917px;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;paint-order:fill markers stroke;stop-color:#000000;stop-opacity:1" + d="m 51.120363,8.204296 c -0.03261,-0.010162 -0.05578,0.014998 -0.05578,0.068972 v 2.483541 c 0,0.09214 0.05211,0.118729 0.116355,0.05973 L 52.61445,9.6168633 c 0.05018,-0.046071 0.05018,-0.1211999 0,-0.167271 L 51.15519,8.2265626 c -0.01254,-0.011517 -0.02395,-0.01888 -0.03483,-0.022267 z m 0.197626,0.5327692 0.992304,0.7967099 -0.983218,0.7939939 z" /> diff --git a/files/opencs/record-previous.svg b/files/opencs/record-previous.svg index 2479c8bd49..dd03d27128 100644 --- a/files/opencs/record-previous.svg +++ b/files/opencs/record-previous.svg @@ -117,7 +117,7 @@ xlink:href="#Main-3" id="linearGradient6778" gradientUnits="userSpaceOnUse" - gradientTransform="translate(0.39694445)" + gradientTransform="matrix(0.95389396,0,0,1.0509392,2.7330252,-0.47696299)" x1="2.116667" y1="-3.7041662" x2="6.3499999" @@ -137,7 +137,7 @@ rx="2.8318619e-14" /> + style="font-variation-settings:normal;opacity:1;vector-effect:none;fill:url(#linearGradient6778);fill-opacity:1;stroke:none;stroke-width:0.264912px;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;paint-order:fill markers stroke;stop-color:#000000;stop-opacity:1" + d="m 51.120353,8.2042965 c -0.03261,-0.010163 -0.05577,0.014998 -0.05577,0.068972 V 10.75681 c 0,0.09214 0.05211,0.118729 0.116349,0.05973 l 1.43352,-1.1996813 c 0.05017,-0.046071 0.05017,-0.1211999 0,-0.167271 L 51.155435,8.2265631 c -0.01254,-0.011517 -0.02421,-0.01888 -0.03509,-0.022267 z M 51.31696,8.7370657 52.310301,9.5337756 51.31696,10.32777 Z" /> diff --git a/files/opencs/record-up.svg b/files/opencs/record-up.svg index 351cb14d4a..28331ae42f 100644 --- a/files/opencs/record-up.svg +++ b/files/opencs/record-up.svg @@ -117,7 +117,7 @@ xlink:href="#Main-3" id="linearGradient6788" gradientUnits="userSpaceOnUse" - gradientTransform="matrix(3.7795276,0,0,3.7795276,-5.9999999,-6.9999999)" + gradientTransform="matrix(0.95388135,0,0,1.0509393,2.6074049,-0.4769654)" x1="2.116667" y1="-3.7041662" x2="6.3499999" @@ -137,8 +137,7 @@ rx="2.8318619e-14" /> + style="font-variation-settings:normal;opacity:1;vector-effect:none;fill:url(#linearGradient6788);fill-opacity:1;stroke:none;stroke-width:0.26491px;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;paint-order:fill markers stroke;stop-color:#000000;stop-opacity:1" + d="m 51.120277,8.2042951 c -0.03261,-0.010162 -0.0557,0.014998 -0.0557,0.068972 v 2.4835409 c 0,0.09214 0.05209,0.118729 0.116333,0.05974 l 1.433536,-1.1996855 c 0.05018,-0.04607 0.05018,-0.1211998 0,-0.167271 L 51.155278,8.2265617 c -0.01254,-0.011517 -0.02412,-0.01888 -0.035,-0.022267 z m 0.197668,0.5327694 0.992382,0.7967099 -0.992382,0.7939946 z" /> diff --git a/files/shaders/lib/light/lighting_util.glsl b/files/shaders/lib/light/lighting_util.glsl index afa38af86b..059f024b4a 100644 --- a/files/shaders/lib/light/lighting_util.glsl +++ b/files/shaders/lib/light/lighting_util.glsl @@ -59,6 +59,39 @@ uniform int PointLightCount; #endif +float lcalcConstantAttenuation(int lightIndex) +{ +#if @lightingMethodPerObjectUniform + return @getLight[lightIndex][0].w; +#elif @lightingMethodUBO + return @getLight[lightIndex].attenuation.x; +#else + return @getLight[lightIndex].constantAttenuation; +#endif +} + +float lcalcLinearAttenuation(int lightIndex) +{ +#if @lightingMethodPerObjectUniform + return @getLight[lightIndex][1].w; +#elif @lightingMethodUBO + return @getLight[lightIndex].attenuation.y; +#else + return @getLight[lightIndex].linearAttenuation; +#endif +} + +float lcalcQuadraticAttenuation(int lightIndex) +{ +#if @lightingMethodPerObjectUniform + return @getLight[lightIndex][2].w; +#elif @lightingMethodUBO + return @getLight[lightIndex].attenuation.z; +#else + return @getLight[lightIndex].quadraticAttenuation; +#endif +} + #if !@lightingMethodFFP float lcalcRadius(int lightIndex) { @@ -70,17 +103,16 @@ float lcalcRadius(int lightIndex) } #endif -float lcalcIllumination(int lightIndex, float lightDistance) +float lcalcIllumination(int lightIndex, float dist) { -#if @lightingMethodPerObjectUniform - float illumination = clamp(1.0 / (@getLight[lightIndex][0].w + @getLight[lightIndex][1].w * lightDistance + @getLight[lightIndex][2].w * lightDistance * lightDistance), 0.0, 1.0); - return (illumination * (1.0 - quickstep((lightDistance / lcalcRadius(lightIndex)) - 1.0))); -#elif @lightingMethodUBO - float illumination = clamp(1.0 / (@getLight[lightIndex].attenuation.x + @getLight[lightIndex].attenuation.y * lightDistance + @getLight[lightIndex].attenuation.z * lightDistance * lightDistance), 0.0, 1.0); - return (illumination * (1.0 - quickstep((lightDistance / lcalcRadius(lightIndex)) - 1.0))); -#else - return clamp(1.0 / (@getLight[lightIndex].constantAttenuation + @getLight[lightIndex].linearAttenuation * lightDistance + @getLight[lightIndex].quadraticAttenuation * lightDistance * lightDistance), 0.0, 1.0); + float illumination = 1.0 / (lcalcConstantAttenuation(lightIndex) + lcalcLinearAttenuation(lightIndex) * dist + lcalcQuadraticAttenuation(lightIndex) * dist * dist); + // FIXME: FFP doesn't do this + illumination = clamp(illumination, 0.0, 1.0); +#if @lightingMethodPerObjectUniform || @lightingMethodUBO + // Fade illumination between the radius and the radius doubled to diminish pop-in + illumination *= 1.0 - quickstep((dist / lcalcRadius(lightIndex)) - 1.0); #endif + return illumination; } vec3 lcalcPosition(int lightIndex)