diff --git a/CHANGELOG.md b/CHANGELOG.md
index a2df2e025e..e3b281b909 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -75,6 +75,7 @@
Feature #8580: Sort characters in the save loading menu
Feature #8597: Lua: Add more built-in event handlers
Feature #8629: Expose path grid data to Lua
+ Feature #8654: Allow lua world.createRecord to create NPC records
0.49.0
------
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 57ebeefcfd..201cc600c7 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -82,7 +82,7 @@ message(STATUS "Configuring OpenMW...")
set(OPENMW_VERSION_MAJOR 0)
set(OPENMW_VERSION_MINOR 50)
set(OPENMW_VERSION_RELEASE 0)
-set(OPENMW_LUA_API_REVISION 87)
+set(OPENMW_LUA_API_REVISION 90)
set(OPENMW_POSTPROCESSING_API_REVISION 3)
set(OPENMW_VERSION_COMMITHASH "")
diff --git a/apps/launcher/settingspage.cpp b/apps/launcher/settingspage.cpp
index 849f13076d..39396f1273 100644
--- a/apps/launcher/settingspage.cpp
+++ b/apps/launcher/settingspage.cpp
@@ -303,6 +303,9 @@ bool Launcher::SettingsPage::loadSettings()
loadSettingBool(Settings::gui().mColorTopicEnable, *changeDialogTopicsCheckBox);
showOwnedComboBox->setCurrentIndex(Settings::game().mShowOwned);
loadSettingBool(Settings::gui().mStretchMenuBackground, *stretchBackgroundCheckBox);
+ connect(controllerMenusCheckBox, &QCheckBox::toggled, this, &SettingsPage::slotControllerMenusToggled);
+ loadSettingBool(Settings::gui().mControllerMenus, *controllerMenusCheckBox);
+ loadSettingBool(Settings::gui().mControllerTooltips, *controllerMenuTooltipsCheckBox);
loadSettingBool(Settings::map().mAllowZooming, *useZoomOnMapCheckBox);
loadSettingBool(Settings::game().mGraphicHerbalism, *graphicHerbalismCheckBox);
scalingSpinBox->setValue(Settings::gui().mScalingFactor);
@@ -496,6 +499,8 @@ void Launcher::SettingsPage::saveSettings()
saveSettingBool(*changeDialogTopicsCheckBox, Settings::gui().mColorTopicEnable);
saveSettingInt(*showOwnedComboBox, Settings::game().mShowOwned);
saveSettingBool(*stretchBackgroundCheckBox, Settings::gui().mStretchMenuBackground);
+ saveSettingBool(*controllerMenusCheckBox, Settings::gui().mControllerMenus);
+ saveSettingBool(*controllerMenuTooltipsCheckBox, Settings::gui().mControllerTooltips);
saveSettingBool(*useZoomOnMapCheckBox, Settings::map().mAllowZooming);
saveSettingBool(*graphicHerbalismCheckBox, Settings::game().mGraphicHerbalism);
Settings::gui().mScalingFactor.set(scalingSpinBox->value());
@@ -554,6 +559,11 @@ void Launcher::SettingsPage::slotAnimSourcesToggled(bool checked)
}
}
+void Launcher::SettingsPage::slotControllerMenusToggled(bool checked)
+{
+ controllerMenuTooltipsCheckBox->setEnabled(checked);
+}
+
void Launcher::SettingsPage::slotPostProcessToggled(bool checked)
{
postprocessTransparentPostpassCheckBox->setEnabled(checked);
diff --git a/apps/launcher/settingspage.hpp b/apps/launcher/settingspage.hpp
index d2bb80d86a..2c6eca477a 100644
--- a/apps/launcher/settingspage.hpp
+++ b/apps/launcher/settingspage.hpp
@@ -34,6 +34,7 @@ namespace Launcher
void slotSkyBlendingToggled(bool checked);
void slotShadowDistLimitToggled(bool checked);
void slotDistantLandToggled(bool checked);
+ void slotControllerMenusToggled(bool checked);
private:
Config::GameSettings& mGameSettings;
diff --git a/apps/launcher/ui/settingspage.ui b/apps/launcher/ui/settingspage.ui
index d7e1a4b3ab..a591c196c9 100644
--- a/apps/launcher/ui/settingspage.ui
+++ b/apps/launcher/ui/settingspage.ui
@@ -1433,6 +1433,29 @@
+ -
+
+
+ <html><head/><body><p>Make it easier to use game menus with a controller.</p></body></html>
+
+
+ Enable Controller Menus
+
+
+
+ -
+
+
+ false
+
+
+ <html><head/><body><p>When using controller menus, make tooltips visible by default.</p></body></html>
+
+
+ Show Controller Tooltips By Default
+
+
+
-
diff --git a/apps/opencs/model/doc/savingstages.cpp b/apps/opencs/model/doc/savingstages.cpp
index 12fa6e811f..492807eb93 100644
--- a/apps/opencs/model/doc/savingstages.cpp
+++ b/apps/opencs/model/doc/savingstages.cpp
@@ -291,8 +291,7 @@ int CSMDoc::WriteCellCollectionStage::setup()
return mDocument.getData().getCells().getSize();
}
-void CSMDoc::WriteCellCollectionStage::writeReferences(
- const std::deque& references, bool interior, unsigned int& newRefNum)
+void CSMDoc::WriteCellCollectionStage::writeReferences(const std::deque& references, bool interior)
{
ESM::ESMWriter& writer = mState.getWriter();
@@ -304,6 +303,8 @@ void CSMDoc::WriteCellCollectionStage::writeReferences(
{
CSMWorld::CellRef refRecord = ref.get();
+ const bool isLocal = refRecord.mRefNum.mContentFile == -1;
+
// -1 is the current file, saved indices are 1-based
refRecord.mRefNum.mContentFile++;
@@ -316,12 +317,7 @@ void CSMDoc::WriteCellCollectionStage::writeReferences(
}
ESM::RefId streamId = ESM::RefId::stringRefId(stream.str());
- if (refRecord.mNew || refRecord.mRefNum.mIndex == 0
- || (!interior && ref.mState == CSMWorld::RecordBase::State_ModifiedOnly && refRecord.mCell != streamId))
- {
- refRecord.mRefNum.mIndex = newRefNum++;
- }
- else if ((refRecord.mOriginalCell.empty() ? refRecord.mCell : refRecord.mOriginalCell) != streamId
+ if (!isLocal && (refRecord.mOriginalCell.empty() ? refRecord.mCell : refRecord.mOriginalCell) != streamId
&& !interior)
{
// An empty mOriginalCell is meant to indicate that it is the same as
@@ -362,9 +358,6 @@ void CSMDoc::WriteCellCollectionStage::perform(int stage, Messages& messages)
CSMWorld::Cell cellRecord = cell.get();
const bool interior = !cellRecord.mId.startsWith("#");
- // count new references and adjust RefNumCount accordingsly
- unsigned int newRefNum = cellRecord.mRefNumCounter;
-
if (references != nullptr)
{
for (std::deque::const_iterator iter(references->begin()); iter != references->end(); ++iter)
@@ -390,9 +383,6 @@ void CSMDoc::WriteCellCollectionStage::perform(int stage, Messages& messages)
ESM::RefId::stringRefId(CSMWorld::CellCoordinates(refRecord.getCellIndex()).getId(""))
!= refRecord.mCell))
++cellRecord.mRefNumCounter;
-
- if (refRecord.mRefNum.mIndex >= newRefNum)
- newRefNum = refRecord.mRefNum.mIndex + 1;
}
}
@@ -415,9 +405,9 @@ void CSMDoc::WriteCellCollectionStage::perform(int stage, Messages& messages)
// write references
if (references != nullptr)
{
- writeReferences(persistentRefs, interior, newRefNum);
+ writeReferences(persistentRefs, interior);
cellRecord.saveTempMarker(writer, static_cast(references->size()) - persistentRefs.size());
- writeReferences(tempRefs, interior, newRefNum);
+ writeReferences(tempRefs, interior);
}
writer.endRecord(cellRecord.sRecordId);
diff --git a/apps/opencs/model/doc/savingstages.hpp b/apps/opencs/model/doc/savingstages.hpp
index 5423b8f504..1f86af10a2 100644
--- a/apps/opencs/model/doc/savingstages.hpp
+++ b/apps/opencs/model/doc/savingstages.hpp
@@ -167,7 +167,7 @@ namespace CSMDoc
Document& mDocument;
SavingState& mState;
- void writeReferences(const std::deque& references, bool interior, unsigned int& newRefNum);
+ void writeReferences(const std::deque& references, bool interior);
public:
WriteCellCollectionStage(Document& document, SavingState& state);
diff --git a/apps/opencs/model/world/collection.hpp b/apps/opencs/model/world/collection.hpp
index fa42ee0f09..18fb73330c 100644
--- a/apps/opencs/model/world/collection.hpp
+++ b/apps/opencs/model/world/collection.hpp
@@ -273,15 +273,6 @@ namespace CSMWorld
copy->mState = RecordBase::State_ModifiedOnly;
setRecordId(destination, copy->get());
- if constexpr (std::is_same_v)
- {
- if (type == UniversalId::Type_Reference)
- {
- CSMWorld::CellRef* ptr = (CSMWorld::CellRef*)©->mModified;
- ptr->mRefNum.mIndex = 0;
- }
- }
-
if constexpr (std::is_same_v)
{
copy->mModified.mStringId = copy->mModified.mId.getRefIdString();
diff --git a/apps/opencs/model/world/refcollection.cpp b/apps/opencs/model/world/refcollection.cpp
index 124e697de8..b2b6cec245 100644
--- a/apps/opencs/model/world/refcollection.cpp
+++ b/apps/opencs/model/world/refcollection.cpp
@@ -175,6 +175,9 @@ void CSMWorld::RefCollection::load(ESM::ESMReader& reader, int cellIndex, bool b
ref.mIdNum = mNextId; // FIXME: fragile
ref.mId = ESM::RefId::stringRefId(getNewId());
+ if (!base && ref.mRefNum.mIndex > mHighestUsedRefNum)
+ mHighestUsedRefNum = ref.mRefNum.mIndex;
+
cache.emplace(ref.mRefNum, ref.mIdNum);
auto record = std::make_unique>();
@@ -222,6 +225,11 @@ std::string CSMWorld::RefCollection::getNewId()
return "ref#" + std::to_string(mNextId++);
}
+uint32_t CSMWorld::RefCollection::getNextRefNum()
+{
+ return ++mHighestUsedRefNum;
+}
+
unsigned int CSMWorld::RefCollection::extractIdNum(std::string_view id) const
{
std::string::size_type separator = id.find_last_of('#');
@@ -283,6 +291,7 @@ void CSMWorld::RefCollection::appendBlankRecord(const ESM::RefId& id, UniversalI
record->get().mId = id;
record->get().mIdNum = extractIdNum(id.getRefIdString());
+ record->get().mRefNum.mIndex = getNextRefNum();
Collection::appendRecord(std::move(record));
}
@@ -298,15 +307,13 @@ void CSMWorld::RefCollection::cloneRecord(
copy->get().mId = destination;
copy->get().mIdNum = extractIdNum(destination.getRefIdString());
+ copy->get().mRefNum.mIndex = getNextRefNum();
if (copy->get().mRefNum.hasContentFile())
{
mRefIndex.insert(std::make_pair(static_cast*>(copy.get())->get().mIdNum, index));
copy->get().mRefNum.mContentFile = -1;
- copy->get().mRefNum.mIndex = index;
}
- else
- copy->get().mRefNum.mIndex = copy->get().mIdNum;
insertRecord(std::move(copy), getAppendIndex(destination, type)); // call RefCollection::insertRecord()
}
diff --git a/apps/opencs/model/world/refcollection.hpp b/apps/opencs/model/world/refcollection.hpp
index d3d200e6c2..f70167f922 100644
--- a/apps/opencs/model/world/refcollection.hpp
+++ b/apps/opencs/model/world/refcollection.hpp
@@ -1,6 +1,7 @@
#ifndef CSM_WOLRD_REFCOLLECTION_H
#define CSM_WOLRD_REFCOLLECTION_H
+#include
#include